From a57158a2dc382334147dd3784d1c8bc88c3a7e5c Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Thu, 18 Jun 2020 18:36:52 -0700 Subject: [PATCH 01/18] New type of flutterview --- .../embedding/android/FlutterImageView.java | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 shell/platform/android/io/flutter/embedding/android/FlutterImageView.java diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java new file mode 100644 index 0000000000000..bb2f662331088 --- /dev/null +++ b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java @@ -0,0 +1,77 @@ +// 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; + +impo + +class FlutterImageView extends View implements RenderSurface { + private final ImageReader imageReader; + @Nullable private Image nextImage; + private Image currentImage; + + public FlutterImageView(Context context, ImageReader imageReader) { + super(context, null); + this.imageReader = imageReader; + } + + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + public void acquireLatestImage() { + nextImage = imageReader.acquireLatestImage(); + invalidate(); + } + + @RequiresApi(api = Build.VERSION_CODES.P) + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (nextImage == null) { + return; + } + + currentImage.close(); + currentImage = nextImage; + nextImage = null; + + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) { + drawImageBuffer(canvas); + } else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + drawImagePlane(canvas); + } + } + + @RequiresApi(api = Build.VERSION_CODES.P) + private void drawImageBuffer(Canvas canvas) { + final HardwareBuffer buffer = currentImage.getHardwareBuffer(); + + final Bitmap bitmap = Bitmap.wrapHardwareBuffer( + buffer, + ColorSpace.get(ColorSpace.Named.SRGB)); + canvas.drawBitmap(bitmap, 0, 0, null); + } + + @RequiresApi(api = Build.VERSION_CODES.KITKAT) + private void drawImagePlane(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); + } +} \ No newline at end of file From a4e9f47db6fb49536b36971530573957022b4267 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Thu, 18 Jun 2020 18:38:53 -0700 Subject: [PATCH 02/18] imports --- .../flutter/embedding/android/FlutterImageView.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java index bb2f662331088..9652e1a1c4bfa 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java @@ -4,7 +4,18 @@ package io.flutter.embedding.android; -impo +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.os.Build; +import android.view.View; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; class FlutterImageView extends View implements RenderSurface { private final ImageReader imageReader; From 36e48340c9f1ca383f67f11602d675f457a4cc57 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Fri, 19 Jun 2020 14:38:43 -0700 Subject: [PATCH 03/18] Documentation and other flutterview integration --- .../embedding/android/FlutterImageView.java | 37 +++++++++---- .../embedding/android/FlutterView.java | 53 +++++++++++++++++-- .../flutter/embedding/android/RenderMode.java | 12 ++++- 3 files changed, 87 insertions(+), 15 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java index 9652e1a1c4bfa..7889b72bbfa2a 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java @@ -17,23 +17,41 @@ import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; -class FlutterImageView extends View implements RenderSurface { +/** + * Paints a Flutter UI provided by an {@link android.media.ImageReader} onto a {@link + * android.graphics.Canvas}. + * + *

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}. + * + *

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}. + */ +@RequiresApi(api = Build.VERSION_CODES.KITKAT) +public class FlutterImageView extends View { private final ImageReader imageReader; @Nullable private Image nextImage; - private Image currentImage; + @Nullable private Image currentImage; - public FlutterImageView(Context context, ImageReader imageReader) { + /** + * 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; } - @RequiresApi(api = Build.VERSION_CODES.KITKAT) + /** + * Acquires the next image to be drawn to the {@link android.graphics.Canvas}. + */ public void acquireLatestImage() { nextImage = imageReader.acquireLatestImage(); invalidate(); } - @RequiresApi(api = Build.VERSION_CODES.P) @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); @@ -41,7 +59,9 @@ protected void onDraw(Canvas canvas) { return; } - currentImage.close(); + if (currentImage != null) { + currentImage.close(); + } currentImage = nextImage; nextImage = null; @@ -53,7 +73,7 @@ protected void onDraw(Canvas canvas) { } @RequiresApi(api = Build.VERSION_CODES.P) - private void drawImageBuffer(Canvas canvas) { + private void drawImageBuffer(@Nonnull Canvas canvas) { final HardwareBuffer buffer = currentImage.getHardwareBuffer(); final Bitmap bitmap = Bitmap.wrapHardwareBuffer( @@ -62,8 +82,7 @@ private void drawImageBuffer(Canvas canvas) { canvas.drawBitmap(bitmap, 0, 0, null); } - @RequiresApi(api = Build.VERSION_CODES.KITKAT) - private void drawImagePlane(Canvas canvas) { + private void drawImagePlane(@Nonnull Canvas canvas) { if (currentImage == null) { return; } diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index c05b37bdb4e67..475a2492e8211 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -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 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)); } init(); @@ -216,6 +221,17 @@ 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. + * + *

{@code FlutterView} requires an {@code Activity} instead of a generic {@code Context} to be + * compatible with {@link PlatformViewsController}. + */ + public FlutterView(@NonNull Context context, @NonNull FlutterSurfaceView flutterSurfaceView) { + this(context, null, flutterSurfaceView); + } + /** * Constructs a {@code FlutterView} in an XML-inflation-compliant manner. * @@ -243,9 +259,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 +294,29 @@ private FlutterView( init(); } + 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 +1051,17 @@ 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. + */ + image } /** diff --git a/shell/platform/android/io/flutter/embedding/android/RenderMode.java b/shell/platform/android/io/flutter/embedding/android/RenderMode.java index 3c0907bb850a3..cede7ae68111b 100644 --- a/shell/platform/android/io/flutter/embedding/android/RenderMode.java +++ b/shell/platform/android/io/flutter/embedding/android/RenderMode.java @@ -21,5 +21,15 @@ public enum RenderMode { * Views}. Unless the special capabilities of a {@link android.graphics.SurfaceTexture} are * required, developers should strongly prefer the {@link #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. + */ + image } From 1e8e646b4787979902b6d57c7c32ad4727ab07fc Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Fri, 19 Jun 2020 14:51:39 -0700 Subject: [PATCH 04/18] Get it to compile. Still bad formatting tho --- shell/platform/android/BUILD.gn | 1 + .../flutter/embedding/android/FlutterImageView.java | 13 +++++++------ .../io/flutter/embedding/android/FlutterView.java | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index fc33b1ce4b474..7bd8b22322684 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -138,6 +138,7 @@ android_java_sources = [ "io/flutter/embedding/android/FlutterEngineProvider.java", "io/flutter/embedding/android/FlutterFragment.java", "io/flutter/embedding/android/FlutterFragmentActivity.java", + "io/flutter/embedding/android/FlutterImageView.java", "io/flutter/embedding/android/FlutterSplashView.java", "io/flutter/embedding/android/FlutterSurfaceView.java", "io/flutter/embedding/android/FlutterTextureView.java", diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java index 7889b72bbfa2a..95e88e885980f 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java @@ -14,17 +14,18 @@ import android.media.ImageReader; import android.os.Build; import android.view.View; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; /** * Paints a Flutter UI provided by an {@link android.media.ImageReader} onto a {@link * android.graphics.Canvas}. - * + * *

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}. - * + * *

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}. @@ -39,7 +40,7 @@ public class FlutterImageView extends View { * Constructs a {@code FlutterImageView} with an {@link android.media.ImageReader} that provides * the Flutter UI. */ - public FlutterImageView(@Nonnull Context context, @Nonnull ImageReader imageReader) { + public FlutterImageView(@NonNull Context context, @NonNull ImageReader imageReader) { super(context, null); this.imageReader = imageReader; } @@ -73,7 +74,7 @@ protected void onDraw(Canvas canvas) { } @RequiresApi(api = Build.VERSION_CODES.P) - private void drawImageBuffer(@Nonnull Canvas canvas) { + private void drawImageBuffer(@NonNull Canvas canvas) { final HardwareBuffer buffer = currentImage.getHardwareBuffer(); final Bitmap bitmap = Bitmap.wrapHardwareBuffer( @@ -82,7 +83,7 @@ private void drawImageBuffer(@Nonnull Canvas canvas) { canvas.drawBitmap(bitmap, 0, 0, null); } - private void drawImagePlane(@Nonnull Canvas canvas) { + private void drawImagePlane(@NonNull Canvas canvas) { if (currentImage == null) { return; } @@ -104,4 +105,4 @@ private void drawImagePlane(@Nonnull Canvas canvas) { bitmap.copyPixelsFromBuffer(imagePlane.getBuffer()); canvas.drawBitmap(bitmap, 0, 0, null); } -} \ No newline at end of file +} diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 475a2492e8211..0387c4a629a53 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -228,8 +228,8 @@ public FlutterView(@NonNull Context context, @NonNull FlutterTextureView flutter *

{@code FlutterView} requires an {@code Activity} instead of a generic {@code Context} to be * compatible with {@link PlatformViewsController}. */ - public FlutterView(@NonNull Context context, @NonNull FlutterSurfaceView flutterSurfaceView) { - this(context, null, flutterSurfaceView); + public FlutterView(@NonNull Context context, @NonNull FlutterImageView flutterImageView) { + this(context, null, flutterImageView); } /** From bf77db97de36aa17bbc6d9a681f8e373e1aad833 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Fri, 19 Jun 2020 14:53:34 -0700 Subject: [PATCH 05/18] No need for kitkat check --- .../io/flutter/embedding/android/FlutterImageView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java index 95e88e885980f..badc5b903f01c 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java @@ -68,9 +68,9 @@ protected void onDraw(Canvas canvas) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) { drawImageBuffer(canvas); - } else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - drawImagePlane(canvas); } + + drawImagePlane(canvas); } @RequiresApi(api = Build.VERSION_CODES.P) From 228fb87632186c72e511618746703b6aa5a19d92 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Fri, 19 Jun 2020 15:02:03 -0700 Subject: [PATCH 06/18] formatting --- .../embedding/android/FlutterImageView.java | 21 ++++++---------- .../embedding/android/FlutterView.java | 25 +++++++++---------- .../flutter/embedding/android/RenderMode.java | 11 ++++---- 3 files changed, 25 insertions(+), 32 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java index badc5b903f01c..3f4c0e8f56a2d 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java @@ -26,9 +26,9 @@ * Flutter UI, but also needs to render an interactive {@link * io.flutter.plugin.platform.PlatformView}. * - *

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}. + *

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}. */ @RequiresApi(api = Build.VERSION_CODES.KITKAT) public class FlutterImageView extends View { @@ -45,9 +45,7 @@ public FlutterImageView(@NonNull Context context, @NonNull ImageReader imageRead this.imageReader = imageReader; } - /** - * Acquires the next image to be drawn to the {@link android.graphics.Canvas}. - */ + /** Acquires the next image to be drawn to the {@link android.graphics.Canvas}. */ public void acquireLatestImage() { nextImage = imageReader.acquireLatestImage(); invalidate(); @@ -77,9 +75,7 @@ protected void onDraw(Canvas canvas) { private void drawImageBuffer(@NonNull Canvas canvas) { final HardwareBuffer buffer = currentImage.getHardwareBuffer(); - final Bitmap bitmap = Bitmap.wrapHardwareBuffer( - buffer, - ColorSpace.get(ColorSpace.Named.SRGB)); + final Bitmap bitmap = Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB)); canvas.drawBitmap(bitmap, 0, 0, null); } @@ -97,10 +93,9 @@ private void drawImagePlane(@NonNull Canvas canvas) { 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); + 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); diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index 0387c4a629a53..fb6d8a7447237 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -156,8 +156,8 @@ public FlutterView(@NonNull Context context) { /** * Deprecated - use {@link #FlutterView(Context, FlutterSurfaceView)} or {@link - * #FlutterView(Context, FlutterTextureView)} or {@link - * #FlutterView(Context, FlutterImageView)} instead. + * #FlutterView(Context, FlutterTextureView)} or {@link #FlutterView(Context, FlutterImageView)} + * instead. */ @Deprecated public FlutterView(@NonNull Context context, @NonNull RenderMode renderMode) { @@ -170,8 +170,8 @@ public FlutterView(@NonNull Context context, @NonNull RenderMode renderMode) { flutterTextureView = new FlutterTextureView(context); renderSurface = flutterTextureView; } else { - throw new IllegalArgumentException(String.format("RenderMode not supported with this constructor: ", - renderMode)); + throw new IllegalArgumentException( + String.format("RenderMode not supported with this constructor: ", renderMode)); } init(); @@ -259,12 +259,12 @@ public FlutterView( flutterSurfaceView = new FlutterSurfaceView(context, transparencyMode == TransparencyMode.transparent); renderSurface = flutterSurfaceView; - } else if (renderMode == RenderMode.texture){ + } else if (renderMode == RenderMode.texture) { flutterTextureView = new FlutterTextureView(context); renderSurface = flutterTextureView; } else { - throw new IllegalArgumentException(String.format("RenderMode not supported with this constructor: ", - renderMode)); + throw new IllegalArgumentException( + String.format("RenderMode not supported with this constructor: ", renderMode)); } init(); @@ -1054,12 +1054,11 @@ public enum RenderMode { 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. + * 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. */ image } diff --git a/shell/platform/android/io/flutter/embedding/android/RenderMode.java b/shell/platform/android/io/flutter/embedding/android/RenderMode.java index cede7ae68111b..2471396178aec 100644 --- a/shell/platform/android/io/flutter/embedding/android/RenderMode.java +++ b/shell/platform/android/io/flutter/embedding/android/RenderMode.java @@ -24,12 +24,11 @@ public enum RenderMode { 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. + * 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. */ image } From 6bf656fb3a72d63bf6336af35e666943d8370c87 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Fri, 19 Jun 2020 15:41:33 -0700 Subject: [PATCH 07/18] switch to target api --- .../io/flutter/embedding/android/FlutterImageView.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java index 3f4c0e8f56a2d..ba17f8f0ecdee 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java @@ -16,7 +16,7 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; +import android.annotation.TargetApi; /** * Paints a Flutter UI provided by an {@link android.media.ImageReader} onto a {@link @@ -30,7 +30,7 @@ * an {@link android.media.Image} and renders it to the {@link android.graphics.Canvas} in {@code * onDraw}. */ -@RequiresApi(api = Build.VERSION_CODES.KITKAT) +@TargetApi(api = Build.VERSION_CODES.K) public class FlutterImageView extends View { private final ImageReader imageReader; @Nullable private Image nextImage; @@ -46,6 +46,7 @@ public FlutterImageView(@NonNull Context context, @NonNull ImageReader imageRead } /** Acquires the next image to be drawn to the {@link android.graphics.Canvas}. */ + @TargetApi(api = Build.VERSION_CODES.KITKAT) public void acquireLatestImage() { nextImage = imageReader.acquireLatestImage(); invalidate(); @@ -71,7 +72,7 @@ protected void onDraw(Canvas canvas) { drawImagePlane(canvas); } - @RequiresApi(api = Build.VERSION_CODES.P) + @TargetApi(api = Build.VERSION_CODES.P) private void drawImageBuffer(@NonNull Canvas canvas) { final HardwareBuffer buffer = currentImage.getHardwareBuffer(); From 3a67995fa99f8f91630c96a6fdf27f4f92ff900d Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Fri, 19 Jun 2020 15:49:30 -0700 Subject: [PATCH 08/18] Fix targetapi annotations --- .../io/flutter/embedding/android/FlutterImageView.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java index ba17f8f0ecdee..70401e257df24 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java @@ -30,7 +30,7 @@ * an {@link android.media.Image} and renders it to the {@link android.graphics.Canvas} in {@code * onDraw}. */ -@TargetApi(api = Build.VERSION_CODES.K) +@TargetApi(Build.VERSION_CODES.KITKAT) public class FlutterImageView extends View { private final ImageReader imageReader; @Nullable private Image nextImage; @@ -46,7 +46,7 @@ public FlutterImageView(@NonNull Context context, @NonNull ImageReader imageRead } /** Acquires the next image to be drawn to the {@link android.graphics.Canvas}. */ - @TargetApi(api = Build.VERSION_CODES.KITKAT) + @TargetApi(Build.VERSION_CODES.KITKAT) public void acquireLatestImage() { nextImage = imageReader.acquireLatestImage(); invalidate(); @@ -72,7 +72,7 @@ protected void onDraw(Canvas canvas) { drawImagePlane(canvas); } - @TargetApi(api = Build.VERSION_CODES.P) + @TargetApi(Build.VERSION_CODES.Q) private void drawImageBuffer(@NonNull Canvas canvas) { final HardwareBuffer buffer = currentImage.getHardwareBuffer(); From bf5a9c27eff06df092884059c74cf7e60412d15c Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Fri, 19 Jun 2020 15:57:05 -0700 Subject: [PATCH 09/18] Fix version and add suppress lint --- .../io/flutter/embedding/android/FlutterImageView.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java index 70401e257df24..654a6bd5d8aff 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java @@ -4,6 +4,7 @@ package io.flutter.embedding.android; +import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -30,6 +31,7 @@ * an {@link android.media.Image} and renders it to the {@link android.graphics.Canvas} in {@code * onDraw}. */ +@SuppressLint("ViewConstructor") @TargetApi(Build.VERSION_CODES.KITKAT) public class FlutterImageView extends View { private final ImageReader imageReader; @@ -65,7 +67,7 @@ protected void onDraw(Canvas canvas) { currentImage = nextImage; nextImage = null; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { drawImageBuffer(canvas); } From 527841efb3e01433a09fcc5c2ff60e4b3adb7884 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Fri, 19 Jun 2020 16:03:46 -0700 Subject: [PATCH 10/18] set int --- .../io/flutter/embedding/android/FlutterImageView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java index 654a6bd5d8aff..82bfa8ebfe754 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java @@ -67,14 +67,14 @@ protected void onDraw(Canvas canvas) { currentImage = nextImage; nextImage = null; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { + if (29) { drawImageBuffer(canvas); } drawImagePlane(canvas); } - @TargetApi(Build.VERSION_CODES.Q) + @TargetApi(29) private void drawImageBuffer(@NonNull Canvas canvas) { final HardwareBuffer buffer = currentImage.getHardwareBuffer(); From 79794a5238316765066f16f7db645b5fdaa93ead Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Fri, 19 Jun 2020 16:08:48 -0700 Subject: [PATCH 11/18] Set version code --- .../io/flutter/embedding/android/FlutterImageView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java index 82bfa8ebfe754..654a6bd5d8aff 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java @@ -67,14 +67,14 @@ protected void onDraw(Canvas canvas) { currentImage = nextImage; nextImage = null; - if (29) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { drawImageBuffer(canvas); } drawImagePlane(canvas); } - @TargetApi(29) + @TargetApi(Build.VERSION_CODES.Q) private void drawImageBuffer(@NonNull Canvas canvas) { final HardwareBuffer buffer = currentImage.getHardwareBuffer(); From 8a8fa24aaa39e2adf9ed43364b38c9eaf81c9416 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Fri, 19 Jun 2020 16:16:30 -0700 Subject: [PATCH 12/18] Set int for targetapi --- .../io/flutter/embedding/android/FlutterImageView.java | 8 ++++---- .../android/io/flutter/embedding/android/FlutterView.java | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java index 654a6bd5d8aff..a6e3a5731d40a 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java @@ -32,7 +32,7 @@ * onDraw}. */ @SuppressLint("ViewConstructor") -@TargetApi(Build.VERSION_CODES.KITKAT) +@TargetApi(19) public class FlutterImageView extends View { private final ImageReader imageReader; @Nullable private Image nextImage; @@ -48,7 +48,7 @@ public FlutterImageView(@NonNull Context context, @NonNull ImageReader imageRead } /** Acquires the next image to be drawn to the {@link android.graphics.Canvas}. */ - @TargetApi(Build.VERSION_CODES.KITKAT) + @TargetApi(19) public void acquireLatestImage() { nextImage = imageReader.acquireLatestImage(); invalidate(); @@ -67,14 +67,14 @@ protected void onDraw(Canvas canvas) { currentImage = nextImage; nextImage = null; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { + if (android.os.Build.VERSION.SDK_INT >= 29) { drawImageBuffer(canvas); } drawImagePlane(canvas); } - @TargetApi(Build.VERSION_CODES.Q) + @TargetApi(29) private void drawImageBuffer(@NonNull Canvas canvas) { final HardwareBuffer buffer = currentImage.getHardwareBuffer(); diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterView.java b/shell/platform/android/io/flutter/embedding/android/FlutterView.java index fb6d8a7447237..2fd22da61d4e1 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterView.java @@ -228,6 +228,7 @@ public FlutterView(@NonNull Context context, @NonNull FlutterTextureView flutter *

{@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); } @@ -294,6 +295,7 @@ private FlutterView( init(); } + @TargetApi(19) private FlutterView( @NonNull Context context, @Nullable AttributeSet attrs, From 9f18aaee5723cb294388a1daa329e37bb6135cc1 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Fri, 19 Jun 2020 16:32:06 -0700 Subject: [PATCH 13/18] formatting --- .../android/io/flutter/embedding/android/FlutterImageView.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java index a6e3a5731d40a..39aaa57960349 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java @@ -5,6 +5,7 @@ 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; @@ -13,11 +14,9 @@ import android.media.Image; import android.media.Image.Plane; import android.media.ImageReader; -import android.os.Build; import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import android.annotation.TargetApi; /** * Paints a Flutter UI provided by an {@link android.media.ImageReader} onto a {@link From e08f3cd10585afca0bbd97dce2eae5da49e11323 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Sat, 20 Jun 2020 15:08:24 -0700 Subject: [PATCH 14/18] license --- ci/licenses_golden/licenses_flutter | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index eb2713c557b90..d07a4edc56d6f 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -690,6 +690,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/Flutt FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterEngineProvider.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterFragment.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterFragmentActivity.java +FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterSplashView.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterSurfaceView.java FILE: ../../../flutter/shell/platform/android/io/flutter/embedding/android/FlutterTextureView.java From 406d01dbc25c266cdaade0422ceaa5d57002175f Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Sat, 20 Jun 2020 16:25:19 -0700 Subject: [PATCH 15/18] a test test --- .../io/flutter/embedding/android/FlutterViewTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java index 7461674f243b0..75b4a7081f845 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java @@ -54,6 +54,16 @@ public void setUp() { when(mockFlutterJni.isAttached()).thenReturn(true); } + @Test + public void imageView_test() { + final ImageReader mockReader = mock(ImageReader.class); + final FlutterImageView imageView = spy(new FlutterImageView(RuntimeEnvironment.application, mockReader)); + + imageView.acquireLatestImage(); + verify(mockReader, times(1)).acquireLatestImage(); + verify(imageView, times(1)).invalidate(); + } + @Test public void attachToFlutterEngine_alertsPlatformViews() { FlutterView flutterView = new FlutterView(RuntimeEnvironment.application); From d327acaf2ae6b212d7bdc9c4b6aa287eb0d838a3 Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Sat, 20 Jun 2020 17:04:12 -0700 Subject: [PATCH 16/18] ImageReader import --- .../test/io/flutter/embedding/android/FlutterViewTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java index 75b4a7081f845..110cf7ca2e3c8 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java @@ -34,6 +34,7 @@ import org.mockito.stubbing.Answer; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import android.media.ImageReader; import org.robolectric.Shadows; import org.robolectric.annotation.Config; import org.robolectric.annotation.Implementation; From 74148ce65b0cbbc64723dc9ab81ee45ee1cba80d Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Sat, 20 Jun 2020 18:26:31 -0700 Subject: [PATCH 17/18] trivial test for flutterimageview --- .../embedding/android/FlutterViewTest.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java b/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java index 110cf7ca2e3c8..ad29381ef273d 100644 --- a/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java +++ b/shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java @@ -12,6 +12,7 @@ import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; +import android.media.ImageReader; import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; @@ -34,7 +35,6 @@ import org.mockito.stubbing.Answer; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -import android.media.ImageReader; import org.robolectric.Shadows; import org.robolectric.annotation.Config; import org.robolectric.annotation.Implementation; @@ -55,16 +55,6 @@ public void setUp() { when(mockFlutterJni.isAttached()).thenReturn(true); } - @Test - public void imageView_test() { - final ImageReader mockReader = mock(ImageReader.class); - final FlutterImageView imageView = spy(new FlutterImageView(RuntimeEnvironment.application, mockReader)); - - imageView.acquireLatestImage(); - verify(mockReader, times(1)).acquireLatestImage(); - verify(imageView, times(1)).invalidate(); - } - @Test public void attachToFlutterEngine_alertsPlatformViews() { FlutterView flutterView = new FlutterView(RuntimeEnvironment.application); @@ -381,6 +371,17 @@ public void systemInsetHandlesFullscreenNavbarLeft() { assertEquals(100, viewportMetricsCaptor.getValue().paddingRight); } + @Test + public void flutterImageView_acquiresImageAndInvalidates() { + final ImageReader mockReader = mock(ImageReader.class); + final FlutterImageView imageView = + spy(new FlutterImageView(RuntimeEnvironment.application, mockReader)); + + imageView.acquireLatestImage(); + verify(mockReader, times(1)).acquireLatestImage(); + verify(imageView, times(1)).invalidate(); + } + /* * A custom shadow that reports fullscreen flag for system UI visibility */ From d32aeb26bc3797dd1543f2f2c36a1254fbff929c Mon Sep 17 00:00:00 2001 From: Maurice Parrish Date: Mon, 22 Jun 2020 13:54:45 -0700 Subject: [PATCH 18/18] Return after draw --- .../android/io/flutter/embedding/android/FlutterImageView.java | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java index 39aaa57960349..48863f0d42766 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterImageView.java @@ -68,6 +68,7 @@ protected void onDraw(Canvas canvas) { if (android.os.Build.VERSION.SDK_INT >= 29) { drawImageBuffer(canvas); + return; } drawImagePlane(canvas);