[camerax] Wrap classes to implement resolution configuration for image capture, image analysis, and preview (#4523)

Wraps classes to implement resolution configuration for image capture, image analysis, and preview. Also bumps CameraX version to latest and removes the deprecated classes used previously.

No functionality changes. Also thanks to @bparrishMines who did majority of the work here!

Part of https://github.com/flutter/flutter/issues/120462
This commit is contained in:
Camille Simon
2023-07-27 15:30:49 -07:00
committed by GitHub
parent 867f2a4c92
commit 897f6951d9
40 changed files with 2159 additions and 370 deletions

View File

@ -1,3 +1,9 @@
## 0.5.0+12
* Wraps classes needed to implement resolution configuration for image capture, image analysis, and preview.
* Removes usages of deprecated APIs for resolution configuration.
* Bumps CameraX version to 1.3.0-beta01.
## 0.5.0+11
* Fixes issue with image data not being emitted after relistening to stream returned by `onStreamedFrameAvailable`.

View File

@ -61,7 +61,7 @@ android {
dependencies {
// CameraX core library using the camera2 implementation must use same version number.
def camerax_version = "1.3.0-alpha05"
def camerax_version = "1.3.0-beta01"
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"
implementation "androidx.camera:camera-lifecycle:${camerax_version}"

View File

@ -0,0 +1,65 @@
// 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.plugins.camerax;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.camera.core.resolutionselector.AspectRatioStrategy;
import io.flutter.plugins.camerax.GeneratedCameraXLibrary.AspectRatioStrategyHostApi;
/**
* Host API implementation for {@link AspectRatioStrategy}.
*
* <p>This class handles instantiating and adding native object instances that are attached to a
* Dart instance or handle method calls on the associated native class or an instance of the class.
*/
public class AspectRatioStrategyHostApiImpl implements AspectRatioStrategyHostApi {
private final InstanceManager instanceManager;
private final AspectRatioStrategyProxy proxy;
/** Proxy for constructors and static method of {@link AspectRatioStrategy}. */
@VisibleForTesting
public static class AspectRatioStrategyProxy {
/** Creates an instance of {@link AspectRatioStrategy}. */
@NonNull
public AspectRatioStrategy create(
@NonNull Long preferredAspectRatio, @NonNull Long fallbackRule) {
return new AspectRatioStrategy(preferredAspectRatio.intValue(), fallbackRule.intValue());
}
}
/**
* Constructs an {@link AspectRatioStrategyHostApiImpl}.
*
* @param instanceManager maintains instances stored to communicate with attached Dart objects
*/
public AspectRatioStrategyHostApiImpl(@NonNull InstanceManager instanceManager) {
this(instanceManager, new AspectRatioStrategyProxy());
}
/**
* Constructs an {@link AspectRatioStrategyHostApiImpl}.
*
* @param instanceManager maintains instances stored to communicate with attached Dart objects
* @param proxy proxy for constructors and static method of {@link AspectRatioStrategy}
*/
@VisibleForTesting
AspectRatioStrategyHostApiImpl(
@NonNull InstanceManager instanceManager, @NonNull AspectRatioStrategyProxy proxy) {
this.instanceManager = instanceManager;
this.proxy = proxy;
}
/**
* Creates an {@link AspectRatioStrategy} instance with the preferred aspect ratio and fallback
* rule specified.
*/
@Override
public void create(
@NonNull Long identifier, @NonNull Long preferredAspectRatio, @NonNull Long fallbackRule) {
instanceManager.addDartCreatedInstance(
proxy.create(preferredAspectRatio, fallbackRule), identifier);
}
}

View File

@ -97,6 +97,12 @@ public final class CameraAndroidCameraxPlugin implements FlutterPlugin, Activity
binaryMessenger, pendingRecordingHostApiImpl);
videoCaptureHostApiImpl = new VideoCaptureHostApiImpl(binaryMessenger, instanceManager);
GeneratedCameraXLibrary.VideoCaptureHostApi.setup(binaryMessenger, videoCaptureHostApiImpl);
GeneratedCameraXLibrary.ResolutionSelectorHostApi.setup(
binaryMessenger, new ResolutionSelectorHostApiImpl(instanceManager));
GeneratedCameraXLibrary.ResolutionStrategyHostApi.setup(
binaryMessenger, new ResolutionStrategyHostApiImpl(instanceManager));
GeneratedCameraXLibrary.AspectRatioStrategyHostApi.setup(
binaryMessenger, new AspectRatioStrategyHostApiImpl(instanceManager));
}
@Override

View File

@ -76,6 +76,23 @@ public class GeneratedCameraXLibrary {
}
}
/**
* The types (T) properly wrapped to be used as a LiveData<T>.
*
* <p>If you need to add another type to support a type S to use a LiveData<S> in this plugin,
* ensure the following is done on the Dart side:
*
* <p>* In `../lib/src/live_data.dart`, add new cases for S in
* `_LiveDataHostApiImpl#getValueFromInstances` to get the current value of type S from a
* LiveData<S> instance and in `LiveDataFlutterApiImpl#create` to create the expected type of
* LiveData<S> when requested.
*
* <p>On the native side, ensure the following is done:
*
* <p>* Update `LiveDataHostApiImpl#getValue` is updated to properly return identifiers for
* instances of type S. * Update `ObserverFlutterApiWrapper#onChanged` to properly handle
* receiving calls with instances of type S if a LiveData<S> instance is observed.
*/
public enum LiveDataSupportedType {
CAMERA_STATE(0),
ZOOM_STATE(1);
@ -1297,8 +1314,6 @@ public class GeneratedCameraXLibrary {
switch (type) {
case (byte) 128:
return ResolutionInfo.fromList((ArrayList<Object>) readValue(buffer));
case (byte) 129:
return ResolutionInfo.fromList((ArrayList<Object>) readValue(buffer));
default:
return super.readValueOfType(type, buffer);
}
@ -1309,9 +1324,6 @@ public class GeneratedCameraXLibrary {
if (value instanceof ResolutionInfo) {
stream.write(128);
writeValue(stream, ((ResolutionInfo) value).toList());
} else if (value instanceof ResolutionInfo) {
stream.write(129);
writeValue(stream, ((ResolutionInfo) value).toList());
} else {
super.writeValue(stream, value);
}
@ -1322,9 +1334,7 @@ public class GeneratedCameraXLibrary {
public interface PreviewHostApi {
void create(
@NonNull Long identifier,
@Nullable Long rotation,
@Nullable ResolutionInfo targetResolution);
@NonNull Long identifier, @Nullable Long rotation, @Nullable Long resolutionSelectorId);
@NonNull
Long setSurfaceProvider(@NonNull Long identifier);
@ -1351,12 +1361,14 @@ public class GeneratedCameraXLibrary {
ArrayList<Object> args = (ArrayList<Object>) message;
Number identifierArg = (Number) args.get(0);
Number rotationArg = (Number) args.get(1);
ResolutionInfo targetResolutionArg = (ResolutionInfo) args.get(2);
Number resolutionSelectorIdArg = (Number) args.get(2);
try {
api.create(
(identifierArg == null) ? null : identifierArg.longValue(),
(rotationArg == null) ? null : rotationArg.longValue(),
targetResolutionArg);
(resolutionSelectorIdArg == null)
? null
: resolutionSelectorIdArg.longValue());
wrapped.add(0, null);
} catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception);
@ -1911,40 +1923,11 @@ public class GeneratedCameraXLibrary {
channelReply -> callback.reply(null));
}
}
private static class ImageCaptureHostApiCodec extends StandardMessageCodec {
public static final ImageCaptureHostApiCodec INSTANCE = new ImageCaptureHostApiCodec();
private ImageCaptureHostApiCodec() {}
@Override
protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) {
switch (type) {
case (byte) 128:
return ResolutionInfo.fromList((ArrayList<Object>) readValue(buffer));
default:
return super.readValueOfType(type, buffer);
}
}
@Override
protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) {
if (value instanceof ResolutionInfo) {
stream.write(128);
writeValue(stream, ((ResolutionInfo) value).toList());
} else {
super.writeValue(stream, value);
}
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface ImageCaptureHostApi {
void create(
@NonNull Long identifier,
@Nullable Long flashMode,
@Nullable ResolutionInfo targetResolution);
@NonNull Long identifier, @Nullable Long flashMode, @Nullable Long resolutionSelectorId);
void setFlashMode(@NonNull Long identifier, @NonNull Long flashMode);
@ -1952,7 +1935,7 @@ public class GeneratedCameraXLibrary {
/** The codec used by ImageCaptureHostApi. */
static @NonNull MessageCodec<Object> getCodec() {
return ImageCaptureHostApiCodec.INSTANCE;
return new StandardMessageCodec();
}
/**
* Sets up an instance of `ImageCaptureHostApi` to handle messages through the
@ -1970,12 +1953,14 @@ public class GeneratedCameraXLibrary {
ArrayList<Object> args = (ArrayList<Object>) message;
Number identifierArg = (Number) args.get(0);
Number flashModeArg = (Number) args.get(1);
ResolutionInfo targetResolutionArg = (ResolutionInfo) args.get(2);
Number resolutionSelectorIdArg = (Number) args.get(2);
try {
api.create(
(identifierArg == null) ? null : identifierArg.longValue(),
(flashModeArg == null) ? null : flashModeArg.longValue(),
targetResolutionArg);
(resolutionSelectorIdArg == null)
? null
: resolutionSelectorIdArg.longValue());
wrapped.add(0, null);
} catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception);
@ -2046,6 +2031,182 @@ public class GeneratedCameraXLibrary {
}
}
private static class ResolutionStrategyHostApiCodec extends StandardMessageCodec {
public static final ResolutionStrategyHostApiCodec INSTANCE =
new ResolutionStrategyHostApiCodec();
private ResolutionStrategyHostApiCodec() {}
@Override
protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) {
switch (type) {
case (byte) 128:
return ResolutionInfo.fromList((ArrayList<Object>) readValue(buffer));
default:
return super.readValueOfType(type, buffer);
}
}
@Override
protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) {
if (value instanceof ResolutionInfo) {
stream.write(128);
writeValue(stream, ((ResolutionInfo) value).toList());
} else {
super.writeValue(stream, value);
}
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface ResolutionStrategyHostApi {
void create(
@NonNull Long identifier, @Nullable ResolutionInfo boundSize, @Nullable Long fallbackRule);
/** The codec used by ResolutionStrategyHostApi. */
static @NonNull MessageCodec<Object> getCodec() {
return ResolutionStrategyHostApiCodec.INSTANCE;
}
/**
* Sets up an instance of `ResolutionStrategyHostApi` to handle messages through the
* `binaryMessenger`.
*/
static void setup(
@NonNull BinaryMessenger binaryMessenger, @Nullable ResolutionStrategyHostApi api) {
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger, "dev.flutter.pigeon.ResolutionStrategyHostApi.create", getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<Object>();
ArrayList<Object> args = (ArrayList<Object>) message;
Number identifierArg = (Number) args.get(0);
ResolutionInfo boundSizeArg = (ResolutionInfo) args.get(1);
Number fallbackRuleArg = (Number) args.get(2);
try {
api.create(
(identifierArg == null) ? null : identifierArg.longValue(),
boundSizeArg,
(fallbackRuleArg == null) ? null : fallbackRuleArg.longValue());
wrapped.add(0, null);
} catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception);
wrapped = wrappedError;
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface ResolutionSelectorHostApi {
void create(
@NonNull Long identifier,
@Nullable Long resolutionStrategyIdentifier,
@Nullable Long aspectRatioStrategyIdentifier);
/** The codec used by ResolutionSelectorHostApi. */
static @NonNull MessageCodec<Object> getCodec() {
return new StandardMessageCodec();
}
/**
* Sets up an instance of `ResolutionSelectorHostApi` to handle messages through the
* `binaryMessenger`.
*/
static void setup(
@NonNull BinaryMessenger binaryMessenger, @Nullable ResolutionSelectorHostApi api) {
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger, "dev.flutter.pigeon.ResolutionSelectorHostApi.create", getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<Object>();
ArrayList<Object> args = (ArrayList<Object>) message;
Number identifierArg = (Number) args.get(0);
Number resolutionStrategyIdentifierArg = (Number) args.get(1);
Number aspectRatioStrategyIdentifierArg = (Number) args.get(2);
try {
api.create(
(identifierArg == null) ? null : identifierArg.longValue(),
(resolutionStrategyIdentifierArg == null)
? null
: resolutionStrategyIdentifierArg.longValue(),
(aspectRatioStrategyIdentifierArg == null)
? null
: aspectRatioStrategyIdentifierArg.longValue());
wrapped.add(0, null);
} catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception);
wrapped = wrappedError;
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface AspectRatioStrategyHostApi {
void create(
@NonNull Long identifier, @NonNull Long preferredAspectRatio, @NonNull Long fallbackRule);
/** The codec used by AspectRatioStrategyHostApi. */
static @NonNull MessageCodec<Object> getCodec() {
return new StandardMessageCodec();
}
/**
* Sets up an instance of `AspectRatioStrategyHostApi` to handle messages through the
* `binaryMessenger`.
*/
static void setup(
@NonNull BinaryMessenger binaryMessenger, @Nullable AspectRatioStrategyHostApi api) {
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.AspectRatioStrategyHostApi.create",
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<Object>();
ArrayList<Object> args = (ArrayList<Object>) message;
Number identifierArg = (Number) args.get(0);
Number preferredAspectRatioArg = (Number) args.get(1);
Number fallbackRuleArg = (Number) args.get(2);
try {
api.create(
(identifierArg == null) ? null : identifierArg.longValue(),
(preferredAspectRatioArg == null)
? null
: preferredAspectRatioArg.longValue(),
(fallbackRuleArg == null) ? null : fallbackRuleArg.longValue());
wrapped.add(0, null);
} catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception);
wrapped = wrappedError;
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
}
}
private static class CameraStateFlutterApiCodec extends StandardMessageCodec {
public static final CameraStateFlutterApiCodec INSTANCE = new CameraStateFlutterApiCodec();
@ -2194,37 +2355,10 @@ public class GeneratedCameraXLibrary {
channelReply -> callback.reply(null));
}
}
private static class ImageAnalysisHostApiCodec extends StandardMessageCodec {
public static final ImageAnalysisHostApiCodec INSTANCE = new ImageAnalysisHostApiCodec();
private ImageAnalysisHostApiCodec() {}
@Override
protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) {
switch (type) {
case (byte) 128:
return ResolutionInfo.fromList((ArrayList<Object>) readValue(buffer));
default:
return super.readValueOfType(type, buffer);
}
}
@Override
protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) {
if (value instanceof ResolutionInfo) {
stream.write(128);
writeValue(stream, ((ResolutionInfo) value).toList());
} else {
super.writeValue(stream, value);
}
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface ImageAnalysisHostApi {
void create(@NonNull Long identifier, @Nullable ResolutionInfo targetResolutionIdentifier);
void create(@NonNull Long identifier, @Nullable Long resolutionSelectorId);
void setAnalyzer(@NonNull Long identifier, @NonNull Long analyzerIdentifier);
@ -2232,7 +2366,7 @@ public class GeneratedCameraXLibrary {
/** The codec used by ImageAnalysisHostApi. */
static @NonNull MessageCodec<Object> getCodec() {
return ImageAnalysisHostApiCodec.INSTANCE;
return new StandardMessageCodec();
}
/**
* Sets up an instance of `ImageAnalysisHostApi` to handle messages through the
@ -2250,11 +2384,13 @@ public class GeneratedCameraXLibrary {
ArrayList<Object> wrapped = new ArrayList<Object>();
ArrayList<Object> args = (ArrayList<Object>) message;
Number identifierArg = (Number) args.get(0);
ResolutionInfo targetResolutionIdentifierArg = (ResolutionInfo) args.get(1);
Number resolutionSelectorIdArg = (Number) args.get(1);
try {
api.create(
(identifierArg == null) ? null : identifierArg.longValue(),
targetResolutionIdentifierArg);
(resolutionSelectorIdArg == null)
? null
: resolutionSelectorIdArg.longValue());
wrapped.add(0, null);
} catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception);

View File

@ -9,10 +9,10 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.resolutionselector.ResolutionSelector;
import androidx.core.content.ContextCompat;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugins.camerax.GeneratedCameraXLibrary.ImageAnalysisHostApi;
import io.flutter.plugins.camerax.GeneratedCameraXLibrary.ResolutionInfo;
import java.util.Objects;
public class ImageAnalysisHostApiImpl implements ImageAnalysisHostApi {
@ -38,11 +38,13 @@ public class ImageAnalysisHostApiImpl implements ImageAnalysisHostApi {
/** Creates an {@link ImageAnalysis} instance with the target resolution if specified. */
@Override
public void create(@NonNull Long identifier, @Nullable ResolutionInfo targetResolution) {
public void create(@NonNull Long identifier, @Nullable Long resolutionSelectorId) {
ImageAnalysis.Builder imageAnalysisBuilder = cameraXProxy.createImageAnalysisBuilder();
if (targetResolution != null) {
imageAnalysisBuilder.setTargetResolution(CameraXProxy.sizeFromResolution(targetResolution));
if (resolutionSelectorId != null) {
ResolutionSelector resolutionSelector =
Objects.requireNonNull(instanceManager.getInstance(resolutionSelectorId));
imageAnalysisBuilder.setResolutionSelector(resolutionSelector);
}
ImageAnalysis imageAnalysis = imageAnalysisBuilder.build();

View File

@ -10,6 +10,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.resolutionselector.ResolutionSelector;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugins.camerax.GeneratedCameraXLibrary.ImageCaptureHostApi;
import java.io.File;
@ -52,17 +53,19 @@ public class ImageCaptureHostApiImpl implements ImageCaptureHostApi {
*/
@Override
public void create(
@NonNull Long identifier,
@Nullable Long flashMode,
@Nullable GeneratedCameraXLibrary.ResolutionInfo targetResolution) {
@NonNull Long identifier, @Nullable Long flashMode, @Nullable Long resolutionSelectorId) {
ImageCapture.Builder imageCaptureBuilder = cameraXProxy.createImageCaptureBuilder();
if (flashMode != null) {
// This sets the requested flash mode, but may fail silently.
imageCaptureBuilder.setFlashMode(flashMode.intValue());
}
if (targetResolution != null) {
imageCaptureBuilder.setTargetResolution(CameraXProxy.sizeFromResolution(targetResolution));
if (resolutionSelectorId != null) {
ResolutionSelector resolutionSelector =
Objects.requireNonNull(instanceManager.getInstance(resolutionSelectorId));
imageCaptureBuilder.setResolutionSelector(resolutionSelector);
}
ImageCapture imageCapture = imageCaptureBuilder.build();
instanceManager.addDartCreatedInstance(imageCapture, identifier);
}

View File

@ -12,6 +12,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.camera.core.Preview;
import androidx.camera.core.SurfaceRequest;
import androidx.camera.core.resolutionselector.ResolutionSelector;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugins.camerax.GeneratedCameraXLibrary.PreviewHostApi;
import io.flutter.view.TextureRegistry;
@ -38,16 +39,18 @@ public class PreviewHostApiImpl implements PreviewHostApi {
/** Creates a {@link Preview} with the target rotation and resolution if specified. */
@Override
public void create(
@NonNull Long identifier,
@Nullable Long rotation,
@Nullable GeneratedCameraXLibrary.ResolutionInfo targetResolution) {
@NonNull Long identifier, @Nullable Long rotation, @Nullable Long resolutionSelectorId) {
Preview.Builder previewBuilder = cameraXProxy.createPreviewBuilder();
if (rotation != null) {
previewBuilder.setTargetRotation(rotation.intValue());
}
if (targetResolution != null) {
previewBuilder.setTargetResolution(CameraXProxy.sizeFromResolution(targetResolution));
if (resolutionSelectorId != null) {
ResolutionSelector resolutionSelector =
Objects.requireNonNull(instanceManager.getInstance(resolutionSelectorId));
previewBuilder.setResolutionSelector(resolutionSelector);
}
Preview preview = previewBuilder.build();
instanceManager.addDartCreatedInstance(preview, identifier);
}

View File

@ -0,0 +1,87 @@
// 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.plugins.camerax;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.camera.core.resolutionselector.AspectRatioStrategy;
import androidx.camera.core.resolutionselector.ResolutionSelector;
import androidx.camera.core.resolutionselector.ResolutionStrategy;
import io.flutter.plugins.camerax.GeneratedCameraXLibrary.ResolutionSelectorHostApi;
import java.util.Objects;
/**
* Host API implementation for {@link ResolutionSelector}.
*
* <p>This class handles instantiating and adding native object instances that are attached to a
* Dart instance or handle method calls on the associated native class or an instance of the class.
*/
public class ResolutionSelectorHostApiImpl implements ResolutionSelectorHostApi {
private final InstanceManager instanceManager;
private final ResolutionSelectorProxy proxy;
/** Proxy for constructors and static method of {@link ResolutionSelector}. */
@VisibleForTesting
public static class ResolutionSelectorProxy {
/** Creates an instance of {@link ResolutionSelector}. */
@NonNull
public ResolutionSelector create(
@Nullable ResolutionStrategy resolutionStrategy,
@Nullable AspectRatioStrategy aspectRatioStrategy) {
final ResolutionSelector.Builder builder = new ResolutionSelector.Builder();
if (resolutionStrategy != null) {
builder.setResolutionStrategy(resolutionStrategy);
}
if (aspectRatioStrategy != null) {
builder.setAspectRatioStrategy(aspectRatioStrategy);
}
return builder.build();
}
}
/**
* Constructs a {@link ResolutionSelectorHostApiImpl}.
*
* @param instanceManager maintains instances stored to communicate with attached Dart objects
*/
public ResolutionSelectorHostApiImpl(@NonNull InstanceManager instanceManager) {
this(instanceManager, new ResolutionSelectorProxy());
}
/**
* Constructs a {@link ResolutionSelectorHostApiImpl}.
*
* @param instanceManager maintains instances stored to communicate with attached Dart objects
* @param proxy proxy for constructors and static method of {@link ResolutionSelector}
*/
@VisibleForTesting
ResolutionSelectorHostApiImpl(
@NonNull InstanceManager instanceManager, @NonNull ResolutionSelectorProxy proxy) {
this.instanceManager = instanceManager;
this.proxy = proxy;
}
/**
* Creates a {@link ResolutionSelector} instance with the {@link ResolutionStrategy} and {@link
* AspectRatio} that have the identifiers specified if provided.
*/
@Override
public void create(
@NonNull Long identifier,
@Nullable Long resolutionStrategyIdentifier,
@Nullable Long aspectRatioStrategyIdentifier) {
instanceManager.addDartCreatedInstance(
proxy.create(
resolutionStrategyIdentifier == null
? null
: Objects.requireNonNull(instanceManager.getInstance(resolutionStrategyIdentifier)),
aspectRatioStrategyIdentifier == null
? null
: Objects.requireNonNull(
instanceManager.getInstance(aspectRatioStrategyIdentifier))),
identifier);
}
}

View File

@ -0,0 +1,81 @@
// 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.plugins.camerax;
import android.util.Size;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.camera.core.resolutionselector.ResolutionStrategy;
import io.flutter.plugins.camerax.GeneratedCameraXLibrary.ResolutionStrategyHostApi;
/**
* Host API implementation for {@link ResolutionStrategy}.
*
* <p>This class handles instantiating and adding native object instances that are attached to a
* Dart instance or handle method calls on the associated native class or an instance of the class.
*/
public class ResolutionStrategyHostApiImpl implements ResolutionStrategyHostApi {
private final InstanceManager instanceManager;
private final ResolutionStrategyProxy proxy;
/** Proxy for constructors and static method of {@link ResolutionStrategy}. */
@VisibleForTesting
public static class ResolutionStrategyProxy {
/** Creates an instance of {@link ResolutionStrategy}. */
@NonNull
public ResolutionStrategy create(@NonNull Size boundSize, @NonNull Long fallbackRule) {
return new ResolutionStrategy(boundSize, fallbackRule.intValue());
}
}
/**
* Constructs a {@link ResolutionStrategyHostApiImpl}.
*
* @param instanceManager maintains instances stored to communicate with attached Dart objects
*/
public ResolutionStrategyHostApiImpl(@NonNull InstanceManager instanceManager) {
this(instanceManager, new ResolutionStrategyProxy());
}
/**
* Constructs a {@link ResolutionStrategyHostApiImpl}.
*
* @param instanceManager maintains instances stored to communicate with attached Dart objects
* @param proxy proxy for constructors and static method of {@link ResolutionStrategy}
*/
@VisibleForTesting
ResolutionStrategyHostApiImpl(
@NonNull InstanceManager instanceManager, @NonNull ResolutionStrategyProxy proxy) {
this.instanceManager = instanceManager;
this.proxy = proxy;
}
/**
* Creates a {@link ResolutionStrategy} instance with the {@link
* GeneratedCameraXLibrary.ResolutionInfo} bound size and {@code fallbackRule} if specified.
*/
@Override
public void create(
@NonNull Long identifier,
@Nullable GeneratedCameraXLibrary.ResolutionInfo boundSize,
@Nullable Long fallbackRule) {
ResolutionStrategy resolutionStrategy;
if (boundSize == null && fallbackRule == null) {
// Strategy that chooses the highest available resolution does not have a bound size or fallback rule.
resolutionStrategy = ResolutionStrategy.HIGHEST_AVAILABLE_STRATEGY;
} else if (boundSize == null) {
throw new IllegalArgumentException(
"A bound size must be specified if a non-null fallback rule is specified to create a valid ResolutionStrategy.");
} else {
resolutionStrategy =
proxy.create(
new Size(boundSize.getWidth().intValue(), boundSize.getHeight().intValue()),
fallbackRule);
}
instanceManager.addDartCreatedInstance(resolutionStrategy, identifier);
}
}

View File

@ -0,0 +1,51 @@
// 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.plugins.camerax;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;
import androidx.camera.core.resolutionselector.AspectRatioStrategy;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
public class AspectRatioStrategyTest {
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
@Mock public AspectRatioStrategy mockAspectRatioStrategy;
@Mock public AspectRatioStrategyHostApiImpl.AspectRatioStrategyProxy mockProxy;
InstanceManager instanceManager;
@Before
public void setUp() {
instanceManager = InstanceManager.create(identifier -> {});
}
@After
public void tearDown() {
instanceManager.stopFinalizationListener();
}
@Test
public void hostApiCreate_createsExpectedAspectRatioStrategyInstance() {
final Long preferredAspectRatio = 0L;
final Long fallbackRule = 1L;
when(mockProxy.create(preferredAspectRatio, fallbackRule)).thenReturn(mockAspectRatioStrategy);
final AspectRatioStrategyHostApiImpl hostApi =
new AspectRatioStrategyHostApiImpl(instanceManager, mockProxy);
final long instanceIdentifier = 0;
hostApi.create(instanceIdentifier, preferredAspectRatio, fallbackRule);
assertEquals(instanceManager.getInstance(instanceIdentifier), mockAspectRatioStrategy);
}
}

View File

@ -12,18 +12,16 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.util.Size;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.resolutionselector.ResolutionSelector;
import androidx.test.core.app.ApplicationProvider;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugins.camerax.GeneratedCameraXLibrary.ResolutionInfo;
import java.util.concurrent.Executor;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@ -55,27 +53,19 @@ public class ImageAnalysisTest {
new ImageAnalysisHostApiImpl(mockBinaryMessenger, instanceManager);
final CameraXProxy mockCameraXProxy = mock(CameraXProxy.class);
final ImageAnalysis.Builder mockImageAnalysisBuilder = mock(ImageAnalysis.Builder.class);
final int targetResolutionWidth = 10;
final int targetResolutionHeight = 50;
final ResolutionInfo resolutionInfo =
new ResolutionInfo.Builder()
.setWidth(Long.valueOf(targetResolutionWidth))
.setHeight(Long.valueOf(targetResolutionHeight))
.build();
final ResolutionSelector mockResolutionSelector = mock(ResolutionSelector.class);
final long instanceIdentifier = 0;
final long mockResolutionSelectorId = 25;
hostApi.cameraXProxy = mockCameraXProxy;
final ArgumentCaptor<Size> sizeCaptor = ArgumentCaptor.forClass(Size.class);
instanceManager.addDartCreatedInstance(mockResolutionSelector, mockResolutionSelectorId);
when(mockCameraXProxy.createImageAnalysisBuilder()).thenReturn(mockImageAnalysisBuilder);
when(mockImageAnalysisBuilder.build()).thenReturn(mockImageAnalysis);
hostApi.create(instanceIdentifier, resolutionInfo);
hostApi.create(instanceIdentifier, mockResolutionSelectorId);
verify(mockImageAnalysisBuilder).setTargetResolution(sizeCaptor.capture());
assertEquals(sizeCaptor.getValue().getWidth(), targetResolutionWidth);
assertEquals(sizeCaptor.getValue().getHeight(), targetResolutionHeight);
verify(mockImageAnalysisBuilder).setResolutionSelector(mockResolutionSelector);
assertEquals(instanceManager.getInstance(instanceIdentifier), mockImageAnalysis);
}

View File

@ -4,7 +4,6 @@
package io.flutter.plugins.camerax;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
@ -15,9 +14,9 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.util.Size;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.resolutionselector.ResolutionSelector;
import io.flutter.plugin.common.BinaryMessenger;
import java.io.File;
import java.io.IOException;
@ -27,7 +26,6 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.junit.MockitoJUnit;
@ -66,26 +64,18 @@ public class ImageCaptureTest {
final ImageCapture.Builder mockImageCaptureBuilder = mock(ImageCapture.Builder.class);
final Long imageCaptureIdentifier = 74L;
final Long flashMode = Long.valueOf(ImageCapture.FLASH_MODE_ON);
final int targetResolutionWidth = 10;
final int targetResolutionHeight = 50;
final GeneratedCameraXLibrary.ResolutionInfo resolutionInfo =
new GeneratedCameraXLibrary.ResolutionInfo.Builder()
.setWidth(Long.valueOf(targetResolutionWidth))
.setHeight(Long.valueOf(targetResolutionHeight))
.build();
final ResolutionSelector mockResolutionSelector = mock(ResolutionSelector.class);
final long mockResolutionSelectorId = 77;
imageCaptureHostApiImpl.cameraXProxy = mockCameraXProxy;
testInstanceManager.addDartCreatedInstance(mockResolutionSelector, mockResolutionSelectorId);
when(mockCameraXProxy.createImageCaptureBuilder()).thenReturn(mockImageCaptureBuilder);
when(mockImageCaptureBuilder.build()).thenReturn(mockImageCapture);
final ArgumentCaptor<Size> sizeCaptor = ArgumentCaptor.forClass(Size.class);
imageCaptureHostApiImpl.create(imageCaptureIdentifier, flashMode, resolutionInfo);
imageCaptureHostApiImpl.create(imageCaptureIdentifier, flashMode, mockResolutionSelectorId);
verify(mockImageCaptureBuilder).setFlashMode(flashMode.intValue());
verify(mockImageCaptureBuilder).setTargetResolution(sizeCaptor.capture());
assertEquals(sizeCaptor.getValue().getWidth(), targetResolutionWidth);
assertEquals(sizeCaptor.getValue().getHeight(), targetResolutionHeight);
verify(mockImageCaptureBuilder).setResolutionSelector(mockResolutionSelector);
verify(mockImageCaptureBuilder).build();
verify(testInstanceManager).addDartCreatedInstance(mockImageCapture, imageCaptureIdentifier);
}

View File

@ -18,6 +18,7 @@ import android.util.Size;
import android.view.Surface;
import androidx.camera.core.Preview;
import androidx.camera.core.SurfaceRequest;
import androidx.camera.core.resolutionselector.ResolutionSelector;
import androidx.core.util.Consumer;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugins.camerax.GeneratedCameraXLibrary.ResolutionInfo;
@ -63,27 +64,20 @@ public class PreviewTest {
new PreviewHostApiImpl(mockBinaryMessenger, testInstanceManager, mockTextureRegistry);
final Preview.Builder mockPreviewBuilder = mock(Preview.Builder.class);
final int targetRotation = 90;
final int targetResolutionWidth = 10;
final int targetResolutionHeight = 50;
final Long previewIdentifier = 3L;
final GeneratedCameraXLibrary.ResolutionInfo resolutionInfo =
new GeneratedCameraXLibrary.ResolutionInfo.Builder()
.setWidth(Long.valueOf(targetResolutionWidth))
.setHeight(Long.valueOf(targetResolutionHeight))
.build();
final ResolutionSelector mockResolutionSelector = mock(ResolutionSelector.class);
final long mockResolutionSelectorId = 90;
previewHostApi.cameraXProxy = mockCameraXProxy;
testInstanceManager.addDartCreatedInstance(mockResolutionSelector, mockResolutionSelectorId);
when(mockCameraXProxy.createPreviewBuilder()).thenReturn(mockPreviewBuilder);
when(mockPreviewBuilder.build()).thenReturn(mockPreview);
final ArgumentCaptor<Size> sizeCaptor = ArgumentCaptor.forClass(Size.class);
previewHostApi.create(previewIdentifier, Long.valueOf(targetRotation), resolutionInfo);
previewHostApi.create(
previewIdentifier, Long.valueOf(targetRotation), mockResolutionSelectorId);
verify(mockPreviewBuilder).setTargetRotation(targetRotation);
verify(mockPreviewBuilder).setTargetResolution(sizeCaptor.capture());
assertEquals(sizeCaptor.getValue().getWidth(), targetResolutionWidth);
assertEquals(sizeCaptor.getValue().getHeight(), targetResolutionHeight);
verify(mockPreviewBuilder).setResolutionSelector(mockResolutionSelector);
verify(mockPreviewBuilder).build();
verify(testInstanceManager).addDartCreatedInstance(mockPreview, previewIdentifier);
}

View File

@ -0,0 +1,59 @@
// 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.plugins.camerax;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import androidx.camera.core.resolutionselector.AspectRatioStrategy;
import androidx.camera.core.resolutionselector.ResolutionSelector;
import androidx.camera.core.resolutionselector.ResolutionStrategy;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
public class ResolutionSelectorTest {
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
@Mock public ResolutionSelector mockResolutionSelector;
@Mock public ResolutionSelectorHostApiImpl.ResolutionSelectorProxy mockProxy;
InstanceManager instanceManager;
@Before
public void setUp() {
instanceManager = InstanceManager.create(identifier -> {});
}
@After
public void tearDown() {
instanceManager.stopFinalizationListener();
}
@Test
public void hostApiCreate_createsExpectedResolutionSelectorInstance() {
final ResolutionStrategy mockResolutionStrategy = mock(ResolutionStrategy.class);
final long resolutionStrategyIdentifier = 14;
instanceManager.addDartCreatedInstance(mockResolutionStrategy, resolutionStrategyIdentifier);
final AspectRatioStrategy mockAspectRatioStrategy = mock(AspectRatioStrategy.class);
final long aspectRatioStrategyIdentifier = 15;
instanceManager.addDartCreatedInstance(mockAspectRatioStrategy, aspectRatioStrategyIdentifier);
when(mockProxy.create(mockResolutionStrategy, mockAspectRatioStrategy))
.thenReturn(mockResolutionSelector);
final ResolutionSelectorHostApiImpl hostApi =
new ResolutionSelectorHostApiImpl(instanceManager, mockProxy);
final long instanceIdentifier = 0;
hostApi.create(instanceIdentifier, resolutionStrategyIdentifier, aspectRatioStrategyIdentifier);
assertEquals(instanceManager.getInstance(instanceIdentifier), mockResolutionSelector);
}
}

View File

@ -0,0 +1,71 @@
// 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.plugins.camerax;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import android.util.Size;
import androidx.camera.core.resolutionselector.ResolutionStrategy;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
public class ResolutionStrategyTest {
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
@Mock public ResolutionStrategy mockResolutionStrategy;
@Mock public ResolutionStrategyHostApiImpl.ResolutionStrategyProxy mockProxy;
InstanceManager instanceManager;
@Before
public void setUp() {
instanceManager = InstanceManager.create(identifier -> {});
}
@After
public void tearDown() {
instanceManager.stopFinalizationListener();
}
@Test
public void hostApiCreate_createsExpectedResolutionStrategyInstanceWhenArgumentsValid() {
final GeneratedCameraXLibrary.ResolutionInfo boundSize =
new GeneratedCameraXLibrary.ResolutionInfo.Builder().setWidth(50L).setHeight(30L).build();
final Long fallbackRule = 0L;
when(mockProxy.create(any(Size.class), eq(fallbackRule))).thenReturn(mockResolutionStrategy);
final ResolutionStrategyHostApiImpl hostApi =
new ResolutionStrategyHostApiImpl(instanceManager, mockProxy);
final long instanceIdentifier = 0;
hostApi.create(instanceIdentifier, boundSize, fallbackRule);
assertEquals(instanceManager.getInstance(instanceIdentifier), mockResolutionStrategy);
}
@Test
public void hostApiCreate_throwsAssertionErrorWhenArgumentsInvalid() {
final Long fallbackRule = 8L;
final long instanceIdentifier = 0;
final ResolutionStrategyHostApiImpl hostApi =
new ResolutionStrategyHostApiImpl(instanceManager, mockProxy);
// We expect an exception to be thrown if fallback rule is specified but bound size is not.
assertThrows(
IllegalArgumentException.class,
() -> hostApi.create(instanceIdentifier, null, fallbackRule));
}
}

View File

@ -116,10 +116,6 @@ class AndroidCameraCameraX extends CameraPlatform {
@visibleForTesting
CameraSelector? cameraSelector;
/// The resolution preset used to create a camera that should be used for
/// capturing still images and recording video.
ResolutionPreset? _resolutionPreset;
/// The controller we need to broadcast the different camera events.
///
/// It is a `broadcast` because multiple controllers will connect to
@ -233,19 +229,17 @@ class AndroidCameraCameraX extends CameraPlatform {
processCameraProvider ??= await ProcessCameraProvider.getInstance();
processCameraProvider!.unbindAll();
// TODO(camsim99): Implement resolution configuration for UseCases
// configured here. https://github.com/flutter/flutter/issues/120462
// Configure Preview instance.
_resolutionPreset = resolutionPreset;
final int targetRotation =
_getTargetRotation(cameraDescription.sensorOrientation);
final ResolutionInfo? previewTargetResolution =
_getTargetResolutionForPreview(resolutionPreset);
preview = createPreview(targetRotation, previewTargetResolution);
preview = createPreview(targetRotation);
final int flutterSurfaceTextureId = await preview!.setSurfaceProvider();
// Configure ImageCapture instance.
final ResolutionInfo? imageCaptureTargetResolution =
_getTargetResolutionForImageCapture(_resolutionPreset);
imageCapture = createImageCapture(null, imageCaptureTargetResolution);
imageCapture = createImageCapture(null);
// Configure VideoCapture and Recorder instances.
// TODO(gmackall): Enable video capture resolution configuration in createRecorder().
@ -642,7 +636,7 @@ class AndroidCameraCameraX extends CameraPlatform {
// TODO(camsim99): Support resolution configuration.
// Defaults to YUV_420_888 image format.
imageAnalysis ??= createImageAnalysis(null);
imageAnalysis ??= createImageAnalysis();
unawaited(imageAnalysis!.setAnalyzer(analyzer));
if (await processCameraProvider!.isBound(imageAnalysis!)) {
@ -780,23 +774,6 @@ class AndroidCameraCameraX extends CameraPlatform {
}
}
/// Returns [ResolutionInfo] that maps to the specified resolution preset for
/// a camera preview.
ResolutionInfo? _getTargetResolutionForPreview(ResolutionPreset? resolution) {
// TODO(camsim99): Implement resolution configuration.
// https://github.com/flutter/flutter/issues/120462
return null;
}
/// Returns [ResolutionInfo] that maps to the specified resolution preset for
/// image capture.
ResolutionInfo? _getTargetResolutionForImageCapture(
ResolutionPreset? resolution) {
// TODO(camsim99): Implement resolution configuration.
// https://github.com/flutter/flutter/issues/120462
return null;
}
// Methods for calls that need to be tested:
/// Requests camera permissions.
@ -829,18 +806,15 @@ class AndroidCameraCameraX extends CameraPlatform {
/// Returns a [Preview] configured with the specified target rotation and
/// resolution.
@visibleForTesting
Preview createPreview(int targetRotation, ResolutionInfo? targetResolution) {
return Preview(
targetRotation: targetRotation, targetResolution: targetResolution);
Preview createPreview(int targetRotation) {
return Preview(targetRotation: targetRotation);
}
/// Returns an [ImageCapture] configured with specified flash mode and
/// target resolution.
@visibleForTesting
ImageCapture createImageCapture(
int? flashMode, ResolutionInfo? targetResolution) {
return ImageCapture(
targetFlashMode: flashMode, targetResolution: targetResolution);
ImageCapture createImageCapture(int? flashMode) {
return ImageCapture(targetFlashMode: flashMode);
}
/// Returns a [Recorder] for use in video capture.
@ -857,7 +831,7 @@ class AndroidCameraCameraX extends CameraPlatform {
/// Returns an [ImageAnalysis] configured with specified target resolution.
@visibleForTesting
ImageAnalysis createImageAnalysis(ResolutionInfo? targetResolution) {
return ImageAnalysis(targetResolution: targetResolution);
ImageAnalysis createImageAnalysis() {
return ImageAnalysis();
}
}

View File

@ -0,0 +1,138 @@
// 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.
import 'package:flutter/services.dart';
import 'package:meta/meta.dart' show immutable;
import 'camerax_library.g.dart';
import 'instance_manager.dart';
import 'java_object.dart';
/// The aspect ratio of a UseCase.
///
/// Aspect ratio is the ratio of width to height.
///
/// See https://developer.android.com/reference/androidx/camera/core/AspectRatio.
class AspectRatio {
AspectRatio._();
/// 4:3 standard aspect ratio.
///
/// See https://developer.android.com/reference/androidx/camera/core/AspectRatio#RATIO_4_3().
static const int ratio4To3 = 0;
/// 16:9 standard aspect ratio.
///
/// See https://developer.android.com/reference/androidx/camera/core/AspectRatio#RATIO_16_9().
static const int ratio16To9 = 1;
/// The aspect ratio representing no preference for aspect ratio.
///
/// See https://developer.android.com/reference/androidx/camera/core/AspectRatio#RATIO_DEFAULT().
static const int ratioDefault = -1;
}
/// The aspect ratio strategy defines the sequence of aspect ratios that are
/// used to select the best size for a particular image.
///
/// See https://developer.android.com/reference/androidx/camera/core/resolutionselector/AspectRatioStrategy.
@immutable
class AspectRatioStrategy extends JavaObject {
/// Construct a [AspectRatioStrategy].
AspectRatioStrategy({
required this.preferredAspectRatio,
required this.fallbackRule,
super.binaryMessenger,
super.instanceManager,
}) : _api = _AspectRatioStrategyHostApiImpl(
instanceManager: instanceManager,
binaryMessenger: binaryMessenger,
),
super.detached() {
_api.createFromInstances(this, preferredAspectRatio, fallbackRule);
}
/// Instantiates a [AspectRatioStrategy] without creating and attaching to an
/// instance of the associated native class.
///
/// This should only be used outside of tests by subclasses created by this
/// library or to create a copy for an [InstanceManager].
AspectRatioStrategy.detached({
required this.preferredAspectRatio,
required this.fallbackRule,
super.binaryMessenger,
super.instanceManager,
}) : _api = _AspectRatioStrategyHostApiImpl(
instanceManager: instanceManager,
binaryMessenger: binaryMessenger,
),
super.detached();
/// CameraX doesn't fall back to select sizes of any other aspect ratio when
/// this fallback rule is used.
///
/// See https://developer.android.com/reference/androidx/camera/core/resolutionselector/AspectRatioStrategy#FALLBACK_RULE_NONE().
static const int fallbackRuleNone = 0;
/// CameraX automatically chooses the next best aspect ratio which contains
/// the closest field of view (FOV) of the camera sensor, from the remaining
/// options.
///
/// See https://developer.android.com/reference/androidx/camera/core/resolutionselector/AspectRatioStrategy#FALLBACK_RULE_AUTO().
static const int fallbackRuleAuto = 1;
final _AspectRatioStrategyHostApiImpl _api;
/// The preferred aspect ratio captured by the camera.
final int preferredAspectRatio;
/// The specified fallback rule for choosing the aspect ratio when the
/// preferred aspect ratio is not available.
final int fallbackRule;
}
/// Host API implementation of [AspectRatioStrategy].
class _AspectRatioStrategyHostApiImpl extends AspectRatioStrategyHostApi {
/// Constructs an [_AspectRatioStrategyHostApiImpl].
///
/// If [binaryMessenger] is null, the default [BinaryMessenger] will be used,
/// which routes to the host platform.
///
/// An [instanceManager] is typically passed when a copy of an instance
/// contained by an [InstanceManager] is being created. If left null, it
/// will default to the global instance defined in [JavaObject].
_AspectRatioStrategyHostApiImpl({
this.binaryMessenger,
InstanceManager? instanceManager,
}) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager,
super(binaryMessenger: binaryMessenger);
/// Receives binary data across the Flutter platform barrier.
final BinaryMessenger? binaryMessenger;
/// Maintains instances stored to communicate with native language objects.
final InstanceManager instanceManager;
/// Creates a [AspectRatioStrategy] on the native side with the preferred
/// aspect ratio and fallback rule specified.
Future<void> createFromInstances(
AspectRatioStrategy instance,
int preferredAspectRatio,
int fallbackRule,
) {
return create(
instanceManager.addDartCreatedInstance(
instance,
onCopy: (AspectRatioStrategy original) => AspectRatioStrategy.detached(
preferredAspectRatio: original.preferredAspectRatio,
fallbackRule: original.fallbackRule,
binaryMessenger: binaryMessenger,
instanceManager: instanceManager,
),
),
preferredAspectRatio,
fallbackRule,
);
}
}

View File

@ -22,6 +22,22 @@ enum CameraStateType {
pendingOpen,
}
/// The types (T) properly wrapped to be used as a LiveData<T>.
///
/// If you need to add another type to support a type S to use a LiveData<S> in
/// this plugin, ensure the following is done on the Dart side:
///
/// * In `../lib/src/live_data.dart`, add new cases for S in
/// `_LiveDataHostApiImpl#getValueFromInstances` to get the current value of
/// type S from a LiveData<S> instance and in `LiveDataFlutterApiImpl#create`
/// to create the expected type of LiveData<S> when requested.
///
/// On the native side, ensure the following is done:
///
/// * Update `LiveDataHostApiImpl#getValue` is updated to properly return
/// identifiers for instances of type S.
/// * Update `ObserverFlutterApiWrapper#onChanged` to properly handle receiving
/// calls with instances of type S if a LiveData<S> instance is observed.
enum LiveDataSupportedType {
cameraState,
zoomState,
@ -937,9 +953,6 @@ class _PreviewHostApiCodec extends StandardMessageCodec {
if (value is ResolutionInfo) {
buffer.putUint8(128);
writeValue(buffer, value.encode());
} else if (value is ResolutionInfo) {
buffer.putUint8(129);
writeValue(buffer, value.encode());
} else {
super.writeValue(buffer, value);
}
@ -950,8 +963,6 @@ class _PreviewHostApiCodec extends StandardMessageCodec {
switch (type) {
case 128:
return ResolutionInfo.decode(readValue(buffer)!);
case 129:
return ResolutionInfo.decode(readValue(buffer)!);
default:
return super.readValueOfType(type, buffer);
}
@ -969,12 +980,12 @@ class PreviewHostApi {
static const MessageCodec<Object?> codec = _PreviewHostApiCodec();
Future<void> create(int arg_identifier, int? arg_rotation,
ResolutionInfo? arg_targetResolution) async {
int? arg_resolutionSelectorId) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.PreviewHostApi.create', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = await channel
.send(<Object?>[arg_identifier, arg_rotation, arg_targetResolution])
final List<Object?>? replyList = await channel.send(
<Object?>[arg_identifier, arg_rotation, arg_resolutionSelectorId])
as List<Object?>?;
if (replyList == null) {
throw PlatformException(
@ -1505,29 +1516,6 @@ abstract class RecordingFlutterApi {
}
}
class _ImageCaptureHostApiCodec extends StandardMessageCodec {
const _ImageCaptureHostApiCodec();
@override
void writeValue(WriteBuffer buffer, Object? value) {
if (value is ResolutionInfo) {
buffer.putUint8(128);
writeValue(buffer, value.encode());
} else {
super.writeValue(buffer, value);
}
}
@override
Object? readValueOfType(int type, ReadBuffer buffer) {
switch (type) {
case 128:
return ResolutionInfo.decode(readValue(buffer)!);
default:
return super.readValueOfType(type, buffer);
}
}
}
class ImageCaptureHostApi {
/// Constructor for [ImageCaptureHostApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
@ -1536,15 +1524,15 @@ class ImageCaptureHostApi {
: _binaryMessenger = binaryMessenger;
final BinaryMessenger? _binaryMessenger;
static const MessageCodec<Object?> codec = _ImageCaptureHostApiCodec();
static const MessageCodec<Object?> codec = StandardMessageCodec();
Future<void> create(int arg_identifier, int? arg_flashMode,
ResolutionInfo? arg_targetResolution) async {
int? arg_resolutionSelectorId) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.ImageCaptureHostApi.create', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = await channel.send(
<Object?>[arg_identifier, arg_flashMode, arg_targetResolution])
<Object?>[arg_identifier, arg_flashMode, arg_resolutionSelectorId])
as List<Object?>?;
if (replyList == null) {
throw PlatformException(
@ -1612,6 +1600,138 @@ class ImageCaptureHostApi {
}
}
class _ResolutionStrategyHostApiCodec extends StandardMessageCodec {
const _ResolutionStrategyHostApiCodec();
@override
void writeValue(WriteBuffer buffer, Object? value) {
if (value is ResolutionInfo) {
buffer.putUint8(128);
writeValue(buffer, value.encode());
} else {
super.writeValue(buffer, value);
}
}
@override
Object? readValueOfType(int type, ReadBuffer buffer) {
switch (type) {
case 128:
return ResolutionInfo.decode(readValue(buffer)!);
default:
return super.readValueOfType(type, buffer);
}
}
}
class ResolutionStrategyHostApi {
/// Constructor for [ResolutionStrategyHostApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
ResolutionStrategyHostApi({BinaryMessenger? binaryMessenger})
: _binaryMessenger = binaryMessenger;
final BinaryMessenger? _binaryMessenger;
static const MessageCodec<Object?> codec = _ResolutionStrategyHostApiCodec();
Future<void> create(int arg_identifier, ResolutionInfo? arg_boundSize,
int? arg_fallbackRule) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.ResolutionStrategyHostApi.create', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = await channel
.send(<Object?>[arg_identifier, arg_boundSize, arg_fallbackRule])
as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else {
return;
}
}
}
class ResolutionSelectorHostApi {
/// Constructor for [ResolutionSelectorHostApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
ResolutionSelectorHostApi({BinaryMessenger? binaryMessenger})
: _binaryMessenger = binaryMessenger;
final BinaryMessenger? _binaryMessenger;
static const MessageCodec<Object?> codec = StandardMessageCodec();
Future<void> create(int arg_identifier, int? arg_resolutionStrategyIdentifier,
int? arg_aspectRatioStrategyIdentifier) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.ResolutionSelectorHostApi.create', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = await channel.send(<Object?>[
arg_identifier,
arg_resolutionStrategyIdentifier,
arg_aspectRatioStrategyIdentifier
]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else {
return;
}
}
}
class AspectRatioStrategyHostApi {
/// Constructor for [AspectRatioStrategyHostApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
AspectRatioStrategyHostApi({BinaryMessenger? binaryMessenger})
: _binaryMessenger = binaryMessenger;
final BinaryMessenger? _binaryMessenger;
static const MessageCodec<Object?> codec = StandardMessageCodec();
Future<void> create(int arg_identifier, int arg_preferredAspectRatio,
int arg_fallbackRule) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.AspectRatioStrategyHostApi.create', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = await channel.send(<Object?>[
arg_identifier,
arg_preferredAspectRatio,
arg_fallbackRule
]) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else {
return;
}
}
}
class _CameraStateFlutterApiCodec extends StandardMessageCodec {
const _CameraStateFlutterApiCodec();
@override
@ -1767,29 +1887,6 @@ abstract class ZoomStateFlutterApi {
}
}
class _ImageAnalysisHostApiCodec extends StandardMessageCodec {
const _ImageAnalysisHostApiCodec();
@override
void writeValue(WriteBuffer buffer, Object? value) {
if (value is ResolutionInfo) {
buffer.putUint8(128);
writeValue(buffer, value.encode());
} else {
super.writeValue(buffer, value);
}
}
@override
Object? readValueOfType(int type, ReadBuffer buffer) {
switch (type) {
case 128:
return ResolutionInfo.decode(readValue(buffer)!);
default:
return super.readValueOfType(type, buffer);
}
}
}
class ImageAnalysisHostApi {
/// Constructor for [ImageAnalysisHostApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
@ -1798,16 +1895,15 @@ class ImageAnalysisHostApi {
: _binaryMessenger = binaryMessenger;
final BinaryMessenger? _binaryMessenger;
static const MessageCodec<Object?> codec = _ImageAnalysisHostApiCodec();
static const MessageCodec<Object?> codec = StandardMessageCodec();
Future<void> create(int arg_identifier,
ResolutionInfo? arg_targetResolutionIdentifier) async {
Future<void> create(int arg_identifier, int? arg_resolutionSelectorId) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.ImageAnalysisHostApi.create', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = await channel
.send(<Object?>[arg_identifier, arg_targetResolutionIdentifier])
as List<Object?>?;
final List<Object?>? replyList =
await channel.send(<Object?>[arg_identifier, arg_resolutionSelectorId])
as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',

View File

@ -12,6 +12,7 @@ import 'android_camera_camerax_flutter_api_impls.dart';
import 'camerax_library.g.dart';
import 'instance_manager.dart';
import 'java_object.dart';
import 'resolution_selector.dart';
import 'use_case.dart';
/// Use case for providing CPU accessible images for performing image analysis.
@ -23,13 +24,13 @@ class ImageAnalysis extends UseCase {
ImageAnalysis(
{BinaryMessenger? binaryMessenger,
InstanceManager? instanceManager,
this.targetResolution})
this.resolutionSelector})
: super.detached(
binaryMessenger: binaryMessenger,
instanceManager: instanceManager) {
_api = _ImageAnalysisHostApiImpl(
binaryMessenger: binaryMessenger, instanceManager: instanceManager);
_api.createfromInstances(this, targetResolution);
_api.createfromInstances(this, resolutionSelector);
AndroidCameraXCameraFlutterApis.instance.ensureSetUp();
}
@ -37,7 +38,7 @@ class ImageAnalysis extends UseCase {
ImageAnalysis.detached(
{BinaryMessenger? binaryMessenger,
InstanceManager? instanceManager,
this.targetResolution})
this.resolutionSelector})
: super.detached(
binaryMessenger: binaryMessenger,
instanceManager: instanceManager) {
@ -49,7 +50,10 @@ class ImageAnalysis extends UseCase {
late final _ImageAnalysisHostApiImpl _api;
/// Target resolution of the camera preview stream.
final ResolutionInfo? targetResolution;
///
/// If not set, this [UseCase] will default to the behavior described in:
/// https://developer.android.com/reference/androidx/camera/core/ImageAnalysis.Builder#setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector).
final ResolutionSelector? resolutionSelector;
/// Sets an [Analyzer] to receive and analyze images.
Future<void> setAnalyzer(Analyzer analyzer) =>
@ -83,18 +87,20 @@ class _ImageAnalysisHostApiImpl extends ImageAnalysisHostApi {
/// on the native side.
Future<void> createfromInstances(
ImageAnalysis instance,
ResolutionInfo? targetResolution,
ResolutionSelector? resolutionSelector,
) {
return create(
instanceManager.addDartCreatedInstance(
instance,
onCopy: (ImageAnalysis original) => ImageAnalysis.detached(
targetResolution: original.targetResolution,
resolutionSelector: original.resolutionSelector,
binaryMessenger: binaryMessenger,
instanceManager: instanceManager,
),
),
targetResolution,
resolutionSelector == null
? null
: instanceManager.getIdentifier(resolutionSelector),
);
}

View File

@ -8,6 +8,7 @@ import 'package:meta/meta.dart' show immutable;
import 'camerax_library.g.dart';
import 'instance_manager.dart';
import 'java_object.dart';
import 'resolution_selector.dart';
import 'use_case.dart';
/// Use case for picture taking.
@ -20,14 +21,14 @@ class ImageCapture extends UseCase {
BinaryMessenger? binaryMessenger,
InstanceManager? instanceManager,
this.targetFlashMode,
this.targetResolution,
this.resolutionSelector,
}) : super.detached(
binaryMessenger: binaryMessenger,
instanceManager: instanceManager,
) {
_api = ImageCaptureHostApiImpl(
binaryMessenger: binaryMessenger, instanceManager: instanceManager);
_api.createFromInstance(this, targetFlashMode, targetResolution);
_api.createFromInstance(this, targetFlashMode, resolutionSelector);
}
/// Constructs a [ImageCapture] that is not automatically attached to a native object.
@ -35,7 +36,7 @@ class ImageCapture extends UseCase {
BinaryMessenger? binaryMessenger,
InstanceManager? instanceManager,
this.targetFlashMode,
this.targetResolution,
this.resolutionSelector,
}) : super.detached(
binaryMessenger: binaryMessenger,
instanceManager: instanceManager,
@ -50,7 +51,10 @@ class ImageCapture extends UseCase {
final int? targetFlashMode;
/// Target resolution of the image output from taking a picture.
final ResolutionInfo? targetResolution;
///
/// If not set, this [UseCase] will default to the behavior described in:
/// https://developer.android.com/reference/androidx/camera/core/ImageCapture.Builder#setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector).
final ResolutionSelector? resolutionSelector;
/// Constant for automatic flash mode.
///
@ -121,16 +125,21 @@ class ImageCaptureHostApiImpl extends ImageCaptureHostApi {
/// Creates an [ImageCapture] instance with the flash mode and target resolution
/// if specified.
void createFromInstance(ImageCapture instance, int? targetFlashMode,
ResolutionInfo? targetResolution) {
ResolutionSelector? resolutionSelector) {
final int identifier = instanceManager.addDartCreatedInstance(instance,
onCopy: (ImageCapture original) {
return ImageCapture.detached(
binaryMessenger: binaryMessenger,
instanceManager: instanceManager,
targetFlashMode: original.targetFlashMode,
targetResolution: original.targetResolution);
resolutionSelector: original.resolutionSelector);
});
create(identifier, targetFlashMode, targetResolution);
create(
identifier,
targetFlashMode,
resolutionSelector == null
? null
: instanceManager.getIdentifier(resolutionSelector));
}
/// Sets the flash mode for the specified [ImageCapture] instance to take

View File

@ -8,6 +8,7 @@ import 'package:meta/meta.dart' show immutable;
import 'camerax_library.g.dart';
import 'instance_manager.dart';
import 'java_object.dart';
import 'resolution_selector.dart';
import 'use_case.dart';
/// Use case that provides a camera preview stream for display.
@ -20,13 +21,13 @@ class Preview extends UseCase {
{BinaryMessenger? binaryMessenger,
InstanceManager? instanceManager,
this.targetRotation,
this.targetResolution})
this.resolutionSelector})
: super.detached(
binaryMessenger: binaryMessenger,
instanceManager: instanceManager) {
_api = PreviewHostApiImpl(
binaryMessenger: binaryMessenger, instanceManager: instanceManager);
_api.createFromInstance(this, targetRotation, targetResolution);
_api.createFromInstance(this, targetRotation, resolutionSelector);
}
/// Constructs a [Preview] that is not automatically attached to a native object.
@ -34,7 +35,7 @@ class Preview extends UseCase {
{BinaryMessenger? binaryMessenger,
InstanceManager? instanceManager,
this.targetRotation,
this.targetResolution})
this.resolutionSelector})
: super.detached(
binaryMessenger: binaryMessenger,
instanceManager: instanceManager) {
@ -48,7 +49,10 @@ class Preview extends UseCase {
final int? targetRotation;
/// Target resolution of the camera preview stream.
final ResolutionInfo? targetResolution;
///
/// If not set, this [UseCase] will default to the behavior described in:
/// https://developer.android.com/reference/androidx/camera/core/Preview.Builder#setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector).
final ResolutionSelector? resolutionSelector;
/// Sets the surface provider for the preview stream.
///
@ -92,17 +96,22 @@ class PreviewHostApiImpl extends PreviewHostApi {
/// Creates a [Preview] with the target rotation and target resolution if
/// specified.
void createFromInstance(
Preview instance, int? targetRotation, ResolutionInfo? targetResolution) {
void createFromInstance(Preview instance, int? targetRotation,
ResolutionSelector? resolutionSelector) {
final int identifier = instanceManager.addDartCreatedInstance(instance,
onCopy: (Preview original) {
return Preview.detached(
binaryMessenger: binaryMessenger,
instanceManager: instanceManager,
targetRotation: original.targetRotation,
targetResolution: original.targetResolution);
resolutionSelector: original.resolutionSelector);
});
create(identifier, targetRotation, targetResolution);
create(
identifier,
targetRotation,
resolutionSelector == null
? null
: instanceManager.getIdentifier(resolutionSelector));
}
/// Sets the surface provider of the specified [Preview] instance and returns

View File

@ -0,0 +1,108 @@
// 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.
import 'package:flutter/services.dart';
import 'package:meta/meta.dart' show immutable;
import 'aspect_ratio_strategy.dart';
import 'camerax_library.g.dart';
import 'instance_manager.dart';
import 'java_object.dart';
import 'resolution_strategy.dart';
/// A set of requirements and priorities used to select a resolution for a
/// UseCase.
///
/// See https://developer.android.com/reference/androidx/camera/core/resolutionselector/ResolutionSelector.
@immutable
class ResolutionSelector extends JavaObject {
/// Construct a [ResolutionSelector].
ResolutionSelector({
this.resolutionStrategy,
this.aspectRatioStrategy,
super.binaryMessenger,
super.instanceManager,
}) : _api = _ResolutionSelectorHostApiImpl(
instanceManager: instanceManager,
binaryMessenger: binaryMessenger,
),
super.detached() {
_api.createFromInstances(this, resolutionStrategy, aspectRatioStrategy);
}
/// Instantiates a [ResolutionSelector] without creating and attaching to an
/// instance of the associated native class.
///
/// This should only be used outside of tests by subclasses created by this
/// library or to create a copy for an [InstanceManager].
ResolutionSelector.detached({
this.resolutionStrategy,
this.aspectRatioStrategy,
super.binaryMessenger,
super.instanceManager,
}) : _api = _ResolutionSelectorHostApiImpl(
instanceManager: instanceManager,
binaryMessenger: binaryMessenger,
),
super.detached();
final _ResolutionSelectorHostApiImpl _api;
/// Determines how the UseCase will choose the resolution of the captured
/// image.
final ResolutionStrategy? resolutionStrategy;
/// Determines how the UseCase will choose the aspect ratio of the captured
/// image.
final AspectRatioStrategy? aspectRatioStrategy;
}
/// Host API implementation of [ResolutionSelector].
class _ResolutionSelectorHostApiImpl extends ResolutionSelectorHostApi {
/// Constructs an [_ResolutionSelectorHostApiImpl].
///
/// If [binaryMessenger] is null, the default [BinaryMessenger] will be used,
/// which routes to the host platform.
///
/// An [instanceManager] is typically passed when a copy of an instance
/// contained by an [InstanceManager] is being created. If left null, it
/// will default to the global instance defined in [JavaObject].
_ResolutionSelectorHostApiImpl({
this.binaryMessenger,
InstanceManager? instanceManager,
}) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager,
super(binaryMessenger: binaryMessenger);
/// Receives binary data across the Flutter platform barrier.
final BinaryMessenger? binaryMessenger;
/// Maintains instances stored to communicate with native language objects.
final InstanceManager instanceManager;
/// Creates a [ResolutionSelector] on the native side with the
/// [ResolutionStrategy] and [AspectRatioStrategy] if specified.
Future<void> createFromInstances(
ResolutionSelector instance,
ResolutionStrategy? resolutionStrategy,
AspectRatioStrategy? aspectRatioStrategy,
) {
return create(
instanceManager.addDartCreatedInstance(
instance,
onCopy: (ResolutionSelector original) => ResolutionSelector.detached(
resolutionStrategy: original.resolutionStrategy,
aspectRatioStrategy: original.aspectRatioStrategy,
binaryMessenger: binaryMessenger,
instanceManager: instanceManager,
),
),
resolutionStrategy == null
? null
: instanceManager.getIdentifier(resolutionStrategy)!,
aspectRatioStrategy == null
? null
: instanceManager.getIdentifier(aspectRatioStrategy)!,
);
}
}

View File

@ -0,0 +1,189 @@
// 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.
import 'package:flutter/services.dart';
import 'package:meta/meta.dart' show immutable;
import 'camerax_library.g.dart';
import 'instance_manager.dart';
import 'java_object.dart';
/// The resolution strategy defines the resolution selection sequence to select
/// the best size.
///
/// See https://developer.android.com/reference/androidx/camera/core/resolutionselector/ResolutionStrategy.
@immutable
class ResolutionStrategy extends JavaObject {
/// Constructs a [ResolutionStrategy].
ResolutionStrategy({
required Size this.boundSize,
this.fallbackRule,
super.binaryMessenger,
super.instanceManager,
}) : _api = _ResolutionStrategyHostApiImpl(
instanceManager: instanceManager,
binaryMessenger: binaryMessenger,
),
super.detached() {
_api.createFromInstances(this, boundSize, fallbackRule);
}
/// Constructs a [ResolutionStrategy] that represents the strategy that
/// chooses the highest available resolution.
///
/// See https://developer.android.com/reference/androidx/camera/core/resolutionselector/ResolutionStrategy#HIGHEST_AVAILABLE_STRATEGY().
ResolutionStrategy.highestAvailableStrategy({
super.binaryMessenger,
super.instanceManager,
}) : _api = _ResolutionStrategyHostApiImpl(
instanceManager: instanceManager,
binaryMessenger: binaryMessenger,
),
boundSize = null,
fallbackRule = null,
super.detached() {
_api.createFromInstances(this, boundSize, fallbackRule);
}
/// Instantiates a [ResolutionStrategy] without creating and attaching to an
/// instance of the associated native class.
///
/// This should only be used outside of tests by subclasses created by this
/// library or to create a copy for an [InstanceManager].
ResolutionStrategy.detached({
required this.boundSize,
this.fallbackRule,
super.binaryMessenger,
super.instanceManager,
}) : _api = _ResolutionStrategyHostApiImpl(
instanceManager: instanceManager,
binaryMessenger: binaryMessenger,
),
super.detached();
/// Instantiates a [ResolutionStrategy] that represents the strategy that
/// chooses the highest available resolution without creating and attaching to
/// an instance of the associated native class.
///
/// This should only be used outside of tests by subclasses created by this
/// library or to create a copy for an [InstanceManager].
ResolutionStrategy.detachedHighestAvailableStrategy({
super.binaryMessenger,
super.instanceManager,
}) : _api = _ResolutionStrategyHostApiImpl(
instanceManager: instanceManager,
binaryMessenger: binaryMessenger,
),
boundSize = null,
fallbackRule = null,
super.detached();
/// CameraX doesn't select an alternate size when the specified bound size is
/// unavailable.
///
/// Applications will receive [PlatformException] when binding the [UseCase]s
/// with this fallback rule if the device doesn't support the specified bound
/// size.
///
/// See https://developer.android.com/reference/androidx/camera/core/resolutionselector/ResolutionStrategy#FALLBACK_RULE_NONE().
static const int fallbackRuleNone = 0;
/// When the specified bound size is unavailable, CameraX falls back to select
/// the closest higher resolution size.
///
/// See https://developer.android.com/reference/androidx/camera/core/resolutionselector/ResolutionStrategy#FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER().
static const int fallbackRuleClosestHigherThenLower = 1;
/// When the specified bound size is unavailable, CameraX falls back to the
/// closest higher resolution size.
///
/// If CameraX still cannot find any available resolution, it will fallback to
/// select other lower resolutions.
///
/// See https://developer.android.com/reference/androidx/camera/core/resolutionselector/ResolutionStrategy#FALLBACK_RULE_CLOSEST_HIGHER().
static const int fallbackRuleClosestHigher = 2;
/// When the specified bound size is unavailable, CameraX falls back to select
/// the closest lower resolution size.
///
/// If CameraX still cannot find any available resolution, it will fallback to
/// select other higher resolutions.
///
/// See https://developer.android.com/reference/androidx/camera/core/resolutionselector/ResolutionStrategy#FALLBACK_RULE_CLOSEST_LOWER_THEN_HIGHER().
static const int fallbackRuleClosestLowerThenHigher = 3;
/// When the specified bound size is unavailable, CameraX falls back to the
/// closest lower resolution size.
///
/// See https://developer.android.com/reference/androidx/camera/core/resolutionselector/ResolutionStrategy#FALLBACK_RULE_CLOSEST_LOWER().
static const int fallbackRuleClosestLower = 4;
final _ResolutionStrategyHostApiImpl _api;
/// The specified bound size for the desired resolution of the camera.
///
/// If left null, [fallbackRule] must also be left null in order to create a
/// valid [ResolutionStrategy]. This will create the [ResolutionStrategy]
/// that chooses the highest available resolution, which can also be retrieved
/// by calling [getHighestAvailableStrategy].
final Size? boundSize;
/// The fallback rule for choosing an alternate size when the specified bound
/// size is unavailable.
///
/// Must be left null if [boundSize] is specified as null. This will create
/// the [ResolutionStrategy] that chooses the highest available resolution,
/// which can also be retrieved by calling [getHighestAvailableStrategy].
final int? fallbackRule;
}
/// Host API implementation of [ResolutionStrategy].
class _ResolutionStrategyHostApiImpl extends ResolutionStrategyHostApi {
/// Constructs an [_ResolutionStrategyHostApiImpl].
///
/// If [binaryMessenger] is null, the default [BinaryMessenger] will be used,
/// which routes to the host platform.
///
/// An [instanceManager] is typically passed when a copy of an instance
/// contained by an [InstanceManager] is being created. If left null, it
/// will default to the global instance defined in [JavaObject].
_ResolutionStrategyHostApiImpl({
this.binaryMessenger,
InstanceManager? instanceManager,
}) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager,
super(binaryMessenger: binaryMessenger);
/// Receives binary data across the Flutter platform barrier.
final BinaryMessenger? binaryMessenger;
/// Maintains instances stored to communicate with native language objects.
final InstanceManager instanceManager;
/// Creates a [ResolutionStrategy] on the native side with the bound [Size]
/// and fallback rule, if specified.
Future<void> createFromInstances(
ResolutionStrategy instance,
Size? boundSize,
int? fallbackRule,
) {
return create(
instanceManager.addDartCreatedInstance(
instance,
onCopy: (ResolutionStrategy original) => ResolutionStrategy.detached(
boundSize: original.boundSize,
fallbackRule: original.fallbackRule,
binaryMessenger: binaryMessenger,
instanceManager: instanceManager,
),
),
boundSize == null
? null
: ResolutionInfo(
width: boundSize.width.toInt(),
height: boundSize.height.toInt(),
),
fallbackRule,
);
}
}

View File

@ -196,7 +196,7 @@ abstract class SystemServicesFlutterApi {
@HostApi(dartHostTestHandler: 'TestPreviewHostApi')
abstract class PreviewHostApi {
void create(int identifier, int? rotation, ResolutionInfo? targetResolution);
void create(int identifier, int? rotation, int? resolutionSelectorId);
int setSurfaceProvider(int identifier);
@ -261,7 +261,7 @@ abstract class RecordingFlutterApi {
@HostApi(dartHostTestHandler: 'TestImageCaptureHostApi')
abstract class ImageCaptureHostApi {
void create(int identifier, int? flashMode, ResolutionInfo? targetResolution);
void create(int identifier, int? flashMode, int? resolutionSelectorId);
void setFlashMode(int identifier, int flashMode);
@ -269,6 +269,25 @@ abstract class ImageCaptureHostApi {
String takePicture(int identifier);
}
@HostApi(dartHostTestHandler: 'TestResolutionStrategyHostApi')
abstract class ResolutionStrategyHostApi {
void create(int identifier, ResolutionInfo? boundSize, int? fallbackRule);
}
@HostApi(dartHostTestHandler: 'TestResolutionSelectorHostApi')
abstract class ResolutionSelectorHostApi {
void create(
int identifier,
int? resolutionStrategyIdentifier,
int? aspectRatioStrategyIdentifier,
);
}
@HostApi(dartHostTestHandler: 'TestAspectRatioStrategyHostApi')
abstract class AspectRatioStrategyHostApi {
void create(int identifier, int preferredAspectRatio, int fallbackRule);
}
@FlutterApi()
abstract class CameraStateFlutterApi {
void create(int identifier, CameraStateTypeData type, int? errorIdentifier);
@ -289,7 +308,7 @@ abstract class ZoomStateFlutterApi {
@HostApi(dartHostTestHandler: 'TestImageAnalysisHostApi')
abstract class ImageAnalysisHostApi {
void create(int identifier, ResolutionInfo? targetResolutionIdentifier);
void create(int identifier, int? resolutionSelectorId);
void setAnalyzer(int identifier, int analyzerIdentifier);

View File

@ -2,7 +2,7 @@ name: camera_android_camerax
description: Android implementation of the camera plugin using the CameraX library.
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_android_camerax
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
version: 0.5.0+11
version: 0.5.0+12
environment:
sdk: ">=2.19.0 <4.0.0"

View File

@ -1127,13 +1127,12 @@ class FakeAndroidCameraCameraX extends AndroidCameraCameraX {
}
@override
Preview createPreview(int targetRotation, ResolutionInfo? targetResolution) {
Preview createPreview(int targetRotation) {
return testPreview;
}
@override
ImageCapture createImageCapture(
int? flashMode, ResolutionInfo? targetResolution) {
ImageCapture createImageCapture(int? flashMode) {
return testImageCapture;
}
@ -1148,7 +1147,7 @@ class FakeAndroidCameraCameraX extends AndroidCameraCameraX {
}
@override
ImageAnalysis createImageAnalysis(ResolutionInfo? targetResolution) {
ImageAnalysis createImageAnalysis() {
return mockImageAnalysis;
}
}

View File

@ -0,0 +1,84 @@
// 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.
import 'package:camera_android_camerax/src/aspect_ratio_strategy.dart';
import 'package:camera_android_camerax/src/instance_manager.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'aspect_ratio_strategy_test.mocks.dart';
import 'test_camerax_library.g.dart';
@GenerateMocks(<Type>[
TestAspectRatioStrategyHostApi,
TestInstanceManagerHostApi,
])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('AspectRatioStrategy', () {
tearDown(() {
TestAspectRatioStrategyHostApi.setup(null);
TestInstanceManagerHostApi.setup(null);
});
test(
'detached create does not make call to create expected AspectRatioStrategy instance',
() async {
final MockTestAspectRatioStrategyHostApi mockApi =
MockTestAspectRatioStrategyHostApi();
TestAspectRatioStrategyHostApi.setup(mockApi);
final InstanceManager instanceManager = InstanceManager(
onWeakReferenceRemoved: (_) {},
);
const int preferredAspectRatio = 1;
const int fallbackRule = 1;
AspectRatioStrategy.detached(
preferredAspectRatio: preferredAspectRatio,
fallbackRule: fallbackRule,
instanceManager: instanceManager,
);
verifyNever(mockApi.create(
argThat(isA<int>()),
preferredAspectRatio,
fallbackRule,
));
});
test(
'HostApi create makes call to create expected AspectRatioStrategy instance',
() {
final MockTestAspectRatioStrategyHostApi mockApi =
MockTestAspectRatioStrategyHostApi();
TestAspectRatioStrategyHostApi.setup(mockApi);
TestInstanceManagerHostApi.setup(MockTestInstanceManagerHostApi());
final InstanceManager instanceManager = InstanceManager(
onWeakReferenceRemoved: (_) {},
);
const int preferredAspectRatio = 0;
const int fallbackRule = 0;
final AspectRatioStrategy instance = AspectRatioStrategy(
preferredAspectRatio: preferredAspectRatio,
fallbackRule: fallbackRule,
instanceManager: instanceManager,
);
verify(mockApi.create(
instanceManager.getIdentifier(instance),
preferredAspectRatio,
fallbackRule,
));
});
});
}

View File

@ -0,0 +1,68 @@
// Mocks generated by Mockito 5.4.1 from annotations
// in camera_android_camerax/test/aspect_ratio_strategy_test.dart.
// Do not manually edit this file.
// @dart=2.19
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:mockito/mockito.dart' as _i1;
import 'test_camerax_library.g.dart' as _i2;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class
/// A class which mocks [TestAspectRatioStrategyHostApi].
///
/// See the documentation for Mockito's code generation for more information.
class MockTestAspectRatioStrategyHostApi extends _i1.Mock
implements _i2.TestAspectRatioStrategyHostApi {
MockTestAspectRatioStrategyHostApi() {
_i1.throwOnMissingStub(this);
}
@override
void create(
int? identifier,
int? preferredAspectRatio,
int? fallbackRule,
) =>
super.noSuchMethod(
Invocation.method(
#create,
[
identifier,
preferredAspectRatio,
fallbackRule,
],
),
returnValueForMissingStub: null,
);
}
/// A class which mocks [TestInstanceManagerHostApi].
///
/// See the documentation for Mockito's code generation for more information.
class MockTestInstanceManagerHostApi extends _i1.Mock
implements _i2.TestInstanceManagerHostApi {
MockTestInstanceManagerHostApi() {
_i1.throwOnMissingStub(this);
}
@override
void clear() => super.noSuchMethod(
Invocation.method(
#clear,
[],
),
returnValueForMissingStub: null,
);
}

View File

@ -3,10 +3,10 @@
// found in the LICENSE file.
import 'package:camera_android_camerax/src/analyzer.dart';
import 'package:camera_android_camerax/src/camerax_library.g.dart';
import 'package:camera_android_camerax/src/image_analysis.dart';
import 'package:camera_android_camerax/src/image_proxy.dart';
import 'package:camera_android_camerax/src/instance_manager.dart';
import 'package:camera_android_camerax/src/resolution_selector.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
@ -14,7 +14,11 @@ import 'package:mockito/mockito.dart';
import 'image_analysis_test.mocks.dart';
import 'test_camerax_library.g.dart';
@GenerateMocks(<Type>[TestImageAnalysisHostApi, TestInstanceManagerHostApi])
@GenerateMocks(<Type>[
TestImageAnalysisHostApi,
TestInstanceManagerHostApi,
ResolutionSelector,
])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
@ -22,13 +26,11 @@ void main() {
TestInstanceManagerHostApi.setup(MockTestInstanceManagerHostApi());
group('ImageAnalysis', () {
setUp(() {});
tearDown(() {
TestImageAnalysisHostApi.setup(null);
});
test('HostApi create', () {
test('create calls create on the Java side', () {
final MockTestImageAnalysisHostApi mockApi =
MockTestImageAnalysisHostApi();
TestImageAnalysisHostApi.setup(mockApi);
@ -37,25 +39,28 @@ void main() {
onWeakReferenceRemoved: (_) {},
);
const int targetResolutionWidth = 65;
const int targetResolutionHeight = 99;
final ResolutionInfo targetResolution =
ResolutionInfo(width: 65, height: 99);
final MockResolutionSelector mockResolutionSelector =
MockResolutionSelector();
const int mockResolutionSelectorId = 24;
instanceManager.addHostCreatedInstance(
mockResolutionSelector, mockResolutionSelectorId,
onCopy: (ResolutionSelector original) {
return MockResolutionSelector();
});
final ImageAnalysis instance = ImageAnalysis(
targetResolution: targetResolution,
resolutionSelector: mockResolutionSelector,
instanceManager: instanceManager,
);
final VerificationResult createVerification = verify(mockApi.create(
verify(mockApi.create(
argThat(equals(instanceManager.getIdentifier(instance))),
captureAny));
final ResolutionInfo capturedResolutionInfo =
createVerification.captured.single as ResolutionInfo;
expect(capturedResolutionInfo.width, equals(targetResolutionWidth));
expect(capturedResolutionInfo.height, equals(targetResolutionHeight));
argThat(equals(mockResolutionSelectorId))));
});
test('setAnalyzer', () async {
test('setAnalyzer makes call to set analyzer on ImageAnalysis instance',
() async {
final MockTestImageAnalysisHostApi mockApi =
MockTestImageAnalysisHostApi();
TestImageAnalysisHostApi.setup(mockApi);
@ -65,7 +70,7 @@ void main() {
);
final ImageAnalysis instance = ImageAnalysis.detached(
targetResolution: ResolutionInfo(width: 75, height: 98),
resolutionSelector: MockResolutionSelector(),
instanceManager: instanceManager,
);
const int instanceIdentifier = 0;
@ -73,7 +78,7 @@ void main() {
instance,
instanceIdentifier,
onCopy: (ImageAnalysis original) => ImageAnalysis.detached(
targetResolution: original.targetResolution,
resolutionSelector: original.resolutionSelector,
instanceManager: instanceManager,
),
);
@ -102,7 +107,8 @@ void main() {
));
});
test('clearAnalyzer', () async {
test('clearAnalyzer makes call to clear analyzer on ImageAnalysis instance',
() async {
final MockTestImageAnalysisHostApi mockApi =
MockTestImageAnalysisHostApi();
TestImageAnalysisHostApi.setup(mockApi);
@ -112,7 +118,7 @@ void main() {
);
final ImageAnalysis instance = ImageAnalysis.detached(
targetResolution: ResolutionInfo(width: 75, height: 98),
resolutionSelector: MockResolutionSelector(),
instanceManager: instanceManager,
);
const int instanceIdentifier = 0;
@ -120,7 +126,7 @@ void main() {
instance,
instanceIdentifier,
onCopy: (ImageAnalysis original) => ImageAnalysis.detached(
targetResolution: original.targetResolution,
resolutionSelector: original.resolutionSelector,
instanceManager: instanceManager,
),
);

View File

@ -5,7 +5,7 @@
// @dart=2.19
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:camera_android_camerax/src/camerax_library.g.dart' as _i3;
import 'package:camera_android_camerax/src/resolution_selector.dart' as _i3;
import 'package:mockito/mockito.dart' as _i1;
import 'test_camerax_library.g.dart' as _i2;
@ -33,14 +33,14 @@ class MockTestImageAnalysisHostApi extends _i1.Mock
@override
void create(
int? identifier,
_i3.ResolutionInfo? targetResolutionIdentifier,
int? resolutionSelectorId,
) =>
super.noSuchMethod(
Invocation.method(
#create,
[
identifier,
targetResolutionIdentifier,
resolutionSelectorId,
],
),
returnValueForMissingStub: null,
@ -88,3 +88,14 @@ class MockTestInstanceManagerHostApi extends _i1.Mock
returnValueForMissingStub: null,
);
}
/// A class which mocks [ResolutionSelector].
///
/// See the documentation for Mockito's code generation for more information.
// ignore: must_be_immutable
class MockResolutionSelector extends _i1.Mock
implements _i3.ResolutionSelector {
MockResolutionSelector() {
_i1.throwOnMissingStub(this);
}
}

View File

@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:camera_android_camerax/src/camerax_library.g.dart';
import 'package:camera_android_camerax/src/image_capture.dart';
import 'package:camera_android_camerax/src/instance_manager.dart';
import 'package:camera_android_camerax/src/resolution_selector.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
@ -12,7 +12,11 @@ import 'package:mockito/mockito.dart';
import 'image_capture_test.mocks.dart';
import 'test_camerax_library.g.dart';
@GenerateMocks(<Type>[TestImageCaptureHostApi, TestInstanceManagerHostApi])
@GenerateMocks(<Type>[
TestImageCaptureHostApi,
TestInstanceManagerHostApi,
ResolutionSelector
])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
@ -32,11 +36,11 @@ void main() {
ImageCapture.detached(
instanceManager: instanceManager,
targetFlashMode: ImageCapture.flashModeOn,
targetResolution: ResolutionInfo(width: 50, height: 10),
resolutionSelector: MockResolutionSelector(),
);
verifyNever(mockApi.create(argThat(isA<int>()), argThat(isA<int>()),
argThat(isA<ResolutionInfo>())));
argThat(isA<ResolutionSelector>())));
});
test('create calls create on the Java side', () async {
@ -47,21 +51,26 @@ void main() {
onWeakReferenceRemoved: (_) {},
);
const int targetFlashMode = ImageCapture.flashModeAuto;
const int targetResolutionWidth = 10;
const int targetResolutionHeight = 50;
final MockResolutionSelector mockResolutionSelector =
MockResolutionSelector();
const int mockResolutionSelectorId = 24;
instanceManager.addHostCreatedInstance(
mockResolutionSelector, mockResolutionSelectorId,
onCopy: (ResolutionSelector original) {
return MockResolutionSelector();
});
ImageCapture(
instanceManager: instanceManager,
targetFlashMode: targetFlashMode,
targetResolution: ResolutionInfo(
width: targetResolutionWidth, height: targetResolutionHeight),
resolutionSelector: mockResolutionSelector,
);
final VerificationResult createVerification = verify(mockApi.create(
argThat(isA<int>()), argThat(equals(targetFlashMode)), captureAny));
final ResolutionInfo capturedResolutionInfo =
createVerification.captured.single as ResolutionInfo;
expect(capturedResolutionInfo.width, equals(targetResolutionWidth));
expect(capturedResolutionInfo.height, equals(targetResolutionHeight));
verify(mockApi.create(
argThat(isA<int>()),
argThat(equals(targetFlashMode)),
argThat(equals(mockResolutionSelectorId))));
});
test('setFlashMode makes call to set flash mode for ImageCapture instance',

View File

@ -5,9 +5,9 @@
// @dart=2.19
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i4;
import 'dart:async' as _i3;
import 'package:camera_android_camerax/src/camerax_library.g.dart' as _i3;
import 'package:camera_android_camerax/src/resolution_selector.dart' as _i4;
import 'package:mockito/mockito.dart' as _i1;
import 'test_camerax_library.g.dart' as _i2;
@ -36,7 +36,7 @@ class MockTestImageCaptureHostApi extends _i1.Mock
void create(
int? identifier,
int? flashMode,
_i3.ResolutionInfo? targetResolution,
int? resolutionSelectorId,
) =>
super.noSuchMethod(
Invocation.method(
@ -44,7 +44,7 @@ class MockTestImageCaptureHostApi extends _i1.Mock
[
identifier,
flashMode,
targetResolution,
resolutionSelectorId,
],
),
returnValueForMissingStub: null,
@ -65,13 +65,13 @@ class MockTestImageCaptureHostApi extends _i1.Mock
returnValueForMissingStub: null,
);
@override
_i4.Future<String> takePicture(int? identifier) => (super.noSuchMethod(
_i3.Future<String> takePicture(int? identifier) => (super.noSuchMethod(
Invocation.method(
#takePicture,
[identifier],
),
returnValue: _i4.Future<String>.value(''),
) as _i4.Future<String>);
returnValue: _i3.Future<String>.value(''),
) as _i3.Future<String>);
}
/// A class which mocks [TestInstanceManagerHostApi].
@ -92,3 +92,14 @@ class MockTestInstanceManagerHostApi extends _i1.Mock
returnValueForMissingStub: null,
);
}
/// A class which mocks [ResolutionSelector].
///
/// See the documentation for Mockito's code generation for more information.
// ignore: must_be_immutable
class MockResolutionSelector extends _i1.Mock
implements _i4.ResolutionSelector {
MockResolutionSelector() {
_i1.throwOnMissingStub(this);
}
}

View File

@ -5,6 +5,7 @@
import 'package:camera_android_camerax/src/camerax_library.g.dart';
import 'package:camera_android_camerax/src/instance_manager.dart';
import 'package:camera_android_camerax/src/preview.dart';
import 'package:camera_android_camerax/src/resolution_selector.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
@ -12,7 +13,8 @@ import 'package:mockito/mockito.dart';
import 'preview_test.mocks.dart';
import 'test_camerax_library.g.dart';
@GenerateMocks(<Type>[TestInstanceManagerHostApi, TestPreviewHostApi])
@GenerateMocks(
<Type>[TestInstanceManagerHostApi, TestPreviewHostApi, ResolutionSelector])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
@ -32,11 +34,11 @@ void main() {
Preview.detached(
instanceManager: instanceManager,
targetRotation: 90,
targetResolution: ResolutionInfo(width: 50, height: 10),
resolutionSelector: MockResolutionSelector(),
);
verifyNever(mockApi.create(argThat(isA<int>()), argThat(isA<int>()),
argThat(isA<ResolutionInfo>())));
argThat(isA<ResolutionSelector>())));
});
test('create calls create on the Java side', () async {
@ -47,21 +49,26 @@ void main() {
onWeakReferenceRemoved: (_) {},
);
const int targetRotation = 90;
const int targetResolutionWidth = 10;
const int targetResolutionHeight = 50;
final MockResolutionSelector mockResolutionSelector =
MockResolutionSelector();
const int mockResolutionSelectorId = 24;
instanceManager.addHostCreatedInstance(
mockResolutionSelector, mockResolutionSelectorId,
onCopy: (ResolutionSelector original) {
return MockResolutionSelector();
});
Preview(
instanceManager: instanceManager,
targetRotation: targetRotation,
targetResolution: ResolutionInfo(
width: targetResolutionWidth, height: targetResolutionHeight),
resolutionSelector: mockResolutionSelector,
);
final VerificationResult createVerification = verify(mockApi.create(
argThat(isA<int>()), argThat(equals(targetRotation)), captureAny));
final ResolutionInfo capturedResolutionInfo =
createVerification.captured.single as ResolutionInfo;
expect(capturedResolutionInfo.width, equals(targetResolutionWidth));
expect(capturedResolutionInfo.height, equals(targetResolutionHeight));
verify(mockApi.create(
argThat(isA<int>()),
argThat(equals(targetRotation)),
argThat(equals(mockResolutionSelectorId))));
});
test(

View File

@ -6,6 +6,7 @@
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:camera_android_camerax/src/camerax_library.g.dart' as _i2;
import 'package:camera_android_camerax/src/resolution_selector.dart' as _i4;
import 'package:mockito/mockito.dart' as _i1;
import 'test_camerax_library.g.dart' as _i3;
@ -64,7 +65,7 @@ class MockTestPreviewHostApi extends _i1.Mock
void create(
int? identifier,
int? rotation,
_i2.ResolutionInfo? targetResolution,
int? resolutionSelectorId,
) =>
super.noSuchMethod(
Invocation.method(
@ -72,7 +73,7 @@ class MockTestPreviewHostApi extends _i1.Mock
[
identifier,
rotation,
targetResolution,
resolutionSelectorId,
],
),
returnValueForMissingStub: null,
@ -108,3 +109,14 @@ class MockTestPreviewHostApi extends _i1.Mock
),
) as _i2.ResolutionInfo);
}
/// A class which mocks [ResolutionSelector].
///
/// See the documentation for Mockito's code generation for more information.
// ignore: must_be_immutable
class MockResolutionSelector extends _i1.Mock
implements _i4.ResolutionSelector {
MockResolutionSelector() {
_i1.throwOnMissingStub(this);
}
}

View File

@ -0,0 +1,124 @@
// 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.
import 'dart:ui';
import 'package:camera_android_camerax/src/aspect_ratio_strategy.dart';
import 'package:camera_android_camerax/src/instance_manager.dart';
import 'package:camera_android_camerax/src/resolution_selector.dart';
import 'package:camera_android_camerax/src/resolution_strategy.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'resolution_selector_test.mocks.dart';
import 'test_camerax_library.g.dart';
@GenerateMocks(<Type>[
AspectRatioStrategy,
ResolutionStrategy,
TestResolutionSelectorHostApi,
TestInstanceManagerHostApi,
])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('ResolutionSelector', () {
tearDown(() {
TestResolutionSelectorHostApi.setup(null);
TestInstanceManagerHostApi.setup(null);
});
test(
'detached constructor does not make call to create expected AspectRatioStrategy instance',
() async {
final MockTestResolutionSelectorHostApi mockApi =
MockTestResolutionSelectorHostApi();
TestResolutionSelectorHostApi.setup(mockApi);
TestInstanceManagerHostApi.setup(MockTestInstanceManagerHostApi());
final InstanceManager instanceManager = InstanceManager(
onWeakReferenceRemoved: (_) {},
);
const int preferredAspectRatio = 1;
const int fallbackRule = 1;
AspectRatioStrategy.detached(
preferredAspectRatio: preferredAspectRatio,
fallbackRule: fallbackRule,
instanceManager: instanceManager,
);
ResolutionSelector.detached(
resolutionStrategy: MockResolutionStrategy(),
aspectRatioStrategy: MockAspectRatioStrategy(),
instanceManager: instanceManager,
);
verifyNever(mockApi.create(
argThat(isA<int>()),
argThat(isA<int>()),
argThat(isA<int>()),
));
});
test('HostApi create creates expected ResolutionSelector instance', () {
final MockTestResolutionSelectorHostApi mockApi =
MockTestResolutionSelectorHostApi();
TestResolutionSelectorHostApi.setup(mockApi);
TestInstanceManagerHostApi.setup(MockTestInstanceManagerHostApi());
final InstanceManager instanceManager = InstanceManager(
onWeakReferenceRemoved: (_) {},
);
final ResolutionStrategy resolutionStrategy = ResolutionStrategy.detached(
boundSize: const Size(50, 30),
fallbackRule: ResolutionStrategy.fallbackRuleClosestLower,
instanceManager: instanceManager,
);
const int resolutionStrategyIdentifier = 14;
instanceManager.addHostCreatedInstance(
resolutionStrategy,
resolutionStrategyIdentifier,
onCopy: (ResolutionStrategy original) => ResolutionStrategy.detached(
boundSize: original.boundSize,
fallbackRule: original.fallbackRule,
instanceManager: instanceManager,
),
);
final AspectRatioStrategy aspectRatioStrategy =
AspectRatioStrategy.detached(
preferredAspectRatio: AspectRatio.ratio4To3,
fallbackRule: AspectRatioStrategy.fallbackRuleAuto,
instanceManager: instanceManager,
);
const int aspectRatioStrategyIdentifier = 15;
instanceManager.addHostCreatedInstance(
aspectRatioStrategy,
aspectRatioStrategyIdentifier,
onCopy: (AspectRatioStrategy original) => AspectRatioStrategy.detached(
preferredAspectRatio: original.preferredAspectRatio,
fallbackRule: original.fallbackRule,
instanceManager: instanceManager,
),
);
final ResolutionSelector instance = ResolutionSelector(
resolutionStrategy: resolutionStrategy,
aspectRatioStrategy: aspectRatioStrategy,
instanceManager: instanceManager,
);
verify(mockApi.create(
instanceManager.getIdentifier(instance),
resolutionStrategyIdentifier,
aspectRatioStrategyIdentifier,
));
});
});
}

View File

@ -0,0 +1,103 @@
// Mocks generated by Mockito 5.4.1 from annotations
// in camera_android_camerax/test/resolution_selector_test.dart.
// Do not manually edit this file.
// @dart=2.19
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:camera_android_camerax/src/aspect_ratio_strategy.dart' as _i2;
import 'package:camera_android_camerax/src/resolution_strategy.dart' as _i3;
import 'package:mockito/mockito.dart' as _i1;
import 'test_camerax_library.g.dart' as _i4;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class
/// A class which mocks [AspectRatioStrategy].
///
/// See the documentation for Mockito's code generation for more information.
// ignore: must_be_immutable
class MockAspectRatioStrategy extends _i1.Mock
implements _i2.AspectRatioStrategy {
MockAspectRatioStrategy() {
_i1.throwOnMissingStub(this);
}
@override
int get preferredAspectRatio => (super.noSuchMethod(
Invocation.getter(#preferredAspectRatio),
returnValue: 0,
) as int);
@override
int get fallbackRule => (super.noSuchMethod(
Invocation.getter(#fallbackRule),
returnValue: 0,
) as int);
}
/// A class which mocks [ResolutionStrategy].
///
/// See the documentation for Mockito's code generation for more information.
// ignore: must_be_immutable
class MockResolutionStrategy extends _i1.Mock
implements _i3.ResolutionStrategy {
MockResolutionStrategy() {
_i1.throwOnMissingStub(this);
}
}
/// A class which mocks [TestResolutionSelectorHostApi].
///
/// See the documentation for Mockito's code generation for more information.
class MockTestResolutionSelectorHostApi extends _i1.Mock
implements _i4.TestResolutionSelectorHostApi {
MockTestResolutionSelectorHostApi() {
_i1.throwOnMissingStub(this);
}
@override
void create(
int? identifier,
int? resolutionStrategyIdentifier,
int? aspectRatioStrategyIdentifier,
) =>
super.noSuchMethod(
Invocation.method(
#create,
[
identifier,
resolutionStrategyIdentifier,
aspectRatioStrategyIdentifier,
],
),
returnValueForMissingStub: null,
);
}
/// A class which mocks [TestInstanceManagerHostApi].
///
/// See the documentation for Mockito's code generation for more information.
class MockTestInstanceManagerHostApi extends _i1.Mock
implements _i4.TestInstanceManagerHostApi {
MockTestInstanceManagerHostApi() {
_i1.throwOnMissingStub(this);
}
@override
void clear() => super.noSuchMethod(
Invocation.method(
#clear,
[],
),
returnValueForMissingStub: null,
);
}

View File

@ -0,0 +1,109 @@
// 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.
import 'dart:ui';
import 'package:camera_android_camerax/src/camerax_library.g.dart';
import 'package:camera_android_camerax/src/instance_manager.dart';
import 'package:camera_android_camerax/src/resolution_strategy.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'resolution_strategy_test.mocks.dart';
import 'test_camerax_library.g.dart';
@GenerateMocks(<Type>[
TestResolutionStrategyHostApi,
TestInstanceManagerHostApi,
])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('ResolutionStrategy', () {
tearDown(() {
TestResolutionStrategyHostApi.setup(null);
TestInstanceManagerHostApi.setup(null);
});
test(
'detached resolutionStrategy constructors do not make call to Host API create',
() {
final MockTestResolutionStrategyHostApi mockApi =
MockTestResolutionStrategyHostApi();
TestResolutionStrategyHostApi.setup(mockApi);
TestInstanceManagerHostApi.setup(MockTestInstanceManagerHostApi());
final InstanceManager instanceManager = InstanceManager(
onWeakReferenceRemoved: (_) {},
);
const Size boundSize = Size(70, 20);
const int fallbackRule = 1;
ResolutionStrategy.detached(
boundSize: boundSize,
fallbackRule: fallbackRule,
instanceManager: instanceManager,
);
verifyNever(mockApi.create(
argThat(isA<int>()),
argThat(isA<ResolutionInfo>()
.having((ResolutionInfo size) => size.width, 'width', 50)
.having((ResolutionInfo size) => size.height, 'height', 30)),
fallbackRule,
));
ResolutionStrategy.detachedHighestAvailableStrategy(
instanceManager: instanceManager,
);
verifyNever(mockApi.create(
argThat(isA<int>()),
null,
null,
));
});
test('HostApi create creates expected ResolutionStrategies', () {
final MockTestResolutionStrategyHostApi mockApi =
MockTestResolutionStrategyHostApi();
TestResolutionStrategyHostApi.setup(mockApi);
TestInstanceManagerHostApi.setup(MockTestInstanceManagerHostApi());
final InstanceManager instanceManager = InstanceManager(
onWeakReferenceRemoved: (_) {},
);
const Size boundSize = Size(50, 30);
const int fallbackRule = 0;
final ResolutionStrategy instance = ResolutionStrategy(
boundSize: boundSize,
fallbackRule: fallbackRule,
instanceManager: instanceManager,
);
verify(mockApi.create(
instanceManager.getIdentifier(instance),
argThat(isA<ResolutionInfo>()
.having((ResolutionInfo size) => size.width, 'width', 50)
.having((ResolutionInfo size) => size.height, 'height', 30)),
fallbackRule,
));
final ResolutionStrategy highestAvailableInstance =
ResolutionStrategy.highestAvailableStrategy(
instanceManager: instanceManager,
);
verify(mockApi.create(
instanceManager.getIdentifier(highestAvailableInstance),
null,
null,
));
});
});
}

View File

@ -0,0 +1,69 @@
// Mocks generated by Mockito 5.4.1 from annotations
// in camera_android_camerax/test/resolution_strategy_test.dart.
// Do not manually edit this file.
// @dart=2.19
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:camera_android_camerax/src/camerax_library.g.dart' as _i3;
import 'package:mockito/mockito.dart' as _i1;
import 'test_camerax_library.g.dart' as _i2;
// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class
/// A class which mocks [TestResolutionStrategyHostApi].
///
/// See the documentation for Mockito's code generation for more information.
class MockTestResolutionStrategyHostApi extends _i1.Mock
implements _i2.TestResolutionStrategyHostApi {
MockTestResolutionStrategyHostApi() {
_i1.throwOnMissingStub(this);
}
@override
void create(
int? identifier,
_i3.ResolutionInfo? boundSize,
int? fallbackRule,
) =>
super.noSuchMethod(
Invocation.method(
#create,
[
identifier,
boundSize,
fallbackRule,
],
),
returnValueForMissingStub: null,
);
}
/// A class which mocks [TestInstanceManagerHostApi].
///
/// See the documentation for Mockito's code generation for more information.
class MockTestInstanceManagerHostApi extends _i1.Mock
implements _i2.TestInstanceManagerHostApi {
MockTestInstanceManagerHostApi() {
_i1.throwOnMissingStub(this);
}
@override
void clear() => super.noSuchMethod(
Invocation.method(
#clear,
[],
),
returnValueForMissingStub: null,
);
}

View File

@ -597,9 +597,6 @@ class _TestPreviewHostApiCodec extends StandardMessageCodec {
if (value is ResolutionInfo) {
buffer.putUint8(128);
writeValue(buffer, value.encode());
} else if (value is ResolutionInfo) {
buffer.putUint8(129);
writeValue(buffer, value.encode());
} else {
super.writeValue(buffer, value);
}
@ -610,8 +607,6 @@ class _TestPreviewHostApiCodec extends StandardMessageCodec {
switch (type) {
case 128:
return ResolutionInfo.decode(readValue(buffer)!);
case 129:
return ResolutionInfo.decode(readValue(buffer)!);
default:
return super.readValueOfType(type, buffer);
}
@ -623,7 +618,7 @@ abstract class TestPreviewHostApi {
TestDefaultBinaryMessengerBinding.instance;
static const MessageCodec<Object?> codec = _TestPreviewHostApiCodec();
void create(int identifier, int? rotation, ResolutionInfo? targetResolution);
void create(int identifier, int? rotation, int? resolutionSelectorId);
int setSurfaceProvider(int identifier);
@ -651,9 +646,8 @@ abstract class TestPreviewHostApi {
assert(arg_identifier != null,
'Argument for dev.flutter.pigeon.PreviewHostApi.create was null, expected non-null int.');
final int? arg_rotation = (args[1] as int?);
final ResolutionInfo? arg_targetResolution =
(args[2] as ResolutionInfo?);
api.create(arg_identifier!, arg_rotation, arg_targetResolution);
final int? arg_resolutionSelectorId = (args[2] as int?);
api.create(arg_identifier!, arg_rotation, arg_resolutionSelectorId);
return <Object?>[];
});
}
@ -1033,35 +1027,12 @@ abstract class TestRecordingHostApi {
}
}
class _TestImageCaptureHostApiCodec extends StandardMessageCodec {
const _TestImageCaptureHostApiCodec();
@override
void writeValue(WriteBuffer buffer, Object? value) {
if (value is ResolutionInfo) {
buffer.putUint8(128);
writeValue(buffer, value.encode());
} else {
super.writeValue(buffer, value);
}
}
@override
Object? readValueOfType(int type, ReadBuffer buffer) {
switch (type) {
case 128:
return ResolutionInfo.decode(readValue(buffer)!);
default:
return super.readValueOfType(type, buffer);
}
}
}
abstract class TestImageCaptureHostApi {
static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
TestDefaultBinaryMessengerBinding.instance;
static const MessageCodec<Object?> codec = _TestImageCaptureHostApiCodec();
static const MessageCodec<Object?> codec = StandardMessageCodec();
void create(int identifier, int? flashMode, ResolutionInfo? targetResolution);
void create(int identifier, int? flashMode, int? resolutionSelectorId);
void setFlashMode(int identifier, int flashMode);
@ -1087,9 +1058,8 @@ abstract class TestImageCaptureHostApi {
assert(arg_identifier != null,
'Argument for dev.flutter.pigeon.ImageCaptureHostApi.create was null, expected non-null int.');
final int? arg_flashMode = (args[1] as int?);
final ResolutionInfo? arg_targetResolution =
(args[2] as ResolutionInfo?);
api.create(arg_identifier!, arg_flashMode, arg_targetResolution);
final int? arg_resolutionSelectorId = (args[2] as int?);
api.create(arg_identifier!, arg_flashMode, arg_resolutionSelectorId);
return <Object?>[];
});
}
@ -1144,8 +1114,8 @@ abstract class TestImageCaptureHostApi {
}
}
class _TestImageAnalysisHostApiCodec extends StandardMessageCodec {
const _TestImageAnalysisHostApiCodec();
class _TestResolutionStrategyHostApiCodec extends StandardMessageCodec {
const _TestResolutionStrategyHostApiCodec();
@override
void writeValue(WriteBuffer buffer, Object? value) {
if (value is ResolutionInfo) {
@ -1167,12 +1137,128 @@ class _TestImageAnalysisHostApiCodec extends StandardMessageCodec {
}
}
abstract class TestResolutionStrategyHostApi {
static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
TestDefaultBinaryMessengerBinding.instance;
static const MessageCodec<Object?> codec =
_TestResolutionStrategyHostApiCodec();
void create(int identifier, ResolutionInfo? boundSize, int? fallbackRule);
static void setup(TestResolutionStrategyHostApi? api,
{BinaryMessenger? binaryMessenger}) {
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.ResolutionStrategyHostApi.create', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
_testBinaryMessengerBinding!.defaultBinaryMessenger
.setMockDecodedMessageHandler<Object?>(channel, null);
} else {
_testBinaryMessengerBinding!.defaultBinaryMessenger
.setMockDecodedMessageHandler<Object?>(channel,
(Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.ResolutionStrategyHostApi.create was null.');
final List<Object?> args = (message as List<Object?>?)!;
final int? arg_identifier = (args[0] as int?);
assert(arg_identifier != null,
'Argument for dev.flutter.pigeon.ResolutionStrategyHostApi.create was null, expected non-null int.');
final ResolutionInfo? arg_boundSize = (args[1] as ResolutionInfo?);
final int? arg_fallbackRule = (args[2] as int?);
api.create(arg_identifier!, arg_boundSize, arg_fallbackRule);
return <Object?>[];
});
}
}
}
}
abstract class TestResolutionSelectorHostApi {
static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
TestDefaultBinaryMessengerBinding.instance;
static const MessageCodec<Object?> codec = StandardMessageCodec();
void create(int identifier, int? resolutionStrategyIdentifier,
int? aspectRatioStrategyIdentifier);
static void setup(TestResolutionSelectorHostApi? api,
{BinaryMessenger? binaryMessenger}) {
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.ResolutionSelectorHostApi.create', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
_testBinaryMessengerBinding!.defaultBinaryMessenger
.setMockDecodedMessageHandler<Object?>(channel, null);
} else {
_testBinaryMessengerBinding!.defaultBinaryMessenger
.setMockDecodedMessageHandler<Object?>(channel,
(Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.ResolutionSelectorHostApi.create was null.');
final List<Object?> args = (message as List<Object?>?)!;
final int? arg_identifier = (args[0] as int?);
assert(arg_identifier != null,
'Argument for dev.flutter.pigeon.ResolutionSelectorHostApi.create was null, expected non-null int.');
final int? arg_resolutionStrategyIdentifier = (args[1] as int?);
final int? arg_aspectRatioStrategyIdentifier = (args[2] as int?);
api.create(arg_identifier!, arg_resolutionStrategyIdentifier,
arg_aspectRatioStrategyIdentifier);
return <Object?>[];
});
}
}
}
}
abstract class TestAspectRatioStrategyHostApi {
static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
TestDefaultBinaryMessengerBinding.instance;
static const MessageCodec<Object?> codec = StandardMessageCodec();
void create(int identifier, int preferredAspectRatio, int fallbackRule);
static void setup(TestAspectRatioStrategyHostApi? api,
{BinaryMessenger? binaryMessenger}) {
{
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.AspectRatioStrategyHostApi.create', codec,
binaryMessenger: binaryMessenger);
if (api == null) {
_testBinaryMessengerBinding!.defaultBinaryMessenger
.setMockDecodedMessageHandler<Object?>(channel, null);
} else {
_testBinaryMessengerBinding!.defaultBinaryMessenger
.setMockDecodedMessageHandler<Object?>(channel,
(Object? message) async {
assert(message != null,
'Argument for dev.flutter.pigeon.AspectRatioStrategyHostApi.create was null.');
final List<Object?> args = (message as List<Object?>?)!;
final int? arg_identifier = (args[0] as int?);
assert(arg_identifier != null,
'Argument for dev.flutter.pigeon.AspectRatioStrategyHostApi.create was null, expected non-null int.');
final int? arg_preferredAspectRatio = (args[1] as int?);
assert(arg_preferredAspectRatio != null,
'Argument for dev.flutter.pigeon.AspectRatioStrategyHostApi.create was null, expected non-null int.');
final int? arg_fallbackRule = (args[2] as int?);
assert(arg_fallbackRule != null,
'Argument for dev.flutter.pigeon.AspectRatioStrategyHostApi.create was null, expected non-null int.');
api.create(
arg_identifier!, arg_preferredAspectRatio!, arg_fallbackRule!);
return <Object?>[];
});
}
}
}
}
abstract class TestImageAnalysisHostApi {
static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding =>
TestDefaultBinaryMessengerBinding.instance;
static const MessageCodec<Object?> codec = _TestImageAnalysisHostApiCodec();
static const MessageCodec<Object?> codec = StandardMessageCodec();
void create(int identifier, ResolutionInfo? targetResolutionIdentifier);
void create(int identifier, int? resolutionSelectorId);
void setAnalyzer(int identifier, int analyzerIdentifier);
@ -1197,9 +1283,8 @@ abstract class TestImageAnalysisHostApi {
final int? arg_identifier = (args[0] as int?);
assert(arg_identifier != null,
'Argument for dev.flutter.pigeon.ImageAnalysisHostApi.create was null, expected non-null int.');
final ResolutionInfo? arg_targetResolutionIdentifier =
(args[1] as ResolutionInfo?);
api.create(arg_identifier!, arg_targetResolutionIdentifier);
final int? arg_resolutionSelectorId = (args[1] as int?);
api.create(arg_identifier!, arg_resolutionSelectorId);
return <Object?>[];
});
}