-
Notifications
You must be signed in to change notification settings - Fork 6k
Creates a new RenderMode for FlutterView #19143
Changes from all commits
a57158a
a4e9f47
36e4834
1e8e646
bf77db9
228fb87
6bf656f
3a67995
bf5a9c2
527841e
79794a5
8a8fa24
9f18aae
e08f3cd
406d01d
d327aca
74148ce
d32aeb2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| package io.flutter.embedding.android; | ||
|
|
||
| import android.annotation.SuppressLint; | ||
| import android.annotation.TargetApi; | ||
| import android.content.Context; | ||
| import android.graphics.Bitmap; | ||
| import android.graphics.Canvas; | ||
| import android.graphics.ColorSpace; | ||
| import android.hardware.HardwareBuffer; | ||
| import android.media.Image; | ||
| import android.media.Image.Plane; | ||
| import android.media.ImageReader; | ||
| import android.view.View; | ||
| import androidx.annotation.NonNull; | ||
| import androidx.annotation.Nullable; | ||
|
|
||
| /** | ||
| * Paints a Flutter UI provided by an {@link android.media.ImageReader} onto a {@link | ||
| * android.graphics.Canvas}. | ||
| * | ||
| * <p>A {@code FlutterImageView} is intended for situations where a developer needs to render a | ||
| * Flutter UI, but also needs to render an interactive {@link | ||
| * io.flutter.plugin.platform.PlatformView}. | ||
| * | ||
| * <p>This {@code View} takes an {@link android.media.ImageReader} that provides the Flutter UI in | ||
| * an {@link android.media.Image} and renders it to the {@link android.graphics.Canvas} in {@code | ||
| * onDraw}. | ||
| */ | ||
| @SuppressLint("ViewConstructor") | ||
| @TargetApi(19) | ||
| public class FlutterImageView extends View { | ||
| private final ImageReader imageReader; | ||
| @Nullable private Image nextImage; | ||
| @Nullable private Image currentImage; | ||
|
|
||
| /** | ||
| * Constructs a {@code FlutterImageView} with an {@link android.media.ImageReader} that provides | ||
| * the Flutter UI. | ||
| */ | ||
| public FlutterImageView(@NonNull Context context, @NonNull ImageReader imageReader) { | ||
| super(context, null); | ||
| this.imageReader = imageReader; | ||
| } | ||
|
|
||
| /** Acquires the next image to be drawn to the {@link android.graphics.Canvas}. */ | ||
| @TargetApi(19) | ||
| public void acquireLatestImage() { | ||
| nextImage = imageReader.acquireLatestImage(); | ||
| invalidate(); | ||
| } | ||
|
|
||
| @Override | ||
| protected void onDraw(Canvas canvas) { | ||
| super.onDraw(canvas); | ||
| if (nextImage == null) { | ||
| return; | ||
| } | ||
|
|
||
| if (currentImage != null) { | ||
| currentImage.close(); | ||
| } | ||
| currentImage = nextImage; | ||
| nextImage = null; | ||
|
|
||
| if (android.os.Build.VERSION.SDK_INT >= 29) { | ||
| drawImageBuffer(canvas); | ||
| return; | ||
| } | ||
|
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. else: throw unsupported Android version
Contributor
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. Since, I moved the |
||
|
|
||
| drawImagePlane(canvas); | ||
| } | ||
|
|
||
| @TargetApi(29) | ||
| private void drawImageBuffer(@NonNull Canvas canvas) { | ||
| final HardwareBuffer buffer = currentImage.getHardwareBuffer(); | ||
|
|
||
| final Bitmap bitmap = Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB)); | ||
| canvas.drawBitmap(bitmap, 0, 0, null); | ||
| } | ||
|
|
||
| private void drawImagePlane(@NonNull Canvas canvas) { | ||
| if (currentImage == null) { | ||
| return; | ||
| } | ||
|
|
||
| final Plane[] imagePlanes = currentImage.getPlanes(); | ||
| if (imagePlanes.length != 1) { | ||
| return; | ||
| } | ||
|
|
||
| final Plane imagePlane = imagePlanes[0]; | ||
| final int desiredWidth = imagePlane.getRowStride() / imagePlane.getPixelStride(); | ||
| final int desiredHeight = currentImage.getHeight(); | ||
|
|
||
| final Bitmap bitmap = | ||
| android.graphics.Bitmap.createBitmap( | ||
| desiredWidth, desiredHeight, android.graphics.Bitmap.Config.ARGB_8888); | ||
|
|
||
| bitmap.copyPixelsFromBuffer(imagePlane.getBuffer()); | ||
| canvas.drawBitmap(bitmap, 0, 0, null); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -79,6 +79,7 @@ public class FlutterView extends FrameLayout implements MouseCursorPlugin.MouseC | |
| // Internal view hierarchy references. | ||
| @Nullable private FlutterSurfaceView flutterSurfaceView; | ||
| @Nullable private FlutterTextureView flutterTextureView; | ||
| @Nullable private FlutterImageView flutterImageView; | ||
| @Nullable private RenderSurface renderSurface; | ||
| private final Set<FlutterUiDisplayListener> flutterUiDisplayListeners = new HashSet<>(); | ||
| private boolean isFlutterUiDisplayed; | ||
|
|
@@ -155,7 +156,8 @@ public FlutterView(@NonNull Context context) { | |
|
|
||
| /** | ||
| * Deprecated - use {@link #FlutterView(Context, FlutterSurfaceView)} or {@link | ||
| * #FlutterView(Context, FlutterTextureView)} instead. | ||
| * #FlutterView(Context, FlutterTextureView)} or {@link #FlutterView(Context, FlutterImageView)} | ||
| * instead. | ||
| */ | ||
| @Deprecated | ||
| public FlutterView(@NonNull Context context, @NonNull RenderMode renderMode) { | ||
|
|
@@ -164,9 +166,12 @@ public FlutterView(@NonNull Context context, @NonNull RenderMode renderMode) { | |
| if (renderMode == RenderMode.surface) { | ||
| flutterSurfaceView = new FlutterSurfaceView(context); | ||
| renderSurface = flutterSurfaceView; | ||
| } else { | ||
| } else if (renderMode == RenderMode.texture) { | ||
| flutterTextureView = new FlutterTextureView(context); | ||
| renderSurface = flutterTextureView; | ||
| } else { | ||
| throw new IllegalArgumentException( | ||
| String.format("RenderMode not supported with this constructor: ", renderMode)); | ||
|
Contributor
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. Hi, the missing format arguments break Google test (here and below line 268). If we have not yet, can we fix this? 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. |
||
| } | ||
|
|
||
| init(); | ||
|
|
@@ -216,6 +221,18 @@ public FlutterView(@NonNull Context context, @NonNull FlutterTextureView flutter | |
| this(context, null, flutterTextureView); | ||
| } | ||
|
|
||
| /** | ||
| * Constructs a {@code FlutterView} programmatically, without any XML attributes, uses the given | ||
| * {@link FlutterImageView} to render the Flutter UI. | ||
| * | ||
| * <p>{@code FlutterView} requires an {@code Activity} instead of a generic {@code Context} to be | ||
| * compatible with {@link PlatformViewsController}. | ||
| */ | ||
| @TargetApi(19) | ||
| public FlutterView(@NonNull Context context, @NonNull FlutterImageView flutterImageView) { | ||
| this(context, null, flutterImageView); | ||
| } | ||
|
|
||
| /** | ||
| * Constructs a {@code FlutterView} in an XML-inflation-compliant manner. | ||
| * | ||
|
|
@@ -243,9 +260,12 @@ public FlutterView( | |
| flutterSurfaceView = | ||
| new FlutterSurfaceView(context, transparencyMode == TransparencyMode.transparent); | ||
| renderSurface = flutterSurfaceView; | ||
| } else { | ||
| } else if (renderMode == RenderMode.texture) { | ||
| flutterTextureView = new FlutterTextureView(context); | ||
| renderSurface = flutterTextureView; | ||
| } else { | ||
| throw new IllegalArgumentException( | ||
| String.format("RenderMode not supported with this constructor: ", renderMode)); | ||
| } | ||
|
|
||
| init(); | ||
|
|
@@ -275,15 +295,30 @@ private FlutterView( | |
| init(); | ||
| } | ||
|
|
||
| @TargetApi(19) | ||
| private FlutterView( | ||
| @NonNull Context context, | ||
| @Nullable AttributeSet attrs, | ||
| @NonNull FlutterImageView flutterImageView) { | ||
| super(context, attrs); | ||
|
|
||
| this.flutterImageView = flutterImageView; | ||
|
|
||
| init(); | ||
| } | ||
|
|
||
| private void init() { | ||
| Log.v(TAG, "Initializing FlutterView"); | ||
|
|
||
| if (flutterSurfaceView != null) { | ||
| Log.v(TAG, "Internally using a FlutterSurfaceView."); | ||
| addView(flutterSurfaceView); | ||
| } else { | ||
| } else if (flutterTextureView != null) { | ||
| Log.v(TAG, "Internally using a FlutterTextureView."); | ||
| addView(flutterTextureView); | ||
| } else { | ||
| Log.v(TAG, "Internally using a FlutterImageView."); | ||
| addView(flutterImageView); | ||
| } | ||
|
|
||
| // FlutterView needs to be focusable so that the InputMethodManager can interact with it. | ||
|
|
@@ -1018,7 +1053,16 @@ public enum RenderMode { | |
| * android.graphics.SurfaceTexture} are required, developers should strongly prefer the {@link | ||
| * RenderMode#surface} render mode. | ||
| */ | ||
| texture | ||
| texture, | ||
| /** | ||
| * {@code RenderMode}, which paints Paints a Flutter UI provided by an {@link | ||
| * android.media.ImageReader} onto a {@link android.graphics.Canvas}. This mode is not as | ||
| * performant as {@link RenderMode#surface}, but a {@code FlutterView} in this mode can handle | ||
| * full interactivity with a {@link io.flutter.plugin.platform.PlatformView}. Unless {@link | ||
| * io.flutter.plugin.platform.PlatformView}s are required developers should strongly prefer the | ||
| * {@link RenderMode#surface} render mode. | ||
|
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. this is awesome! |
||
| */ | ||
| image | ||
| } | ||
|
|
||
| /** | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.