This repository was archived by the owner on Feb 25, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6k
Reland: Create PlatformView instance right after method channel call from Dart #20568
Merged
Merged
Changes from 2 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 view returned by `PlatformView#getView()`. | ||
| // | ||
| // This only applies to hybrid composition. | ||
| private final SparseArray<View> platformViews; | ||
| private final SparseArray<FlutterMutatorView> mutatorViews; | ||
|
|
||
| // The platform view parent that is 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; | ||
|
|
@@ -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); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -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(); | ||
| } | ||
|
|
@@ -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) { | ||
|
|
@@ -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); | ||
|
|
@@ -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); | ||
| } | ||
|
|
@@ -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 | ||
|
|
@@ -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); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible parentView will be null?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
|
|
||
| // 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); | ||
| } | ||
| } | ||
| } | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nits: views
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done