diff --git a/.ci/flutter_master.version b/.ci/flutter_master.version index 9af3ba0ad9a..7ad6ea50162 100644 --- a/.ci/flutter_master.version +++ b/.ci/flutter_master.version @@ -1 +1 @@ -828a04040e111e5eec07056e82037a930f5fd5a2 +66fa4c5d301c5093cb4403b39e3d61f604b96d90 diff --git a/packages/animations/example/android/.pluginToolsConfig.yaml b/packages/animations/example/android/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/animations/example/android/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/camera/camera_android_camerax/CHANGELOG.md b/packages/camera/camera_android_camerax/CHANGELOG.md index 1c901a82bfa..24fbec47e8b 100644 --- a/packages/camera/camera_android_camerax/CHANGELOG.md +++ b/packages/camera/camera_android_camerax/CHANGELOG.md @@ -21,3 +21,4 @@ * Implements image streaming. * Provides LifecycleOwner implementation for Activities that use the plugin that do not implement it themselves. * Implements retrieval of camera information. +* Implements onCameraClosing callback method for indicating the camera is closing and bumps CameraX version to 1.3.0-alpha05. diff --git a/packages/camera/camera_android_camerax/android/build.gradle b/packages/camera/camera_android_camerax/android/build.gradle index d056449de87..ad3e8902b3a 100644 --- a/packages/camera/camera_android_camerax/android/build.gradle +++ b/packages/camera/camera_android_camerax/android/build.gradle @@ -62,7 +62,7 @@ android { dependencies { // CameraX core library using the camera2 implementation must use same version number. - def camerax_version = "1.3.0-alpha04" + def camerax_version = "1.3.0-alpha05" implementation "androidx.camera:camera-core:${camerax_version}" implementation "androidx.camera:camera-camera2:${camerax_version}" implementation "androidx.camera:camera-lifecycle:${camerax_version}" diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraAndroidCameraxPlugin.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraAndroidCameraxPlugin.java index 0289c93cb7c..23ef4ff6ed9 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraAndroidCameraxPlugin.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraAndroidCameraxPlugin.java @@ -23,7 +23,8 @@ public final class CameraAndroidCameraxPlugin implements FlutterPlugin, Activity private ImageCaptureHostApiImpl imageCaptureHostApiImpl; public SystemServicesHostApiImpl systemServicesHostApiImpl; - @VisibleForTesting ProcessCameraProviderHostApiImpl processCameraProviderHostApiImpl; + @VisibleForTesting public ProcessCameraProviderHostApiImpl processCameraProviderHostApiImpl; + @VisibleForTesting public LiveDataHostApiImpl liveDataHostApiImpl; /** * Initialize this within the {@code #configureFlutterEngine} of a Flutter activity or fragment. @@ -67,6 +68,12 @@ public void setUp( imageCaptureHostApiImpl = new ImageCaptureHostApiImpl(binaryMessenger, instanceManager, context); GeneratedCameraXLibrary.ImageCaptureHostApi.setup(binaryMessenger, imageCaptureHostApiImpl); + GeneratedCameraXLibrary.CameraHostApi.setup( + binaryMessenger, new CameraHostApiImpl(binaryMessenger, instanceManager)); + liveDataHostApiImpl = new LiveDataHostApiImpl(binaryMessenger, instanceManager); + GeneratedCameraXLibrary.LiveDataHostApi.setup(binaryMessenger, liveDataHostApiImpl); + GeneratedCameraXLibrary.ObserverHostApi.setup( + binaryMessenger, new ObserverHostApiImpl(binaryMessenger, instanceManager)); imageAnalysisHostApiImpl = new ImageAnalysisHostApiImpl(binaryMessenger, instanceManager); GeneratedCameraXLibrary.ImageAnalysisHostApi.setup(binaryMessenger, imageAnalysisHostApiImpl); GeneratedCameraXLibrary.AnalyzerHostApi.setup( @@ -91,19 +98,21 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { @Override public void onAttachedToActivity(@NonNull ActivityPluginBinding activityPluginBinding) { - setUp( - pluginBinding.getBinaryMessenger(), - pluginBinding.getApplicationContext(), - pluginBinding.getTextureRegistry()); - updateContext(pluginBinding.getApplicationContext()); - Activity activity = activityPluginBinding.getActivity(); + Context applicationContext = activity.getApplicationContext(); + + setUp( + pluginBinding.getBinaryMessenger(), applicationContext, pluginBinding.getTextureRegistry()); + updateContext(applicationContext); if (activity instanceof LifecycleOwner) { processCameraProviderHostApiImpl.setLifecycleOwner((LifecycleOwner) activity); + liveDataHostApiImpl.setLifecycleOwner((LifecycleOwner) activity); + } else { ProxyLifecycleProvider proxyLifecycleProvider = new ProxyLifecycleProvider(activity); processCameraProviderHostApiImpl.setLifecycleOwner(proxyLifecycleProvider); + liveDataHostApiImpl.setLifecycleOwner(proxyLifecycleProvider); } systemServicesHostApiImpl.setActivity(activity); diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraHostApiImpl.java index 2c40b13c008..98f5f74b959 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraHostApiImpl.java @@ -31,10 +31,11 @@ public Long getCameraInfo(@NonNull Long identifier) { Camera camera = (Camera) Objects.requireNonNull(instanceManager.getInstance(identifier)); CameraInfo cameraInfo = camera.getCameraInfo(); - CameraInfoFlutterApiImpl cameraInfoFlutterApiImpl = - new CameraInfoFlutterApiImpl(binaryMessenger, instanceManager); - cameraInfoFlutterApiImpl.create(cameraInfo, reply -> {}); - + if (!instanceManager.containsInstance(cameraInfo)) { + CameraInfoFlutterApiImpl cameraInfoFlutterApiImpl = + new CameraInfoFlutterApiImpl(binaryMessenger, instanceManager); + cameraInfoFlutterApiImpl.create(cameraInfo, reply -> {}); + } return instanceManager.getIdentifierForStrongReference(cameraInfo); } } diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraInfoFlutterApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraInfoFlutterApiImpl.java index d19349bcd83..45fd784b65c 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraInfoFlutterApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraInfoFlutterApiImpl.java @@ -17,6 +17,9 @@ public CameraInfoFlutterApiImpl( this.instanceManager = instanceManager; } + /** + * Creates a {@link CameraInfo} instance in Dart. {@code reply} is not used so it can be empty. + */ void create(CameraInfo cameraInfo, Reply reply) { if (!instanceManager.containsInstance(cameraInfo)) { create(instanceManager.addHostCreatedInstance(cameraInfo), reply); diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraInfoHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraInfoHostApiImpl.java index f9fd7722fc8..b43996da427 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraInfoHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraInfoHostApiImpl.java @@ -5,24 +5,35 @@ package io.flutter.plugins.camerax; import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; import androidx.camera.core.CameraInfo; +import androidx.camera.core.CameraState; import androidx.camera.core.ExposureState; import androidx.camera.core.ZoomState; +import androidx.lifecycle.LiveData; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugins.camerax.GeneratedCameraXLibrary.CameraInfoHostApi; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.LiveDataSupportedType; import java.util.Objects; public class CameraInfoHostApiImpl implements CameraInfoHostApi { private final BinaryMessenger binaryMessenger; private final InstanceManager instanceManager; + @VisibleForTesting public LiveDataFlutterApiWrapper liveDataFlutterApiWrapper; + public CameraInfoHostApiImpl( @NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) { this.binaryMessenger = binaryMessenger; this.instanceManager = instanceManager; + this.liveDataFlutterApiWrapper = + new LiveDataFlutterApiWrapper(binaryMessenger, instanceManager); } - /** Retrieves the sensor rotation in degrees, relative to the device's default orientation. */ + /** + * Retrieves the sensor rotation degrees of the {@link androidx.camera.core.Camera} that is + * represented by the {@link CameraInfo} with the specified identifier. + */ @Override @NonNull public Long getSensorRotationDegrees(@NonNull Long identifier) { @@ -31,6 +42,22 @@ public Long getSensorRotationDegrees(@NonNull Long identifier) { return Long.valueOf(cameraInfo.getSensorRotationDegrees()); } + /** + * Retrieves the {@link LiveData} of the {@link CameraState} that is tied to the {@link + * androidx.camera.core.Camera} that is represented by the {@link CameraInfo} with the specified + * identifier. + */ + @Override + @NonNull + public Long getLiveCameraState(@NonNull Long identifier) { + CameraInfo cameraInfo = + (CameraInfo) Objects.requireNonNull(instanceManager.getInstance(identifier)); + LiveData liveCameraState = cameraInfo.getCameraState(); + liveDataFlutterApiWrapper.create( + liveCameraState, LiveDataSupportedType.CAMERA_STATE, reply -> {}); + return instanceManager.getIdentifierForStrongReference(liveCameraState); + } + /** * Retrieves the {@link ExposureState} of the {@link CameraInfo} with the specified identifier. */ diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraStateErrorFlutterApiWrapper.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraStateErrorFlutterApiWrapper.java new file mode 100644 index 00000000000..f4c8d6ee4af --- /dev/null +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraStateErrorFlutterApiWrapper.java @@ -0,0 +1,57 @@ +// 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.CameraState; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.CameraStateErrorFlutterApi; + +/** + * Flutter API implementation for {@link CameraStateError}. + * + *

This class may handle adding native instances that are attached to a Dart instance or passing + * arguments of callbacks methods to a Dart instance. + */ +public class CameraStateErrorFlutterApiWrapper { + private final BinaryMessenger binaryMessenger; + private final InstanceManager instanceManager; + private CameraStateErrorFlutterApi cameraStateErrorFlutterApi; + + /** + * Constructs a {@link CameraStateErrorFlutterApiWrapper}. + * + * @param binaryMessenger used to communicate with Dart over asynchronous messages + * @param instanceManager maintains instances stored to communicate with attached Dart objects + */ + public CameraStateErrorFlutterApiWrapper( + @NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) { + this.binaryMessenger = binaryMessenger; + this.instanceManager = instanceManager; + cameraStateErrorFlutterApi = new CameraStateErrorFlutterApi(binaryMessenger); + } + + /** + * Stores the {@link CameraStateError} instance and notifies Dart to create and store a new {@link + * CameraStateError} instance that is attached to this one. If {@code instance} has already been + * added, this method does nothing. + */ + public void create( + @NonNull CameraState.StateError instance, + @NonNull Long code, + @NonNull CameraStateErrorFlutterApi.Reply callback) { + if (!instanceManager.containsInstance(instance)) { + cameraStateErrorFlutterApi.create( + instanceManager.addHostCreatedInstance(instance), code, callback); + } + } + + /** Sets the Flutter API used to send messages to Dart. */ + @VisibleForTesting + void setApi(@NonNull CameraStateErrorFlutterApi api) { + this.cameraStateErrorFlutterApi = api; + } +} diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraStateFlutterApiWrapper.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraStateFlutterApiWrapper.java new file mode 100644 index 00000000000..e6e83c4af99 --- /dev/null +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraStateFlutterApiWrapper.java @@ -0,0 +1,101 @@ +// 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.CameraState; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.CameraStateFlutterApi; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.CameraStateType; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.CameraStateTypeData; + +/** + * Flutter API implementation for {@link CameraState}. + * + *

This class may handle adding native instances that are attached to a Dart instance or passing + * arguments of callbacks methods to a Dart instance. + */ +public class CameraStateFlutterApiWrapper { + private final BinaryMessenger binaryMessenger; + private final InstanceManager instanceManager; + private CameraStateFlutterApi cameraStateFlutterApi; + + /** + * Constructs a {@link CameraStateFlutterApiWrapper}. + * + * @param binaryMessenger used to communicate with Dart over asynchronous messages + * @param instanceManager maintains instances stored to communicate with attached Dart objects + */ + public CameraStateFlutterApiWrapper( + @NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) { + this.binaryMessenger = binaryMessenger; + this.instanceManager = instanceManager; + cameraStateFlutterApi = new CameraStateFlutterApi(binaryMessenger); + } + + /** + * Stores the {@link CameraState} instance and notifies Dart to create and store a new {@link + * CameraState} instance that is attached to this one. If {@code instance} has already been added, + * this method does nothing. + */ + public void create( + @NonNull CameraState instance, + @NonNull CameraStateType type, + @Nullable CameraState.StateError error, + @NonNull CameraStateFlutterApi.Reply callback) { + if (instanceManager.containsInstance(instance)) { + return; + } + + if (error != null) { + // We need to create a CameraStateError if there is a problem with the current camera + // state to send to the Dart side. + new CameraStateErrorFlutterApiWrapper(binaryMessenger, instanceManager) + .create(error, Long.valueOf(error.getCode()), reply -> {}); + } + + cameraStateFlutterApi.create( + instanceManager.addHostCreatedInstance(instance), + new CameraStateTypeData.Builder().setValue(type).build(), + instanceManager.getIdentifierForStrongReference(error), + callback); + } + + /** Convert CameraX CameraState.Type to CameraStateType that the Dart side understands. */ + public static CameraStateType getCameraStateType(@NonNull CameraState.Type type) { + CameraStateType cameraStateType = null; + switch (type) { + case CLOSED: + cameraStateType = CameraStateType.CLOSED; + break; + case CLOSING: + cameraStateType = CameraStateType.CLOSING; + break; + case OPEN: + cameraStateType = CameraStateType.OPEN; + break; + case OPENING: + cameraStateType = CameraStateType.OPENING; + break; + case PENDING_OPEN: + cameraStateType = CameraStateType.PENDING_OPEN; + break; + } + + if (cameraStateType == null) { + throw new IllegalArgumentException( + "The CameraState.Type passed to this method was not recognized."); + } + return cameraStateType; + } + + /** Sets the Flutter API used to send messages to Dart. */ + @VisibleForTesting + void setApi(@NonNull CameraStateFlutterApi api) { + this.cameraStateFlutterApi = api; + } +} diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraXProxy.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraXProxy.java index da025b11dac..441a87035e9 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraXProxy.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraXProxy.java @@ -31,10 +31,12 @@ public CameraSelector.Builder createCameraSelectorBuilder() { return new CameraSelector.Builder(); } + /** Creates an instance of {@link CameraPermissionsManager}. */ public CameraPermissionsManager createCameraPermissionsManager() { return new CameraPermissionsManager(); } + /** Creates an instance of the {@link DeviceOrientationManager}. */ public DeviceOrientationManager createDeviceOrientationManager( @NonNull Activity activity, @NonNull Boolean isFrontFacing, @@ -43,16 +45,18 @@ public DeviceOrientationManager createDeviceOrientationManager( return new DeviceOrientationManager(activity, isFrontFacing, sensorOrientation, callback); } + /** Creates a builder for an instance of the {@link Preview} use case. */ public Preview.Builder createPreviewBuilder() { return new Preview.Builder(); } + /** Creates a {@link Surface} instance from the specified {@link SurfaceTexture}. */ public Surface createSurface(@NonNull SurfaceTexture surfaceTexture) { return new Surface(surfaceTexture); } /** - * Creates an instance of the {@code SystemServicesFlutterApiImpl}. + * Creates an instance of the {@link SystemServicesFlutterApiImpl}. * *

Included in this class to utilize the callback methods it provides, e.g. {@code * onCameraError(String)}. @@ -62,6 +66,7 @@ public SystemServicesFlutterApiImpl createSystemServicesFlutterApiImpl( return new SystemServicesFlutterApiImpl(binaryMessenger); } + /** Creates a builder for an instance of the {@link ImageCapture} use case. */ public ImageCapture.Builder createImageCaptureBuilder() { return new ImageCapture.Builder(); } diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/GeneratedCameraXLibrary.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/GeneratedCameraXLibrary.java index 882c1d14632..81d71a141ae 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/GeneratedCameraXLibrary.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/GeneratedCameraXLibrary.java @@ -57,6 +57,35 @@ protected static ArrayList wrapError(@NonNull Throwable exception) { return errorList; } + /** + * The states the camera can be in. + * + *

See https://developer.android.com/reference/androidx/camera/core/CameraState.Type. + */ + public enum CameraStateType { + CLOSED(0), + CLOSING(1), + OPEN(2), + OPENING(3), + PENDING_OPEN(4); + + final int index; + + private CameraStateType(final int index) { + this.index = index; + } + } + + public enum LiveDataSupportedType { + CAMERA_STATE(0); + + final int index; + + private LiveDataSupportedType(final int index) { + this.index = index; + } + } + /** Generated class from Pigeon that represents data sent in messages. */ public static final class ResolutionInfo { private @NonNull Long width; @@ -207,6 +236,104 @@ ArrayList toList() { } } + /** Generated class from Pigeon that represents data sent in messages. */ + public static final class CameraStateTypeData { + private @NonNull CameraStateType value; + + public @NonNull CameraStateType getValue() { + return value; + } + + public void setValue(@NonNull CameraStateType setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"value\" is null."); + } + this.value = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + CameraStateTypeData() {} + + public static final class Builder { + + private @Nullable CameraStateType value; + + public @NonNull Builder setValue(@NonNull CameraStateType setterArg) { + this.value = setterArg; + return this; + } + + public @NonNull CameraStateTypeData build() { + CameraStateTypeData pigeonReturn = new CameraStateTypeData(); + pigeonReturn.setValue(value); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(value == null ? null : value.index); + return toListResult; + } + + static @NonNull CameraStateTypeData fromList(@NonNull ArrayList list) { + CameraStateTypeData pigeonResult = new CameraStateTypeData(); + Object value = list.get(0); + pigeonResult.setValue(value == null ? null : CameraStateType.values()[(int) value]); + return pigeonResult; + } + } + + /** Generated class from Pigeon that represents data sent in messages. */ + public static final class LiveDataSupportedTypeData { + private @NonNull LiveDataSupportedType value; + + public @NonNull LiveDataSupportedType getValue() { + return value; + } + + public void setValue(@NonNull LiveDataSupportedType setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"value\" is null."); + } + this.value = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + LiveDataSupportedTypeData() {} + + public static final class Builder { + + private @Nullable LiveDataSupportedType value; + + public @NonNull Builder setValue(@NonNull LiveDataSupportedType setterArg) { + this.value = setterArg; + return this; + } + + public @NonNull LiveDataSupportedTypeData build() { + LiveDataSupportedTypeData pigeonReturn = new LiveDataSupportedTypeData(); + pigeonReturn.setValue(value); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(value == null ? null : value.index); + return toListResult; + } + + static @NonNull LiveDataSupportedTypeData fromList(@NonNull ArrayList list) { + LiveDataSupportedTypeData pigeonResult = new LiveDataSupportedTypeData(); + Object value = list.get(0); + pigeonResult.setValue(value == null ? null : LiveDataSupportedType.values()[(int) value]); + return pigeonResult; + } + } + /** Generated class from Pigeon that represents data sent in messages. */ public static final class ExposureCompensationRange { private @NonNull Long minCompensation; @@ -409,6 +536,9 @@ public interface CameraInfoHostApi { @NonNull Long getSensorRotationDegrees(@NonNull Long identifier); + @NonNull + Long getLiveCameraState(@NonNull Long identifier); + @NonNull Long getExposureState(@NonNull Long identifier); @@ -450,6 +580,33 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable CameraInfo channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.CameraInfoHostApi.getLiveCameraState", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + Number identifierArg = (Number) args.get(0); + try { + Long output = + api.getLiveCameraState( + (identifierArg == null) ? null : identifierArg.longValue()); + wrapped.add(0, output); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } { BasicMessageChannel channel = new BasicMessageChannel<>( @@ -1395,6 +1552,64 @@ public void error(Throwable error) { } } + private static class CameraStateFlutterApiCodec extends StandardMessageCodec { + public static final CameraStateFlutterApiCodec INSTANCE = new CameraStateFlutterApiCodec(); + + private CameraStateFlutterApiCodec() {} + + @Override + protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { + switch (type) { + case (byte) 128: + return CameraStateTypeData.fromList((ArrayList) readValue(buffer)); + default: + return super.readValueOfType(type, buffer); + } + } + + @Override + protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) { + if (value instanceof CameraStateTypeData) { + stream.write(128); + writeValue(stream, ((CameraStateTypeData) value).toList()); + } else { + super.writeValue(stream, value); + } + } + } + + /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ + public static class CameraStateFlutterApi { + private final @NonNull BinaryMessenger binaryMessenger; + + public CameraStateFlutterApi(@NonNull BinaryMessenger argBinaryMessenger) { + this.binaryMessenger = argBinaryMessenger; + } + + /** Public interface for sending reply. */ + @SuppressWarnings("UnknownNullness") + public interface Reply { + void reply(T reply); + } + /** The codec used by CameraStateFlutterApi. */ + static @NonNull MessageCodec getCodec() { + return CameraStateFlutterApiCodec.INSTANCE; + } + + public void create( + @NonNull Long identifierArg, + @NonNull CameraStateTypeData typeArg, + @Nullable Long errorIdentifierArg, + @NonNull Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.CameraStateFlutterApi.create", getCodec()); + channel.send( + new ArrayList(Arrays.asList(identifierArg, typeArg, errorIdentifierArg)), + channelReply -> callback.reply(null)); + } + } + private static class ExposureStateFlutterApiCodec extends StandardMessageCodec { public static final ExposureStateFlutterApiCodec INSTANCE = new ExposureStateFlutterApiCodec(); @@ -1648,6 +1863,225 @@ static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable AnalyzerHo } } } + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ + public interface ObserverHostApi { + + void create(@NonNull Long identifier); + + /** The codec used by ObserverHostApi. */ + static @NonNull MessageCodec getCodec() { + return new StandardMessageCodec(); + } + /** + * Sets up an instance of `ObserverHostApi` to handle messages through the `binaryMessenger`. + */ + static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable ObserverHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.ObserverHostApi.create", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + Number identifierArg = (Number) args.get(0); + try { + api.create((identifierArg == null) ? null : identifierArg.longValue()); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } + /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ + public static class ObserverFlutterApi { + private final @NonNull BinaryMessenger binaryMessenger; + + public ObserverFlutterApi(@NonNull BinaryMessenger argBinaryMessenger) { + this.binaryMessenger = argBinaryMessenger; + } + + /** Public interface for sending reply. */ + @SuppressWarnings("UnknownNullness") + public interface Reply { + void reply(T reply); + } + /** The codec used by ObserverFlutterApi. */ + static @NonNull MessageCodec getCodec() { + return new StandardMessageCodec(); + } + + public void onChanged( + @NonNull Long identifierArg, + @NonNull Long valueIdentifierArg, + @NonNull Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.ObserverFlutterApi.onChanged", getCodec()); + channel.send( + new ArrayList(Arrays.asList(identifierArg, valueIdentifierArg)), + channelReply -> callback.reply(null)); + } + } + /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ + public static class CameraStateErrorFlutterApi { + private final @NonNull BinaryMessenger binaryMessenger; + + public CameraStateErrorFlutterApi(@NonNull BinaryMessenger argBinaryMessenger) { + this.binaryMessenger = argBinaryMessenger; + } + + /** Public interface for sending reply. */ + @SuppressWarnings("UnknownNullness") + public interface Reply { + void reply(T reply); + } + /** The codec used by CameraStateErrorFlutterApi. */ + static @NonNull MessageCodec getCodec() { + return new StandardMessageCodec(); + } + + public void create( + @NonNull Long identifierArg, @NonNull Long codeArg, @NonNull Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.CameraStateErrorFlutterApi.create", getCodec()); + channel.send( + new ArrayList(Arrays.asList(identifierArg, codeArg)), + channelReply -> callback.reply(null)); + } + } + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ + public interface LiveDataHostApi { + + void observe(@NonNull Long identifier, @NonNull Long observerIdentifier); + + void removeObservers(@NonNull Long identifier); + + /** The codec used by LiveDataHostApi. */ + static @NonNull MessageCodec getCodec() { + return new StandardMessageCodec(); + } + /** + * Sets up an instance of `LiveDataHostApi` to handle messages through the `binaryMessenger`. + */ + static void setup(@NonNull BinaryMessenger binaryMessenger, @Nullable LiveDataHostApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.LiveDataHostApi.observe", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + Number identifierArg = (Number) args.get(0); + Number observerIdentifierArg = (Number) args.get(1); + try { + api.observe( + (identifierArg == null) ? null : identifierArg.longValue(), + (observerIdentifierArg == null) ? null : observerIdentifierArg.longValue()); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.LiveDataHostApi.removeObservers", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + Number identifierArg = (Number) args.get(0); + try { + api.removeObservers((identifierArg == null) ? null : identifierArg.longValue()); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } + + private static class LiveDataFlutterApiCodec extends StandardMessageCodec { + public static final LiveDataFlutterApiCodec INSTANCE = new LiveDataFlutterApiCodec(); + + private LiveDataFlutterApiCodec() {} + + @Override + protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { + switch (type) { + case (byte) 128: + return LiveDataSupportedTypeData.fromList((ArrayList) readValue(buffer)); + default: + return super.readValueOfType(type, buffer); + } + } + + @Override + protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) { + if (value instanceof LiveDataSupportedTypeData) { + stream.write(128); + writeValue(stream, ((LiveDataSupportedTypeData) value).toList()); + } else { + super.writeValue(stream, value); + } + } + } + + /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ + public static class LiveDataFlutterApi { + private final @NonNull BinaryMessenger binaryMessenger; + + public LiveDataFlutterApi(@NonNull BinaryMessenger argBinaryMessenger) { + this.binaryMessenger = argBinaryMessenger; + } + + /** Public interface for sending reply. */ + @SuppressWarnings("UnknownNullness") + public interface Reply { + void reply(T reply); + } + /** The codec used by LiveDataFlutterApi. */ + static @NonNull MessageCodec getCodec() { + return LiveDataFlutterApiCodec.INSTANCE; + } + + public void create( + @NonNull Long identifierArg, + @NonNull LiveDataSupportedTypeData typeArg, + @NonNull Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.LiveDataFlutterApi.create", getCodec()); + channel.send( + new ArrayList(Arrays.asList(identifierArg, typeArg)), + channelReply -> callback.reply(null)); + } + } /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ public static class AnalyzerFlutterApi { private final @NonNull BinaryMessenger binaryMessenger; diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/LiveDataFlutterApiWrapper.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/LiveDataFlutterApiWrapper.java new file mode 100644 index 00000000000..50b10fc7620 --- /dev/null +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/LiveDataFlutterApiWrapper.java @@ -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.lifecycle.LiveData; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.LiveDataFlutterApi; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.LiveDataSupportedType; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.LiveDataSupportedTypeData; + +/** + * Flutter API implementation for {@link LiveData}. + * + *

This class may handle adding native instances that are attached to a Dart instance or passing + * arguments of callbacks methods to a Dart instance. + */ +public class LiveDataFlutterApiWrapper { + private final BinaryMessenger binaryMessenger; + private final InstanceManager instanceManager; + private LiveDataFlutterApi liveDataFlutterApi; + + /** + * Constructs a {@link LiveDataFlutterApiWrapper}. + * + * @param binaryMessenger used to communicate with Dart over asynchronous messages + * @param instanceManager maintains instances stored to communicate with attached Dart objects + */ + public LiveDataFlutterApiWrapper( + @NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) { + this.binaryMessenger = binaryMessenger; + this.instanceManager = instanceManager; + liveDataFlutterApi = new LiveDataFlutterApi(binaryMessenger); + } + + /** + * Stores the {@link LiveData} instance and notifies Dart to create and store a new {@link + * LiveData} instance that is attached to this one. If {@code instance} has already been added, + * this method does nothing. + */ + public void create( + @NonNull LiveData instance, + @NonNull LiveDataSupportedType type, + @NonNull LiveDataFlutterApi.Reply callback) { + if (!instanceManager.containsInstance(instance)) { + liveDataFlutterApi.create( + instanceManager.addHostCreatedInstance(instance), + new LiveDataSupportedTypeData.Builder().setValue(type).build(), + callback); + } + } + + /** + * Sets the Flutter API used to send messages to Dart. + * + *

This is only visible for testing. + */ + @VisibleForTesting + void setApi(@NonNull LiveDataFlutterApi api) { + this.liveDataFlutterApi = api; + } +} diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/LiveDataHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/LiveDataHostApiImpl.java new file mode 100644 index 00000000000..0cac5c621d7 --- /dev/null +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/LiveDataHostApiImpl.java @@ -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.lifecycle.LifecycleOwner; +import androidx.lifecycle.LiveData; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.LiveDataHostApi; +import java.util.Objects; + +/** + * Host API implementation for {@link LiveData}. + * + *

This class may handle 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 LiveDataHostApiImpl implements LiveDataHostApi { + private final BinaryMessenger binaryMessenger; + private final InstanceManager instanceManager; + private LifecycleOwner lifecycleOwner; + + /** + * Constructs a {@link LiveDataHostApiImpl}. + * + * @param binaryMessenger used to communicate with Dart over asynchronous messages + * @param instanceManager maintains instances stored to communicate with attached Dart objects + */ + public LiveDataHostApiImpl( + @NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) { + this.binaryMessenger = binaryMessenger; + this.instanceManager = instanceManager; + } + + /** Sets {@link LifecycleOwner} used to observe the camera state if so requested. */ + public void setLifecycleOwner(@NonNull LifecycleOwner lifecycleOwner) { + this.lifecycleOwner = lifecycleOwner; + } + + /** + * Adds an {@link Observer} with the specified identifier to the observers list of this instance + * within the lifespan of the {@link lifecycleOwner}. + */ + @Override + @SuppressWarnings("unchecked") + public void observe(@NonNull Long identifier, @NonNull Long observerIdentifier) { + getLiveDataInstance(identifier) + .observe( + lifecycleOwner, + Objects.requireNonNull(instanceManager.getInstance(observerIdentifier))); + } + + /** Removes all observers of this instance that are tied to the {@link lifecycleOwner}. */ + @Override + public void removeObservers(@NonNull Long identifier) { + getLiveDataInstance(identifier).removeObservers(lifecycleOwner); + } + + /** Retrieves the {@link LiveData} instance that has the specified identifier. */ + private LiveData getLiveDataInstance(@NonNull Long identifier) { + return Objects.requireNonNull(instanceManager.getInstance(identifier)); + } +} diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ObserverFlutterApiWrapper.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ObserverFlutterApiWrapper.java new file mode 100644 index 00000000000..a337385f79a --- /dev/null +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ObserverFlutterApiWrapper.java @@ -0,0 +1,83 @@ +// 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.CameraState; +import androidx.lifecycle.Observer; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.ObserverFlutterApi; +import java.util.Objects; + +/** + * Flutter API implementation for {@link Observer}. + * + *

This class may handle adding native instances that are attached to a Dart instance or passing + * arguments of callbacks methods to a Dart instance. + */ +public class ObserverFlutterApiWrapper { + private final BinaryMessenger binaryMessenger; + private final InstanceManager instanceManager; + private ObserverFlutterApi observerFlutterApi; + + @VisibleForTesting public CameraStateFlutterApiWrapper cameraStateFlutterApiWrapper; + + /** + * Constructs a {@link ObserverFlutterApiWrapper}. + * + * @param binaryMessenger used to communicate with Dart over asynchronous messages + * @param instanceManager maintains instances stored to communicate with attached Dart objects + */ + public ObserverFlutterApiWrapper( + @NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) { + this.binaryMessenger = binaryMessenger; + this.instanceManager = instanceManager; + observerFlutterApi = new ObserverFlutterApi(binaryMessenger); + } + + /** + * Sends a message to Dart to call {@link Observer.onChanged} on the Dart object representing + * {@code instance}. + */ + public void onChanged( + @NonNull Observer instance, + @NonNull Object value, + @NonNull ObserverFlutterApi.Reply callback) { + + // Cast value to type of data that is being observed if supported by this plugin. + if (value instanceof CameraState) { + CameraState state = (CameraState) value; + + if (cameraStateFlutterApiWrapper == null) { + cameraStateFlutterApiWrapper = + new CameraStateFlutterApiWrapper(binaryMessenger, instanceManager); + } + cameraStateFlutterApiWrapper.create( + state, + CameraStateFlutterApiWrapper.getCameraStateType(state.getType()), + state.getError(), + reply -> {}); + } else { + throw new UnsupportedOperationException( + "The type of value in observance is not wrapped by this plugin."); + } + + observerFlutterApi.onChanged( + Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(instance)), + instanceManager.getIdentifierForStrongReference(value), + callback); + } + + /** + * Sets the Flutter API used to send messages to Dart. + * + *

This is only visible for testing. + */ + @VisibleForTesting + void setApi(@NonNull ObserverFlutterApi api) { + this.observerFlutterApi = api; + } +} diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ObserverHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ObserverHostApiImpl.java new file mode 100644 index 00000000000..963c0df5a22 --- /dev/null +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ObserverHostApiImpl.java @@ -0,0 +1,107 @@ +// 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.lifecycle.Observer; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.ObserverHostApi; +import java.util.Objects; + +/** + * Host API implementation for {@link Observer}. + * + *

This class may handle 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 ObserverHostApiImpl implements ObserverHostApi { + private final BinaryMessenger binaryMessenger; + private final InstanceManager instanceManager; + private final ObserverProxy observerProxy; + + /** Proxy for constructors and static method of {@link Observer}. */ + @VisibleForTesting + public static class ObserverProxy { + + /** Creates an instance of {@link Observer}. */ + @NonNull + public ObserverImpl create( + @NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) { + return new ObserverImpl(binaryMessenger, instanceManager); + } + } + + /** Implementation of {@link Observer} that passes arguments of callback methods to Dart. */ + public static class ObserverImpl implements Observer { + private ObserverFlutterApiWrapper observerFlutterApiWrapper; + + /** + * Constructs an instance of {@link Observer} that passes arguments of callbacks methods to + * Dart. + */ + public ObserverImpl( + @NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) { + super(); + observerFlutterApiWrapper = new ObserverFlutterApiWrapper(binaryMessenger, instanceManager); + } + + /** Method called when the data in observance is changed to {@code value}. */ + @Override + public void onChanged(T value) { + observerFlutterApiWrapper.onChanged(this, value, reply -> {}); + } + + /** + * Flutter API used to send messages back to Dart. + * + *

This is only visible for testing. + */ + @VisibleForTesting + void setApi(@NonNull ObserverFlutterApiWrapper api) { + this.observerFlutterApiWrapper = api; + } + } + + /** + * Constructs a {@link ObserverHostApiImpl}. + * + * @param binaryMessenger used to communicate with Dart over asynchronous messages + * @param instanceManager maintains instances stored to communicate with attached Dart objects + */ + public ObserverHostApiImpl( + @NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) { + + this(binaryMessenger, instanceManager, new ObserverProxy()); + } + + /** + * Constructs a {@link ObserverHostApiImpl}. + * + * @param binaryMessenger used to communicate with Dart over asynchronous messages + * @param instanceManager maintains instances stored to communicate with attached Dart objects + * @param proxy proxy for constructors and static method of {@link Observer} + */ + @VisibleForTesting + ObserverHostApiImpl( + @NonNull BinaryMessenger binaryMessenger, + @NonNull InstanceManager instanceManager, + @NonNull ObserverProxy observerProxy) { + this.binaryMessenger = binaryMessenger; + this.instanceManager = instanceManager; + this.observerProxy = observerProxy; + } + + /** Creates an {@link Observer} instance with the specified observer. */ + @Override + public void create(@NonNull Long identifier) { + instanceManager.addDartCreatedInstance( + observerProxy.create(binaryMessenger, instanceManager), identifier); + } + + private Observer getObserverInstance(@NonNull Long identifier) { + return Objects.requireNonNull(instanceManager.getInstance(identifier)); + } +} diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/PreviewHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/PreviewHostApiImpl.java index 8491fa25fd4..c7c4c41aa0f 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/PreviewHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/PreviewHostApiImpl.java @@ -112,7 +112,7 @@ public void onSurfaceRequested(SurfaceRequest request) { * Returns an error description for each {@link SurfaceRequest.Result} that represents an error * with providing a surface. */ - private String getProvideSurfaceErrorDescription(@Nullable int resultCode) { + private String getProvideSurfaceErrorDescription(int resultCode) { switch (resultCode) { case SurfaceRequest.Result.RESULT_INVALID_SURFACE: return resultCode + ": Provided surface could not be used by the camera."; diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraAndroidCameraxPluginTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraAndroidCameraxPluginTest.java index a73654d0e69..4a2197624b6 100644 --- a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraAndroidCameraxPluginTest.java +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraAndroidCameraxPluginTest.java @@ -36,17 +36,20 @@ public void onAttachedToActivity_setsLifecycleOwnerAsActivityIfLifecycleOwner() mock(Activity.class, withSettings().extraInterfaces(LifecycleOwner.class)); ProcessCameraProviderHostApiImpl mockProcessCameraProviderHostApiImpl = mock(ProcessCameraProviderHostApiImpl.class); + LiveDataHostApiImpl mockLiveDataHostApiImpl = mock(LiveDataHostApiImpl.class); doNothing().when(plugin).setUp(any(), any(), any()); when(activityPluginBinding.getActivity()).thenReturn(mockActivity); plugin.processCameraProviderHostApiImpl = mockProcessCameraProviderHostApiImpl; + plugin.liveDataHostApiImpl = mockLiveDataHostApiImpl; plugin.systemServicesHostApiImpl = mock(SystemServicesHostApiImpl.class); plugin.onAttachedToEngine(flutterPluginBinding); plugin.onAttachedToActivity(activityPluginBinding); verify(mockProcessCameraProviderHostApiImpl).setLifecycleOwner(any(LifecycleOwner.class)); + verify(mockLiveDataHostApiImpl).setLifecycleOwner(any(LifecycleOwner.class)); } @Test @@ -56,12 +59,14 @@ public void onAttachedToActivity_setsLifecycleOwnerAsActivityIfLifecycleOwner() Activity mockActivity = mock(Activity.class); ProcessCameraProviderHostApiImpl mockProcessCameraProviderHostApiImpl = mock(ProcessCameraProviderHostApiImpl.class); + LiveDataHostApiImpl mockLiveDataHostApiImpl = mock(LiveDataHostApiImpl.class); doNothing().when(plugin).setUp(any(), any(), any()); when(activityPluginBinding.getActivity()).thenReturn(mockActivity); when(mockActivity.getApplication()).thenReturn(mock(Application.class)); plugin.processCameraProviderHostApiImpl = mockProcessCameraProviderHostApiImpl; + plugin.liveDataHostApiImpl = mockLiveDataHostApiImpl; plugin.systemServicesHostApiImpl = mock(SystemServicesHostApiImpl.class); plugin.onAttachedToEngine(flutterPluginBinding); @@ -69,5 +74,6 @@ public void onAttachedToActivity_setsLifecycleOwnerAsActivityIfLifecycleOwner() verify(mockProcessCameraProviderHostApiImpl) .setLifecycleOwner(any(ProxyLifecycleProvider.class)); + verify(mockLiveDataHostApiImpl).setLifecycleOwner(any(ProxyLifecycleProvider.class)); } } diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraInfoTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraInfoTest.java index 5cfd06935b8..f8bbe276498 100644 --- a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraInfoTest.java +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraInfoTest.java @@ -13,10 +13,12 @@ import static org.mockito.Mockito.when; import androidx.camera.core.CameraInfo; +import androidx.camera.core.CameraState; import androidx.camera.core.ExposureState; import androidx.camera.core.ZoomState; import androidx.lifecycle.LiveData; import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.LiveDataSupportedType; import java.util.Objects; import org.junit.After; import org.junit.Before; @@ -45,7 +47,7 @@ public void tearDown() { } @Test - public void getSensorRotationDegrees_retrievesExpectedSensorRotation() { + public void getSensorRotationDegrees_makesCallToRetrieveSensorRotationDegrees() { final CameraInfoHostApiImpl cameraInfoHostApi = new CameraInfoHostApiImpl(mockBinaryMessenger, testInstanceManager); @@ -57,6 +59,30 @@ public void getSensorRotationDegrees_retrievesExpectedSensorRotation() { verify(mockCameraInfo).getSensorRotationDegrees(); } + @Test + public void getLiveCameraState_makesCallToRetrieveLiveCameraState() { + final CameraInfoHostApiImpl cameraInfoHostApiImpl = + new CameraInfoHostApiImpl(mockBinaryMessenger, testInstanceManager); + final LiveDataFlutterApiWrapper mockLiveDataFlutterApiWrapper = + mock(LiveDataFlutterApiWrapper.class); + final Long mockCameraInfoIdentifier = 27L; + @SuppressWarnings("unchecked") + final LiveData mockLiveCameraState = (LiveData) mock(LiveData.class); + + testInstanceManager.addDartCreatedInstance(mockCameraInfo, mockCameraInfoIdentifier); + cameraInfoHostApiImpl.liveDataFlutterApiWrapper = mockLiveDataFlutterApiWrapper; + when(mockCameraInfo.getCameraState()).thenReturn(mockLiveCameraState); + + final Long liveCameraStateIdentifier = + cameraInfoHostApiImpl.getLiveCameraState(mockCameraInfoIdentifier); + + verify(mockLiveDataFlutterApiWrapper) + .create(eq(mockLiveCameraState), eq(LiveDataSupportedType.CAMERA_STATE), any()); + assertEquals( + liveCameraStateIdentifier, + testInstanceManager.getIdentifierForStrongReference(mockLiveCameraState)); + } + @Test public void getExposureState_retrievesExpectedExposureState() { final CameraInfoHostApiImpl cameraInfoHostApiImpl = diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraStateErrorTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraStateErrorTest.java new file mode 100644 index 00000000000..a8260895852 --- /dev/null +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraStateErrorTest.java @@ -0,0 +1,57 @@ +// 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.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; + +import androidx.camera.core.CameraState; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.CameraStateErrorFlutterApi; +import java.util.Objects; +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 CameraStateErrorTest { + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock public CameraState.StateError mockCameraStateError; + @Mock public BinaryMessenger mockBinaryMessenger; + @Mock public CameraStateErrorFlutterApi mockFlutterApi; + + InstanceManager instanceManager; + + @Before + public void setUp() { + instanceManager = InstanceManager.create(identifier -> {}); + } + + @After + public void tearDown() { + instanceManager.clear(); + } + + @Test + public void flutterApiCreate_makesCallToDartToCreateInstance() { + final CameraStateErrorFlutterApiWrapper flutterApi = + new CameraStateErrorFlutterApiWrapper(mockBinaryMessenger, instanceManager); + flutterApi.setApi(mockFlutterApi); + + final Long code = 0L; + + flutterApi.create(mockCameraStateError, code, reply -> {}); + + final long instanceIdentifier = + Objects.requireNonNull( + instanceManager.getIdentifierForStrongReference(mockCameraStateError)); + verify(mockFlutterApi).create(eq(instanceIdentifier), eq(code), any()); + } +} diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraStateTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraStateTest.java new file mode 100644 index 00000000000..c3a41070db6 --- /dev/null +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CameraStateTest.java @@ -0,0 +1,103 @@ +// 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.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import androidx.camera.core.CameraState; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.CameraStateFlutterApi; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.CameraStateType; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.CameraStateTypeData; +import java.util.Objects; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +public class CameraStateTest { + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock public CameraState mockCameraState; + @Mock public BinaryMessenger mockBinaryMessenger; + @Mock public CameraStateFlutterApi mockFlutterApi; + + InstanceManager instanceManager; + + @Before + public void setUp() { + instanceManager = InstanceManager.create(identifier -> {}); + } + + @After + public void tearDown() { + instanceManager.clear(); + } + + @Test + public void flutterApiCreate_makesCallToDartToCreateInstance() { + final CameraStateFlutterApiWrapper flutterApi = + new CameraStateFlutterApiWrapper(mockBinaryMessenger, instanceManager); + flutterApi.setApi(mockFlutterApi); + + final CameraStateType type = CameraStateType.OPEN; + final CameraState.StateError mockError = mock(CameraState.StateError.class); + + flutterApi.create(mockCameraState, type, mockError, reply -> {}); + + final long instanceIdentifier = + Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(mockCameraState)); + final ArgumentCaptor cameraStateTypeDataCaptor = + ArgumentCaptor.forClass(CameraStateTypeData.class); + + verify(mockFlutterApi) + .create( + eq(instanceIdentifier), + cameraStateTypeDataCaptor.capture(), + eq(Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(mockError))), + any()); + + assertEquals(cameraStateTypeDataCaptor.getValue().getValue(), type); + } + + @Test + public void getCameraStateType_returnsExpectedType() { + for (CameraState.Type type : CameraState.Type.values()) { + switch (type) { + case CLOSED: + assertEquals( + CameraStateFlutterApiWrapper.getCameraStateType(type), CameraStateType.CLOSED); + break; + case CLOSING: + assertEquals( + CameraStateFlutterApiWrapper.getCameraStateType(type), CameraStateType.CLOSING); + break; + case OPEN: + assertEquals(CameraStateFlutterApiWrapper.getCameraStateType(type), CameraStateType.OPEN); + break; + case OPENING: + assertEquals( + CameraStateFlutterApiWrapper.getCameraStateType(type), CameraStateType.OPENING); + break; + case PENDING_OPEN: + assertEquals( + CameraStateFlutterApiWrapper.getCameraStateType(type), CameraStateType.PENDING_OPEN); + break; + default: + // There is a CameraState.Type unhandled by this method. + fail(); + } + } + } +} diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ImageCaptureTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ImageCaptureTest.java index d1881b39a43..881b6bea5a7 100644 --- a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ImageCaptureTest.java +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ImageCaptureTest.java @@ -190,12 +190,8 @@ public void takePicture_usesExpectedOnImageSavedCallback() { mock(ImageCapture.OutputFileResults.class); final String mockFileAbsolutePath = "absolute/path/to/captured/image"; final ImageCaptureException mockException = mock(ImageCaptureException.class); - final int testImageCaptureError = 54; - final String testExceptionMessage = "Test exception message"; imageCaptureHostApiImpl.cameraXProxy = mockCameraXProxy; - when(mockCameraXProxy.createSystemServicesFlutterApiImpl(mockBinaryMessenger)) - .thenReturn(mockSystemServicesFlutterApiImpl); when(mockFile.getAbsolutePath()).thenReturn(mockFileAbsolutePath); ImageCapture.OnImageSavedCallback onImageSavedCallback = diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/LiveDataTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/LiveDataTest.java new file mode 100644 index 00000000000..d525b3481fe --- /dev/null +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/LiveDataTest.java @@ -0,0 +1,104 @@ +// 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.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import androidx.camera.core.CameraState; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.Observer; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.LiveDataFlutterApi; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.LiveDataSupportedType; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.LiveDataSupportedTypeData; +import java.util.Objects; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +public class LiveDataTest { + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock public LiveData mockLiveData; + + @Mock public BinaryMessenger mockBinaryMessenger; + @Mock public LiveDataFlutterApi mockFlutterApi; + + InstanceManager instanceManager; + + @Before + public void setUp() { + instanceManager = InstanceManager.create(identifier -> {}); + } + + @After + public void tearDown() { + instanceManager.clear(); + } + + @Test + @SuppressWarnings({"unchecked", "rawtypes"}) + public void observe_addsExpectedObserverToLiveDataInstance() { + final LiveDataHostApiImpl hostApi = + new LiveDataHostApiImpl(mockBinaryMessenger, instanceManager); + final Observer mockObserver = mock(Observer.class); + final long observerIdentifier = 20; + final long instanceIdentifier = 0; + final LifecycleOwner mockLifecycleOwner = mock(LifecycleOwner.class); + + instanceManager.addDartCreatedInstance(mockObserver, observerIdentifier); + instanceManager.addDartCreatedInstance(mockLiveData, instanceIdentifier); + + hostApi.setLifecycleOwner(mockLifecycleOwner); + hostApi.observe(instanceIdentifier, observerIdentifier); + + verify(mockLiveData).observe(mockLifecycleOwner, mockObserver); + } + + @Test + public void removeObservers_makesCallToRemoveObserversFromLiveDataInstance() { + final LiveDataHostApiImpl hostApi = + new LiveDataHostApiImpl(mockBinaryMessenger, instanceManager); + final long instanceIdentifier = 0; + final LifecycleOwner mockLifecycleOwner = mock(LifecycleOwner.class); + + instanceManager.addDartCreatedInstance(mockLiveData, instanceIdentifier); + + hostApi.setLifecycleOwner(mockLifecycleOwner); + hostApi.removeObservers(instanceIdentifier); + + verify(mockLiveData).removeObservers(mockLifecycleOwner); + } + + @Test + public void flutterApiCreate_makesCallToDartToCreateInstance() { + final LiveDataFlutterApiWrapper flutterApi = + new LiveDataFlutterApiWrapper(mockBinaryMessenger, instanceManager); + final LiveDataSupportedType liveDataType = LiveDataSupportedType.CAMERA_STATE; + + flutterApi.setApi(mockFlutterApi); + + final ArgumentCaptor liveDataSupportedTypeDataCaptor = + ArgumentCaptor.forClass(LiveDataSupportedTypeData.class); + + flutterApi.create(mockLiveData, liveDataType, reply -> {}); + + final long instanceIdentifier = + Objects.requireNonNull(instanceManager.getIdentifierForStrongReference(mockLiveData)); + verify(mockFlutterApi) + .create(eq(instanceIdentifier), liveDataSupportedTypeDataCaptor.capture(), any()); + assertEquals(liveDataSupportedTypeDataCaptor.getValue().getValue(), liveDataType); + } +} diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ObserverTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ObserverTest.java new file mode 100644 index 00000000000..2c628905db6 --- /dev/null +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ObserverTest.java @@ -0,0 +1,92 @@ +// 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.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import androidx.camera.core.CameraState; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.CameraStateType; +import io.flutter.plugins.camerax.GeneratedCameraXLibrary.ObserverFlutterApi; +import java.util.Objects; +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 ObserverTest { + @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock public ObserverHostApiImpl.ObserverImpl mockObserver; + + @Mock public BinaryMessenger mockBinaryMessenger; + @Mock public ObserverFlutterApi mockFlutterApi; + @Mock public ObserverHostApiImpl.ObserverProxy mockProxy; + + InstanceManager instanceManager; + + @Before + public void setUp() { + instanceManager = InstanceManager.create(identifier -> {}); + } + + @After + public void tearDown() { + instanceManager.clear(); + } + + @Test + @SuppressWarnings({"rawtypes", "unchecked"}) + public void create_createsObserverInstance() { + final ObserverHostApiImpl hostApi = + new ObserverHostApiImpl(mockBinaryMessenger, instanceManager, mockProxy); + final long instanceIdentifier = 0; + + when(mockProxy.create(mockBinaryMessenger, instanceManager)) + .thenReturn(mockObserver); + + hostApi.create(instanceIdentifier); + + assertEquals(instanceManager.getInstance(instanceIdentifier), mockObserver); + } + + @Test + public void onChanged_makesCallToDartCallbackForCameraState() { + final ObserverFlutterApiWrapper flutterApi = + new ObserverFlutterApiWrapper(mockBinaryMessenger, instanceManager); + final ObserverHostApiImpl.ObserverImpl instance = + new ObserverHostApiImpl.ObserverImpl(mockBinaryMessenger, instanceManager); + final CameraStateFlutterApiWrapper mockCameraStateFlutterApiWrapper = + mock(CameraStateFlutterApiWrapper.class); + final long instanceIdentifier = 0; + final CameraState.StateError testCameraStateError = + CameraState.StateError.create(CameraState.ERROR_CAMERA_IN_USE); + final CameraState testCameraState = + CameraState.create(CameraState.Type.CLOSED, testCameraStateError); + Long mockCameraStateIdentifier = instanceManager.addHostCreatedInstance(testCameraState); + + flutterApi.setApi(mockFlutterApi); + instance.setApi(flutterApi); + flutterApi.cameraStateFlutterApiWrapper = mockCameraStateFlutterApiWrapper; + + instanceManager.addDartCreatedInstance(instance, instanceIdentifier); + + instance.onChanged(testCameraState); + + verify(mockFlutterApi) + .onChanged( + eq(instanceIdentifier), eq(Objects.requireNonNull(mockCameraStateIdentifier)), any()); + verify(mockCameraStateFlutterApiWrapper) + .create(eq(testCameraState), eq(CameraStateType.CLOSED), eq(testCameraStateError), any()); + } +} diff --git a/packages/camera/camera_android_camerax/lib/src/analyzer.dart b/packages/camera/camera_android_camerax/lib/src/analyzer.dart index fc312cd1982..8cdcc137ae4 100644 --- a/packages/camera/camera_android_camerax/lib/src/analyzer.dart +++ b/packages/camera/camera_android_camerax/lib/src/analyzer.dart @@ -87,35 +87,40 @@ class _AnalyzerHostApiImpl extends AnalyzerHostApi { @protected class AnalyzerFlutterApiImpl implements AnalyzerFlutterApi { /// Constructs a [AnalyzerFlutterApiImpl]. + /// + /// 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]. AnalyzerFlutterApiImpl({ - this.binaryMessenger, + BinaryMessenger? binaryMessenger, InstanceManager? instanceManager, - }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager; + }) : _binaryMessenger = binaryMessenger, + _instanceManager = instanceManager ?? JavaObject.globalInstanceManager; /// Receives binary data across the Flutter platform barrier. - /// - /// If it is null, the default BinaryMessenger will be used which routes to - /// the host platform. - final BinaryMessenger? binaryMessenger; + final BinaryMessenger? _binaryMessenger; /// Maintains instances stored to communicate with native language objects. - final InstanceManager instanceManager; + final InstanceManager _instanceManager; @override void create( int identifier, ) { - instanceManager.addHostCreatedInstance( + _instanceManager.addHostCreatedInstance( Analyzer.detached( analyze: (ImageProxy imageProxy) async {}, - binaryMessenger: binaryMessenger, - instanceManager: instanceManager, + binaryMessenger: _binaryMessenger, + instanceManager: _instanceManager, ), identifier, onCopy: (Analyzer original) => Analyzer.detached( analyze: original.analyze, - binaryMessenger: binaryMessenger, - instanceManager: instanceManager, + binaryMessenger: _binaryMessenger, + instanceManager: _instanceManager, ), ); } @@ -126,9 +131,9 @@ class AnalyzerFlutterApiImpl implements AnalyzerFlutterApi { int imageProxyIdentifier, ) { final Analyzer instance = - instanceManager.getInstanceWithWeakReference(identifier)!; + _instanceManager.getInstanceWithWeakReference(identifier)!; final ImageProxy imageProxy = - instanceManager.getInstanceWithWeakReference(imageProxyIdentifier)!; + _instanceManager.getInstanceWithWeakReference(imageProxyIdentifier)!; instance.analyze( imageProxy, ); diff --git a/packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart b/packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart index 174a373e3b9..d95b20768af 100644 --- a/packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart +++ b/packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart @@ -4,6 +4,7 @@ import 'dart:async'; +import 'package:async/async.dart'; import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter/widgets.dart'; import 'package:stream_transform/stream_transform.dart'; @@ -12,11 +13,14 @@ import 'analyzer.dart'; import 'camera.dart'; import 'camera_info.dart'; import 'camera_selector.dart'; +import 'camera_state.dart'; import 'camerax_library.g.dart'; import 'exposure_state.dart'; import 'image_analysis.dart'; import 'image_capture.dart'; import 'image_proxy.dart'; +import 'live_data.dart'; +import 'observer.dart'; import 'plane_proxy.dart'; import 'preview.dart'; import 'process_camera_provider.dart'; @@ -45,6 +49,10 @@ class AndroidCameraCameraX extends CameraPlatform { @visibleForTesting CameraInfo? cameraInfo; + /// The [LiveData] of the [CameraState] that represents the state of the + /// [camera] instance. + LiveData? liveCameraState; + /// The [Preview] instance that can be configured to present a live camera preview. @visibleForTesting Preview? preview; @@ -83,14 +91,14 @@ class AndroidCameraCameraX extends CameraPlatform { cameraEventStreamController.stream .where((CameraEvent event) => event.cameraId == cameraId); - /// The controller we need to stream image data. + /// Conditional used to create detached [Observer]s for testing their + /// callback methods. @visibleForTesting - StreamController? cameraImageDataStreamController; + bool createDetachedObjectForTesting = false; - /// Conditional used to create detached instances for testing their - /// callback methods. + /// The controller we need to stream image data. @visibleForTesting - bool createDetachedCallbacks = false; + StreamController? cameraImageDataStreamController; /// Constant representing the multi-plane Android YUV 420 image format. /// @@ -196,6 +204,7 @@ class AndroidCameraCameraX extends CameraPlatform { // instance as bound but not paused. camera = await processCameraProvider! .bindToLifecycle(cameraSelector!, [preview!, imageCapture!]); + await _updateLiveCameraState(flutterSurfaceTextureId); cameraInfo = await camera!.getCameraInfo(); _previewIsPaused = false; @@ -258,6 +267,7 @@ class AndroidCameraCameraX extends CameraPlatform { @override Future dispose(int cameraId) async { preview?.releaseFlutterSurfaceTexture(); + liveCameraState?.removeObservers(); processCameraProvider?.unbindAll(); } @@ -267,13 +277,23 @@ class AndroidCameraCameraX extends CameraPlatform { return _cameraEvents(cameraId).whereType(); } + /// The camera started to close. + @override + Stream onCameraClosing(int cameraId) { + return _cameraEvents(cameraId).whereType(); + } + /// The camera experienced an error. @override Stream onCameraError(int cameraId) { - return SystemServices.cameraErrorStreamController.stream - .map((String errorDescription) { - return CameraErrorEvent(cameraId, errorDescription); - }); + return StreamGroup.mergeBroadcast< + CameraErrorEvent>(>[ + SystemServices.cameraErrorStreamController.stream + .map((String errorDescription) { + return CameraErrorEvent(cameraId, errorDescription); + }), + _cameraEvents(cameraId).whereType() + ]); } /// Gets the minimum supported exposure offset for the selected camera in EV units. @@ -345,7 +365,7 @@ class AndroidCameraCameraX extends CameraPlatform { /// [cameraId] not used. @override Future resumePreview(int cameraId) async { - await _bindPreviewToLifecycle(); + await _bindPreviewToLifecycle(cameraId); _previewIsPaused = false; } @@ -353,7 +373,7 @@ class AndroidCameraCameraX extends CameraPlatform { @override Widget buildPreview(int cameraId) { return FutureBuilder( - future: _bindPreviewToLifecycle(), + future: _bindPreviewToLifecycle(cameraId), builder: (BuildContext context, AsyncSnapshot snapshot) { switch (snapshot.connectionState) { case ConnectionState.none: @@ -404,7 +424,7 @@ class AndroidCameraCameraX extends CameraPlatform { /// Binds [preview] instance to the camera lifecycle controlled by the /// [processCameraProvider]. - Future _bindPreviewToLifecycle() async { + Future _bindPreviewToLifecycle(int cameraId) async { final bool previewIsBound = await processCameraProvider!.isBound(preview!); if (previewIsBound || _previewIsPaused) { // Only bind if preview is not already bound or intentionally paused. @@ -413,6 +433,7 @@ class AndroidCameraCameraX extends CameraPlatform { camera = await processCameraProvider! .bindToLifecycle(cameraSelector!, [preview!]); + await _updateLiveCameraState(cameraId); cameraInfo = await camera!.getCameraInfo(); } @@ -451,7 +472,7 @@ class AndroidCameraCameraX extends CameraPlatform { imageProxy.close(); } - final Analyzer analyzer = createDetachedCallbacks + final Analyzer analyzer = createDetachedObjectForTesting ? Analyzer.detached(analyze: analyze) : Analyzer(analyze: analyze); @@ -509,6 +530,41 @@ class AndroidCameraCameraX extends CameraPlatform { return ImageFormatGroup.unknown; } + // Methods concerning camera state: + + /// Adds fresh observers to the [LiveData] of the [CameraState] of the + /// current [camera]. + Future _updateLiveCameraState(int cameraId) async { + final CameraInfo cameraInfo = await camera!.getCameraInfo(); + liveCameraState?.removeObservers(); + liveCameraState = await cameraInfo.getLiveCameraState(); + await liveCameraState!.observe(_createCameraClosingObserver(cameraId)); + } + + /// Creates [Observer] of the [CameraState] that will: + /// + /// * Send a [CameraClosingEvent] if the [CameraState] indicates that the + /// camera has begun to close. + /// * Send a [CameraErrorEvent] if the [CameraState] indicates that the + /// camera is in error state. + Observer _createCameraClosingObserver(int cameraId) { + // Callback method used to implement the behavior described above: + void onChanged(Object stateAsObject) { + final CameraState state = stateAsObject as CameraState; + if (state.type == CameraStateType.closing) { + cameraEventStreamController.add(CameraClosingEvent(cameraId)); + } + if (state.error != null) { + cameraEventStreamController + .add(CameraErrorEvent(cameraId, state.error!.getDescription())); + } + } + + return createDetachedObjectForTesting + ? Observer.detached(onChanged: onChanged) + : Observer(onChanged: onChanged); + } + // Methods for mapping Flutter camera constants to CameraX constants: /// Returns [CameraSelector] lens direction that maps to specified diff --git a/packages/camera/camera_android_camerax/lib/src/android_camera_camerax_flutter_api_impls.dart b/packages/camera/camera_android_camerax/lib/src/android_camera_camerax_flutter_api_impls.dart index c5692ae105f..0d385f373f7 100644 --- a/packages/camera/camera_android_camerax/lib/src/android_camera_camerax_flutter_api_impls.dart +++ b/packages/camera/camera_android_camerax/lib/src/android_camera_camerax_flutter_api_impls.dart @@ -6,10 +6,14 @@ import 'analyzer.dart'; import 'camera.dart'; import 'camera_info.dart'; import 'camera_selector.dart'; +import 'camera_state.dart'; +import 'camera_state_error.dart'; import 'camerax_library.g.dart'; import 'exposure_state.dart'; import 'image_proxy.dart'; import 'java_object.dart'; +import 'live_data.dart'; +import 'observer.dart'; import 'plane_proxy.dart'; import 'process_camera_provider.dart'; import 'system_services.dart'; @@ -19,33 +23,46 @@ import 'zoom_state.dart'; class AndroidCameraXCameraFlutterApis { /// Creates a [AndroidCameraXCameraFlutterApis]. AndroidCameraXCameraFlutterApis({ - JavaObjectFlutterApiImpl? javaObjectFlutterApi, - CameraFlutterApiImpl? cameraFlutterApi, - CameraInfoFlutterApiImpl? cameraInfoFlutterApi, - CameraSelectorFlutterApiImpl? cameraSelectorFlutterApi, - ProcessCameraProviderFlutterApiImpl? processCameraProviderFlutterApi, - SystemServicesFlutterApiImpl? systemServicesFlutterApi, + JavaObjectFlutterApiImpl? javaObjectFlutterApiImpl, + CameraFlutterApiImpl? cameraFlutterApiImpl, + CameraInfoFlutterApiImpl? cameraInfoFlutterApiImpl, + CameraSelectorFlutterApiImpl? cameraSelectorFlutterApiImpl, + ProcessCameraProviderFlutterApiImpl? processCameraProviderFlutterApiImpl, + SystemServicesFlutterApiImpl? systemServicesFlutterApiImpl, + CameraStateErrorFlutterApiImpl? cameraStateErrorFlutterApiImpl, + CameraStateFlutterApiImpl? cameraStateFlutterApiImpl, ExposureStateFlutterApiImpl? exposureStateFlutterApiImpl, ZoomStateFlutterApiImpl? zoomStateFlutterApiImpl, - AnalyzerFlutterApiImpl? analyzerFlutterApiImpl, + LiveDataFlutterApiImpl? liveDataFlutterApiImpl, + ObserverFlutterApiImpl? observerFlutterApiImpl, ImageProxyFlutterApiImpl? imageProxyFlutterApiImpl, PlaneProxyFlutterApiImpl? planeProxyFlutterApiImpl, + AnalyzerFlutterApiImpl? analyzerFlutterApiImpl, }) { - this.javaObjectFlutterApi = - javaObjectFlutterApi ?? JavaObjectFlutterApiImpl(); - this.cameraInfoFlutterApi = - cameraInfoFlutterApi ?? CameraInfoFlutterApiImpl(); - this.cameraSelectorFlutterApi = - cameraSelectorFlutterApi ?? CameraSelectorFlutterApiImpl(); - this.processCameraProviderFlutterApi = processCameraProviderFlutterApi ?? - ProcessCameraProviderFlutterApiImpl(); - this.cameraFlutterApi = cameraFlutterApi ?? CameraFlutterApiImpl(); - this.systemServicesFlutterApi = - systemServicesFlutterApi ?? SystemServicesFlutterApiImpl(); + this.javaObjectFlutterApiImpl = + javaObjectFlutterApiImpl ?? JavaObjectFlutterApiImpl(); + this.cameraInfoFlutterApiImpl = + cameraInfoFlutterApiImpl ?? CameraInfoFlutterApiImpl(); + this.cameraSelectorFlutterApiImpl = + cameraSelectorFlutterApiImpl ?? CameraSelectorFlutterApiImpl(); + this.processCameraProviderFlutterApiImpl = + processCameraProviderFlutterApiImpl ?? + ProcessCameraProviderFlutterApiImpl(); + this.cameraFlutterApiImpl = cameraFlutterApiImpl ?? CameraFlutterApiImpl(); + this.systemServicesFlutterApiImpl = + systemServicesFlutterApiImpl ?? SystemServicesFlutterApiImpl(); + this.cameraStateErrorFlutterApiImpl = + cameraStateErrorFlutterApiImpl ?? CameraStateErrorFlutterApiImpl(); + this.cameraStateFlutterApiImpl = + cameraStateFlutterApiImpl ?? CameraStateFlutterApiImpl(); this.exposureStateFlutterApiImpl = exposureStateFlutterApiImpl ?? ExposureStateFlutterApiImpl(); this.zoomStateFlutterApiImpl = zoomStateFlutterApiImpl ?? ZoomStateFlutterApiImpl(); + this.liveDataFlutterApiImpl = + liveDataFlutterApiImpl ?? LiveDataFlutterApiImpl(); + this.observerFlutterApiImpl = + observerFlutterApiImpl ?? ObserverFlutterApiImpl(); this.analyzerFlutterApiImpl = analyzerFlutterApiImpl ?? AnalyzerFlutterApiImpl(); this.imageProxyFlutterApiImpl = @@ -63,23 +80,35 @@ class AndroidCameraXCameraFlutterApis { AndroidCameraXCameraFlutterApis(); /// Handles callbacks methods for the native Java Object class. - late final JavaObjectFlutterApi javaObjectFlutterApi; + late final JavaObjectFlutterApi javaObjectFlutterApiImpl; - /// Flutter Api for [CameraInfo]. - late final CameraInfoFlutterApiImpl cameraInfoFlutterApi; + /// Flutter Api implementation for [CameraInfo]. + late final CameraInfoFlutterApiImpl cameraInfoFlutterApiImpl; - /// Flutter Api for [CameraSelector]. - late final CameraSelectorFlutterApiImpl cameraSelectorFlutterApi; + /// Flutter Api implementation for [CameraSelector]. + late final CameraSelectorFlutterApiImpl cameraSelectorFlutterApiImpl; - /// Flutter Api for [ProcessCameraProvider]. + /// Flutter Api implementation for [ProcessCameraProvider]. late final ProcessCameraProviderFlutterApiImpl - processCameraProviderFlutterApi; + processCameraProviderFlutterApiImpl; + + /// Flutter Api implementation for [Camera]. + late final CameraFlutterApiImpl cameraFlutterApiImpl; + + /// Flutter Api implementation for [SystemServices]. + late final SystemServicesFlutterApiImpl systemServicesFlutterApiImpl; + + /// Flutter Api implementation for [CameraStateError]. + late final CameraStateErrorFlutterApiImpl? cameraStateErrorFlutterApiImpl; + + /// Flutter Api implementation for [CameraState]. + late final CameraStateFlutterApiImpl? cameraStateFlutterApiImpl; - /// Flutter Api for [Camera]. - late final CameraFlutterApiImpl cameraFlutterApi; + /// Flutter Api implementation for [LiveData]. + late final LiveDataFlutterApiImpl? liveDataFlutterApiImpl; - /// Flutter Api for [SystemServices]. - late final SystemServicesFlutterApiImpl systemServicesFlutterApi; + /// Flutter Api implementation for [Observer]. + late final ObserverFlutterApiImpl? observerFlutterApiImpl; /// Flutter Api for [ExposureState]. late final ExposureStateFlutterApiImpl exposureStateFlutterApiImpl; @@ -99,17 +128,22 @@ class AndroidCameraXCameraFlutterApis { /// Ensures all the Flutter APIs have been setup to receive calls from native code. void ensureSetUp() { if (!_haveBeenSetUp) { - JavaObjectFlutterApi.setup(javaObjectFlutterApi); - CameraInfoFlutterApi.setup(cameraInfoFlutterApi); - CameraSelectorFlutterApi.setup(cameraSelectorFlutterApi); - ProcessCameraProviderFlutterApi.setup(processCameraProviderFlutterApi); - CameraFlutterApi.setup(cameraFlutterApi); - SystemServicesFlutterApi.setup(systemServicesFlutterApi); + JavaObjectFlutterApi.setup(javaObjectFlutterApiImpl); + CameraInfoFlutterApi.setup(cameraInfoFlutterApiImpl); + CameraSelectorFlutterApi.setup(cameraSelectorFlutterApiImpl); + ProcessCameraProviderFlutterApi.setup( + processCameraProviderFlutterApiImpl); + CameraFlutterApi.setup(cameraFlutterApiImpl); + SystemServicesFlutterApi.setup(systemServicesFlutterApiImpl); + CameraStateErrorFlutterApi.setup(cameraStateErrorFlutterApiImpl); + CameraStateFlutterApi.setup(cameraStateFlutterApiImpl); ExposureStateFlutterApi.setup(exposureStateFlutterApiImpl); ZoomStateFlutterApi.setup(zoomStateFlutterApiImpl); AnalyzerFlutterApi.setup(analyzerFlutterApiImpl); ImageProxyFlutterApi.setup(imageProxyFlutterApiImpl); PlaneProxyFlutterApi.setup(planeProxyFlutterApiImpl); + LiveDataFlutterApi.setup(liveDataFlutterApiImpl); + ObserverFlutterApi.setup(observerFlutterApiImpl); _haveBeenSetUp = true; } } diff --git a/packages/camera/camera_android_camerax/lib/src/camera.dart b/packages/camera/camera_android_camerax/lib/src/camera.dart index 65821f0734c..8720fdf322f 100644 --- a/packages/camera/camera_android_camerax/lib/src/camera.dart +++ b/packages/camera/camera_android_camerax/lib/src/camera.dart @@ -69,31 +69,34 @@ class CameraHostApiImpl extends CameraHostApi { class CameraFlutterApiImpl implements CameraFlutterApi { /// Constructs a [CameraFlutterApiImpl]. /// + /// 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. + /// contained by an [InstanceManager] is being created. If left null, it + /// will default to the global instance defined in [JavaObject]. CameraFlutterApiImpl({ - this.binaryMessenger, + BinaryMessenger? binaryMessenger, InstanceManager? instanceManager, - }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager; + }) : _binaryMessenger = binaryMessenger, + _instanceManager = instanceManager ?? JavaObject.globalInstanceManager; /// Receives binary data across the Flutter platform barrier. - /// - /// If it is null, the default BinaryMessenger will be used which routes to - /// the host platform. - final BinaryMessenger? binaryMessenger; + final BinaryMessenger? _binaryMessenger; /// Maintains instances stored to communicate with native language objects. - final InstanceManager instanceManager; + final InstanceManager _instanceManager; @override void create(int identifier) { - instanceManager.addHostCreatedInstance( + _instanceManager.addHostCreatedInstance( Camera.detached( - binaryMessenger: binaryMessenger, instanceManager: instanceManager), + binaryMessenger: _binaryMessenger, instanceManager: _instanceManager), identifier, onCopy: (Camera original) { return Camera.detached( - binaryMessenger: binaryMessenger, instanceManager: instanceManager); + binaryMessenger: _binaryMessenger, + instanceManager: _instanceManager); }, ); } diff --git a/packages/camera/camera_android_camerax/lib/src/camera_info.dart b/packages/camera/camera_android_camerax/lib/src/camera_info.dart index f2fdc1fdc87..65ae81b647a 100644 --- a/packages/camera/camera_android_camerax/lib/src/camera_info.dart +++ b/packages/camera/camera_android_camerax/lib/src/camera_info.dart @@ -2,16 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; + import 'package:flutter/services.dart' show BinaryMessenger; import 'android_camera_camerax_flutter_api_impls.dart'; +import 'camera_state.dart'; import 'camerax_library.g.dart'; import 'exposure_state.dart'; import 'instance_manager.dart'; import 'java_object.dart'; +import 'live_data.dart'; import 'zoom_state.dart'; -/// Represents the metadata of a camera. +/// The metadata of a camera. /// /// See https://developer.android.com/reference/androidx/camera/core/CameraInfo. class CameraInfo extends JavaObject { @@ -32,6 +36,10 @@ class CameraInfo extends JavaObject { Future getSensorRotationDegrees() => _api.getSensorRotationDegreesFromInstance(this); + /// Starts listening for the camera closing. + Future> getLiveCameraState() => + _api.getLiveCameraStateFromInstance(this); + /// Gets the exposure state of the camera. Future getExposureState() => _api.getExposureStateFromInstance(this); @@ -60,6 +68,21 @@ class _CameraInfoHostApiImpl extends CameraInfoHostApi { return sensorRotationDegrees; } + /// Gets the [LiveData] that represents the state of the camera + /// to which the CameraInfo [instance] pertains. + Future> getLiveCameraStateFromInstance( + CameraInfo instance) async { + final int? identifier = instanceManager.getIdentifier(instance); + assert(identifier != null, + 'No CameraInfo has the identifer of that which was requested.'); + + final int liveCameraStateId = await getLiveCameraState(identifier!); + final LiveData liveCameraState = + instanceManager.getInstanceWithWeakReference>( + liveCameraStateId)!; + return liveCameraState; + } + /// Gets the [ExposureState] of the specified [CameraInfo] instance. Future getExposureStateFromInstance( CameraInfo instance) async { @@ -81,29 +104,35 @@ class _CameraInfoHostApiImpl extends CameraInfoHostApi { /// Flutter API implementation of [CameraInfo]. class CameraInfoFlutterApiImpl extends CameraInfoFlutterApi { /// Constructs a [CameraInfoFlutterApiImpl]. + /// + /// 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]. CameraInfoFlutterApiImpl({ - this.binaryMessenger, + BinaryMessenger? binaryMessenger, InstanceManager? instanceManager, - }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager; + }) : _binaryMessenger = binaryMessenger, + _instanceManager = instanceManager ?? JavaObject.globalInstanceManager; /// Receives binary data across the Flutter platform barrier. - /// - /// If it is null, the default BinaryMessenger will be used which routes to - /// the host platform. - final BinaryMessenger? binaryMessenger; + final BinaryMessenger? _binaryMessenger; /// Maintains instances stored to communicate with native language objects. - final InstanceManager instanceManager; + final InstanceManager _instanceManager; @override void create(int identifier) { - instanceManager.addHostCreatedInstance( + _instanceManager.addHostCreatedInstance( CameraInfo.detached( - binaryMessenger: binaryMessenger, instanceManager: instanceManager), + binaryMessenger: _binaryMessenger, instanceManager: _instanceManager), identifier, onCopy: (CameraInfo original) { return CameraInfo.detached( - binaryMessenger: binaryMessenger, instanceManager: instanceManager); + binaryMessenger: _binaryMessenger, + instanceManager: _instanceManager); }, ); } diff --git a/packages/camera/camera_android_camerax/lib/src/camera_selector.dart b/packages/camera/camera_android_camerax/lib/src/camera_selector.dart index 8300063204c..1df886b861b 100644 --- a/packages/camera/camera_android_camerax/lib/src/camera_selector.dart +++ b/packages/camera/camera_android_camerax/lib/src/camera_selector.dart @@ -163,32 +163,37 @@ class CameraSelectorHostApiImpl extends CameraSelectorHostApi { /// Flutter API implementation of [CameraSelector]. class CameraSelectorFlutterApiImpl implements CameraSelectorFlutterApi { /// Constructs a [CameraSelectorFlutterApiImpl]. + /// + /// 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]. CameraSelectorFlutterApiImpl({ - this.binaryMessenger, + BinaryMessenger? binaryMessenger, InstanceManager? instanceManager, - }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager; + }) : _binaryMessenger = binaryMessenger, + _instanceManager = instanceManager ?? JavaObject.globalInstanceManager; /// Receives binary data across the Flutter platform barrier. - /// - /// If it is null, the default BinaryMessenger will be used which routes to - /// the host platform. - final BinaryMessenger? binaryMessenger; + final BinaryMessenger? _binaryMessenger; /// Maintains instances stored to communicate with native language objects. - final InstanceManager instanceManager; + final InstanceManager _instanceManager; @override void create(int identifier, int? lensFacing) { - instanceManager.addHostCreatedInstance( + _instanceManager.addHostCreatedInstance( CameraSelector.detached( - binaryMessenger: binaryMessenger, - instanceManager: instanceManager, + binaryMessenger: _binaryMessenger, + instanceManager: _instanceManager, lensFacing: lensFacing), identifier, onCopy: (CameraSelector original) { return CameraSelector.detached( - binaryMessenger: binaryMessenger, - instanceManager: instanceManager, + binaryMessenger: _binaryMessenger, + instanceManager: _instanceManager, lensFacing: original.lensFacing); }, ); diff --git a/packages/camera/camera_android_camerax/lib/src/camera_state.dart b/packages/camera/camera_android_camerax/lib/src/camera_state.dart new file mode 100644 index 00000000000..c3dc25a4689 --- /dev/null +++ b/packages/camera/camera_android_camerax/lib/src/camera_state.dart @@ -0,0 +1,126 @@ +// 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'; + +import 'camera_state_error.dart'; +import 'camerax_library.g.dart'; +import 'instance_manager.dart'; +import 'java_object.dart'; + +/// A snapshot of the camera state. +/// +/// See https://developer.android.com/reference/androidx/camera/core/CameraState. +class CameraState extends JavaObject { + /// Constructs a [CameraState] that is not automatically attached to a native object. + CameraState.detached( + {super.binaryMessenger, + super.instanceManager, + required this.type, + this.error}) + : super.detached(); + + /// The type of state that the camera is in. + final CameraStateType type; + + /// The error that the camera has encountered, if any. + final CameraStateError? error; + + /// Error code indicating that the camera device is already in use. + /// + /// See https://developer.android.com/reference/androidx/camera/core/CameraState#ERROR_CAMERA_IN_USE() + static const int errorCameraInUse = 1; + + /// Error code indicating that the limit number of open cameras has been + /// reached. + /// + /// See https://developer.android.com/reference/androidx/camera/core/CameraState#ERROR_MAX_CAMERAS_IN_USE() + static const int errorMaxCamerasInUse = 2; + + /// Error code indicating that the camera device has encountered a recoverable + /// error. + /// + /// See https://developer.android.com/reference/androidx/camera/core/CameraState#ERROR_OTHER_RECOVERABLE_ERROR() + static const int errorOtherRecoverableError = 3; + + /// Error code inidcating that configuring the camera has failed. + /// + /// https://developer.android.com/reference/androidx/camera/core/CameraState#ERROR_STREAM_CONFIG() + static const int errorStreamConfig = 4; + + /// Error code indicating that the camera device could not be opened due to a + /// device policy. + /// + /// See https://developer.android.com/reference/androidx/camera/core/CameraState#ERROR_CAMERA_DISABLED() + static const int errorCameraDisabled = 5; + + /// Error code indicating that the camera device was closed due to a fatal + /// error. + /// + /// See https://developer.android.com/reference/androidx/camera/core/CameraState#ERROR_CAMERA_FATAL_ERROR() + static const int errorCameraFatalError = 6; + + /// Error code indicating that the camera could not be opened because + /// "Do Not Disturb" mode is enabled on devices affected by a bug in Android 9 + /// (API level 28). + /// + /// See https://developer.android.com/reference/androidx/camera/core/CameraState#ERROR_DO_NOT_DISTURB_MODE_ENABLED() + static const int errorDoNotDisturbModeEnabled = 7; +} + +/// Flutter API implementation for [CameraState]. +/// +/// This class may handle instantiating and adding Dart instances that are +/// attached to a native instance or receiving callback methods from an +/// overridden native class. +@protected +class CameraStateFlutterApiImpl implements CameraStateFlutterApi { + /// Constructs a [CameraStateFlutterApiImpl]. + /// + /// 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]. + CameraStateFlutterApiImpl({ + BinaryMessenger? binaryMessenger, + InstanceManager? instanceManager, + }) : _binaryMessenger = binaryMessenger, + _instanceManager = instanceManager ?? JavaObject.globalInstanceManager; + + /// Receives binary data across the Flutter platform barrier. + final BinaryMessenger? _binaryMessenger; + + /// Maintains instances stored to communicate with native language objects. + final InstanceManager _instanceManager; + + @override + void create( + int identifier, + CameraStateTypeData type, + int? errorIdentifier, + ) { + _instanceManager.addHostCreatedInstance( + CameraState.detached( + type: type.value, + error: errorIdentifier == null + ? null + : _instanceManager.getInstanceWithWeakReference( + errorIdentifier, + ), + binaryMessenger: _binaryMessenger, + instanceManager: _instanceManager, + ), + identifier, + onCopy: (CameraState original) => CameraState.detached( + type: original.type, + error: original.error, + binaryMessenger: _binaryMessenger, + instanceManager: _instanceManager, + ), + ); + } +} diff --git a/packages/camera/camera_android_camerax/lib/src/camera_state_error.dart b/packages/camera/camera_android_camerax/lib/src/camera_state_error.dart new file mode 100644 index 00000000000..89fb0f8ac17 --- /dev/null +++ b/packages/camera/camera_android_camerax/lib/src/camera_state_error.dart @@ -0,0 +1,122 @@ +// 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'; + +import 'camera_state.dart'; +import 'camerax_library.g.dart'; +import 'instance_manager.dart'; +import 'java_object.dart'; + +/// The error that a camera has encountered. +/// +/// See https://developer.android.com/reference/androidx/camera/core/CameraState.StateError. +class CameraStateError extends JavaObject { + /// Constructs a [CameraStateError] that is not automatically attached to a native object. + CameraStateError.detached( + {super.binaryMessenger, super.instanceManager, required this.code}) + : super.detached(); + + /// The code of this error. + /// + /// Will map to one of the [CameraState] error codes that map to the CameraX + /// CameraState codes: + /// https://developer.android.com/reference/androidx/camera/core/CameraState#constants_1. + final int code; + + /// Gets a description of this error corresponding to its [code]. + /// + /// This is not directly provided by the CameraX library, but is determined + /// based on the description of the [code]. + /// + /// Provided for developers to use for error handling. + String getDescription() { + String description = ''; + switch (code) { + case CameraState.errorCameraInUse: + description = + 'The camera was already in use, possibly by a higher-priority camera client.'; + break; + case CameraState.errorMaxCamerasInUse: + description = + 'The limit number of open cameras has been reached, and more cameras cannot be opened until other instances are closed.'; + break; + case CameraState.errorOtherRecoverableError: + description = + 'The camera device has encountered a recoverable error. CameraX will attempt to recover from the error.'; + break; + case CameraState.errorStreamConfig: + description = 'Configuring the camera has failed.'; + break; + case CameraState.errorCameraDisabled: + description = + 'The camera device could not be opened due to a device policy. Thia may be caused by a client from a background process attempting to open the camera.'; + break; + case CameraState.errorCameraFatalError: + description = + 'The camera was closed due to a fatal error. This may require the Android device be shut down and restarted to restore camera function or may indicate a persistent camera hardware problem.'; + break; + case CameraState.errorDoNotDisturbModeEnabled: + description = + 'The camera could not be opened because "Do Not Disturb" mode is enabled. Please disable this mode, and try opening the camera again.'; + break; + default: + description = + 'There was an unspecified issue with the current camera state.'; + break; + } + + return '$code : $description'; + } +} + +/// Flutter API implementation for [CameraStateError]. +/// +/// This class may handle instantiating and adding Dart instances that are +/// attached to a native instance or receiving callback methods from an +/// overridden native class. +@protected +class CameraStateErrorFlutterApiImpl implements CameraStateErrorFlutterApi { + /// Constructs a [CameraStateErrorFlutterApiImpl]. + /// + /// 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]. If left null, it + /// will default to the global instance defined in [JavaObject]. + CameraStateErrorFlutterApiImpl({ + BinaryMessenger? binaryMessenger, + InstanceManager? instanceManager, + }) : _binaryMessenger = binaryMessenger, + _instanceManager = instanceManager ?? JavaObject.globalInstanceManager; + + /// Receives binary data across the Flutter platform barrier. + final BinaryMessenger? _binaryMessenger; + + /// Maintains instances stored to communicate with native language objects. + final InstanceManager _instanceManager; + + @override + void create( + int identifier, + int code, + ) { + _instanceManager.addHostCreatedInstance( + CameraStateError.detached( + code: code, + binaryMessenger: _binaryMessenger, + instanceManager: _instanceManager, + ), + identifier, + onCopy: (CameraStateError original) => CameraStateError.detached( + code: original.code, + binaryMessenger: _binaryMessenger, + instanceManager: _instanceManager, + ), + ); + } +} diff --git a/packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart b/packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart index f2d2e17152f..d355278633b 100644 --- a/packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart +++ b/packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart @@ -11,6 +11,21 @@ import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; import 'package:flutter/services.dart'; +/// The states the camera can be in. +/// +/// See https://developer.android.com/reference/androidx/camera/core/CameraState.Type. +enum CameraStateType { + closed, + closing, + open, + opening, + pendingOpen, +} + +enum LiveDataSupportedType { + cameraState, +} + class ResolutionInfo { ResolutionInfo({ required this.width, @@ -63,6 +78,48 @@ class CameraPermissionsErrorData { } } +class CameraStateTypeData { + CameraStateTypeData({ + required this.value, + }); + + CameraStateType value; + + Object encode() { + return [ + value.index, + ]; + } + + static CameraStateTypeData decode(Object result) { + result as List; + return CameraStateTypeData( + value: CameraStateType.values[result[0]! as int], + ); + } +} + +class LiveDataSupportedTypeData { + LiveDataSupportedTypeData({ + required this.value, + }); + + LiveDataSupportedType value; + + Object encode() { + return [ + value.index, + ]; + } + + static LiveDataSupportedTypeData decode(Object result) { + result as List; + return LiveDataSupportedTypeData( + value: LiveDataSupportedType.values[result[0]! as int], + ); + } +} + class ExposureCompensationRange { ExposureCompensationRange({ required this.minCompensation, @@ -223,6 +280,33 @@ class CameraInfoHostApi { } } + Future getLiveCameraState(int arg_identifier) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.CameraInfoHostApi.getLiveCameraState', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_identifier]) as List?; + 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 if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as int?)!; + } + } + Future getExposureState(int arg_identifier) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.CameraInfoHostApi.getExposureState', codec, @@ -1063,6 +1147,63 @@ class ImageCaptureHostApi { } } +class _CameraStateFlutterApiCodec extends StandardMessageCodec { + const _CameraStateFlutterApiCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is CameraStateTypeData) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return CameraStateTypeData.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +abstract class CameraStateFlutterApi { + static const MessageCodec codec = _CameraStateFlutterApiCodec(); + + void create(int identifier, CameraStateTypeData type, int? errorIdentifier); + + static void setup(CameraStateFlutterApi? api, + {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.CameraStateFlutterApi.create', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.CameraStateFlutterApi.create was null.'); + final List args = (message as List?)!; + final int? arg_identifier = (args[0] as int?); + assert(arg_identifier != null, + 'Argument for dev.flutter.pigeon.CameraStateFlutterApi.create was null, expected non-null int.'); + final CameraStateTypeData? arg_type = + (args[1] as CameraStateTypeData?); + assert(arg_type != null, + 'Argument for dev.flutter.pigeon.CameraStateFlutterApi.create was null, expected non-null CameraStateTypeData.'); + final int? arg_errorIdentifier = (args[2] as int?); + api.create(arg_identifier!, arg_type!, arg_errorIdentifier); + return; + }); + } + } + } +} + class _ExposureStateFlutterApiCodec extends StandardMessageCodec { const _ExposureStateFlutterApiCodec(); @override @@ -1298,6 +1439,215 @@ class AnalyzerHostApi { } } +class ObserverHostApi { + /// Constructor for [ObserverHostApi]. 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. + ObserverHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = StandardMessageCodec(); + + Future create(int arg_identifier) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.ObserverHostApi.create', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_identifier]) as List?; + 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; + } + } +} + +abstract class ObserverFlutterApi { + static const MessageCodec codec = StandardMessageCodec(); + + void onChanged(int identifier, int valueIdentifier); + + static void setup(ObserverFlutterApi? api, + {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.ObserverFlutterApi.onChanged', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.ObserverFlutterApi.onChanged was null.'); + final List args = (message as List?)!; + final int? arg_identifier = (args[0] as int?); + assert(arg_identifier != null, + 'Argument for dev.flutter.pigeon.ObserverFlutterApi.onChanged was null, expected non-null int.'); + final int? arg_valueIdentifier = (args[1] as int?); + assert(arg_valueIdentifier != null, + 'Argument for dev.flutter.pigeon.ObserverFlutterApi.onChanged was null, expected non-null int.'); + api.onChanged(arg_identifier!, arg_valueIdentifier!); + return; + }); + } + } + } +} + +abstract class CameraStateErrorFlutterApi { + static const MessageCodec codec = StandardMessageCodec(); + + void create(int identifier, int code); + + static void setup(CameraStateErrorFlutterApi? api, + {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.CameraStateErrorFlutterApi.create', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.CameraStateErrorFlutterApi.create was null.'); + final List args = (message as List?)!; + final int? arg_identifier = (args[0] as int?); + assert(arg_identifier != null, + 'Argument for dev.flutter.pigeon.CameraStateErrorFlutterApi.create was null, expected non-null int.'); + final int? arg_code = (args[1] as int?); + assert(arg_code != null, + 'Argument for dev.flutter.pigeon.CameraStateErrorFlutterApi.create was null, expected non-null int.'); + api.create(arg_identifier!, arg_code!); + return; + }); + } + } + } +} + +class LiveDataHostApi { + /// Constructor for [LiveDataHostApi]. 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. + LiveDataHostApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = StandardMessageCodec(); + + Future observe(int arg_identifier, int arg_observerIdentifier) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.LiveDataHostApi.observe', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_identifier, arg_observerIdentifier]) + as List?; + 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; + } + } + + Future removeObservers(int arg_identifier) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.LiveDataHostApi.removeObservers', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_identifier]) as List?; + 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 _LiveDataFlutterApiCodec extends StandardMessageCodec { + const _LiveDataFlutterApiCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is LiveDataSupportedTypeData) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return LiveDataSupportedTypeData.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +abstract class LiveDataFlutterApi { + static const MessageCodec codec = _LiveDataFlutterApiCodec(); + + void create(int identifier, LiveDataSupportedTypeData type); + + static void setup(LiveDataFlutterApi? api, + {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.LiveDataFlutterApi.create', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.LiveDataFlutterApi.create was null.'); + final List args = (message as List?)!; + final int? arg_identifier = (args[0] as int?); + assert(arg_identifier != null, + 'Argument for dev.flutter.pigeon.LiveDataFlutterApi.create was null, expected non-null int.'); + final LiveDataSupportedTypeData? arg_type = + (args[1] as LiveDataSupportedTypeData?); + assert(arg_type != null, + 'Argument for dev.flutter.pigeon.LiveDataFlutterApi.create was null, expected non-null LiveDataSupportedTypeData.'); + api.create(arg_identifier!, arg_type!); + return; + }); + } + } + } +} + abstract class AnalyzerFlutterApi { static const MessageCodec codec = StandardMessageCodec(); diff --git a/packages/camera/camera_android_camerax/lib/src/image_analysis.dart b/packages/camera/camera_android_camerax/lib/src/image_analysis.dart index 69cc7829c7a..7ffaba72eca 100644 --- a/packages/camera/camera_android_camerax/lib/src/image_analysis.dart +++ b/packages/camera/camera_android_camerax/lib/src/image_analysis.dart @@ -61,8 +61,12 @@ class ImageAnalysis extends UseCase { class _ImageAnalysisHostApiImpl extends ImageAnalysisHostApi { /// Constructor for [_ImageAnalysisHostApiImpl]. /// + /// 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. + /// contained by an [InstanceManager] is being created. If left null, it + /// will default to the global instance defined in [JavaObject]. _ImageAnalysisHostApiImpl({ this.binaryMessenger, InstanceManager? instanceManager, diff --git a/packages/camera/camera_android_camerax/lib/src/image_capture.dart b/packages/camera/camera_android_camerax/lib/src/image_capture.dart index 9b80c870621..6a9b2dedd04 100644 --- a/packages/camera/camera_android_camerax/lib/src/image_capture.dart +++ b/packages/camera/camera_android_camerax/lib/src/image_capture.dart @@ -96,8 +96,12 @@ class ImageCapture extends UseCase { class ImageCaptureHostApiImpl extends ImageCaptureHostApi { /// Constructs a [ImageCaptureHostApiImpl]. /// + /// 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. + /// contained by an [InstanceManager] is being created. If left null, it + /// will default to the global instance defined in [JavaObject]. ImageCaptureHostApiImpl( {this.binaryMessenger, InstanceManager? instanceManager}) { this.instanceManager = instanceManager ?? JavaObject.globalInstanceManager; diff --git a/packages/camera/camera_android_camerax/lib/src/image_proxy.dart b/packages/camera/camera_android_camerax/lib/src/image_proxy.dart index a1f929c5960..ded09123da6 100644 --- a/packages/camera/camera_android_camerax/lib/src/image_proxy.dart +++ b/packages/camera/camera_android_camerax/lib/src/image_proxy.dart @@ -99,19 +99,24 @@ class _ImageProxyHostApiImpl extends ImageProxyHostApi { @protected class ImageProxyFlutterApiImpl implements ImageProxyFlutterApi { /// Constructs a [ImageProxyFlutterApiImpl]. + /// + /// 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]. ImageProxyFlutterApiImpl({ - this.binaryMessenger, + BinaryMessenger? binaryMessenger, InstanceManager? instanceManager, - }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager; + }) : _binaryMessenger = binaryMessenger, + _instanceManager = instanceManager ?? JavaObject.globalInstanceManager; /// Receives binary data across the Flutter platform barrier. - /// - /// If it is null, the default BinaryMessenger will be used which routes to - /// the host platform. - final BinaryMessenger? binaryMessenger; + final BinaryMessenger? _binaryMessenger; /// Maintains instances stored to communicate with native language objects. - final InstanceManager instanceManager; + final InstanceManager _instanceManager; @override void create( @@ -120,18 +125,18 @@ class ImageProxyFlutterApiImpl implements ImageProxyFlutterApi { int height, int width, ) { - instanceManager.addHostCreatedInstance( + _instanceManager.addHostCreatedInstance( ImageProxy.detached( - binaryMessenger: binaryMessenger, - instanceManager: instanceManager, + binaryMessenger: _binaryMessenger, + instanceManager: _instanceManager, format: format, height: height, width: width, ), identifier, onCopy: (ImageProxy original) => ImageProxy.detached( - binaryMessenger: binaryMessenger, - instanceManager: instanceManager, + binaryMessenger: _binaryMessenger, + instanceManager: _instanceManager, format: original.format, height: original.height, width: original.width), diff --git a/packages/camera/camera_android_camerax/lib/src/instance_manager.dart b/packages/camera/camera_android_camerax/lib/src/instance_manager.dart index ac9856a6367..aeb97ec36fa 100644 --- a/packages/camera/camera_android_camerax/lib/src/instance_manager.dart +++ b/packages/camera/camera_android_camerax/lib/src/instance_manager.dart @@ -123,12 +123,12 @@ class InstanceManager { if (weakInstance == null) { final T? strongInstance = _strongInstances[identifier] as T?; if (strongInstance != null) { - // This cast is safe since it matches the argument type for - // _addInstanceWithIdentifier, which is the only place _copyCallbacks - // is populated. - final T Function(T) copyCallback = - _copyCallbacks[identifier]! as T Function(T); - final T copy = copyCallback(strongInstance); + final Function copyCallback = _copyCallbacks[identifier]!; + // This avoid_dynamic_calls is safe since the type of strongInstance + // matches the argument type for _addInstanceWithIdentifier, which is + // the only place _copyCallbacks is populated. + // ignore: avoid_dynamic_calls + final T copy = copyCallback(strongInstance) as T; _identifiers[copy] = identifier; _weakInstances[identifier] = WeakReference(copy); _finalizer.attach(copy, identifier, detach: copy); diff --git a/packages/camera/camera_android_camerax/lib/src/live_data.dart b/packages/camera/camera_android_camerax/lib/src/live_data.dart new file mode 100644 index 00000000000..7a14ae91d09 --- /dev/null +++ b/packages/camera/camera_android_camerax/lib/src/live_data.dart @@ -0,0 +1,139 @@ +// 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'; + +import 'camera_state.dart'; +import 'camerax_library.g.dart'; +import 'instance_manager.dart'; +import 'java_object.dart'; +import 'observer.dart'; + +/// A data holder class that can be observed. +/// +/// For this wrapped class, observation can only fall within the lifecycle of the +/// Android Activity to which this plugin is attached. +/// +/// See https://developer.android.com/reference/androidx/lifecycle/LiveData. +class LiveData extends JavaObject { + /// Constructs a [LiveData] that is not automatically attached to a native object. + LiveData.detached({this.binaryMessenger, this.instanceManager}) + : _api = _LiveDataHostApiImpl( + binaryMessenger: binaryMessenger, instanceManager: instanceManager), + super.detached( + binaryMessenger: binaryMessenger, instanceManager: instanceManager); + + final _LiveDataHostApiImpl _api; + + /// Receives binary data across the Flutter platform barrier. + final BinaryMessenger? binaryMessenger; + + /// Maintains instances stored to communicate with native language objects. + final InstanceManager? instanceManager; + + /// Adds specified [Observer] to the list of observers of this instance. + Future observe(Observer observer) { + return _api.observeFromInstances(this, observer); + } + + /// Removes all observers of this instance. + Future removeObservers() { + return _api.removeObserversFromInstances(this); + } +} + +/// Host API implementation of [LiveData]. +class _LiveDataHostApiImpl extends LiveDataHostApi { + /// Constructs a [_LiveDataHostApiImpl]. + /// + /// If [binaryMessenger] 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]. + _LiveDataHostApiImpl({ + 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; + + /// Adds specified [Observer] to the list of observers of the specified + /// [LiveData] instance. + Future observeFromInstances( + LiveData instance, + Observer observer, + ) { + return observe( + instanceManager.getIdentifier(instance)!, + instanceManager.getIdentifier(observer)!, + ); + } + + /// Removes all observers of the specified [LiveData] instance. + Future removeObserversFromInstances( + LiveData instance, + ) { + return removeObservers( + instanceManager.getIdentifier(instance)!, + ); + } +} + +/// Flutter API implementation for [LiveData]. +/// +/// This class may handle instantiating and adding Dart instances that are +/// attached to a native instance or receiving callback methods from an +/// overridden native class. +@protected +class LiveDataFlutterApiImpl implements LiveDataFlutterApi { + /// Constructs a [LiveDataFlutterApiImpl]. + /// + /// 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]. + LiveDataFlutterApiImpl({ + BinaryMessenger? binaryMessenger, + InstanceManager? instanceManager, + }) : _binaryMessenger = binaryMessenger, + _instanceManager = instanceManager ?? JavaObject.globalInstanceManager; + + /// Receives binary data across the Flutter platform barrier. + final BinaryMessenger? _binaryMessenger; + + /// Maintains instances stored to communicate with native language objects. + final InstanceManager _instanceManager; + + @override + void create( + int identifier, + LiveDataSupportedTypeData typeData, + ) { + switch (typeData.value) { + case LiveDataSupportedType.cameraState: + _instanceManager.addHostCreatedInstance( + LiveData.detached( + binaryMessenger: _binaryMessenger, + instanceManager: _instanceManager, + ), + identifier, + onCopy: (LiveData original) => + LiveData.detached( + binaryMessenger: _binaryMessenger, + instanceManager: _instanceManager, + ), + ); + } + } +} diff --git a/packages/camera/camera_android_camerax/lib/src/observer.dart b/packages/camera/camera_android_camerax/lib/src/observer.dart new file mode 100644 index 00000000000..70ae0dbb507 --- /dev/null +++ b/packages/camera/camera_android_camerax/lib/src/observer.dart @@ -0,0 +1,126 @@ +// 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'; + +import 'android_camera_camerax_flutter_api_impls.dart'; +import 'camerax_library.g.dart'; +import 'instance_manager.dart'; +import 'java_object.dart'; +import 'live_data.dart'; + +/// Callback that can receive from [LiveData]. +/// +/// See https://developer.android.com/reference/androidx/lifecycle/Observer. +class Observer extends JavaObject { + /// Constructor for [Observer]. + Observer( + {super.binaryMessenger, + super.instanceManager, + required void Function(Object value) onChanged}) + : _api = _ObserverHostApiImpl( + binaryMessenger: binaryMessenger, instanceManager: instanceManager), + super.detached() { + AndroidCameraXCameraFlutterApis.instance.ensureSetUp(); + this.onChanged = (Object value) { + assert(value is T); + onChanged(value); + }; + _api.createFromInstances(this); + } + + /// Constructs a [Observer] that is not automatically attached to a native object. + Observer.detached( + {super.binaryMessenger, + super.instanceManager, + required void Function(Object value) onChanged}) + : _api = _ObserverHostApiImpl( + binaryMessenger: binaryMessenger, instanceManager: instanceManager), + super.detached() { + this.onChanged = (Object value) { + assert(value is T); + onChanged(value); + }; + } + + final _ObserverHostApiImpl _api; + + /// Callback used when the observed data is changed to a new value. + /// + /// The callback parameter cannot take type [T] directly due to the issue + /// described in https://github.com/dart-lang/sdk/issues/51461. + late final void Function(Object value) onChanged; +} + +class _ObserverHostApiImpl extends ObserverHostApi { + /// Constructs an [_ObserverHostApiImpl]. + /// + /// 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]. + _ObserverHostApiImpl({ + this.binaryMessenger, + InstanceManager? instanceManager, + }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager, + super(binaryMessenger: binaryMessenger); + + final BinaryMessenger? binaryMessenger; + + final InstanceManager instanceManager; + + /// Adds specified [Observer] instance to instance manager and makes call + /// to native side to create the instance. + Future createFromInstances( + Observer instance, + ) { + return create( + instanceManager.addDartCreatedInstance( + instance, + onCopy: (Observer original) => Observer.detached( + onChanged: original.onChanged, + binaryMessenger: binaryMessenger, + instanceManager: instanceManager, + ), + ), + ); + } +} + +/// Flutter API implementation for [Observer]. +/// +/// This class may handle instantiating and adding Dart instances that are +/// attached to a native instance or receiving callback methods from an +/// overridden native class. +@protected +class ObserverFlutterApiImpl implements ObserverFlutterApi { + /// Constructs an [ObserverFlutterApiImpl]. + /// + /// 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]. + ObserverFlutterApiImpl({ + InstanceManager? instanceManager, + }) : _instanceManager = instanceManager ?? JavaObject.globalInstanceManager; + + /// Maintains instances stored to communicate with native language objects. + final InstanceManager _instanceManager; + + @override + void onChanged( + int identifier, + int valueIdentifier, + ) { + final Observer instance = + _instanceManager.getInstanceWithWeakReference(identifier)!; + + // ignore: avoid_dynamic_calls, void_checks + instance.onChanged( + _instanceManager.getInstanceWithWeakReference(valueIdentifier)!, + ); + } +} diff --git a/packages/camera/camera_android_camerax/lib/src/plane_proxy.dart b/packages/camera/camera_android_camerax/lib/src/plane_proxy.dart index c057876d1ed..d5b1661b0b4 100644 --- a/packages/camera/camera_android_camerax/lib/src/plane_proxy.dart +++ b/packages/camera/camera_android_camerax/lib/src/plane_proxy.dart @@ -46,23 +46,25 @@ class PlaneProxy extends JavaObject { /// overridden native class. @protected class PlaneProxyFlutterApiImpl implements PlaneProxyFlutterApi { - /// Constructs a [PlaneProxyFlutterApiImpl]. + /// Constructs an [PlaneProxyFlutterApiImpl]. + /// + /// 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. + /// contained by an [InstanceManager] is being created. If left null, it + /// will default to the global instance defined in [JavaObject]. PlaneProxyFlutterApiImpl({ - this.binaryMessenger, + BinaryMessenger? binaryMessenger, InstanceManager? instanceManager, - }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager; + }) : _binaryMessenger = binaryMessenger, + _instanceManager = instanceManager ?? JavaObject.globalInstanceManager; /// Receives binary data across the Flutter platform barrier. - /// - /// If it is null, the default BinaryMessenger will be used which routes to - /// the host platform. - final BinaryMessenger? binaryMessenger; + final BinaryMessenger? _binaryMessenger; /// Maintains instances stored to communicate with native language objects. - final InstanceManager instanceManager; + final InstanceManager _instanceManager; @override void create( @@ -71,18 +73,18 @@ class PlaneProxyFlutterApiImpl implements PlaneProxyFlutterApi { int pixelStride, int rowStride, ) { - instanceManager.addHostCreatedInstance( + _instanceManager.addHostCreatedInstance( PlaneProxy.detached( - binaryMessenger: binaryMessenger, - instanceManager: instanceManager, + binaryMessenger: _binaryMessenger, + instanceManager: _instanceManager, buffer: buffer, pixelStride: pixelStride, rowStride: rowStride, ), identifier, onCopy: (PlaneProxy original) => PlaneProxy.detached( - binaryMessenger: binaryMessenger, - instanceManager: instanceManager, + binaryMessenger: _binaryMessenger, + instanceManager: _instanceManager, buffer: buffer, pixelStride: pixelStride, rowStride: rowStride), diff --git a/packages/camera/camera_android_camerax/lib/src/preview.dart b/packages/camera/camera_android_camerax/lib/src/preview.dart index 02a540a3b50..c3094d71417 100644 --- a/packages/camera/camera_android_camerax/lib/src/preview.dart +++ b/packages/camera/camera_android_camerax/lib/src/preview.dart @@ -70,18 +70,19 @@ class Preview extends UseCase { /// Host API implementation of [Preview]. class PreviewHostApiImpl extends PreviewHostApi { - /// Constructs a [PreviewHostApiImpl]. + /// Constructs an [PreviewHostApiImpl]. + /// + /// 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. + /// contained by an [InstanceManager] is being created. If left null, it + /// will default to the global instance defined in [JavaObject]. PreviewHostApiImpl({this.binaryMessenger, InstanceManager? instanceManager}) { this.instanceManager = instanceManager ?? JavaObject.globalInstanceManager; } /// Receives binary data across the Flutter platform barrier. - /// - /// If it is null, the default BinaryMessenger will be used which routes to - /// the host platform. final BinaryMessenger? binaryMessenger; /// Maintains instances stored to communicate with native language objects. @@ -106,10 +107,8 @@ class PreviewHostApiImpl extends PreviewHostApi { /// the ID corresponding to the surface it will provide. Future setSurfaceProviderFromInstance(Preview instance) async { final int? identifier = instanceManager.getIdentifier(instance); - assert(identifier != null, - 'No Preview has the identifer of that requested to set the surface provider on.'); - final int surfaceTextureEntryId = await setSurfaceProvider(identifier!); + return surfaceTextureEntryId; } @@ -122,10 +121,8 @@ class PreviewHostApiImpl extends PreviewHostApi { /// Gets the resolution information of the specified [Preview] instance. Future getResolutionInfoFromInstance(Preview instance) async { final int? identifier = instanceManager.getIdentifier(instance); - assert(identifier != null, - 'No Preview has the identifer of that requested to get the resolution information for.'); - final ResolutionInfo resolutionInfo = await getResolutionInfo(identifier!); + return resolutionInfo; } } diff --git a/packages/camera/camera_android_camerax/lib/src/process_camera_provider.dart b/packages/camera/camera_android_camerax/lib/src/process_camera_provider.dart index d8cccdb2aa3..88eab07f0be 100644 --- a/packages/camera/camera_android_camerax/lib/src/process_camera_provider.dart +++ b/packages/camera/camera_android_camerax/lib/src/process_camera_provider.dart @@ -74,10 +74,14 @@ class ProcessCameraProvider extends JavaObject { /// Host API implementation of [ProcessCameraProvider]. class ProcessCameraProviderHostApiImpl extends ProcessCameraProviderHostApi { - /// Creates a [ProcessCameraProviderHostApiImpl]. + /// Constructs an [ProcessCameraProviderHostApiImpl]. + /// + /// 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. + /// contained by an [InstanceManager] is being created. If left null, it + /// will default to the global instance defined in [JavaObject]. ProcessCameraProviderHostApiImpl( {this.binaryMessenger, InstanceManager? instanceManager}) : super(binaryMessenger: binaryMessenger) { @@ -85,9 +89,6 @@ class ProcessCameraProviderHostApiImpl extends ProcessCameraProviderHostApi { } /// Receives binary data across the Flutter platform barrier. - /// - /// If it is null, the default BinaryMessenger will be used which routes to - /// the host platform. final BinaryMessenger? binaryMessenger; /// Maintains instances stored to communicate with native language objects. @@ -104,9 +105,6 @@ class ProcessCameraProviderHostApiImpl extends ProcessCameraProviderHostApi { /// the [ProcessCameraProvider] instance. int getProcessCameraProviderIdentifier(ProcessCameraProvider instance) { final int? identifier = instanceManager.getIdentifier(instance); - - assert(identifier != null, - 'No ProcessCameraProvider has the identifer of that which was requested.'); return identifier!; } @@ -186,30 +184,36 @@ class ProcessCameraProviderHostApiImpl extends ProcessCameraProviderHostApi { /// Flutter API Implementation of [ProcessCameraProvider]. class ProcessCameraProviderFlutterApiImpl implements ProcessCameraProviderFlutterApi { - /// Constructs a [ProcessCameraProviderFlutterApiImpl]. + /// Constructs an [ProcessCameraProviderFlutterApiImpl]. + /// + /// 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]. ProcessCameraProviderFlutterApiImpl({ - this.binaryMessenger, + BinaryMessenger? binaryMessenger, InstanceManager? instanceManager, - }) : instanceManager = instanceManager ?? JavaObject.globalInstanceManager; + }) : _binaryMessenger = binaryMessenger, + _instanceManager = instanceManager ?? JavaObject.globalInstanceManager; /// Receives binary data across the Flutter platform barrier. - /// - /// If it is null, the default BinaryMessenger will be used which routes to - /// the host platform. - final BinaryMessenger? binaryMessenger; + final BinaryMessenger? _binaryMessenger; /// Maintains instances stored to communicate with native language objects. - final InstanceManager instanceManager; + final InstanceManager _instanceManager; @override void create(int identifier) { - instanceManager.addHostCreatedInstance( + _instanceManager.addHostCreatedInstance( ProcessCameraProvider.detached( - binaryMessenger: binaryMessenger, instanceManager: instanceManager), + binaryMessenger: _binaryMessenger, instanceManager: _instanceManager), identifier, onCopy: (ProcessCameraProvider original) { return ProcessCameraProvider.detached( - binaryMessenger: binaryMessenger, instanceManager: instanceManager); + binaryMessenger: _binaryMessenger, + instanceManager: _instanceManager); }, ); } diff --git a/packages/camera/camera_android_camerax/lib/src/surface.dart b/packages/camera/camera_android_camerax/lib/src/surface.dart index ea8cf8cb751..42cad38721c 100644 --- a/packages/camera/camera_android_camerax/lib/src/surface.dart +++ b/packages/camera/camera_android_camerax/lib/src/surface.dart @@ -8,7 +8,7 @@ import 'java_object.dart'; /// /// See https://developer.android.com/reference/android/view/Surface.html. class Surface extends JavaObject { - /// Creates a detached [UseCase]. + /// Creates a detached [Surface]. Surface.detached({super.binaryMessenger, super.instanceManager}) : super.detached(); diff --git a/packages/camera/camera_android_camerax/lib/src/system_services.dart b/packages/camera/camera_android_camerax/lib/src/system_services.dart index e108b6140be..8cb2dc83531 100644 --- a/packages/camera/camera_android_camerax/lib/src/system_services.dart +++ b/packages/camera/camera_android_camerax/lib/src/system_services.dart @@ -65,14 +65,14 @@ class SystemServices { /// Host API implementation of [SystemServices]. class SystemServicesHostApiImpl extends SystemServicesHostApi { - /// Creates a [SystemServicesHostApiImpl]. + /// Constructs an [SystemServicesHostApiImpl]. + /// + /// If [binaryMessenger] is null, the default [BinaryMessenger] will be used, + /// which routes to the host platform. SystemServicesHostApiImpl({this.binaryMessenger}) : super(binaryMessenger: binaryMessenger); /// Receives binary data across the Flutter platform barrier. - /// - /// If it is null, the default BinaryMessenger will be used which routes to - /// the host platform. final BinaryMessenger? binaryMessenger; /// Requests permission to access the camera and audio if specified. @@ -94,16 +94,11 @@ class SystemServicesHostApiImpl extends SystemServicesHostApi { /// Flutter API implementation of [SystemServices]. class SystemServicesFlutterApiImpl implements SystemServicesFlutterApi { - /// Constructs a [SystemServicesFlutterApiImpl]. - SystemServicesFlutterApiImpl({ - this.binaryMessenger, - }); - - /// Receives binary data across the Flutter platform barrier. + /// Constructs an [SystemServicesFlutterApiImpl]. /// - /// If it is null, the default BinaryMessenger will be used which routes to - /// the host platform. - final BinaryMessenger? binaryMessenger; + /// If [binaryMessenger] is null, the default [BinaryMessenger] will be used, + /// which routes to the host platform. + SystemServicesFlutterApiImpl(); /// Callback method for any changes in device orientation. /// diff --git a/packages/camera/camera_android_camerax/lib/src/use_case.dart b/packages/camera/camera_android_camerax/lib/src/use_case.dart index f8910d9c534..256caf8c01b 100644 --- a/packages/camera/camera_android_camerax/lib/src/use_case.dart +++ b/packages/camera/camera_android_camerax/lib/src/use_case.dart @@ -4,7 +4,7 @@ import 'java_object.dart'; -/// An object representing the different functionalitites of the camera. +/// An object representing the different functionalities of the camera. /// /// See https://developer.android.com/reference/androidx/camera/core/UseCase. class UseCase extends JavaObject { diff --git a/packages/camera/camera_android_camerax/pigeons/camerax_library.dart b/packages/camera/camera_android_camerax/pigeons/camerax_library.dart index c8b3885d064..152ac53967c 100644 --- a/packages/camera/camera_android_camerax/pigeons/camerax_library.dart +++ b/packages/camera/camera_android_camerax/pigeons/camerax_library.dart @@ -46,6 +46,29 @@ class CameraPermissionsErrorData { String description; } +/// The states the camera can be in. +/// +/// See https://developer.android.com/reference/androidx/camera/core/CameraState.Type. +enum CameraStateType { + closed, + closing, + open, + opening, + pendingOpen, +} + +class CameraStateTypeData { + late CameraStateType value; +} + +enum LiveDataSupportedType { + cameraState, +} + +class LiveDataSupportedTypeData { + late LiveDataSupportedType value; +} + class ExposureCompensationRange { ExposureCompensationRange({ required this.minCompensation, @@ -78,6 +101,8 @@ abstract class JavaObjectFlutterApi { abstract class CameraInfoHostApi { int getSensorRotationDegrees(int identifier); + int getLiveCameraState(int identifier); + int getExposureState(int identifier); int getZoomState(int identifier); @@ -171,6 +196,11 @@ abstract class ImageCaptureHostApi { String takePicture(int identifier); } +@FlutterApi() +abstract class CameraStateFlutterApi { + void create(int identifier, CameraStateTypeData type, int? errorIdentifier); +} + @FlutterApi() abstract class ExposureStateFlutterApi { void create( @@ -198,6 +228,33 @@ abstract class AnalyzerHostApi { void create(int identifier); } +@HostApi(dartHostTestHandler: 'TestObserverHostApi') +abstract class ObserverHostApi { + void create(int identifier); +} + +@FlutterApi() +abstract class ObserverFlutterApi { + void onChanged(int identifier, int valueIdentifier); +} + +@FlutterApi() +abstract class CameraStateErrorFlutterApi { + void create(int identifier, int code); +} + +@HostApi(dartHostTestHandler: 'TestLiveDataHostApi') +abstract class LiveDataHostApi { + void observe(int identifier, int observerIdentifier); + + void removeObservers(int identifier); +} + +@FlutterApi() +abstract class LiveDataFlutterApi { + void create(int identifier, LiveDataSupportedTypeData type); +} + @FlutterApi() abstract class AnalyzerFlutterApi { void create(int identifier); diff --git a/packages/camera/camera_android_camerax/pubspec.yaml b/packages/camera/camera_android_camerax/pubspec.yaml index f4630a7ab26..bb140f5a41b 100644 --- a/packages/camera/camera_android_camerax/pubspec.yaml +++ b/packages/camera/camera_android_camerax/pubspec.yaml @@ -18,6 +18,7 @@ flutter: dartPluginClass: AndroidCameraCameraX dependencies: + async: ^2.5.0 camera_platform_interface: ^2.2.0 flutter: sdk: flutter @@ -27,7 +28,6 @@ dependencies: stream_transform: ^2.1.0 dev_dependencies: - async: ^2.5.0 build_runner: ^2.2.0 flutter_test: sdk: flutter diff --git a/packages/camera/camera_android_camerax/test/android_camera_camerax_test.dart b/packages/camera/camera_android_camerax/test/android_camera_camerax_test.dart index e7a6707d6e3..e873e192205 100644 --- a/packages/camera/camera_android_camerax/test/android_camera_camerax_test.dart +++ b/packages/camera/camera_android_camerax/test/android_camera_camerax_test.dart @@ -10,11 +10,15 @@ import 'package:camera_android_camerax/src/analyzer.dart'; import 'package:camera_android_camerax/src/camera.dart'; import 'package:camera_android_camerax/src/camera_info.dart'; import 'package:camera_android_camerax/src/camera_selector.dart'; +import 'package:camera_android_camerax/src/camera_state.dart'; +import 'package:camera_android_camerax/src/camera_state_error.dart'; import 'package:camera_android_camerax/src/camerax_library.g.dart'; import 'package:camera_android_camerax/src/exposure_state.dart'; import 'package:camera_android_camerax/src/image_analysis.dart'; import 'package:camera_android_camerax/src/image_capture.dart'; import 'package:camera_android_camerax/src/image_proxy.dart'; +import 'package:camera_android_camerax/src/live_data.dart'; +import 'package:camera_android_camerax/src/observer.dart'; import 'package:camera_android_camerax/src/plane_proxy.dart'; import 'package:camera_android_camerax/src/preview.dart'; import 'package:camera_android_camerax/src/process_camera_provider.dart'; @@ -39,6 +43,7 @@ import 'test_camerax_library.g.dart'; MockSpec(), MockSpec(), MockSpec(), + MockSpec>(), MockSpec(), MockSpec(), MockSpec(), @@ -49,6 +54,36 @@ import 'test_camerax_library.g.dart'; @GenerateMocks([BuildContext]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); + // Mocks the call to clear the native InstanceManager. + + TestInstanceManagerHostApi.setup(MockTestInstanceManagerHostApi()); + + Future testCameraClosingObserver(AndroidCameraCameraX camera, + int cameraId, Observer observer) async { + final CameraStateError testCameraStateError = + CameraStateError.detached(code: 0); + final Stream cameraClosingEventStream = + camera.onCameraClosing(cameraId); + final StreamQueue cameraClosingStreamQueue = + StreamQueue(cameraClosingEventStream); + final Stream cameraErrorEventStream = + camera.onCameraError(cameraId); + final StreamQueue cameraErrorStreamQueue = + StreamQueue(cameraErrorEventStream); + + observer.onChanged(CameraState.detached( + type: CameraStateType.closing, error: testCameraStateError)); + + final bool cameraClosingEventSent = + await cameraClosingStreamQueue.next == CameraClosingEvent(cameraId); + final bool cameraErrorSent = await cameraErrorStreamQueue.next == + CameraErrorEvent(cameraId, testCameraStateError.getDescription()); + + await cameraClosingStreamQueue.cancel(); + await cameraErrorStreamQueue.cancel(); + + return cameraClosingEventSent && cameraErrorSent; + } // Mocks the call to clear the native InstanceManager. TestInstanceManagerHostApi.setup(MockTestInstanceManagerHostApi()); @@ -114,12 +149,11 @@ void main() { }); test( - 'createCamera requests permissions, starts listening for device orientation changes, and returns flutter surface texture ID', + 'createCamera requests permissions, starts listening for device orientation changes, updates camera state observers, and returns flutter surface texture ID', () async { final MockAndroidCameraCameraX camera = MockAndroidCameraCameraX(); final MockProcessCameraProvider mockProcessCameraProvider = MockProcessCameraProvider(); - final MockCamera mockCamera = MockCamera(); const CameraLensDirection testLensDirection = CameraLensDirection.back; const int testSensorOrientation = 90; const CameraDescription testCameraDescription = CameraDescription( @@ -129,15 +163,23 @@ void main() { const ResolutionPreset testResolutionPreset = ResolutionPreset.veryHigh; const bool enableAudio = true; const int testSurfaceTextureId = 6; + final MockCamera mockCamera = MockCamera(); + final MockCameraInfo mockCameraInfo = MockCameraInfo(); + final MockLiveData mockLiveCameraState = MockLiveData(); camera.processCameraProvider = mockProcessCameraProvider; when(camera.testPreview.setSurfaceProvider()) .thenAnswer((_) async => testSurfaceTextureId); - when(mockProcessCameraProvider.bindToLifecycle(any, any)) - .thenAnswer((_) => Future.value(mockCamera)); - when(mockCamera.getCameraInfo()) - .thenAnswer((_) => Future.value(MockCameraInfo())); + when(mockProcessCameraProvider.bindToLifecycle( + camera.mockBackCameraSelector, + [camera.testPreview, camera.testImageCapture])) + .thenAnswer((_) async => mockCamera); + when(mockCamera.getCameraInfo()).thenAnswer((_) async => mockCameraInfo); + when(mockCameraInfo.getLiveCameraState()) + .thenAnswer((_) async => mockLiveCameraState); + camera.processCameraProvider = mockProcessCameraProvider; + camera.createDetachedObjectForTesting = true; expect( await camera.createCamera(testCameraDescription, testResolutionPreset, @@ -159,16 +201,23 @@ void main() { // Verify the camera's Preview instance has its surface provider set. verify(camera.preview!.setSurfaceProvider()); + + // Verify the camera state observer is updated. + expect( + await testCameraClosingObserver( + camera, + testSurfaceTextureId, + verify(mockLiveCameraState.observe(captureAny)).captured.single + as Observer), + isTrue); }); test( 'createCamera binds Preview and ImageCapture use cases to ProcessCameraProvider instance', () async { final MockAndroidCameraCameraX camera = MockAndroidCameraCameraX(); - final MockProcessCameraProvider mockProcessCameraProvider = + final ProcessCameraProvider mockProcessCameraProvider = MockProcessCameraProvider(); - final MockCamera mockCamera = MockCamera(); - final MockCameraInfo mockCameraInfo = MockCameraInfo(); const CameraLensDirection testLensDirection = CameraLensDirection.back; const int testSensorOrientation = 90; const CameraDescription testCameraDescription = CameraDescription( @@ -177,6 +226,18 @@ void main() { sensorOrientation: testSensorOrientation); const ResolutionPreset testResolutionPreset = ResolutionPreset.veryHigh; const bool enableAudio = true; + final MockCamera mockCamera = MockCamera(); + final MockCameraInfo mockCameraInfo = MockCameraInfo(); + + when(mockProcessCameraProvider.bindToLifecycle( + camera.mockBackCameraSelector, + [camera.testPreview, camera.testImageCapture])) + .thenAnswer((_) async => mockCamera); + when(mockCamera.getCameraInfo()).thenAnswer((_) async => mockCameraInfo); + when(mockCameraInfo.getLiveCameraState()) + .thenAnswer((_) async => MockLiveData()); + camera.processCameraProvider = mockProcessCameraProvider; + camera.createDetachedObjectForTesting = true; camera.processCameraProvider = mockProcessCameraProvider; @@ -223,6 +284,7 @@ void main() { final Camera mockCamera = MockCamera(); final ResolutionInfo testResolutionInfo = ResolutionInfo(width: resolutionWidth, height: resolutionHeight); + final CameraInfo mockCameraInfo = MockCameraInfo(); // TODO(camsim99): Modify this when camera configuration is supported and // defualt values no longer being used. @@ -244,6 +306,18 @@ void main() { when(camera.testPreview.setSurfaceProvider()) .thenAnswer((_) async => cameraId); + when(camera.processCameraProvider!.bindToLifecycle( + camera.mockBackCameraSelector, + [camera.testPreview, camera.testImageCapture])) + .thenAnswer((_) async => mockCamera); + when(mockCamera.getCameraInfo()).thenAnswer((_) async => mockCameraInfo); + when(mockCameraInfo.getLiveCameraState()) + .thenAnswer((_) async => MockLiveData()); + camera.createDetachedObjectForTesting = true; + + await camera.createCamera(testCameraDescription, testResolutionPreset, + enableAudio: enableAudio); + when(mockProcessCameraProvider.bindToLifecycle(any, any)) .thenAnswer((_) async => mockCamera); when(mockCamera.getCameraInfo()) @@ -266,16 +340,19 @@ void main() { expect(camera.camera, isNotNull); }); - test('dispose releases Flutter surface texture and unbinds all use cases', + test( + 'dispose releases Flutter surface texture, removes camera state observers, and unbinds all use cases', () async { final AndroidCameraCameraX camera = AndroidCameraCameraX(); camera.preview = MockPreview(); camera.processCameraProvider = MockProcessCameraProvider(); + camera.liveCameraState = MockLiveData(); camera.dispose(3); verify(camera.preview!.releaseFlutterSurfaceTexture()); + verify(camera.liveCameraState!.removeObservers()); verify(camera.processCameraProvider!.unbindAll()); }); @@ -295,18 +372,43 @@ void main() { await streamQueue.cancel(); }); - test('onCameraError stream emits errors caught by system services', () async { + test( + 'onCameraClosing stream emits camera closing event when cameraEventStreamController emits a camera closing event', + () async { + final AndroidCameraCameraX camera = AndroidCameraCameraX(); + const int cameraId = 99; + const CameraClosingEvent cameraClosingEvent = CameraClosingEvent(cameraId); + final Stream eventStream = + camera.onCameraClosing(cameraId); + final StreamQueue streamQueue = + StreamQueue(eventStream); + + camera.cameraEventStreamController.add(cameraClosingEvent); + + expect(await streamQueue.next, equals(cameraClosingEvent)); + await streamQueue.cancel(); + }); + + test( + 'onCameraError stream emits errors caught by system services or added to stream within plugin', + () async { final AndroidCameraCameraX camera = AndroidCameraCameraX(); const int cameraId = 27; - const String testErrorDescription = 'Test error description!'; + const String firstTestErrorDescription = 'Test error description 1!'; + const String secondTestErrorDescription = 'Test error description 2!'; + const CameraErrorEvent secondCameraErrorEvent = + CameraErrorEvent(cameraId, secondTestErrorDescription); final Stream eventStream = camera.onCameraError(cameraId); final StreamQueue streamQueue = StreamQueue(eventStream); - SystemServices.cameraErrorStreamController.add(testErrorDescription); - + SystemServices.cameraErrorStreamController.add(firstTestErrorDescription); expect(await streamQueue.next, - equals(const CameraErrorEvent(cameraId, testErrorDescription))); + equals(const CameraErrorEvent(cameraId, firstTestErrorDescription))); + + camera.cameraEventStreamController.add(secondCameraErrorEvent); + expect(await streamQueue.next, equals(secondCameraErrorEvent)); + await streamQueue.cancel(); }); @@ -357,13 +459,15 @@ void main() { camera.processCameraProvider!.unbind([camera.preview!])); }); - test('resumePreview does not bind preview to lifecycle if already bound', + test( + 'resumePreview does not bind preview to lifecycle or update camera state observers if already bound', () async { final AndroidCameraCameraX camera = AndroidCameraCameraX(); final MockProcessCameraProvider mockProcessCameraProvider = MockProcessCameraProvider(); final MockCamera mockCamera = MockCamera(); final MockCameraInfo mockCameraInfo = MockCameraInfo(); + final MockLiveData mockLiveCameraState = MockLiveData(); camera.processCameraProvider = mockProcessCameraProvider; camera.cameraSelector = MockCameraSelector(); @@ -372,29 +476,42 @@ void main() { when(camera.processCameraProvider!.isBound(camera.preview!)) .thenAnswer((_) async => true); - when(mockProcessCameraProvider.bindToLifecycle(any, any)) - .thenAnswer((_) => Future.value(mockCamera)); - when(mockCamera.getCameraInfo()) - .thenAnswer((_) => Future.value(mockCameraInfo)); + when(mockProcessCameraProvider + .bindToLifecycle(camera.cameraSelector, [camera.preview!])) + .thenAnswer((_) async => mockCamera); + when(mockCamera.getCameraInfo()).thenAnswer((_) async => mockCameraInfo); + when(mockCameraInfo.getLiveCameraState()) + .thenAnswer((_) async => mockLiveCameraState); await camera.resumePreview(78); verifyNever(camera.processCameraProvider! .bindToLifecycle(camera.cameraSelector!, [camera.preview!])); + verifyNever(mockLiveCameraState.observe(any)); expect(camera.cameraInfo, isNot(mockCameraInfo)); }); - test('resumePreview binds preview to lifecycle if not already bound', + test( + 'resumePreview binds preview to lifecycle and updates camera state observers if not already bound', () async { final AndroidCameraCameraX camera = AndroidCameraCameraX(); final MockProcessCameraProvider mockProcessCameraProvider = MockProcessCameraProvider(); final MockCamera mockCamera = MockCamera(); final MockCameraInfo mockCameraInfo = MockCameraInfo(); + final MockLiveData mockLiveCameraState = MockLiveData(); camera.processCameraProvider = mockProcessCameraProvider; camera.cameraSelector = MockCameraSelector(); camera.preview = MockPreview(); + camera.createDetachedObjectForTesting = true; + + when(mockProcessCameraProvider + .bindToLifecycle(camera.cameraSelector, [camera.preview!])) + .thenAnswer((_) async => mockCamera); + when(mockCamera.getCameraInfo()).thenAnswer((_) async => mockCameraInfo); + when(mockCameraInfo.getLiveCameraState()) + .thenAnswer((_) async => mockLiveCameraState); when(mockProcessCameraProvider.bindToLifecycle(any, any)) .thenAnswer((_) => Future.value(mockCamera)); @@ -405,6 +522,13 @@ void main() { verify(camera.processCameraProvider! .bindToLifecycle(camera.cameraSelector!, [camera.preview!])); + expect( + await testCameraClosingObserver( + camera, + 78, + verify(mockLiveCameraState.observe(captureAny)).captured.single + as Observer), + isTrue); expect(camera.cameraInfo, equals(mockCameraInfo)); }); @@ -415,11 +539,20 @@ void main() { final MockProcessCameraProvider mockProcessCameraProvider = MockProcessCameraProvider(); final MockCamera mockCamera = MockCamera(); + final MockCameraInfo mockCameraInfo = MockCameraInfo(); const int textureId = 75; camera.processCameraProvider = mockProcessCameraProvider; camera.cameraSelector = MockCameraSelector(); camera.preview = MockPreview(); + camera.createDetachedObjectForTesting = true; + + when(mockProcessCameraProvider + .bindToLifecycle(camera.cameraSelector, [camera.preview!])) + .thenAnswer((_) async => mockCamera); + when(mockCamera.getCameraInfo()).thenAnswer((_) async => mockCameraInfo); + when(mockCameraInfo.getLiveCameraState()) + .thenAnswer((_) async => MockLiveData()); when(mockProcessCameraProvider.bindToLifecycle(any, any)) .thenAnswer((_) => Future.value(mockCamera)); @@ -456,6 +589,14 @@ void main() { camera.processCameraProvider = mockProcessCameraProvider; camera.cameraSelector = MockCameraSelector(); camera.preview = MockPreview(); + camera.createDetachedObjectForTesting = true; + + when(mockProcessCameraProvider + .bindToLifecycle(camera.cameraSelector, [camera.preview!])) + .thenAnswer((_) async => mockCamera); + when(mockCamera.getCameraInfo()).thenAnswer((_) async => mockCameraInfo); + when(mockCameraInfo.getLiveCameraState()) + .thenAnswer((_) async => MockLiveData()); when(mockProcessCameraProvider.bindToLifecycle(any, any)) .thenAnswer((_) => Future.value(mockCamera)); @@ -579,7 +720,7 @@ void main() { camera.processCameraProvider = mockProcessCameraProvider; camera.cameraSelector = MockCameraSelector(); - camera.createDetachedCallbacks = true; + camera.createDetachedObjectForTesting = true; when(mockProcessCameraProvider.bindToLifecycle(any, any)) .thenAnswer((_) => Future.value(mockCamera)); @@ -620,7 +761,7 @@ void main() { camera.processCameraProvider = mockProcessCameraProvider; camera.cameraSelector = mockCameraSelector; - camera.createDetachedCallbacks = true; + camera.createDetachedObjectForTesting = true; when(mockProcessCameraProvider.bindToLifecycle( mockCameraSelector, [camera.mockImageAnalysis])) @@ -681,7 +822,7 @@ void main() { camera.processCameraProvider = mockProcessCameraProvider; camera.cameraSelector = mockCameraSelector; - camera.createDetachedCallbacks = true; + camera.createDetachedObjectForTesting = true; when(mockProcessCameraProvider.bindToLifecycle( mockCameraSelector, [camera.mockImageAnalysis])) diff --git a/packages/camera/camera_android_camerax/test/android_camera_camerax_test.mocks.dart b/packages/camera/camera_android_camerax/test/android_camera_camerax_test.mocks.dart index b7365a2e90d..4e94e98236a 100644 --- a/packages/camera/camera_android_camerax/test/android_camera_camerax_test.mocks.dart +++ b/packages/camera/camera_android_camerax/test/android_camera_camerax_test.mocks.dart @@ -3,32 +3,35 @@ // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'dart:async' as _i11; -import 'dart:typed_data' as _i18; +import 'dart:async' as _i12; +import 'dart:typed_data' as _i21; -import 'package:camera_android_camerax/src/analyzer.dart' as _i14; -import 'package:camera_android_camerax/src/camera.dart' as _i7; +import 'package:camera_android_camerax/src/analyzer.dart' as _i16; +import 'package:camera_android_camerax/src/camera.dart' as _i8; import 'package:camera_android_camerax/src/camera_info.dart' as _i2; -import 'package:camera_android_camerax/src/camera_selector.dart' as _i12; -import 'package:camera_android_camerax/src/camerax_library.g.dart' as _i6; -import 'package:camera_android_camerax/src/exposure_state.dart' as _i3; -import 'package:camera_android_camerax/src/image_analysis.dart' as _i13; -import 'package:camera_android_camerax/src/image_capture.dart' as _i15; -import 'package:camera_android_camerax/src/image_proxy.dart' as _i16; -import 'package:camera_android_camerax/src/plane_proxy.dart' as _i17; -import 'package:camera_android_camerax/src/preview.dart' as _i19; +import 'package:camera_android_camerax/src/camera_selector.dart' as _i14; +import 'package:camera_android_camerax/src/camera_state.dart' as _i13; +import 'package:camera_android_camerax/src/camerax_library.g.dart' as _i7; +import 'package:camera_android_camerax/src/exposure_state.dart' as _i4; +import 'package:camera_android_camerax/src/image_analysis.dart' as _i15; +import 'package:camera_android_camerax/src/image_capture.dart' as _i17; +import 'package:camera_android_camerax/src/image_proxy.dart' as _i19; +import 'package:camera_android_camerax/src/live_data.dart' as _i3; +import 'package:camera_android_camerax/src/observer.dart' as _i18; +import 'package:camera_android_camerax/src/plane_proxy.dart' as _i20; +import 'package:camera_android_camerax/src/preview.dart' as _i22; import 'package:camera_android_camerax/src/process_camera_provider.dart' - as _i20; -import 'package:camera_android_camerax/src/use_case.dart' as _i21; -import 'package:camera_android_camerax/src/zoom_state.dart' as _i4; + as _i23; +import 'package:camera_android_camerax/src/use_case.dart' as _i24; +import 'package:camera_android_camerax/src/zoom_state.dart' as _i5; import 'package:camera_platform_interface/camera_platform_interface.dart' - as _i5; -import 'package:flutter/foundation.dart' as _i10; -import 'package:flutter/services.dart' as _i9; -import 'package:flutter/widgets.dart' as _i8; + as _i6; +import 'package:flutter/foundation.dart' as _i11; +import 'package:flutter/services.dart' as _i10; +import 'package:flutter/widgets.dart' as _i9; import 'package:mockito/mockito.dart' as _i1; -import 'test_camerax_library.g.dart' as _i22; +import 'test_camerax_library.g.dart' as _i25; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -51,8 +54,8 @@ class _FakeCameraInfo_0 extends _i1.SmartFake implements _i2.CameraInfo { ); } -class _FakeExposureState_1 extends _i1.SmartFake implements _i3.ExposureState { - _FakeExposureState_1( +class _FakeLiveData_1 extends _i1.SmartFake implements _i3.LiveData { + _FakeLiveData_1( Object parent, Invocation parentInvocation, ) : super( @@ -61,8 +64,8 @@ class _FakeExposureState_1 extends _i1.SmartFake implements _i3.ExposureState { ); } -class _FakeZoomState_2 extends _i1.SmartFake implements _i4.ZoomState { - _FakeZoomState_2( +class _FakeExposureState_2 extends _i1.SmartFake implements _i4.ExposureState { + _FakeExposureState_2( Object parent, Invocation parentInvocation, ) : super( @@ -71,9 +74,8 @@ class _FakeZoomState_2 extends _i1.SmartFake implements _i4.ZoomState { ); } -class _FakeCameraImageFormat_3 extends _i1.SmartFake - implements _i5.CameraImageFormat { - _FakeCameraImageFormat_3( +class _FakeZoomState_3 extends _i1.SmartFake implements _i5.ZoomState { + _FakeZoomState_3( Object parent, Invocation parentInvocation, ) : super( @@ -82,9 +84,9 @@ class _FakeCameraImageFormat_3 extends _i1.SmartFake ); } -class _FakeExposureCompensationRange_4 extends _i1.SmartFake - implements _i6.ExposureCompensationRange { - _FakeExposureCompensationRange_4( +class _FakeCameraImageFormat_4 extends _i1.SmartFake + implements _i6.CameraImageFormat { + _FakeCameraImageFormat_4( Object parent, Invocation parentInvocation, ) : super( @@ -93,9 +95,9 @@ class _FakeExposureCompensationRange_4 extends _i1.SmartFake ); } -class _FakeResolutionInfo_5 extends _i1.SmartFake - implements _i6.ResolutionInfo { - _FakeResolutionInfo_5( +class _FakeExposureCompensationRange_5 extends _i1.SmartFake + implements _i7.ExposureCompensationRange { + _FakeExposureCompensationRange_5( Object parent, Invocation parentInvocation, ) : super( @@ -104,8 +106,9 @@ class _FakeResolutionInfo_5 extends _i1.SmartFake ); } -class _FakeCamera_6 extends _i1.SmartFake implements _i7.Camera { - _FakeCamera_6( +class _FakeResolutionInfo_6 extends _i1.SmartFake + implements _i7.ResolutionInfo { + _FakeResolutionInfo_6( Object parent, Invocation parentInvocation, ) : super( @@ -114,8 +117,18 @@ class _FakeCamera_6 extends _i1.SmartFake implements _i7.Camera { ); } -class _FakeWidget_7 extends _i1.SmartFake implements _i8.Widget { - _FakeWidget_7( +class _FakeCamera_7 extends _i1.SmartFake implements _i8.Camera { + _FakeCamera_7( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeWidget_8 extends _i1.SmartFake implements _i9.Widget { + _FakeWidget_8( Object parent, Invocation parentInvocation, ) : super( @@ -124,13 +137,14 @@ class _FakeWidget_7 extends _i1.SmartFake implements _i8.Widget { ); @override - String toString({_i9.DiagnosticLevel? minLevel = _i9.DiagnosticLevel.info}) => + String toString( + {_i10.DiagnosticLevel? minLevel = _i10.DiagnosticLevel.info}) => super.toString(); } -class _FakeInheritedWidget_8 extends _i1.SmartFake - implements _i8.InheritedWidget { - _FakeInheritedWidget_8( +class _FakeInheritedWidget_9 extends _i1.SmartFake + implements _i9.InheritedWidget { + _FakeInheritedWidget_9( Object parent, Invocation parentInvocation, ) : super( @@ -139,13 +153,14 @@ class _FakeInheritedWidget_8 extends _i1.SmartFake ); @override - String toString({_i9.DiagnosticLevel? minLevel = _i9.DiagnosticLevel.info}) => + String toString( + {_i10.DiagnosticLevel? minLevel = _i10.DiagnosticLevel.info}) => super.toString(); } -class _FakeDiagnosticsNode_9 extends _i1.SmartFake - implements _i10.DiagnosticsNode { - _FakeDiagnosticsNode_9( +class _FakeDiagnosticsNode_10 extends _i1.SmartFake + implements _i11.DiagnosticsNode { + _FakeDiagnosticsNode_10( Object parent, Invocation parentInvocation, ) : super( @@ -155,8 +170,8 @@ class _FakeDiagnosticsNode_9 extends _i1.SmartFake @override String toString({ - _i10.TextTreeConfiguration? parentConfiguration, - _i9.DiagnosticLevel? minLevel = _i9.DiagnosticLevel.info, + _i11.TextTreeConfiguration? parentConfiguration, + _i10.DiagnosticLevel? minLevel = _i10.DiagnosticLevel.info, }) => super.toString(); } @@ -164,14 +179,14 @@ class _FakeDiagnosticsNode_9 extends _i1.SmartFake /// A class which mocks [Camera]. /// /// See the documentation for Mockito's code generation for more information. -class MockCamera extends _i1.Mock implements _i7.Camera { +class MockCamera extends _i1.Mock implements _i8.Camera { @override - _i11.Future<_i2.CameraInfo> getCameraInfo() => (super.noSuchMethod( + _i12.Future<_i2.CameraInfo> getCameraInfo() => (super.noSuchMethod( Invocation.method( #getCameraInfo, [], ), - returnValue: _i11.Future<_i2.CameraInfo>.value(_FakeCameraInfo_0( + returnValue: _i12.Future<_i2.CameraInfo>.value(_FakeCameraInfo_0( this, Invocation.method( #getCameraInfo, @@ -179,14 +194,14 @@ class MockCamera extends _i1.Mock implements _i7.Camera { ), )), returnValueForMissingStub: - _i11.Future<_i2.CameraInfo>.value(_FakeCameraInfo_0( + _i12.Future<_i2.CameraInfo>.value(_FakeCameraInfo_0( this, Invocation.method( #getCameraInfo, [], ), )), - ) as _i11.Future<_i2.CameraInfo>); + ) as _i12.Future<_i2.CameraInfo>); } /// A class which mocks [CameraInfo]. @@ -194,21 +209,46 @@ class MockCamera extends _i1.Mock implements _i7.Camera { /// See the documentation for Mockito's code generation for more information. class MockCameraInfo extends _i1.Mock implements _i2.CameraInfo { @override - _i11.Future getSensorRotationDegrees() => (super.noSuchMethod( + _i12.Future getSensorRotationDegrees() => (super.noSuchMethod( Invocation.method( #getSensorRotationDegrees, [], ), - returnValue: _i11.Future.value(0), - returnValueForMissingStub: _i11.Future.value(0), - ) as _i11.Future); + returnValue: _i12.Future.value(0), + returnValueForMissingStub: _i12.Future.value(0), + ) as _i12.Future); + @override + _i12.Future<_i3.LiveData<_i13.CameraState>> getLiveCameraState() => + (super.noSuchMethod( + Invocation.method( + #getLiveCameraState, + [], + ), + returnValue: _i12.Future<_i3.LiveData<_i13.CameraState>>.value( + _FakeLiveData_1<_i13.CameraState>( + this, + Invocation.method( + #getLiveCameraState, + [], + ), + )), + returnValueForMissingStub: + _i12.Future<_i3.LiveData<_i13.CameraState>>.value( + _FakeLiveData_1<_i13.CameraState>( + this, + Invocation.method( + #getLiveCameraState, + [], + ), + )), + ) as _i12.Future<_i3.LiveData<_i13.CameraState>>); @override - _i11.Future<_i3.ExposureState> getExposureState() => (super.noSuchMethod( + _i12.Future<_i4.ExposureState> getExposureState() => (super.noSuchMethod( Invocation.method( #getExposureState, [], ), - returnValue: _i11.Future<_i3.ExposureState>.value(_FakeExposureState_1( + returnValue: _i12.Future<_i4.ExposureState>.value(_FakeExposureState_2( this, Invocation.method( #getExposureState, @@ -216,21 +256,21 @@ class MockCameraInfo extends _i1.Mock implements _i2.CameraInfo { ), )), returnValueForMissingStub: - _i11.Future<_i3.ExposureState>.value(_FakeExposureState_1( + _i12.Future<_i4.ExposureState>.value(_FakeExposureState_2( this, Invocation.method( #getExposureState, [], ), )), - ) as _i11.Future<_i3.ExposureState>); + ) as _i12.Future<_i4.ExposureState>); @override - _i11.Future<_i4.ZoomState> getZoomState() => (super.noSuchMethod( + _i12.Future<_i5.ZoomState> getZoomState() => (super.noSuchMethod( Invocation.method( #getZoomState, [], ), - returnValue: _i11.Future<_i4.ZoomState>.value(_FakeZoomState_2( + returnValue: _i12.Future<_i5.ZoomState>.value(_FakeZoomState_3( this, Invocation.method( #getZoomState, @@ -238,33 +278,33 @@ class MockCameraInfo extends _i1.Mock implements _i2.CameraInfo { ), )), returnValueForMissingStub: - _i11.Future<_i4.ZoomState>.value(_FakeZoomState_2( + _i12.Future<_i5.ZoomState>.value(_FakeZoomState_3( this, Invocation.method( #getZoomState, [], ), )), - ) as _i11.Future<_i4.ZoomState>); + ) as _i12.Future<_i5.ZoomState>); } /// A class which mocks [CameraImageData]. /// /// See the documentation for Mockito's code generation for more information. // ignore: must_be_immutable -class MockCameraImageData extends _i1.Mock implements _i5.CameraImageData { +class MockCameraImageData extends _i1.Mock implements _i6.CameraImageData { @override - _i5.CameraImageFormat get format => (super.noSuchMethod( + _i6.CameraImageFormat get format => (super.noSuchMethod( Invocation.getter(#format), - returnValue: _FakeCameraImageFormat_3( + returnValue: _FakeCameraImageFormat_4( this, Invocation.getter(#format), ), - returnValueForMissingStub: _FakeCameraImageFormat_3( + returnValueForMissingStub: _FakeCameraImageFormat_4( this, Invocation.getter(#format), ), - ) as _i5.CameraImageFormat); + ) as _i6.CameraImageFormat); @override int get height => (super.noSuchMethod( Invocation.getter(#height), @@ -278,48 +318,48 @@ class MockCameraImageData extends _i1.Mock implements _i5.CameraImageData { returnValueForMissingStub: 0, ) as int); @override - List<_i5.CameraImagePlane> get planes => (super.noSuchMethod( + List<_i6.CameraImagePlane> get planes => (super.noSuchMethod( Invocation.getter(#planes), - returnValue: <_i5.CameraImagePlane>[], - returnValueForMissingStub: <_i5.CameraImagePlane>[], - ) as List<_i5.CameraImagePlane>); + returnValue: <_i6.CameraImagePlane>[], + returnValueForMissingStub: <_i6.CameraImagePlane>[], + ) as List<_i6.CameraImagePlane>); } /// A class which mocks [CameraSelector]. /// /// See the documentation for Mockito's code generation for more information. -class MockCameraSelector extends _i1.Mock implements _i12.CameraSelector { +class MockCameraSelector extends _i1.Mock implements _i14.CameraSelector { @override - _i11.Future> filter(List<_i2.CameraInfo>? cameraInfos) => + _i12.Future> filter(List<_i2.CameraInfo>? cameraInfos) => (super.noSuchMethod( Invocation.method( #filter, [cameraInfos], ), returnValue: - _i11.Future>.value(<_i2.CameraInfo>[]), + _i12.Future>.value(<_i2.CameraInfo>[]), returnValueForMissingStub: - _i11.Future>.value(<_i2.CameraInfo>[]), - ) as _i11.Future>); + _i12.Future>.value(<_i2.CameraInfo>[]), + ) as _i12.Future>); } /// A class which mocks [ExposureState]. /// /// See the documentation for Mockito's code generation for more information. -class MockExposureState extends _i1.Mock implements _i3.ExposureState { +class MockExposureState extends _i1.Mock implements _i4.ExposureState { @override - _i6.ExposureCompensationRange get exposureCompensationRange => + _i7.ExposureCompensationRange get exposureCompensationRange => (super.noSuchMethod( Invocation.getter(#exposureCompensationRange), - returnValue: _FakeExposureCompensationRange_4( + returnValue: _FakeExposureCompensationRange_5( this, Invocation.getter(#exposureCompensationRange), ), - returnValueForMissingStub: _FakeExposureCompensationRange_4( + returnValueForMissingStub: _FakeExposureCompensationRange_5( this, Invocation.getter(#exposureCompensationRange), ), - ) as _i6.ExposureCompensationRange); + ) as _i7.ExposureCompensationRange); @override double get exposureCompensationStep => (super.noSuchMethod( Invocation.getter(#exposureCompensationStep), @@ -331,55 +371,80 @@ class MockExposureState extends _i1.Mock implements _i3.ExposureState { /// A class which mocks [ImageAnalysis]. /// /// See the documentation for Mockito's code generation for more information. -class MockImageAnalysis extends _i1.Mock implements _i13.ImageAnalysis { +class MockImageAnalysis extends _i1.Mock implements _i15.ImageAnalysis { @override - _i11.Future setAnalyzer(_i14.Analyzer? analyzer) => (super.noSuchMethod( + _i12.Future setAnalyzer(_i16.Analyzer? analyzer) => (super.noSuchMethod( Invocation.method( #setAnalyzer, [analyzer], ), - returnValue: _i11.Future.value(), - returnValueForMissingStub: _i11.Future.value(), - ) as _i11.Future); + returnValue: _i12.Future.value(), + returnValueForMissingStub: _i12.Future.value(), + ) as _i12.Future); @override - _i11.Future clearAnalyzer() => (super.noSuchMethod( + _i12.Future clearAnalyzer() => (super.noSuchMethod( Invocation.method( #clearAnalyzer, [], ), - returnValue: _i11.Future.value(), - returnValueForMissingStub: _i11.Future.value(), - ) as _i11.Future); + returnValue: _i12.Future.value(), + returnValueForMissingStub: _i12.Future.value(), + ) as _i12.Future); } /// A class which mocks [ImageCapture]. /// /// See the documentation for Mockito's code generation for more information. -class MockImageCapture extends _i1.Mock implements _i15.ImageCapture { +class MockImageCapture extends _i1.Mock implements _i17.ImageCapture { @override - _i11.Future setFlashMode(int? newFlashMode) => (super.noSuchMethod( + _i12.Future setFlashMode(int? newFlashMode) => (super.noSuchMethod( Invocation.method( #setFlashMode, [newFlashMode], ), - returnValue: _i11.Future.value(), - returnValueForMissingStub: _i11.Future.value(), - ) as _i11.Future); + returnValue: _i12.Future.value(), + returnValueForMissingStub: _i12.Future.value(), + ) as _i12.Future); @override - _i11.Future takePicture() => (super.noSuchMethod( + _i12.Future takePicture() => (super.noSuchMethod( Invocation.method( #takePicture, [], ), - returnValue: _i11.Future.value(''), - returnValueForMissingStub: _i11.Future.value(''), - ) as _i11.Future); + returnValue: _i12.Future.value(''), + returnValueForMissingStub: _i12.Future.value(''), + ) as _i12.Future); +} + +/// A class which mocks [LiveData]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockLiveData extends _i1.Mock implements _i3.LiveData<_i13.CameraState> { + @override + _i12.Future observe(_i18.Observer<_i13.CameraState>? observer) => + (super.noSuchMethod( + Invocation.method( + #observe, + [observer], + ), + returnValue: _i12.Future.value(), + returnValueForMissingStub: _i12.Future.value(), + ) as _i12.Future); + @override + _i12.Future removeObservers() => (super.noSuchMethod( + Invocation.method( + #removeObservers, + [], + ), + returnValue: _i12.Future.value(), + returnValueForMissingStub: _i12.Future.value(), + ) as _i12.Future); } /// A class which mocks [ImageProxy]. /// /// See the documentation for Mockito's code generation for more information. -class MockImageProxy extends _i1.Mock implements _i16.ImageProxy { +class MockImageProxy extends _i1.Mock implements _i19.ImageProxy { @override int get format => (super.noSuchMethod( Invocation.getter(#format), @@ -399,37 +464,37 @@ class MockImageProxy extends _i1.Mock implements _i16.ImageProxy { returnValueForMissingStub: 0, ) as int); @override - _i11.Future> getPlanes() => (super.noSuchMethod( + _i12.Future> getPlanes() => (super.noSuchMethod( Invocation.method( #getPlanes, [], ), returnValue: - _i11.Future>.value(<_i17.PlaneProxy>[]), + _i12.Future>.value(<_i20.PlaneProxy>[]), returnValueForMissingStub: - _i11.Future>.value(<_i17.PlaneProxy>[]), - ) as _i11.Future>); + _i12.Future>.value(<_i20.PlaneProxy>[]), + ) as _i12.Future>); @override - _i11.Future close() => (super.noSuchMethod( + _i12.Future close() => (super.noSuchMethod( Invocation.method( #close, [], ), - returnValue: _i11.Future.value(), - returnValueForMissingStub: _i11.Future.value(), - ) as _i11.Future); + returnValue: _i12.Future.value(), + returnValueForMissingStub: _i12.Future.value(), + ) as _i12.Future); } /// A class which mocks [PlaneProxy]. /// /// See the documentation for Mockito's code generation for more information. -class MockPlaneProxy extends _i1.Mock implements _i17.PlaneProxy { +class MockPlaneProxy extends _i1.Mock implements _i20.PlaneProxy { @override - _i18.Uint8List get buffer => (super.noSuchMethod( + _i21.Uint8List get buffer => (super.noSuchMethod( Invocation.getter(#buffer), - returnValue: _i18.Uint8List(0), - returnValueForMissingStub: _i18.Uint8List(0), - ) as _i18.Uint8List); + returnValue: _i21.Uint8List(0), + returnValueForMissingStub: _i21.Uint8List(0), + ) as _i21.Uint8List); @override int get pixelStride => (super.noSuchMethod( Invocation.getter(#pixelStride), @@ -447,16 +512,16 @@ class MockPlaneProxy extends _i1.Mock implements _i17.PlaneProxy { /// A class which mocks [Preview]. /// /// See the documentation for Mockito's code generation for more information. -class MockPreview extends _i1.Mock implements _i19.Preview { +class MockPreview extends _i1.Mock implements _i22.Preview { @override - _i11.Future setSurfaceProvider() => (super.noSuchMethod( + _i12.Future setSurfaceProvider() => (super.noSuchMethod( Invocation.method( #setSurfaceProvider, [], ), - returnValue: _i11.Future.value(0), - returnValueForMissingStub: _i11.Future.value(0), - ) as _i11.Future); + returnValue: _i12.Future.value(0), + returnValueForMissingStub: _i12.Future.value(0), + ) as _i12.Future); @override void releaseFlutterSurfaceTexture() => super.noSuchMethod( Invocation.method( @@ -466,13 +531,13 @@ class MockPreview extends _i1.Mock implements _i19.Preview { returnValueForMissingStub: null, ); @override - _i11.Future<_i6.ResolutionInfo> getResolutionInfo() => (super.noSuchMethod( + _i12.Future<_i7.ResolutionInfo> getResolutionInfo() => (super.noSuchMethod( Invocation.method( #getResolutionInfo, [], ), returnValue: - _i11.Future<_i6.ResolutionInfo>.value(_FakeResolutionInfo_5( + _i12.Future<_i7.ResolutionInfo>.value(_FakeResolutionInfo_6( this, Invocation.method( #getResolutionInfo, @@ -480,37 +545,37 @@ class MockPreview extends _i1.Mock implements _i19.Preview { ), )), returnValueForMissingStub: - _i11.Future<_i6.ResolutionInfo>.value(_FakeResolutionInfo_5( + _i12.Future<_i7.ResolutionInfo>.value(_FakeResolutionInfo_6( this, Invocation.method( #getResolutionInfo, [], ), )), - ) as _i11.Future<_i6.ResolutionInfo>); + ) as _i12.Future<_i7.ResolutionInfo>); } /// A class which mocks [ProcessCameraProvider]. /// /// See the documentation for Mockito's code generation for more information. class MockProcessCameraProvider extends _i1.Mock - implements _i20.ProcessCameraProvider { + implements _i23.ProcessCameraProvider { @override - _i11.Future> getAvailableCameraInfos() => + _i12.Future> getAvailableCameraInfos() => (super.noSuchMethod( Invocation.method( #getAvailableCameraInfos, [], ), returnValue: - _i11.Future>.value(<_i2.CameraInfo>[]), + _i12.Future>.value(<_i2.CameraInfo>[]), returnValueForMissingStub: - _i11.Future>.value(<_i2.CameraInfo>[]), - ) as _i11.Future>); + _i12.Future>.value(<_i2.CameraInfo>[]), + ) as _i12.Future>); @override - _i11.Future<_i7.Camera> bindToLifecycle( - _i12.CameraSelector? cameraSelector, - List<_i21.UseCase>? useCases, + _i12.Future<_i8.Camera> bindToLifecycle( + _i14.CameraSelector? cameraSelector, + List<_i24.UseCase>? useCases, ) => (super.noSuchMethod( Invocation.method( @@ -520,7 +585,7 @@ class MockProcessCameraProvider extends _i1.Mock useCases, ], ), - returnValue: _i11.Future<_i7.Camera>.value(_FakeCamera_6( + returnValue: _i12.Future<_i8.Camera>.value(_FakeCamera_7( this, Invocation.method( #bindToLifecycle, @@ -530,7 +595,7 @@ class MockProcessCameraProvider extends _i1.Mock ], ), )), - returnValueForMissingStub: _i11.Future<_i7.Camera>.value(_FakeCamera_6( + returnValueForMissingStub: _i12.Future<_i8.Camera>.value(_FakeCamera_7( this, Invocation.method( #bindToLifecycle, @@ -540,18 +605,18 @@ class MockProcessCameraProvider extends _i1.Mock ], ), )), - ) as _i11.Future<_i7.Camera>); + ) as _i12.Future<_i8.Camera>); @override - _i11.Future isBound(_i21.UseCase? useCase) => (super.noSuchMethod( + _i12.Future isBound(_i24.UseCase? useCase) => (super.noSuchMethod( Invocation.method( #isBound, [useCase], ), - returnValue: _i11.Future.value(false), - returnValueForMissingStub: _i11.Future.value(false), - ) as _i11.Future); + returnValue: _i12.Future.value(false), + returnValueForMissingStub: _i12.Future.value(false), + ) as _i12.Future); @override - void unbind(List<_i21.UseCase>? useCases) => super.noSuchMethod( + void unbind(List<_i24.UseCase>? useCases) => super.noSuchMethod( Invocation.method( #unbind, [useCases], @@ -572,7 +637,7 @@ class MockProcessCameraProvider extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockTestInstanceManagerHostApi extends _i1.Mock - implements _i22.TestInstanceManagerHostApi { + implements _i25.TestInstanceManagerHostApi { @override void clear() => super.noSuchMethod( Invocation.method( @@ -586,7 +651,7 @@ class MockTestInstanceManagerHostApi extends _i1.Mock /// A class which mocks [ZoomState]. /// /// See the documentation for Mockito's code generation for more information. -class MockZoomState extends _i1.Mock implements _i4.ZoomState { +class MockZoomState extends _i1.Mock implements _i5.ZoomState { @override double get minZoomRatio => (super.noSuchMethod( Invocation.getter(#minZoomRatio), @@ -604,19 +669,19 @@ class MockZoomState extends _i1.Mock implements _i4.ZoomState { /// A class which mocks [BuildContext]. /// /// See the documentation for Mockito's code generation for more information. -class MockBuildContext extends _i1.Mock implements _i8.BuildContext { +class MockBuildContext extends _i1.Mock implements _i9.BuildContext { MockBuildContext() { _i1.throwOnMissingStub(this); } @override - _i8.Widget get widget => (super.noSuchMethod( + _i9.Widget get widget => (super.noSuchMethod( Invocation.getter(#widget), - returnValue: _FakeWidget_7( + returnValue: _FakeWidget_8( this, Invocation.getter(#widget), ), - ) as _i8.Widget); + ) as _i9.Widget); @override bool get mounted => (super.noSuchMethod( Invocation.getter(#mounted), @@ -628,8 +693,8 @@ class MockBuildContext extends _i1.Mock implements _i8.BuildContext { returnValue: false, ) as bool); @override - _i8.InheritedWidget dependOnInheritedElement( - _i8.InheritedElement? ancestor, { + _i9.InheritedWidget dependOnInheritedElement( + _i9.InheritedElement? ancestor, { Object? aspect, }) => (super.noSuchMethod( @@ -638,7 +703,7 @@ class MockBuildContext extends _i1.Mock implements _i8.BuildContext { [ancestor], {#aspect: aspect}, ), - returnValue: _FakeInheritedWidget_8( + returnValue: _FakeInheritedWidget_9( this, Invocation.method( #dependOnInheritedElement, @@ -646,9 +711,9 @@ class MockBuildContext extends _i1.Mock implements _i8.BuildContext { {#aspect: aspect}, ), ), - ) as _i8.InheritedWidget); + ) as _i9.InheritedWidget); @override - void visitAncestorElements(bool Function(_i8.Element)? visitor) => + void visitAncestorElements(bool Function(_i9.Element)? visitor) => super.noSuchMethod( Invocation.method( #visitAncestorElements, @@ -657,7 +722,7 @@ class MockBuildContext extends _i1.Mock implements _i8.BuildContext { returnValueForMissingStub: null, ); @override - void visitChildElements(_i8.ElementVisitor? visitor) => super.noSuchMethod( + void visitChildElements(_i9.ElementVisitor? visitor) => super.noSuchMethod( Invocation.method( #visitChildElements, [visitor], @@ -665,7 +730,7 @@ class MockBuildContext extends _i1.Mock implements _i8.BuildContext { returnValueForMissingStub: null, ); @override - void dispatchNotification(_i8.Notification? notification) => + void dispatchNotification(_i9.Notification? notification) => super.noSuchMethod( Invocation.method( #dispatchNotification, @@ -674,9 +739,9 @@ class MockBuildContext extends _i1.Mock implements _i8.BuildContext { returnValueForMissingStub: null, ); @override - _i10.DiagnosticsNode describeElement( + _i11.DiagnosticsNode describeElement( String? name, { - _i10.DiagnosticsTreeStyle? style = _i10.DiagnosticsTreeStyle.errorProperty, + _i11.DiagnosticsTreeStyle? style = _i11.DiagnosticsTreeStyle.errorProperty, }) => (super.noSuchMethod( Invocation.method( @@ -684,7 +749,7 @@ class MockBuildContext extends _i1.Mock implements _i8.BuildContext { [name], {#style: style}, ), - returnValue: _FakeDiagnosticsNode_9( + returnValue: _FakeDiagnosticsNode_10( this, Invocation.method( #describeElement, @@ -692,11 +757,11 @@ class MockBuildContext extends _i1.Mock implements _i8.BuildContext { {#style: style}, ), ), - ) as _i10.DiagnosticsNode); + ) as _i11.DiagnosticsNode); @override - _i10.DiagnosticsNode describeWidget( + _i11.DiagnosticsNode describeWidget( String? name, { - _i10.DiagnosticsTreeStyle? style = _i10.DiagnosticsTreeStyle.errorProperty, + _i11.DiagnosticsTreeStyle? style = _i11.DiagnosticsTreeStyle.errorProperty, }) => (super.noSuchMethod( Invocation.method( @@ -704,7 +769,7 @@ class MockBuildContext extends _i1.Mock implements _i8.BuildContext { [name], {#style: style}, ), - returnValue: _FakeDiagnosticsNode_9( + returnValue: _FakeDiagnosticsNode_10( this, Invocation.method( #describeWidget, @@ -712,9 +777,9 @@ class MockBuildContext extends _i1.Mock implements _i8.BuildContext { {#style: style}, ), ), - ) as _i10.DiagnosticsNode); + ) as _i11.DiagnosticsNode); @override - List<_i10.DiagnosticsNode> describeMissingAncestor( + List<_i11.DiagnosticsNode> describeMissingAncestor( {required Type? expectedAncestorType}) => (super.noSuchMethod( Invocation.method( @@ -722,21 +787,21 @@ class MockBuildContext extends _i1.Mock implements _i8.BuildContext { [], {#expectedAncestorType: expectedAncestorType}, ), - returnValue: <_i10.DiagnosticsNode>[], - ) as List<_i10.DiagnosticsNode>); + returnValue: <_i11.DiagnosticsNode>[], + ) as List<_i11.DiagnosticsNode>); @override - _i10.DiagnosticsNode describeOwnershipChain(String? name) => + _i11.DiagnosticsNode describeOwnershipChain(String? name) => (super.noSuchMethod( Invocation.method( #describeOwnershipChain, [name], ), - returnValue: _FakeDiagnosticsNode_9( + returnValue: _FakeDiagnosticsNode_10( this, Invocation.method( #describeOwnershipChain, [name], ), ), - ) as _i10.DiagnosticsNode); + ) as _i11.DiagnosticsNode); } diff --git a/packages/camera/camera_android_camerax/test/camera_info_test.dart b/packages/camera/camera_android_camerax/test/camera_info_test.dart index 9826b88e367..c3aa85fd676 100644 --- a/packages/camera/camera_android_camerax/test/camera_info_test.dart +++ b/packages/camera/camera_android_camerax/test/camera_info_test.dart @@ -3,9 +3,11 @@ // found in the LICENSE file. import 'package:camera_android_camerax/src/camera_info.dart'; +import 'package:camera_android_camerax/src/camera_state.dart'; import 'package:camera_android_camerax/src/camerax_library.g.dart'; import 'package:camera_android_camerax/src/exposure_state.dart'; import 'package:camera_android_camerax/src/instance_manager.dart'; +import 'package:camera_android_camerax/src/live_data.dart'; import 'package:camera_android_camerax/src/zoom_state.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; @@ -14,7 +16,11 @@ import 'package:mockito/mockito.dart'; import 'camera_info_test.mocks.dart'; import 'test_camerax_library.g.dart'; -@GenerateMocks([TestCameraInfoHostApi, TestInstanceManagerHostApi]) +@GenerateMocks([ + LiveData, + TestCameraInfoHostApi, + TestInstanceManagerHostApi +]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -50,7 +56,7 @@ void main() { verify(mockApi.getSensorRotationDegrees(0)); }); - test('getExposureState makes call to retrieve expected ExposureState', + test('getLiveCameraState makes call to retrieve live camera state', () async { final MockTestCameraInfoHostApi mockApi = MockTestCameraInfoHostApi(); TestCameraInfoHostApi.setup(mockApi); @@ -58,7 +64,40 @@ void main() { final InstanceManager instanceManager = InstanceManager( onWeakReferenceRemoved: (_) {}, ); + final CameraInfo cameraInfo = CameraInfo.detached( + instanceManager: instanceManager, + ); + const int cameraIdentifier = 55; + final MockLiveData mockLiveCameraState = + MockLiveData(); + const int liveCameraStateIdentifier = 73; + instanceManager.addHostCreatedInstance( + cameraInfo, + cameraIdentifier, + onCopy: (_) => CameraInfo.detached(), + ); + instanceManager.addHostCreatedInstance( + mockLiveCameraState, + liveCameraStateIdentifier, + onCopy: (_) => MockLiveData(), + ); + + when(mockApi.getLiveCameraState(cameraIdentifier)) + .thenReturn(liveCameraStateIdentifier); + expect( + await cameraInfo.getLiveCameraState(), equals(mockLiveCameraState)); + verify(mockApi.getLiveCameraState(cameraIdentifier)); + }); + + test('getExposureState makes call to retrieve expected ExposureState', + () async { + final MockTestCameraInfoHostApi mockApi = MockTestCameraInfoHostApi(); + TestCameraInfoHostApi.setup(mockApi); + + final InstanceManager instanceManager = InstanceManager( + onWeakReferenceRemoved: (_) {}, + ); final CameraInfo cameraInfo = CameraInfo.detached( instanceManager: instanceManager, ); diff --git a/packages/camera/camera_android_camerax/test/camera_info_test.mocks.dart b/packages/camera/camera_android_camerax/test/camera_info_test.mocks.dart index 968dc6e8b62..8da0675983a 100644 --- a/packages/camera/camera_android_camerax/test/camera_info_test.mocks.dart +++ b/packages/camera/camera_android_camerax/test/camera_info_test.mocks.dart @@ -3,9 +3,13 @@ // Do not manually edit this file. // ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; + +import 'package:camera_android_camerax/src/live_data.dart' as _i2; +import 'package:camera_android_camerax/src/observer.dart' as _i4; import 'package:mockito/mockito.dart' as _i1; -import 'test_camerax_library.g.dart' as _i2; +import 'test_camerax_library.g.dart' as _i5; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -18,11 +22,39 @@ import 'test_camerax_library.g.dart' as _i2; // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class +/// A class which mocks [LiveData]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockLiveData extends _i1.Mock implements _i2.LiveData { + MockLiveData() { + _i1.throwOnMissingStub(this); + } + + @override + _i3.Future observe(_i4.Observer? observer) => (super.noSuchMethod( + Invocation.method( + #observe, + [observer], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override + _i3.Future removeObservers() => (super.noSuchMethod( + Invocation.method( + #removeObservers, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); +} + /// A class which mocks [TestCameraInfoHostApi]. /// /// See the documentation for Mockito's code generation for more information. class MockTestCameraInfoHostApi extends _i1.Mock - implements _i2.TestCameraInfoHostApi { + implements _i5.TestCameraInfoHostApi { MockTestCameraInfoHostApi() { _i1.throwOnMissingStub(this); } @@ -36,6 +68,14 @@ class MockTestCameraInfoHostApi extends _i1.Mock returnValue: 0, ) as int); @override + int getLiveCameraState(int? identifier) => (super.noSuchMethod( + Invocation.method( + #getLiveCameraState, + [identifier], + ), + returnValue: 0, + ) as int); + @override int getExposureState(int? identifier) => (super.noSuchMethod( Invocation.method( #getExposureState, @@ -57,7 +97,7 @@ class MockTestCameraInfoHostApi extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockTestInstanceManagerHostApi extends _i1.Mock - implements _i2.TestInstanceManagerHostApi { + implements _i5.TestInstanceManagerHostApi { MockTestInstanceManagerHostApi() { _i1.throwOnMissingStub(this); } diff --git a/packages/camera/camera_android_camerax/test/camera_state_error_test.dart b/packages/camera/camera_android_camerax/test/camera_state_error_test.dart new file mode 100644 index 00000000000..48da38d7af3 --- /dev/null +++ b/packages/camera/camera_android_camerax/test/camera_state_error_test.dart @@ -0,0 +1,53 @@ +// 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/camera_state_error.dart'; +import 'package:camera_android_camerax/src/instance_manager.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; + +import 'test_camerax_library.g.dart'; + +@GenerateMocks([TestInstanceManagerHostApi]) +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('CameraStateError', () { + tearDown(() { + TestInstanceManagerHostApi.setup(null); + }); + + test( + 'FlutterAPI create makes call to create CameraStateError instance with expected identifier', + () { + final InstanceManager instanceManager = InstanceManager( + onWeakReferenceRemoved: (_) {}, + ); + + final CameraStateErrorFlutterApiImpl api = CameraStateErrorFlutterApiImpl( + instanceManager: instanceManager, + ); + + const int instanceIdentifier = 0; + const int code = 23; + + api.create( + instanceIdentifier, + code, + ); + + // Test instance type. + final Object? instance = + instanceManager.getInstanceWithWeakReference(instanceIdentifier); + expect( + instance, + isA(), + ); + + // Test instance properties. + final CameraStateError cameraStateError = instance! as CameraStateError; + expect(cameraStateError.code, equals(code)); + }); + }); +} diff --git a/packages/camera/camera_android_camerax/test/camera_state_error_test.mocks.dart b/packages/camera/camera_android_camerax/test/camera_state_error_test.mocks.dart new file mode 100644 index 00000000000..0590cd5b44d --- /dev/null +++ b/packages/camera/camera_android_camerax/test/camera_state_error_test.mocks.dart @@ -0,0 +1,38 @@ +// Mocks generated by Mockito 5.4.0 from annotations +// in camera_android_camerax/test/camera_state_error_test.dart. +// Do not manually edit this file. + +// 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 [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, + ); +} diff --git a/packages/camera/camera_android_camerax/test/camera_state_test.dart b/packages/camera/camera_android_camerax/test/camera_state_test.dart new file mode 100644 index 00000000000..9265cee4d57 --- /dev/null +++ b/packages/camera/camera_android_camerax/test/camera_state_test.dart @@ -0,0 +1,68 @@ +// 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/camera_state.dart'; +import 'package:camera_android_camerax/src/camera_state_error.dart'; +import 'package:camera_android_camerax/src/camerax_library.g.dart'; +import 'package:camera_android_camerax/src/instance_manager.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; + +import 'test_camerax_library.g.dart'; + +@GenerateMocks([TestInstanceManagerHostApi]) +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('CameraState', () { + tearDown(() { + TestInstanceManagerHostApi.setup(null); + }); + + test( + 'FlutterAPI create makes call to create CameraState instance with expected identifier', + () { + final InstanceManager instanceManager = InstanceManager( + onWeakReferenceRemoved: (_) {}, + ); + + final CameraStateFlutterApiImpl api = CameraStateFlutterApiImpl( + instanceManager: instanceManager, + ); + + // Create CameraStateError for CameraState instance. + const int code = 23; + final CameraStateError cameraStateError = CameraStateError.detached( + instanceManager: instanceManager, + code: code, + ); + final int cameraStateErrorIdentifier = + instanceManager.addDartCreatedInstance(cameraStateError, onCopy: (_) { + return CameraStateError.detached(code: code); + }); + + // Create CameraState. + const int instanceIdentifier = 46; + const CameraStateType cameraStateType = CameraStateType.closed; + api.create( + instanceIdentifier, + CameraStateTypeData(value: cameraStateType), + cameraStateErrorIdentifier, + ); + + // Test instance type. + final Object? instance = + instanceManager.getInstanceWithWeakReference(instanceIdentifier); + expect( + instanceManager.getInstanceWithWeakReference(instanceIdentifier), + isA(), + ); + + // Test instance properties. + final CameraState cameraState = instance! as CameraState; + expect(cameraState.type, equals(cameraStateType)); + expect(cameraState.error, equals(cameraStateError)); + }); + }); +} diff --git a/packages/camera/camera_android_camerax/test/camera_state_test.mocks.dart b/packages/camera/camera_android_camerax/test/camera_state_test.mocks.dart new file mode 100644 index 00000000000..3431bf69b8e --- /dev/null +++ b/packages/camera/camera_android_camerax/test/camera_state_test.mocks.dart @@ -0,0 +1,38 @@ +// Mocks generated by Mockito 5.4.0 from annotations +// in camera_android_camerax/test/camera_state_test.dart. +// Do not manually edit this file. + +// 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 [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, + ); +} diff --git a/packages/camera/camera_android_camerax/test/camera_test.dart b/packages/camera/camera_android_camerax/test/camera_test.dart index 742a60799e6..05f5fe7dd02 100644 --- a/packages/camera/camera_android_camerax/test/camera_test.dart +++ b/packages/camera/camera_android_camerax/test/camera_test.dart @@ -20,6 +20,8 @@ void main() { TestInstanceManagerHostApi.setup(MockTestInstanceManagerHostApi()); group('Camera', () { + tearDown(() => TestCameraHostApi.setup(null)); + test('getCameraInfo makes call to retrieve expected CameraInfo', () async { final MockTestCameraHostApi mockApi = MockTestCameraHostApi(); TestCameraHostApi.setup(mockApi); @@ -52,7 +54,7 @@ void main() { verify(mockApi.getCameraInfo(cameraIdentifier)); }); - test('flutterApiCreateTest', () { + test('flutterApiCreate makes call to add instance to instance manager', () { final InstanceManager instanceManager = InstanceManager( onWeakReferenceRemoved: (_) {}, ); diff --git a/packages/camera/camera_android_camerax/test/live_data_test.dart b/packages/camera/camera_android_camerax/test/live_data_test.dart new file mode 100644 index 00000000000..04c64c7c80c --- /dev/null +++ b/packages/camera/camera_android_camerax/test/live_data_test.dart @@ -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 'package:camera_android_camerax/src/camera_state.dart'; +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/live_data.dart'; +import 'package:camera_android_camerax/src/observer.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'live_data_test.mocks.dart'; +import 'test_camerax_library.g.dart'; + +@GenerateMocks([TestLiveDataHostApi, TestInstanceManagerHostApi]) +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('LiveData', () { + tearDown(() { + TestLiveDataHostApi.setup(null); + TestInstanceManagerHostApi.setup(null); + }); + + test('observe makes call to add observer to LiveData instance', () async { + final MockTestLiveDataHostApi mockApi = MockTestLiveDataHostApi(); + TestLiveDataHostApi.setup(mockApi); + + final InstanceManager instanceManager = InstanceManager( + onWeakReferenceRemoved: (_) {}, + ); + + final LiveData instance = LiveData.detached( + instanceManager: instanceManager, + ); + const int instanceIdentifier = 0; + instanceManager.addHostCreatedInstance( + instance, + instanceIdentifier, + onCopy: (LiveData original) => LiveData.detached( + instanceManager: instanceManager, + ), + ); + + final Observer observer = Observer.detached( + instanceManager: instanceManager, + onChanged: (Object value) {}, + ); + const int observerIdentifier = 20; + instanceManager.addHostCreatedInstance( + observer, + observerIdentifier, + onCopy: (_) => Observer.detached( + instanceManager: instanceManager, + onChanged: (Object value) {}, + ), + ); + + await instance.observe( + observer, + ); + + verify(mockApi.observe( + instanceIdentifier, + observerIdentifier, + )); + }); + + test( + 'removeObservers makes call to remove observers from LiveData instance', + () async { + final MockTestLiveDataHostApi mockApi = MockTestLiveDataHostApi(); + TestLiveDataHostApi.setup(mockApi); + + final InstanceManager instanceManager = InstanceManager( + onWeakReferenceRemoved: (_) {}, + ); + + final LiveData instance = LiveData.detached( + instanceManager: instanceManager, + ); + const int instanceIdentifier = 0; + instanceManager.addHostCreatedInstance( + instance, + instanceIdentifier, + onCopy: (LiveData original) => LiveData.detached( + instanceManager: instanceManager, + ), + ); + + await instance.removeObservers(); + + verify(mockApi.removeObservers( + instanceIdentifier, + )); + }); + + test( + 'FlutterAPI create makes call to create LiveData instance with expected identifier', + () { + final InstanceManager instanceManager = InstanceManager( + onWeakReferenceRemoved: (_) {}, + ); + + final LiveDataFlutterApiImpl api = LiveDataFlutterApiImpl( + instanceManager: instanceManager, + ); + + const int instanceIdentifier = 0; + + api.create( + instanceIdentifier, + LiveDataSupportedTypeData(value: LiveDataSupportedType.cameraState), + ); + + expect( + instanceManager.getInstanceWithWeakReference(instanceIdentifier), + isA>(), + ); + }); + }); +} diff --git a/packages/camera/camera_android_camerax/test/live_data_test.mocks.dart b/packages/camera/camera_android_camerax/test/live_data_test.mocks.dart new file mode 100644 index 00000000000..f5568593510 --- /dev/null +++ b/packages/camera/camera_android_camerax/test/live_data_test.mocks.dart @@ -0,0 +1,72 @@ +// Mocks generated by Mockito 5.4.0 from annotations +// in camera_android_camerax/test/live_data_test.dart. +// Do not manually edit this file. + +// 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 [TestLiveDataHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestLiveDataHostApi extends _i1.Mock + implements _i2.TestLiveDataHostApi { + MockTestLiveDataHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + void observe( + int? identifier, + int? observerIdentifier, + ) => + super.noSuchMethod( + Invocation.method( + #observe, + [ + identifier, + observerIdentifier, + ], + ), + returnValueForMissingStub: null, + ); + @override + void removeObservers(int? identifier) => super.noSuchMethod( + Invocation.method( + #removeObservers, + [identifier], + ), + 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, + ); +} diff --git a/packages/camera/camera_android_camerax/test/observer_test.dart b/packages/camera/camera_android_camerax/test/observer_test.dart new file mode 100644 index 00000000000..41c3eba5598 --- /dev/null +++ b/packages/camera/camera_android_camerax/test/observer_test.dart @@ -0,0 +1,114 @@ +// 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/camera_state.dart'; +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/observer.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'observer_test.mocks.dart'; +import 'test_camerax_library.g.dart'; + +@GenerateMocks([TestObserverHostApi, TestInstanceManagerHostApi]) +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('Observer', () { + tearDown(() { + TestObserverHostApi.setup(null); + TestInstanceManagerHostApi.setup(null); + }); + + test('HostApi create makes call to create Observer instance', () { + final MockTestObserverHostApi mockApi = MockTestObserverHostApi(); + TestObserverHostApi.setup(mockApi); + TestInstanceManagerHostApi.setup(MockTestInstanceManagerHostApi()); + + final InstanceManager instanceManager = InstanceManager( + onWeakReferenceRemoved: (_) {}, + ); + + final Observer instance = Observer( + instanceManager: instanceManager, + onChanged: (Object value) {}, + ); + + verify(mockApi.create( + instanceManager.getIdentifier(instance), + )); + }); + + test( + 'HostAPI create makes Observer instance that throws assertion error if onChanged receives unexpected parameter type', + () { + final MockTestObserverHostApi mockApi = MockTestObserverHostApi(); + TestObserverHostApi.setup(mockApi); + TestInstanceManagerHostApi.setup(MockTestInstanceManagerHostApi()); + + final Observer cameraStateObserver = + Observer.detached(onChanged: (Object value) {}); + + expect( + () => cameraStateObserver.onChanged( + CameraState.detached(type: CameraStateType.pendingOpen)), + throwsAssertionError); + }); + + test( + 'FlutterAPI onChanged makes call with expected parameter to Observer instance onChanged callback', + () { + final InstanceManager instanceManager = InstanceManager( + onWeakReferenceRemoved: (_) {}, + ); + + const int instanceIdentifier = 0; + late final Object? callbackParameter; + final Observer instance = Observer.detached( + onChanged: (Object value) { + callbackParameter = value; + }, + instanceManager: instanceManager, + ); + instanceManager.addHostCreatedInstance( + instance, + instanceIdentifier, + onCopy: (Observer original) => + Observer.detached( + onChanged: original.onChanged, + instanceManager: instanceManager, + ), + ); + + final ObserverFlutterApiImpl flutterApi = ObserverFlutterApiImpl( + instanceManager: instanceManager, + ); + + const CameraStateType cameraStateType = CameraStateType.closed; + + final CameraState value = CameraState.detached( + instanceManager: instanceManager, + type: cameraStateType, + ); + const int valueIdentifier = 11; + instanceManager.addHostCreatedInstance( + value, + valueIdentifier, + onCopy: (_) => CameraState.detached( + instanceManager: instanceManager, + type: cameraStateType, + ), + ); + + flutterApi.onChanged( + instanceIdentifier, + valueIdentifier, + ); + + expect(callbackParameter, value); + }); + }); +} diff --git a/packages/camera/camera_android_camerax/test/observer_test.mocks.dart b/packages/camera/camera_android_camerax/test/observer_test.mocks.dart new file mode 100644 index 00000000000..9880bde0ae9 --- /dev/null +++ b/packages/camera/camera_android_camerax/test/observer_test.mocks.dart @@ -0,0 +1,57 @@ +// Mocks generated by Mockito 5.4.0 from annotations +// in camera_android_camerax/test/observer_test.dart. +// Do not manually edit this file. + +// 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 [TestObserverHostApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTestObserverHostApi extends _i1.Mock + implements _i2.TestObserverHostApi { + MockTestObserverHostApi() { + _i1.throwOnMissingStub(this); + } + + @override + void create(int? identifier) => super.noSuchMethod( + Invocation.method( + #create, + [identifier], + ), + 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, + ); +} diff --git a/packages/camera/camera_android_camerax/test/process_camera_provider_test.dart b/packages/camera/camera_android_camerax/test/process_camera_provider_test.dart index f08fa8a466f..a497956da5f 100644 --- a/packages/camera/camera_android_camerax/test/process_camera_provider_test.dart +++ b/packages/camera/camera_android_camerax/test/process_camera_provider_test.dart @@ -195,7 +195,7 @@ void main() { verify(mockApi.unbind(0, [1])); }); - test('unbindAllTest', () async { + test('unbindAll unbinds UseCases', () async { final MockTestProcessCameraProviderHostApi mockApi = MockTestProcessCameraProviderHostApi(); TestProcessCameraProviderHostApi.setup(mockApi); @@ -207,22 +207,15 @@ void main() { ProcessCameraProvider.detached( instanceManager: instanceManager, ); - final UseCase fakeUseCase = - UseCase.detached(instanceManager: instanceManager); instanceManager.addHostCreatedInstance( processCameraProvider, 0, onCopy: (_) => ProcessCameraProvider.detached(), ); - instanceManager.addHostCreatedInstance( - fakeUseCase, - 1, - onCopy: (_) => UseCase.detached(), - ); - processCameraProvider.unbind([fakeUseCase]); - verify(mockApi.unbind(0, [1])); + processCameraProvider.unbindAll(); + verify(mockApi.unbindAll(0)); }); test('flutterApiCreateTest', () { diff --git a/packages/camera/camera_android_camerax/test/test_camerax_library.g.dart b/packages/camera/camera_android_camerax/test/test_camerax_library.g.dart index 40bd8f2e433..198f106ac79 100644 --- a/packages/camera/camera_android_camerax/test/test_camerax_library.g.dart +++ b/packages/camera/camera_android_camerax/test/test_camerax_library.g.dart @@ -86,6 +86,8 @@ abstract class TestCameraInfoHostApi { int getSensorRotationDegrees(int identifier); + int getLiveCameraState(int identifier); + int getExposureState(int identifier); int getZoomState(int identifier); @@ -115,6 +117,28 @@ abstract class TestCameraInfoHostApi { }); } } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.CameraInfoHostApi.getLiveCameraState', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, + (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.CameraInfoHostApi.getLiveCameraState was null.'); + final List args = (message as List?)!; + final int? arg_identifier = (args[0] as int?); + assert(arg_identifier != null, + 'Argument for dev.flutter.pigeon.CameraInfoHostApi.getLiveCameraState was null, expected non-null int.'); + final int output = api.getLiveCameraState(arg_identifier!); + return [output]; + }); + } + } { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.CameraInfoHostApi.getExposureState', codec, @@ -927,6 +951,101 @@ abstract class TestAnalyzerHostApi { } } +abstract class TestObserverHostApi { + static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => + TestDefaultBinaryMessengerBinding.instance; + static const MessageCodec codec = StandardMessageCodec(); + + void create(int identifier); + + static void setup(TestObserverHostApi? api, + {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.ObserverHostApi.create', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, + (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.ObserverHostApi.create was null.'); + final List args = (message as List?)!; + final int? arg_identifier = (args[0] as int?); + assert(arg_identifier != null, + 'Argument for dev.flutter.pigeon.ObserverHostApi.create was null, expected non-null int.'); + api.create(arg_identifier!); + return []; + }); + } + } + } +} + +abstract class TestLiveDataHostApi { + static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => + TestDefaultBinaryMessengerBinding.instance; + static const MessageCodec codec = StandardMessageCodec(); + + void observe(int identifier, int observerIdentifier); + + void removeObservers(int identifier); + + static void setup(TestLiveDataHostApi? api, + {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.LiveDataHostApi.observe', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, + (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.LiveDataHostApi.observe was null.'); + final List args = (message as List?)!; + final int? arg_identifier = (args[0] as int?); + assert(arg_identifier != null, + 'Argument for dev.flutter.pigeon.LiveDataHostApi.observe was null, expected non-null int.'); + final int? arg_observerIdentifier = (args[1] as int?); + assert(arg_observerIdentifier != null, + 'Argument for dev.flutter.pigeon.LiveDataHostApi.observe was null, expected non-null int.'); + api.observe(arg_identifier!, arg_observerIdentifier!); + return []; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.LiveDataHostApi.removeObservers', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, + (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.LiveDataHostApi.removeObservers was null.'); + final List args = (message as List?)!; + final int? arg_identifier = (args[0] as int?); + assert(arg_identifier != null, + 'Argument for dev.flutter.pigeon.LiveDataHostApi.removeObservers was null, expected non-null int.'); + api.removeObservers(arg_identifier!); + return []; + }); + } + } + } +} + abstract class TestImageProxyHostApi { static TestDefaultBinaryMessengerBinding? get _testBinaryMessengerBinding => TestDefaultBinaryMessengerBinding.instance; diff --git a/packages/dynamic_layouts/example/.pluginToolsConfig.yaml b/packages/dynamic_layouts/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/dynamic_layouts/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/espresso/example/.pluginToolsConfig.yaml b/packages/espresso/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/espresso/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/extension_google_sign_in_as_googleapis_auth/example/.pluginToolsConfig.yaml b/packages/extension_google_sign_in_as_googleapis_auth/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/extension_google_sign_in_as_googleapis_auth/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/flutter_adaptive_scaffold/example/.pluginToolsConfig.yaml b/packages/flutter_adaptive_scaffold/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/flutter_adaptive_scaffold/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/flutter_markdown/example/.pluginToolsConfig.yaml b/packages/flutter_markdown/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/flutter_markdown/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/flutter_plugin_android_lifecycle/example/.pluginToolsConfig.yaml b/packages/flutter_plugin_android_lifecycle/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/flutter_plugin_android_lifecycle/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/go_router/example/.pluginToolsConfig.yaml b/packages/go_router/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/go_router/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/google_maps_flutter/google_maps_flutter/example/.pluginToolsConfig.yaml b/packages/google_maps_flutter/google_maps_flutter/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/google_maps_flutter/google_maps_flutter/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/google_maps_flutter/google_maps_flutter_android/example/.pluginToolsConfig.yaml b/packages/google_maps_flutter/google_maps_flutter_android/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/google_maps_flutter/google_maps_flutter_android/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/google_sign_in/google_sign_in/example/.pluginToolsConfig.yaml b/packages/google_sign_in/google_sign_in/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/google_sign_in/google_sign_in/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/google_sign_in/google_sign_in_android/example/.pluginToolsConfig.yaml b/packages/google_sign_in/google_sign_in_android/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/google_sign_in/google_sign_in_android/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md b/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md index 843a9e8d60e..82cb24bd565 100644 --- a/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md @@ -1,7 +1,3 @@ -## 5.6.2 - -* Updates functions without a prototype to avoid deprecation warning. - ## 5.6.1 * Clarifies explanation of endorsement in README. diff --git a/packages/google_sign_in/google_sign_in_ios/ios/Classes/FLTGoogleSignInPlugin.m b/packages/google_sign_in/google_sign_in_ios/ios/Classes/FLTGoogleSignInPlugin.m index 06992842286..7beb604aaee 100644 --- a/packages/google_sign_in/google_sign_in_ios/ios/Classes/FLTGoogleSignInPlugin.m +++ b/packages/google_sign_in/google_sign_in_ios/ios/Classes/FLTGoogleSignInPlugin.m @@ -14,7 +14,7 @@ static NSString *const kServerClientIdKey = @"SERVER_CLIENT_ID"; -static NSDictionary *loadGoogleServiceInfo(void) { +static NSDictionary *loadGoogleServiceInfo() { NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" ofType:@"plist"]; if (plistPath) { diff --git a/packages/google_sign_in/google_sign_in_ios/pubspec.yaml b/packages/google_sign_in/google_sign_in_ios/pubspec.yaml index 6ce44b89b53..50c33f80aa1 100644 --- a/packages/google_sign_in/google_sign_in_ios/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_ios/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in_ios description: iOS implementation of the google_sign_in plugin. repository: https://github.com/flutter/packages/tree/main/packages/google_sign_in/google_sign_in_ios issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22 -version: 5.6.2 +version: 5.6.1 environment: sdk: ">=2.18.0 <4.0.0" diff --git a/packages/image_picker/image_picker_android/example/.pluginToolsConfig.yaml b/packages/image_picker/image_picker_android/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/image_picker/image_picker_android/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/local_auth/local_auth/example/.pluginToolsConfig.yaml b/packages/local_auth/local_auth/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/local_auth/local_auth/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/local_auth/local_auth_android/example/.pluginToolsConfig.yaml b/packages/local_auth/local_auth_android/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/local_auth/local_auth_android/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/palette_generator/example/.pluginToolsConfig.yaml b/packages/palette_generator/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/palette_generator/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/path_provider/path_provider/example/.pluginToolsConfig.yaml b/packages/path_provider/path_provider/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/path_provider/path_provider/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/path_provider/path_provider_android/example/.pluginToolsConfig.yaml b/packages/path_provider/path_provider_android/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/path_provider/path_provider_android/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/pigeon/example/app/.pluginToolsConfig.yaml b/packages/pigeon/example/app/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/pigeon/example/app/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/quick_actions/quick_actions/example/.pluginToolsConfig.yaml b/packages/quick_actions/quick_actions/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/quick_actions/quick_actions/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/quick_actions/quick_actions_android/example/.pluginToolsConfig.yaml b/packages/quick_actions/quick_actions_android/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/quick_actions/quick_actions_android/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/shared_preferences/shared_preferences/example/.pluginToolsConfig.yaml b/packages/shared_preferences/shared_preferences/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/shared_preferences/shared_preferences/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/shared_preferences/shared_preferences_android/example/.pluginToolsConfig.yaml b/packages/shared_preferences/shared_preferences_android/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/shared_preferences/shared_preferences_android/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/url_launcher/url_launcher/example/.pluginToolsConfig.yaml b/packages/url_launcher/url_launcher/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/url_launcher/url_launcher/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/url_launcher/url_launcher_android/example/.pluginToolsConfig.yaml b/packages/url_launcher/url_launcher_android/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/url_launcher/url_launcher_android/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/video_player/video_player/example/.pluginToolsConfig.yaml b/packages/video_player/video_player/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/video_player/video_player/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/video_player/video_player_android/example/.pluginToolsConfig.yaml b/packages/video_player/video_player_android/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/video_player/video_player_android/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/video_player/video_player_avfoundation/CHANGELOG.md b/packages/video_player/video_player_avfoundation/CHANGELOG.md index c4425521fa9..8c1e2bc3426 100644 --- a/packages/video_player/video_player_avfoundation/CHANGELOG.md +++ b/packages/video_player/video_player_avfoundation/CHANGELOG.md @@ -1,7 +1,3 @@ -## 2.4.5 - -* Updates functions without a prototype to avoid deprecation warning. - ## 2.4.4 * Updates pigeon to fix warnings with clang 15. diff --git a/packages/video_player/video_player_avfoundation/ios/Classes/FLTVideoPlayerPlugin.m b/packages/video_player/video_player_avfoundation/ios/Classes/FLTVideoPlayerPlugin.m index 6c39cb9a4a7..586d6555bef 100644 --- a/packages/video_player/video_player_avfoundation/ios/Classes/FLTVideoPlayerPlugin.m +++ b/packages/video_player/video_player_avfoundation/ios/Classes/FLTVideoPlayerPlugin.m @@ -146,7 +146,7 @@ NS_INLINE CGFloat radiansToDegrees(CGFloat radians) { return degrees; }; -NS_INLINE UIViewController *rootViewController(void) { +NS_INLINE UIViewController *rootViewController() { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" // TODO: (hellohuanlin) Provide a non-deprecated codepath. See diff --git a/packages/video_player/video_player_avfoundation/pubspec.yaml b/packages/video_player/video_player_avfoundation/pubspec.yaml index 53bbe63fce3..c579ee0be2e 100644 --- a/packages/video_player/video_player_avfoundation/pubspec.yaml +++ b/packages/video_player/video_player_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: video_player_avfoundation description: iOS implementation of the video_player plugin. repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22 -version: 2.4.5 +version: 2.4.4 environment: sdk: ">=2.18.0 <4.0.0" diff --git a/packages/webview_flutter/webview_flutter/example/.pluginToolsConfig.yaml b/packages/webview_flutter/webview_flutter/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/webview_flutter/webview_flutter/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/packages/webview_flutter/webview_flutter_android/example/.pluginToolsConfig.yaml b/packages/webview_flutter/webview_flutter_android/example/.pluginToolsConfig.yaml deleted file mode 100644 index 3b6017b7609..00000000000 --- a/packages/webview_flutter/webview_flutter_android/example/.pluginToolsConfig.yaml +++ /dev/null @@ -1,4 +0,0 @@ -buildFlags: - _pluginToolsConfigGlobalKey: - - "--no-tree-shake-icons" - - "--dart-define=buildmode=testing" diff --git a/script/tool/lib/src/common/package_state_utils.dart b/script/tool/lib/src/common/package_state_utils.dart index 2b18f017652..fbba75c6116 100644 --- a/script/tool/lib/src/common/package_state_utils.dart +++ b/script/tool/lib/src/common/package_state_utils.dart @@ -195,7 +195,6 @@ bool _isExampleBuildFile(List pathComponents) { pathComponents.contains('build.gradle') || pathComponents.contains('Runner.xcodeproj') || pathComponents.contains('CMakeLists.txt') || - pathComponents.contains('.pluginToolsConfig.yaml') || pathComponents.contains('pubspec.yaml'); } diff --git a/script/tool/test/version_check_command_test.dart b/script/tool/test/version_check_command_test.dart index f3e6f9227dc..b614d8cef57 100644 --- a/script/tool/test/version_check_command_test.dart +++ b/script/tool/test/version_check_command_test.dart @@ -874,7 +874,6 @@ tool/plugin/lib/plugin.dart processRunner.mockProcessesForExecutable['git-diff'] = [ FakeProcessInfo(MockProcess(stdout: ''' -packages/plugin/example/android/.pluginToolsConfig.yaml packages/plugin/example/android/lint-baseline.xml packages/plugin/example/android/src/androidTest/foo/bar/FooTest.java packages/plugin/example/ios/RunnerTests/Foo.m