Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -80,29 +80,47 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result

private void create(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
Map<String, Object> createArgs = call.arguments();
double width = (createArgs.containsKey("width")) ? (double) createArgs.get("width") : 0;
double height =
(createArgs.containsKey("height")) ? (double) createArgs.get("height") : 0;
boolean usesHybridComposition =
createArgs.containsKey("hybrid") && (boolean) createArgs.get("hybrid");

PlatformViewCreationRequest request =
new PlatformViewCreationRequest(
(int) createArgs.get("id"),
(String) createArgs.get("viewType"),
(double) createArgs.get("width"),
(double) createArgs.get("height"),
width,
height,
(int) createArgs.get("direction"),
createArgs.containsKey("params")
? ByteBuffer.wrap((byte[]) createArgs.get("params"))
: null);

try {
long textureId = handler.createPlatformView(request);
result.success(textureId);
if (usesHybridComposition) {
handler.createAndroidViewForPlatformView(request);
result.success(null);
} else {
long textureId = handler.createVirtualDisplayForPlatformView(request);
result.success(textureId);
}
} catch (IllegalStateException exception) {
result.error("error", detailedExceptionString(exception), null);
}
}

private void dispose(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
int viewId = call.arguments();
Map<String, Object> disposeArgs = call.arguments();
int viewId = (int) disposeArgs.get("id");
boolean usesHybridComposition =
disposeArgs.containsKey("hybrid") && (boolean) disposeArgs.get("hybrid");

try {
handler.disposePlatformView(viewId);
if (usesHybridComposition) {
handler.disposeAndroidViewForPlatformView(viewId);
} else {
handler.disposeVirtualDisplayForPlatformView(viewId);
}
result.success(null);
} catch (IllegalStateException exception) {
result.error("error", detailedExceptionString(exception), null);
Expand Down Expand Up @@ -216,18 +234,29 @@ public interface PlatformViewsHandler {
* The Flutter application would like to display a new Android {@code View}, i.e., platform
* view.
*
* <p>The handler should instantiate the desired Android {@code View}, create a new {@link
* io.flutter.view.FlutterView.SurfaceTextureRegistryEntry} within the given Flutter execution
* context, and then return the new texture's ID.
* <p>The Android {@code View} is added to the view hierarchy.
*/
// TODO(mattcarroll): Introduce an annotation for @TextureId
long createPlatformView(@NonNull PlatformViewCreationRequest request);
void createAndroidViewForPlatformView(@NonNull PlatformViewCreationRequest request);

/**
* The Flutter application could like dispose of an existing Android {@code View}, i.e.,
* platform view.
* The Flutter application would like dispose of an existing Android {@code View} rendered in
Copy link
Member

Choose a reason for hiding this comment

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

typo: "would like to dispose"

Copy link
Author

Choose a reason for hiding this comment

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

Done.

* the view hierarchy.
*/
void disposePlatformView(int viewId);
void disposeAndroidViewForPlatformView(int viewId);

/**
* The Flutter application would like to display a new Android {@code View}.
*
* <p>{@code View} is added to a {@code VirtualDisplay}. The framework uses id returned by this
* method to lookup the texture in the engine.
*/
long createVirtualDisplayForPlatformView(@NonNull PlatformViewCreationRequest request);

/**
* The Flutter application would like dispose of an existing Android {@code View} rendered in a
* virtual display.
*/
void disposeVirtualDisplayForPlatformView(int viewId);

/**
* The Flutter application would like to resize an existing Android {@code View}, i.e., platform
Expand Down Expand Up @@ -279,6 +308,7 @@ public static class PlatformViewCreationRequest {
/** Custom parameters that are unique to the desired platform view. */
@Nullable public final ByteBuffer params;

/** Creates a request to construct a platform view that uses a virtual display. */
public PlatformViewCreationRequest(
int viewId,
@NonNull String viewType,
Expand All @@ -295,7 +325,11 @@ public PlatformViewCreationRequest(
}
}

/** Request sent from Flutter to resize a platform view. */
/**
* Request sent from Flutter to resize a platform view.
*
* <p>This only applies to platform views that use virtual displays.
*/
public static class PlatformViewResizeRequest {
/** The ID of the platform view as seen by the Flutter side. */
public final int viewId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,6 @@
public class PlatformViewsController implements PlatformViewsAccessibilityDelegate {
private static final String TAG = "PlatformViewsController";

// API level 20 is required for VirtualDisplay#setSurface which we use when resizing a platform
// view.
private static final int MINIMAL_SDK = Build.VERSION_CODES.KITKAT_WATCH;

private final PlatformViewRegistryImpl registry;

// The context of the Activity or Fragment hosting the render target for the Flutter engine.
Expand Down Expand Up @@ -80,6 +76,9 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
// it is associated with(e.g if a platform view creates other views in the same virtual display.
private final HashMap<Context, View> contextToPlatformView;

private final SparseArray<PlatformViewsChannel.PlatformViewCreationRequest> platformViewRequests;
private final SparseArray<View> platformViews;

// Map of unique IDs to views that render overlay layers.
private final SparseArray<FlutterImageView> overlayLayerViews;

Expand All @@ -94,12 +93,34 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega

private final PlatformViewsChannel.PlatformViewsHandler channelHandler =
new PlatformViewsChannel.PlatformViewsHandler() {
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)

@Override
public long createPlatformView(
public void createAndroidViewForPlatformView(
@NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
ensureValidAndroidVersion();
// API level 19 is required for android.graphics.ImageReader.
ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT);
platformViewRequests.put(request.viewId, request);
}

@Override
public void disposeAndroidViewForPlatformView(int viewId) {
// Hybrid view.
if (platformViewRequests.get(viewId) != null) {
platformViewRequests.remove(viewId);
}
if (platformViews.get(viewId) != null) {
((FlutterView) flutterView).addView(platformViews.get(viewId));
platformViews.remove(viewId);
}
}

@Override
public long createVirtualDisplayForPlatformView(
@NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
// API level 20 is required for VirtualDisplay#setSurface which we use when resizing a
// platform
Copy link
Member

Choose a reason for hiding this comment

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

typo: put "platform view" on one line

Copy link
Author

Choose a reason for hiding this comment

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

Done.

// view.
ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT_WATCH);
if (!validateDirection(request.direction)) {
throw new IllegalStateException(
"Trying to create a view with unknown direction value: "
Expand Down Expand Up @@ -171,9 +192,8 @@ public long createPlatformView(
}

@Override
public void disposePlatformView(int viewId) {
ensureValidAndroidVersion();

public void disposeVirtualDisplayForPlatformView(int viewId) {
ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT_WATCH);
VirtualDisplayController vdController = vdControllers.get(viewId);
if (vdController == null) {
throw new IllegalStateException(
Expand All @@ -193,7 +213,7 @@ public void disposePlatformView(int viewId) {
public void resizePlatformView(
@NonNull PlatformViewsChannel.PlatformViewResizeRequest request,
@NonNull Runnable onComplete) {
ensureValidAndroidVersion();
ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT_WATCH);

final VirtualDisplayController vdController = vdControllers.get(request.viewId);
if (vdController == null) {
Expand Down Expand Up @@ -224,8 +244,6 @@ public void run() {

@Override
public void onTouch(@NonNull PlatformViewsChannel.PlatformViewTouch touch) {
ensureValidAndroidVersion();

float density = context.getResources().getDisplayMetrics().density;
PointerProperties[] pointerProperties =
parsePointerPropertiesList(touch.rawPointerPropertiesList)
Expand Down Expand Up @@ -256,14 +274,12 @@ public void onTouch(@NonNull PlatformViewsChannel.PlatformViewTouch touch) {
touch.source,
touch.flags);

ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT_WATCH);
vdControllers.get(touch.viewId).dispatchTouchEvent(event);
}

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public void setDirection(int viewId, int direction) {
ensureValidAndroidVersion();

if (!validateDirection(direction)) {
throw new IllegalStateException(
"Trying to set unknown direction value: "
Expand All @@ -273,6 +289,7 @@ public void setDirection(int viewId, int direction) {
+ ")");
}

ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT_WATCH);
View view = vdControllers.get(viewId).getView();
if (view == null) {
throw new IllegalStateException(
Expand All @@ -284,17 +301,18 @@ public void setDirection(int viewId, int direction) {

@Override
public void clearFocus(int viewId) {
ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT_WATCH);
View view = vdControllers.get(viewId).getView();
view.clearFocus();
}

private void ensureValidAndroidVersion() {
if (Build.VERSION.SDK_INT < MINIMAL_SDK) {
private void ensureValidAndroidVersion(int minSdkVersion) {
if (Build.VERSION.SDK_INT < minSdkVersion) {
throw new IllegalStateException(
"Trying to use platform views with API "
+ Build.VERSION.SDK_INT
+ ", required API level is: "
+ MINIMAL_SDK);
+ minSdkVersion);
}
}
};
Expand All @@ -306,6 +324,9 @@ public PlatformViewsController() {
contextToPlatformView = new HashMap<>();
overlayLayerViews = new SparseArray<>();
currentFrameUsedOverlayLayerIds = new HashSet<>();

platformViewRequests = new SparseArray<>();
platformViews = new SparseArray<>();
}

/**
Expand Down Expand Up @@ -565,13 +586,60 @@ private void initializeRootImageViewIfNeeded() {
}
}

private void initializePlatformViewIfNeeded(int viewId) {
if (platformViews.get(viewId) != null) {
return;
}

PlatformViewsChannel.PlatformViewCreationRequest request = platformViewRequests.get(viewId);
if (request == null) {
throw new IllegalStateException(
"Platform view hasn't been initialized from the platform view channel.");
}

if (!validateDirection(request.direction)) {
throw new IllegalStateException(
"Trying to create a view with unknown direction value: "
+ request.direction
+ "(view id: "
+ viewId
+ ")");
}

PlatformViewFactory factory = registry.getFactory(request.viewType);
if (factory == null) {
throw new IllegalStateException(
"Trying to create a platform view of unregistered type: " + request.viewType);
}

Object createParams = null;
if (request.params != null) {
createParams = factory.getCreateArgsCodec().decodeMessage(request.params);
}

PlatformView platformView = factory.create(context, viewId, createParams);
View view = platformView.getView();
platformViews.put(viewId, view);

((FlutterView) flutterView).addView(view);
}

public void onDisplayPlatformView(int viewId, int x, int y, int width, int height) {
initializeRootImageViewIfNeeded();
// TODO: Implement this method. https://github.com/flutter/flutter/issues/58288
initializePlatformViewIfNeeded(viewId);

View platformView = platformViews.get(viewId);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams((int) width, (int) height);
layoutParams.leftMargin = (int) x;
layoutParams.topMargin = (int) y;
platformView.setLayoutParams(layoutParams);
platformView.setVisibility(View.VISIBLE);
platformView.bringToFront();
}

public void onDisplayOverlaySurface(int id, int x, int y, int width, int height) {
initializeRootImageViewIfNeeded();

FlutterImageView overlayView = overlayLayerViews.get(id);
if (overlayView.getParent() == null) {
((FlutterView) flutterView).addView(overlayView);
Expand Down