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

Reland: Create PlatformView instance right after method channel call from Dart #20568

Merged
merged 4 commits into from
Aug 17, 2020
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,20 @@ 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;
// The views returned by `PlatformView#getView()`.
//
// This only applies to hybrid composition.
private final SparseArray<View> platformViews;
private final SparseArray<FlutterMutatorView> mutatorViews;

// The platform view parents that are appended to `FlutterView`.
// If an entry in `platformViews` doesn't have an entry in this array, the platform view isn't
// in the view hierarchy.
//
// This view provides a wrapper that applies scene builder operations to the platform view.
// For example, a transform matrix, or setting opacity on the platform view layer.
//
// This is only applies to hybrid composition.
private final SparseArray<FlutterMutatorView> platformViewParent;

// Map of unique IDs to views that render overlay layers.
private final SparseArray<FlutterImageView> overlayLayerViews;
Expand All @@ -107,25 +118,57 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
@Override
public void createAndroidViewForPlatformView(
@NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
// API level 19 is required for android.graphics.ImageReader.
// API level 19 is required for `android.graphics.ImageReader`.
ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT);
platformViewRequests.put(request.viewId, request);

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

final 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);
}

final PlatformView platformView = factory.create(context, request.viewId, createParams);
final View view = platformView.getView();
if (view == null) {
throw new IllegalStateException(
"PlatformView#getView() returned null, but an Android view reference was expected.");
}
if (view.getParent() != null) {
throw new IllegalStateException(
"The Android view returned from PlatformView#getView() was already added to a parent view.");
}
platformViews.put(request.viewId, view);
}

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

final View platformView = platformViews.get(viewId);
final FlutterMutatorView parentView = platformViewParent.get(viewId);
if (platformView != null) {
final FlutterMutatorView mutatorView = mutatorViews.get(viewId);
mutatorView.removeView(platformView);
((FlutterView) flutterView).removeView(mutatorView);
if (parentView != null) {
parentView.removeView(platformView);
}
platformViews.remove(viewId);
mutatorViews.remove(viewId);
}

if (parentView != null) {
((FlutterView) flutterView).removeView(parentView);
platformViewParent.remove(viewId);
}
}

Expand Down Expand Up @@ -378,9 +421,8 @@ public PlatformViewsController() {
currentFrameUsedOverlayLayerIds = new HashSet<>();
currentFrameUsedPlatformViewIds = new HashSet<>();

platformViewRequests = new SparseArray<>();
platformViews = new SparseArray<>();
mutatorViews = new SparseArray<>();
platformViewParent = new SparseArray<>();

motionEventTracker = MotionEventTracker.getInstance();
}
Expand Down Expand Up @@ -651,55 +693,20 @@ private void initializeRootImageViewIfNeeded() {

@VisibleForTesting
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();

final View view = platformViews.get(viewId);
if (view == null) {
throw new IllegalStateException(
"PlatformView#getView() returned null, but an Android view reference was expected.");
"Platform view hasn't been initialized from the platform view channel.");
}
if (view.getParent() != null) {
throw new IllegalStateException(
"The Android view returned from PlatformView#getView() was already added to a parent view.");
if (platformViewParent.get(viewId) != null) {
return;
}
platformViews.put(viewId, view);

FlutterMutatorView mutatorView =
final FlutterMutatorView parentView =
new FlutterMutatorView(
context, context.getResources().getDisplayMetrics().density, androidTouchProcessor);
mutatorViews.put(viewId, mutatorView);
mutatorView.addView(view);
((FlutterView) flutterView).addView(mutatorView);
platformViewParent.put(viewId, parentView);
parentView.addView(view);
((FlutterView) flutterView).addView(parentView);
}

public void attachToFlutterRenderer(FlutterRenderer flutterRenderer) {
Expand All @@ -718,13 +725,14 @@ public void onDisplayPlatformView(
initializeRootImageViewIfNeeded();
initializePlatformViewIfNeeded(viewId);

FlutterMutatorView mutatorView = mutatorViews.get(viewId);
mutatorView.readyToDisplay(mutatorsStack, x, y, width, height);
mutatorView.setVisibility(View.VISIBLE);
mutatorView.bringToFront();
final FlutterMutatorView parentView = platformViewParent.get(viewId);
parentView.readyToDisplay(mutatorsStack, x, y, width, height);
parentView.setVisibility(View.VISIBLE);
parentView.bringToFront();

FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(viewWidth, viewHeight);
View platformView = platformViews.get(viewId);
final FrameLayout.LayoutParams layoutParams =
new FrameLayout.LayoutParams(viewWidth, viewHeight);
final View platformView = platformViews.get(viewId);
platformView.setLayoutParams(layoutParams);
platformView.bringToFront();
currentFrameUsedPlatformViewIds.add(viewId);
Expand All @@ -733,7 +741,7 @@ public void onDisplayPlatformView(
public void onDisplayOverlaySurface(int id, int x, int y, int width, int height) {
initializeRootImageViewIfNeeded();

FlutterImageView overlayView = overlayLayerViews.get(id);
final FlutterImageView overlayView = overlayLayerViews.get(id);
if (overlayView.getParent() == null) {
((FlutterView) flutterView).addView(overlayView);
}
Expand Down Expand Up @@ -776,19 +784,19 @@ public void onEndFrame() {
// If one of the surfaces doesn't have an image, the frame may be incomplete and must be
// dropped.
// For example, a toolbar widget painted by Flutter may not be rendered.
boolean isFrameRenderedUsingImageReaders =
final boolean isFrameRenderedUsingImageReaders =
flutterViewConvertedToImageView && view.acquireLatestImageViewFrame();
finishFrame(isFrameRenderedUsingImageReaders);
}

private void finishFrame(boolean isFrameRenderedUsingImageReaders) {
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);

if (currentFrameUsedOverlayLayerIds.contains(overlayId)) {
((FlutterView) flutterView).attachOverlaySurfaceToRender(overlayView);
boolean didAcquireOverlaySurfaceImage = overlayView.acquireLatestImage();
final boolean didAcquireOverlaySurfaceImage = overlayView.acquireLatestImage();
isFrameRenderedUsingImageReaders &= didAcquireOverlaySurfaceImage;
} else {
// If the background surface isn't rendered by the image view, then the
Expand All @@ -802,22 +810,20 @@ private void finishFrame(boolean isFrameRenderedUsingImageReaders) {
}
}

for (int i = 0; i < platformViews.size(); i++) {
int viewId = platformViews.keyAt(i);
View platformView = platformViews.get(viewId);
View mutatorView = mutatorViews.get(viewId);
for (int i = 0; i < platformViewParent.size(); i++) {
final int viewId = platformViewParent.keyAt(i);
final View parentView = platformViewParent.get(viewId);
Copy link
Member

Choose a reason for hiding this comment

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

Is it possible parentView will be null?

Copy link
Author

Choose a reason for hiding this comment

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

It's not possible. This is iterating over the existing entries, and the code never puts null in the dictionary.


// Show platform views only if the surfaces have images available in this frame,
// and if the platform view is rendered in this frame.
// The platform view is appended to a mutator view.
//
// Otherwise, hide the platform view, but don't remove it from the view hierarchy yet as
// they are removed when the framework diposes the platform view widget.
if (isFrameRenderedUsingImageReaders && currentFrameUsedPlatformViewIds.contains(viewId)) {
platformView.setVisibility(View.VISIBLE);
mutatorView.setVisibility(View.VISIBLE);
parentView.setVisibility(View.VISIBLE);
} else {
platformView.setVisibility(View.GONE);
mutatorView.setVisibility(View.GONE);
parentView.setVisibility(View.GONE);
}
}
}
Expand Down
Loading