5package io.flutter.embedding.android;
7import static io.flutter.Build.API_LEVELS;
9import android.annotation.SuppressLint;
10import android.annotation.TargetApi;
14import android.graphics.ColorSpace;
15import android.graphics.PixelFormat;
16import android.hardware.HardwareBuffer;
18import android.media.Image.Plane;
19import android.media.ImageReader;
20import android.util.AttributeSet;
23import androidx.annotation.NonNull;
24import androidx.annotation.Nullable;
25import androidx.annotation.VisibleForTesting;
27import io.flutter.embedding.engine.renderer.FlutterRenderer;
28import io.flutter.embedding.engine.renderer.RenderSurface;
29import java.nio.ByteBuffer;
30import java.util.Locale;
45 private static final String TAG =
"FlutterImageView";
47 @NonNull
private ImageReader imageReader;
48 @Nullable
private Image currentImage;
49 @Nullable
private Bitmap currentBitmap;
68 private boolean isAttachedToFlutterRenderer =
false;
75 this(context, createImageReader(
width,
height), kind);
88 @NonNull Context context, @NonNull ImageReader imageReader,
SurfaceKind kind) {
90 this.imageReader = imageReader;
99 private static void logW(String
format, Object...
args) {
103 @SuppressLint(
"WrongConstant")
105 private static ImageReader createImageReader(
int width,
int height) {
107 logW(
"ImageReader width must be greater than 0, but given width=%d, set width=1",
width);
111 logW(
"ImageReader height must be greater than 0, but given height=%d, set height=1",
height);
114 if (
android.os.Build.VERSION.SDK_INT >= API_LEVELS.API_29) {
115 return ImageReader.newInstance(
120 HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE | HardwareBuffer.USAGE_GPU_COLOR_OUTPUT);
128 return imageReader.getSurface();
134 return flutterRenderer;
145 flutterRenderer.swapSurface(imageReader.getSurface());
153 this.flutterRenderer = flutterRenderer;
154 isAttachedToFlutterRenderer =
true;
162 if (!isAttachedToFlutterRenderer) {
170 currentBitmap =
null;
175 isAttachedToFlutterRenderer =
false;
191 if (!isAttachedToFlutterRenderer) {
200 final Image newImage = imageReader.acquireLatestImage();
201 if (newImage !=
null) {
204 currentImage = newImage;
207 return newImage !=
null;
212 if (flutterRenderer ==
null) {
215 if (
width == imageReader.getWidth() &&
height == imageReader.getHeight()) {
239 super.onDraw(canvas);
240 if (currentImage !=
null) {
241 updateCurrentBitmap();
243 if (currentBitmap !=
null) {
244 canvas.drawBitmap(currentBitmap, 0, 0,
null);
248 private void closeCurrentImage() {
250 if (currentImage !=
null) {
251 currentImage.close();
256 @TargetApi(API_LEVELS.API_29)
257 private
void updateCurrentBitmap() {
258 if (
android.os.Build.VERSION.SDK_INT >= API_LEVELS.API_29) {
259 final HardwareBuffer
buffer = currentImage.getHardwareBuffer();
263 final Plane[] imagePlanes = currentImage.getPlanes();
264 if (imagePlanes.length != 1) {
268 final Plane imagePlane = imagePlanes[0];
269 final int desiredWidth = imagePlane.getRowStride() / imagePlane.getPixelStride();
270 final int desiredHeight = currentImage.getHeight();
272 if (currentBitmap ==
null
273 || currentBitmap.getWidth() != desiredWidth
274 || currentBitmap.getHeight() != desiredHeight) {
277 desiredWidth, desiredHeight,
android.graphics.Bitmap.Config.ARGB_8888);
279 ByteBuffer
buffer = imagePlane.getBuffer();
281 currentBitmap.copyPixelsFromBuffer(
buffer);
287 if (
width == imageReader.getWidth() &&
height == imageReader.getHeight()) {
297 flutterRenderer.swapSurface(imageReader.getSurface());
static void w(@NonNull String tag, @NonNull String message)
FlutterImageView(@NonNull Context context)
FlutterImageView(@NonNull Context context, @NonNull AttributeSet attrs)
void resizeIfNeeded(int width, int height)
void onSizeChanged(int width, int height, int oldWidth, int oldHeight)
ImageReader getImageReader()
FlutterImageView(@NonNull Context context, int width, int height, SurfaceKind kind)
void detachFromRenderer()
void onDraw(Canvas canvas)
void attachToRenderer(@NonNull FlutterRenderer flutterRenderer)
FlutterRenderer getAttachedRenderer()
FlutterImageView( @NonNull Context context, @NonNull ImageReader imageReader, SurfaceKind kind)
boolean acquireLatestImage()
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint32_t uint32_t * format
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...