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

Commit b33dd4b

Browse files
committed
Initial work toward converting the FlutterView to use a FlutterImageView on demand
1 parent 291dab6 commit b33dd4b

File tree

3 files changed

+113
-54
lines changed

3 files changed

+113
-54
lines changed

shell/platform/android/io/flutter/embedding/android/FlutterImageView.java

Lines changed: 64 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import android.view.View;
1818
import androidx.annotation.NonNull;
1919
import androidx.annotation.Nullable;
20+
import io.flutter.embedding.engine.renderer.FlutterRenderer;
21+
import io.flutter.embedding.engine.renderer.RenderSurface;
2022

2123
/**
2224
* Paints a Flutter UI provided by an {@link android.media.ImageReader} onto a {@link
@@ -32,10 +34,12 @@
3234
*/
3335
@SuppressLint("ViewConstructor")
3436
@TargetApi(19)
35-
public class FlutterImageView extends View {
37+
public class FlutterImageView extends View implements RenderSurface {
3638
private final ImageReader imageReader;
3739
@Nullable private Image nextImage;
3840
@Nullable private Image currentImage;
41+
@Nullable private Bitmap currentBitmap;
42+
@Nullable private FlutterRenderer flutterRenderer;
3943

4044
/**
4145
* Constructs a {@code FlutterImageView} with an {@link android.media.ImageReader} that provides
@@ -46,6 +50,37 @@ public FlutterImageView(@NonNull Context context, @NonNull ImageReader imageRead
4650
this.imageReader = imageReader;
4751
}
4852

53+
@Nullable
54+
@Override
55+
public FlutterRenderer getAttachedRenderer() {
56+
return flutterRenderer;
57+
}
58+
59+
/**
60+
* Invoked by the owner of this {@code FlutterImageView} when it wants to begin rendering a
61+
* Flutter UI to this {@code FlutterImageView}.
62+
*/
63+
@Override
64+
public void attachToRenderer(@NonNull FlutterRenderer flutterRenderer) {
65+
if (this.flutterRenderer != null) {
66+
this.flutterRenderer.stopRenderingToSurface();
67+
}
68+
69+
this.flutterRenderer = flutterRenderer;
70+
flutterRenderer.startRenderingToSurface(imageReader.getSurface());
71+
}
72+
73+
/**
74+
* Invoked by the owner of this {@code FlutterTextureView} when it no longer wants to render a
75+
* Flutter UI to this {@code FlutterTextureView}.
76+
*/
77+
public void detachFromRenderer() {
78+
if (flutterRenderer != null) {
79+
flutterRenderer.stopRenderingToSurface();
80+
flutterRenderer = null;
81+
}
82+
}
83+
4984
/** Acquires the next image to be drawn to the {@link android.graphics.Canvas}. */
5085
@TargetApi(19)
5186
public void acquireLatestImage() {
@@ -56,51 +91,40 @@ public void acquireLatestImage() {
5691
@Override
5792
protected void onDraw(Canvas canvas) {
5893
super.onDraw(canvas);
59-
if (nextImage == null) {
60-
return;
61-
}
62-
63-
if (currentImage != null) {
64-
currentImage.close();
94+
if (nextImage != null) {
95+
if (currentImage != null) {
96+
currentImage.close();
97+
}
98+
currentImage = nextImage;
99+
nextImage = null;
100+
updateCurrentBitmap();
65101
}
66-
currentImage = nextImage;
67-
nextImage = null;
68102

69-
if (android.os.Build.VERSION.SDK_INT >= 29) {
70-
drawImageBuffer(canvas);
71-
return;
103+
if (currentBitmap != null) {
104+
canvas.drawBitmap(currentBitmap, 0, 0, null);
72105
}
73-
74-
drawImagePlane(canvas);
75106
}
76107

77108
@TargetApi(29)
78-
private void drawImageBuffer(@NonNull Canvas canvas) {
79-
final HardwareBuffer buffer = currentImage.getHardwareBuffer();
80-
81-
final Bitmap bitmap = Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB));
82-
canvas.drawBitmap(bitmap, 0, 0, null);
83-
}
84-
85-
private void drawImagePlane(@NonNull Canvas canvas) {
86-
if (currentImage == null) {
87-
return;
88-
}
89-
90-
final Plane[] imagePlanes = currentImage.getPlanes();
91-
if (imagePlanes.length != 1) {
92-
return;
109+
private void updateCurrentBitmap() {
110+
if (android.os.Build.VERSION.SDK_INT >= 29) {
111+
final HardwareBuffer buffer = currentImage.getHardwareBuffer();
112+
currentBitmap = Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB));
113+
} else {
114+
final Plane[] imagePlanes = currentImage.getPlanes();
115+
if (imagePlanes.length != 1) {
116+
return;
117+
}
118+
119+
final Plane imagePlane = imagePlanes[0];
120+
final int desiredWidth = imagePlane.getRowStride() / imagePlane.getPixelStride();
121+
final int desiredHeight = currentImage.getHeight();
122+
123+
currentBitmap =
124+
android.graphics.Bitmap.createBitmap(
125+
desiredWidth, desiredHeight, android.graphics.Bitmap.Config.ARGB_8888);
126+
127+
currentBitmap.copyPixelsFromBuffer(imagePlane.getBuffer());
93128
}
94-
95-
final Plane imagePlane = imagePlanes[0];
96-
final int desiredWidth = imagePlane.getRowStride() / imagePlane.getPixelStride();
97-
final int desiredHeight = currentImage.getHeight();
98-
99-
final Bitmap bitmap =
100-
android.graphics.Bitmap.createBitmap(
101-
desiredWidth, desiredHeight, android.graphics.Bitmap.Config.ARGB_8888);
102-
103-
bitmap.copyPixelsFromBuffer(imagePlane.getBuffer());
104-
canvas.drawBitmap(bitmap, 0, 0, null);
105129
}
106130
}

shell/platform/android/io/flutter/embedding/android/FlutterView.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import android.content.res.Configuration;
1111
import android.graphics.Insets;
1212
import android.graphics.Rect;
13+
import android.media.ImageReader;
1314
import android.os.Build;
1415
import android.text.format.DateFormat;
1516
import android.util.AttributeSet;
@@ -303,6 +304,7 @@ private FlutterView(
303304
super(context, attrs);
304305

305306
this.flutterImageView = flutterImageView;
307+
this.renderSurface = flutterImageView;
306308

307309
init();
308310
}
@@ -940,6 +942,32 @@ public void detachFromFlutterEngine() {
940942
flutterEngine = null;
941943
}
942944

945+
public void convertToImageView() {
946+
renderSurface.detachFromRenderer();
947+
948+
ImageReader imageReader = PlatformViewsController.createImageReader(getWidth(), getHeight());
949+
flutterImageView = new FlutterImageView(getContext(), imageReader);
950+
renderSurface = flutterImageView;
951+
if (flutterEngine != null) {
952+
renderSurface.attachToRenderer(flutterEngine.getRenderer());
953+
}
954+
955+
removeAllViews();
956+
addView(flutterImageView);
957+
958+
// TODO(jsimmons): this is a temporary hack that schedules a redraw of the FlutterImageView
959+
// at a time when the engine has presumably posted a frame. Remove this when
960+
// PlatformViewsController.onEndFrame callbacks have been implemented.
961+
postDelayed(
962+
new Runnable() {
963+
public void run() {
964+
flutterImageView.acquireLatestImage();
965+
flutterImageView.invalidate();
966+
}
967+
},
968+
1000);
969+
}
970+
943971
/** Returns true if this {@code FlutterView} is currently attached to a {@link FlutterEngine}. */
944972
@VisibleForTesting
945973
public boolean isAttachedToFlutterEngine() {

shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import androidx.annotation.UiThread;
2323
import androidx.annotation.VisibleForTesting;
2424
import io.flutter.embedding.android.FlutterImageView;
25+
import io.flutter.embedding.android.FlutterView;
2526
import io.flutter.embedding.engine.FlutterOverlaySurface;
2627
import io.flutter.embedding.engine.dart.DartExecutor;
2728
import io.flutter.embedding.engine.systemchannels.PlatformViewsChannel;
@@ -79,9 +80,12 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
7980
// Map of unique IDs to views that render overlay layers.
8081
private final LongSparseArray<FlutterImageView> overlayLayerViews;
8182

82-
// Next available unique ID for use in overlayLayerViews;
83+
// Next available unique ID for use in overlayLayerViews.
8384
private long nextOverlayLayerId = 0;
8485

86+
// Tracks whether the flutterView has been converted to use a FlutterImageView.
87+
private boolean flutterViewConvertedToImageView = false;
88+
8589
private final PlatformViewsChannel.PlatformViewsHandler channelHandler =
8690
new PlatformViewsChannel.PlatformViewsHandler() {
8791
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@@ -552,7 +556,10 @@ public void onDisplayPlatformView(int viewId, int x, int y, int width, int heigh
552556
}
553557

554558
public void onDisplayOverlaySurface(int id, int x, int y, int width, int height) {
555-
// TODO: Implement this method. https://github.com/flutter/flutter/issues/58288
559+
if (!flutterViewConvertedToImageView) {
560+
((FlutterView) flutterView).convertToImageView();
561+
flutterViewConvertedToImageView = true;
562+
}
556563
}
557564

558565
public void onBeginFrame() {
@@ -564,22 +571,22 @@ public void onEndFrame() {
564571
}
565572

566573
@TargetApi(19)
567-
public FlutterOverlaySurface createOverlaySurface() {
568-
ImageReader imageReader;
574+
public static ImageReader createImageReader(int width, int height) {
569575
if (android.os.Build.VERSION.SDK_INT >= 29) {
570-
imageReader =
571-
ImageReader.newInstance(
572-
flutterView.getWidth(),
573-
flutterView.getHeight(),
574-
PixelFormat.RGBA_8888,
575-
2,
576-
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE | HardwareBuffer.USAGE_GPU_COLOR_OUTPUT);
576+
return ImageReader.newInstance(
577+
width,
578+
height,
579+
PixelFormat.RGBA_8888,
580+
2,
581+
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE | HardwareBuffer.USAGE_GPU_COLOR_OUTPUT);
577582
} else {
578-
imageReader =
579-
ImageReader.newInstance(
580-
flutterView.getWidth(), flutterView.getHeight(), PixelFormat.RGBA_8888, 2);
583+
return ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 2);
581584
}
585+
}
582586

587+
@TargetApi(19)
588+
public FlutterOverlaySurface createOverlaySurface() {
589+
ImageReader imageReader = createImageReader(flutterView.getWidth(), flutterView.getHeight());
583590
FlutterImageView imageView = new FlutterImageView(flutterView.getContext(), imageReader);
584591
long id = nextOverlayLayerId++;
585592
overlayLayerViews.put(id, imageView);

0 commit comments

Comments
 (0)