From ce6b47e5d48ad67b930824d51918dae08961d446 Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 2 Jan 2024 14:05:02 -0800 Subject: [PATCH 1/7] Draft fixes for issue --- .../camerax/CameraAndroidCameraxPlugin.java | 62 +++++++++++++++---- .../plugins/camerax/LiveDataHostApiImpl.java | 2 +- .../ProcessCameraProviderHostApiImpl.java | 2 +- .../camerax/SystemServicesHostApiImpl.java | 2 +- 4 files changed, 54 insertions(+), 14 deletions(-) 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 c8046db5af6d..ea14141e3c0f 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 @@ -136,37 +136,49 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { public void onAttachedToActivity(@NonNull ActivityPluginBinding activityPluginBinding) { Activity activity = activityPluginBinding.getActivity(); + // Set up Host API implementations based on the context that `activity` provides. setUp(pluginBinding.getBinaryMessenger(), activity, pluginBinding.getTextureRegistry()); - if (activity instanceof LifecycleOwner) { - processCameraProviderHostApiImpl.setLifecycleOwner((LifecycleOwner) activity); - liveDataHostApiImpl.setLifecycleOwner((LifecycleOwner) activity); - } else { - ProxyLifecycleProvider proxyLifecycleProvider = new ProxyLifecycleProvider(activity); - processCameraProviderHostApiImpl.setLifecycleOwner(proxyLifecycleProvider); - liveDataHostApiImpl.setLifecycleOwner(proxyLifecycleProvider); - } + // Set any needed references to `activity` itself. + updateLifecycleOwner(activity); + updateActivity(activity); - systemServicesHostApiImpl.setActivity(activity); + // Set permissions registry reference. systemServicesHostApiImpl.setPermissionsRegistry( activityPluginBinding::addRequestPermissionsResultListener); - deviceOrientationManagerHostApiImpl.setActivity(activity); } @Override public void onDetachedFromActivityForConfigChanges() { + // Clear any references to previously attached `ActivityPluginBinding`/`Activity`. updateContext(pluginBinding.getApplicationContext()); + updateLifecycleOwner(null); + updateActivity(null); + systemServicesHostApiImpl.setPermissionsRegistry(null); } @Override public void onReattachedToActivityForConfigChanges( @NonNull ActivityPluginBinding activityPluginBinding) { - updateContext(activityPluginBinding.getActivity()); + Activity activity = activityPluginBinding.getActivity(); + + // Set any needed references to `activity` itself or its context. + updateContext(activity); + updateLifecycleOwner(activity); + updateActivity(activity); + + // Set permissions registry reference. + systemServicesHostApiImpl.setPermissionsRegistry( + activityPluginBinding::addRequestPermissionsResultListener); } @Override public void onDetachedFromActivity() { + // Clear any references to previously attached `ActivityPluginBinding`/`Activity`. updateContext(pluginBinding.getApplicationContext()); + updateLifecycleOwner(null); + updateActivity(null); + systemServicesHostApiImpl.setPermissionsRegistry(null); } /** @@ -196,4 +208,32 @@ public void updateContext(@NonNull Context context) { cameraControlHostApiImpl.setContext(context); } } + + /** + * Sets {@code LifecycleOwner} that is used to control the lifecycle + * of the camera by CameraX. + */ + public void updateLifecycleOwner(@NonNull Activity activity) { + if (activity instanceof LifecycleOwner) { + processCameraProviderHostApiImpl.setLifecycleOwner((LifecycleOwner) activity); + liveDataHostApiImpl.setLifecycleOwner((LifecycleOwner) activity); + } else { + ProxyLifecycleProvider proxyLifecycleProvider = new ProxyLifecycleProvider(activity); + processCameraProviderHostApiImpl.setLifecycleOwner(proxyLifecycleProvider); + liveDataHostApiImpl.setLifecycleOwner(proxyLifecycleProvider); + } + } + + /** + * Updates {@code Activity} that is used for requesting camera permissions + * and tracking the orientation of the device. + */ + public void updateActivity(@Nullable Activity activity) { + if (systemServicesHostApiImpl != null) { + systemServicesHostApiImpl.setActivity(activity); + } + if (deviceOrientationManagerHostApiImpl != null) { + deviceOrientationManagerHostApiImpl.setActivity(activity); + } + } } 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 index 3e9e595d4b0f..5a25d5f45212 100644 --- 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 @@ -40,7 +40,7 @@ public LiveDataHostApiImpl( } /** Sets {@link LifecycleOwner} used to observe the camera state if so requested. */ - public void setLifecycleOwner(@NonNull LifecycleOwner lifecycleOwner) { + public void setLifecycleOwner(@Nullable LifecycleOwner lifecycleOwner) { this.lifecycleOwner = lifecycleOwner; } diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java index 9292ee93fc43..9963d0f17320 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java @@ -36,7 +36,7 @@ public ProcessCameraProviderHostApiImpl( this.context = context; } - public void setLifecycleOwner(@NonNull LifecycleOwner lifecycleOwner) { + public void setLifecycleOwner(@Nullable LifecycleOwner lifecycleOwner) { this.lifecycleOwner = lifecycleOwner; } diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/SystemServicesHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/SystemServicesHostApiImpl.java index 4e0b18069ffb..5da5629037c7 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/SystemServicesHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/SystemServicesHostApiImpl.java @@ -46,7 +46,7 @@ public void setActivity(@NonNull Activity activity) { this.activity = activity; } - public void setPermissionsRegistry(@NonNull PermissionsRegistry permissionsRegistry) { + public void setPermissionsRegistry(@Nullable PermissionsRegistry permissionsRegistry) { this.permissionsRegistry = permissionsRegistry; } From 42d7f8474cb41b14465864441ea063abad53b642 Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 9 Jan 2024 11:26:55 -0800 Subject: [PATCH 2/7] Add annotations --- .../io/flutter/plugins/camerax/ImageAnalysisHostApiImpl.java | 2 +- .../io/flutter/plugins/camerax/ImageCaptureHostApiImpl.java | 2 +- .../java/io/flutter/plugins/camerax/LiveDataHostApiImpl.java | 2 +- .../flutter/plugins/camerax/PendingRecordingHostApiImpl.java | 2 +- .../plugins/camerax/ProcessCameraProviderHostApiImpl.java | 5 +++-- .../java/io/flutter/plugins/camerax/RecorderHostApiImpl.java | 2 +- .../flutter/plugins/camerax/SystemServicesHostApiImpl.java | 3 ++- 7 files changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageAnalysisHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageAnalysisHostApiImpl.java index f44db11cba1f..5b194ca4742b 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageAnalysisHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageAnalysisHostApiImpl.java @@ -19,7 +19,7 @@ public class ImageAnalysisHostApiImpl implements ImageAnalysisHostApi { private InstanceManager instanceManager; private BinaryMessenger binaryMessenger; - private Context context; + @Nullable private Context context; @VisibleForTesting @NonNull public CameraXProxy cameraXProxy = new CameraXProxy(); diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageCaptureHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageCaptureHostApiImpl.java index e17d386632f5..75939fe18fbb 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageCaptureHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageCaptureHostApiImpl.java @@ -22,7 +22,7 @@ public class ImageCaptureHostApiImpl implements ImageCaptureHostApi { private final BinaryMessenger binaryMessenger; private final InstanceManager instanceManager; - private Context context; + @Nullable private Context context; private SystemServicesFlutterApiImpl systemServicesFlutterApiImpl; public static final String TEMPORARY_FILE_NAME = "CAP"; 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 index 5a25d5f45212..bae64edc7637 100644 --- 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 @@ -25,7 +25,7 @@ public class LiveDataHostApiImpl implements LiveDataHostApi { private final BinaryMessenger binaryMessenger; private final InstanceManager instanceManager; - private LifecycleOwner lifecycleOwner; + @Nullable private LifecycleOwner lifecycleOwner; /** * Constructs a {@link LiveDataHostApiImpl}. diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/PendingRecordingHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/PendingRecordingHostApiImpl.java index d4acebefbffb..88c004712fb6 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/PendingRecordingHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/PendingRecordingHostApiImpl.java @@ -20,7 +20,7 @@ public class PendingRecordingHostApiImpl implements PendingRecordingHostApi { private final BinaryMessenger binaryMessenger; private final InstanceManager instanceManager; - private Context context; + @Nullable private Context context; @VisibleForTesting @NonNull public CameraXProxy cameraXProxy = new CameraXProxy(); diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java index 9963d0f17320..6e0baa3e7e04 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java @@ -6,6 +6,7 @@ import android.content.Context; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.camera.core.Camera; import androidx.camera.core.CameraInfo; import androidx.camera.core.CameraSelector; @@ -24,8 +25,8 @@ public class ProcessCameraProviderHostApiImpl implements ProcessCameraProviderHo private final BinaryMessenger binaryMessenger; private final InstanceManager instanceManager; - private Context context; - private LifecycleOwner lifecycleOwner; + @Nullable private Context context; + @Nullable private LifecycleOwner lifecycleOwner; public ProcessCameraProviderHostApiImpl( @NonNull BinaryMessenger binaryMessenger, diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/RecorderHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/RecorderHostApiImpl.java index 8f7e8d293f45..67b76b3c0b5c 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/RecorderHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/RecorderHostApiImpl.java @@ -23,7 +23,7 @@ public class RecorderHostApiImpl implements RecorderHostApi { private final BinaryMessenger binaryMessenger; private final InstanceManager instanceManager; - private Context context; + @Nullable private Context context; @NonNull @VisibleForTesting public CameraXProxy cameraXProxy = new CameraXProxy(); diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/SystemServicesHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/SystemServicesHostApiImpl.java index 5da5629037c7..c85c9806be39 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/SystemServicesHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/SystemServicesHostApiImpl.java @@ -7,6 +7,7 @@ import android.app.Activity; import android.content.Context; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugins.camerax.CameraPermissionsManager.PermissionsRegistry; @@ -19,7 +20,7 @@ public class SystemServicesHostApiImpl implements SystemServicesHostApi { private final BinaryMessenger binaryMessenger; private final InstanceManager instanceManager; - private Context context; + @Nullable private Context context; @VisibleForTesting public @NonNull CameraXProxy cameraXProxy = new CameraXProxy(); @VisibleForTesting public @NonNull SystemServicesFlutterApiImpl systemServicesFlutterApi; From 2ebad4bc2244da52f638d74044a90345e4a7868a Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 9 Jan 2024 14:16:51 -0800 Subject: [PATCH 3/7] Add new test sigs --- .../CameraAndroidCameraxPluginTest.java | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) 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 58f517edc653..e079665018ff 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 @@ -30,7 +30,7 @@ public class CameraAndroidCameraxPluginTest { @Mock FlutterPluginBinding flutterPluginBinding; @Test - public void onAttachedToActivity_setsLifecycleOwnerAsActivityIfLifecycleOwner() { + public void onAttachedToActivity_setsLifecycleOwnerAsActivityIfLifecycleOwnerAsNeeded() { CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); Activity mockActivity = mock(Activity.class, withSettings().extraInterfaces(LifecycleOwner.class)); @@ -55,7 +55,7 @@ public void onAttachedToActivity_setsLifecycleOwnerAsActivityIfLifecycleOwner() @Test public void - onAttachedToActivity_setsLifecycleOwnerAsProxyLifecycleProviderIfActivityNotLifecycleOwner() { + onAttachedToActivity_setsLifecycleOwnerAsProxyLifecycleProviderIfActivityNotLifecycleOwnerAsNeeded() { CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); Activity mockActivity = mock(Activity.class); ProcessCameraProviderHostApiImpl mockProcessCameraProviderHostApiImpl = @@ -78,4 +78,34 @@ public void onAttachedToActivity_setsLifecycleOwnerAsActivityIfLifecycleOwner() .setLifecycleOwner(any(ProxyLifecycleProvider.class)); verify(mockLiveDataHostApiImpl).setLifecycleOwner(any(ProxyLifecycleProvider.class)); } + + @Test + public void onAttachedToActivity_setsActivityAsNeeded() { + + } + + @Test + public void onDetachedFromActivityForConfigChanges_removesReferencesToActivityPluginBindingAndActivity() { + + } + + @Test + public void onReattachedToActivityForConfigChanges_setsLifecycleOwnerAsActivityIfLifecycleOwnerAsNeeded() { + + } + + @Test + public void onReattachedToActivityForConfigChanges_setsLifecycleOwnerAsProxyLifecycleProviderIfActivityNotLifecycleOwnerAsNeeded() { + + } + + @Test + public void onReattachedToActivityForConfigChanges_setsActivityAsNeeded() { + + } + + @Test + public void onDetachedFromActivity_removesReferencesToActivityPluginBindingAndActivity() { + + } } From 1c18f5201c19b9c604c076718e18f68d6792c01d Mon Sep 17 00:00:00 2001 From: camsim99 Date: Wed, 10 Jan 2024 10:35:46 -0800 Subject: [PATCH 4/7] Start tests --- .../camerax/CameraAndroidCameraxPlugin.java | 4 +- .../CameraAndroidCameraxPluginTest.java | 53 ++++++++++++++++++- 2 files changed, 54 insertions(+), 3 deletions(-) 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 ea14141e3c0f..dac0286f8447 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 @@ -183,7 +183,7 @@ public void onDetachedFromActivity() { /** * Updates context that is used to fetch the corresponding instance of a {@code - * ProcessCameraProvider}. + * ProcessCameraProvider} to each of the relevant camera controls. */ public void updateContext(@NonNull Context context) { if (processCameraProviderHostApiImpl != null) { @@ -213,7 +213,7 @@ public void updateContext(@NonNull Context context) { * Sets {@code LifecycleOwner} that is used to control the lifecycle * of the camera by CameraX. */ - public void updateLifecycleOwner(@NonNull Activity activity) { + public void updateLifecycleOwner(@Nullable Activity activity) { if (activity instanceof LifecycleOwner) { processCameraProviderHostApiImpl.setLifecycleOwner((LifecycleOwner) activity); liveDataHostApiImpl.setLifecycleOwner((LifecycleOwner) activity); 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 e079665018ff..be7ed98dde81 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 @@ -81,12 +81,34 @@ public void onAttachedToActivity_setsLifecycleOwnerAsActivityIfLifecycleOwnerAsN @Test public void onAttachedToActivity_setsActivityAsNeeded() { + CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); + Activity mockActivity = mock(Activity.class); + SystemServicesHostApiImpl mockSystemServicesHostApiImpl = mock(SystemServicesHostApiImpl.class); + DeviceOrientationManagerHostApiImpl mockDeviceOrientationManagerHostApiImpl = mock(DeviceOrientationManagerHostApiImpl.class); + + doNothing().when(plugin).setUp(any(), any(), any()); + when(activityPluginBinding.getActivity()).thenReturn(mockActivity); + when(mockActivity.getApplication()).thenReturn(mock(Application.class)); + + plugin.systemServicesHostApiImpl = mockSystemServicesHostApiImpl; + plugin.deviceOrientationManagerHostApiImpl = mockDeviceOrientationManagerHostApiImpl; + plugin.onAttachedToEngine(flutterPluginBinding); + plugin.onAttachedToActivity(activityPluginBinding); + + verify(mockSystemServicesHostApiImpl).setActivity(mockActivity); + verify(mockDeviceOrientationManagerHostApiImpl).setActivity(mockActivity); } @Test public void onDetachedFromActivityForConfigChanges_removesReferencesToActivityPluginBindingAndActivity() { + + verify(mockProcessCameraProviderHostApiImpl) + .setLifecycleOwner(null); + verify(mockLiveDataHostApiImpl).setLifecycleOwner(null); + verify(mockSystemServicesHostApiImpl).setActivity(null); + verify(mockDeviceOrientationManagerHostApiImpl).setActivity(null); } @Test @@ -100,12 +122,41 @@ public void onReattachedToActivityForConfigChanges_setsLifecycleOwnerAsProxyLife } @Test - public void onReattachedToActivityForConfigChanges_setsActivityAsNeeded() { + public void onReattachedToActivityForConfigChanges_setsActivityAndPermissionsRegistryAsNeeded() { + CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); + Activity mockActivity = mock(Activity.class); + SystemServicesHostApiImpl mockSystemServicesHostApiImpl = mock(SystemServicesHostApiImpl.class); + DeviceOrientationManagerHostApiImpl mockDeviceOrientationManagerHostApiImpl = mock(DeviceOrientationManagerHostApiImpl.class); + ??? mockPermissionsRegistry = mock(???.class); + + doNothing().when(plugin).setUp(any(), any(), any()); + when(activityPluginBinding.getActivity()).thenReturn(mockActivity); + when(mockActivity.getApplication()).thenReturn(mock(Application.class)); + + plugin.systemServicesHostApiImpl = mockSystemServicesHostApiImpl; + plugin.deviceOrientationManagerHostApiImpl = mockDeviceOrientationManagerHostApiImpl; + + plugin.onAttachedToEngine(flutterPluginBinding); + plugin.onReattachedToActivityForConfigChanges(activityPluginBinding); + + // Check Activity references are set. + verify(mockSystemServicesHostApiImpl).setActivity(mockActivity); + verify(mockDeviceOrientationManagerHostApiImpl).setActivity(mockActivity); + + // Check Activity as Context references are set. + + // Check permissions registry reference is set. + verify(mockSystemServicesHostApiImpl).setPermissionsRegistry(mockPermissionsRegistry); } @Test public void onDetachedFromActivity_removesReferencesToActivityPluginBindingAndActivity() { + verify(mockProcessCameraProviderHostApiImpl) + .setLifecycleOwner(null); + verify(mockLiveDataHostApiImpl).setLifecycleOwner(null); + verify(mockSystemServicesHostApiImpl).setActivity(null); + verify(mockDeviceOrientationManagerHostApiImpl).setActivity(null); } } From 3aee9925c6dc6d31644bca3775a2695e97ca37cb Mon Sep 17 00:00:00 2001 From: camsim99 Date: Thu, 11 Jan 2024 13:41:20 -0800 Subject: [PATCH 5/7] Bump version + fix test + add error handling --- .../camera_android_camerax/CHANGELOG.md | 5 + .../camerax/CameraAndroidCameraxPlugin.java | 30 +-- .../camerax/CameraControlHostApiImpl.java | 8 + .../DeviceOrientationManagerHostApiImpl.java | 4 + .../camerax/ImageAnalysisHostApiImpl.java | 4 + .../camerax/ImageCaptureHostApiImpl.java | 4 + .../plugins/camerax/LiveDataHostApiImpl.java | 8 + .../camerax/PendingRecordingHostApiImpl.java | 4 + .../ProcessCameraProviderHostApiImpl.java | 8 + .../plugins/camerax/RecorderHostApiImpl.java | 8 + .../camerax/SystemServicesHostApiImpl.java | 8 + .../CameraAndroidCameraxPluginTest.java | 254 +++++++++++++++--- .../camera_android_camerax/pubspec.yaml | 2 +- 13 files changed, 301 insertions(+), 46 deletions(-) diff --git a/packages/camera/camera_android_camerax/CHANGELOG.md b/packages/camera/camera_android_camerax/CHANGELOG.md index af2488eb6695..84ed2549a28b 100644 --- a/packages/camera/camera_android_camerax/CHANGELOG.md +++ b/packages/camera/camera_android_camerax/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.5.0+26 + +* Removes or updates any references to an `ActivityPluginBinding` when the plugin is detached + or attached/re-attached, respectively, to an `Activity.` + ## 0.5.0+25 * Implements `lockCaptureOrientation` and `unlockCaptureOrientation`. 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 dac0286f8447..83f912871f42 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 @@ -20,14 +20,14 @@ public final class CameraAndroidCameraxPlugin implements FlutterPlugin, ActivityAware { private InstanceManager instanceManager; private FlutterPluginBinding pluginBinding; - private PendingRecordingHostApiImpl pendingRecordingHostApiImpl; - private RecorderHostApiImpl recorderHostApiImpl; - private VideoCaptureHostApiImpl videoCaptureHostApiImpl; - private ImageAnalysisHostApiImpl imageAnalysisHostApiImpl; - private ImageCaptureHostApiImpl imageCaptureHostApiImpl; - private CameraControlHostApiImpl cameraControlHostApiImpl; - public @Nullable SystemServicesHostApiImpl systemServicesHostApiImpl; - public @Nullable DeviceOrientationManagerHostApiImpl deviceOrientationManagerHostApiImpl; + @VisibleForTesting public PendingRecordingHostApiImpl pendingRecordingHostApiImpl; + @VisibleForTesting public RecorderHostApiImpl recorderHostApiImpl; + @VisibleForTesting public VideoCaptureHostApiImpl videoCaptureHostApiImpl; + @VisibleForTesting public ImageAnalysisHostApiImpl imageAnalysisHostApiImpl; + @VisibleForTesting public ImageCaptureHostApiImpl imageCaptureHostApiImpl; + @VisibleForTesting public CameraControlHostApiImpl cameraControlHostApiImpl; + @VisibleForTesting public @Nullable SystemServicesHostApiImpl systemServicesHostApiImpl; + @VisibleForTesting public @Nullable DeviceOrientationManagerHostApiImpl deviceOrientationManagerHostApiImpl; @VisibleForTesting public @Nullable ProcessCameraProviderHostApiImpl processCameraProviderHostApiImpl; @@ -209,12 +209,12 @@ public void updateContext(@NonNull Context context) { } } - /** - * Sets {@code LifecycleOwner} that is used to control the lifecycle - * of the camera by CameraX. - */ + /** Sets {@code LifecycleOwner} that is used to control the lifecycle of the camera by CameraX. */ public void updateLifecycleOwner(@Nullable Activity activity) { - if (activity instanceof LifecycleOwner) { + if (activity == null) { + processCameraProviderHostApiImpl.setLifecycleOwner(null); + liveDataHostApiImpl.setLifecycleOwner(null); + } else if (activity instanceof LifecycleOwner) { processCameraProviderHostApiImpl.setLifecycleOwner((LifecycleOwner) activity); liveDataHostApiImpl.setLifecycleOwner((LifecycleOwner) activity); } else { @@ -225,8 +225,8 @@ public void updateLifecycleOwner(@Nullable Activity activity) { } /** - * Updates {@code Activity} that is used for requesting camera permissions - * and tracking the orientation of the device. + * Updates {@code Activity} that is used for requesting camera permissions and tracking the + * orientation of the device. */ public void updateActivity(@Nullable Activity activity) { if (systemServicesHostApiImpl != null) { diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraControlHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraControlHostApiImpl.java index e70714a8bffe..3e0bf7b9997c 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraControlHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraControlHostApiImpl.java @@ -36,6 +36,10 @@ public void enableTorch( @NonNull CameraControl cameraControl, @NonNull Boolean torch, @NonNull GeneratedCameraXLibrary.Result result) { + if (context == null) { + throw new IllegalStateException("Context must be set to enable the torch."); + } + ListenableFuture enableTorchFuture = cameraControl.enableTorch(torch); Futures.addCallback( @@ -58,6 +62,10 @@ public void setZoomRatio( @NonNull CameraControl cameraControl, @NonNull Double ratio, @NonNull GeneratedCameraXLibrary.Result result) { + if (context == null) { + throw new IllegalStateException("Context must be set to set zoom ratio."); + } + float ratioAsFloat = ratio.floatValue(); ListenableFuture setZoomRatioFuture = cameraControl.setZoomRatio(ratioAsFloat); diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/DeviceOrientationManagerHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/DeviceOrientationManagerHostApiImpl.java index e617d53c99cd..a6c0ffb91618 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/DeviceOrientationManagerHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/DeviceOrientationManagerHostApiImpl.java @@ -48,6 +48,10 @@ public void setActivity(@NonNull Activity activity) { @Override public void startListeningForDeviceOrientationChange( @NonNull Boolean isFrontFacing, @NonNull Long sensorOrientation) { + if (activity == null) { + throw new IllegalStateException("Activity must be set to start listening for device orientation changes."); + } + deviceOrientationManager = cameraXProxy.createDeviceOrientationManager( activity, diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageAnalysisHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageAnalysisHostApiImpl.java index 5b194ca4742b..95b2cd46798d 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageAnalysisHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageAnalysisHostApiImpl.java @@ -65,6 +65,10 @@ public void create( */ @Override public void setAnalyzer(@NonNull Long identifier, @NonNull Long analyzerIdentifier) { + if (context == null) { + throw new IllegalStateException("Context must be set to set an Analyzer."); + } + getImageAnalysisInstance(identifier) .setAnalyzer( ContextCompat.getMainExecutor(context), diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageCaptureHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageCaptureHostApiImpl.java index 75939fe18fbb..8e2e6f7291a5 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageCaptureHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageCaptureHostApiImpl.java @@ -87,6 +87,10 @@ public void setFlashMode(@NonNull Long identifier, @NonNull Long flashMode) { @Override public void takePicture( @NonNull Long identifier, @NonNull GeneratedCameraXLibrary.Result result) { + if (context == null) { + throw new IllegalStateException("Context must be set to take picture."); + } + ImageCapture imageCapture = getImageCaptureInstance(identifier); final File outputDir = context.getCacheDir(); File temporaryCaptureFile; 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 index bae64edc7637..3f7ec5125ec4 100644 --- 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 @@ -51,6 +51,10 @@ public void setLifecycleOwner(@Nullable LifecycleOwner lifecycleOwner) { @Override @SuppressWarnings("unchecked") public void observe(@NonNull Long identifier, @NonNull Long observerIdentifier) { + if (lifecycleOwner == null) { + throw new IllegalStateException("LifecycleOwner must be set to observe a LiveData instance."); + } + getLiveDataInstance(identifier) .observe( lifecycleOwner, @@ -60,6 +64,10 @@ public void observe(@NonNull Long identifier, @NonNull Long observerIdentifier) /** Removes all observers of this instance that are tied to the {@link lifecycleOwner}. */ @Override public void removeObservers(@NonNull Long identifier) { + if (lifecycleOwner == null) { + throw new IllegalStateException("LifecycleOwner must be set to remove LiveData observers."); + } + getLiveDataInstance(identifier).removeObservers(lifecycleOwner); } diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/PendingRecordingHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/PendingRecordingHostApiImpl.java index 88c004712fb6..a1d661d1d9c1 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/PendingRecordingHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/PendingRecordingHostApiImpl.java @@ -63,6 +63,10 @@ public Long start(@NonNull Long identifier) { @Nullable @VisibleForTesting public Executor getExecutor() { + if (context == null) { + throw new IllegalStateException("Context must be set to get an executor to start recording."); + } + return ContextCompat.getMainExecutor(context); } diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java index 6e0baa3e7e04..47b01121ca1c 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java @@ -58,6 +58,10 @@ public void setContext(@NonNull Context context) { */ @Override public void getInstance(@NonNull GeneratedCameraXLibrary.Result result) { + if (context == null) { + throw new IllegalStateException("Context must be set to get ProcessCameraProvider instance."); + } + ListenableFuture processCameraProviderFuture = ProcessCameraProvider.getInstance(context); @@ -111,6 +115,10 @@ public List getAvailableCameraInfos(@NonNull Long identifier) { @NonNull Long identifier, @NonNull Long cameraSelectorIdentifier, @NonNull List useCaseIds) { + if (lifecycleOwner == null) { + throw new IllegalStateException("LifecycleOwner must be set to get ProcessCameraProvider instance."); + } + ProcessCameraProvider processCameraProvider = (ProcessCameraProvider) Objects.requireNonNull(instanceManager.getInstance(identifier)); CameraSelector cameraSelector = diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/RecorderHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/RecorderHostApiImpl.java index 67b76b3c0b5c..74b301e6c0b4 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/RecorderHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/RecorderHostApiImpl.java @@ -46,6 +46,10 @@ public void create( @Nullable Long aspectRatio, @Nullable Long bitRate, @Nullable Long qualitySelector) { + if (context == null) { + throw new IllegalStateException("Context must be set to create Recorder instance."); + } + Recorder.Builder recorderBuilder = cameraXProxy.createRecorderBuilder(); if (aspectRatio != null) { recorderBuilder.setAspectRatio(aspectRatio.intValue()); @@ -89,6 +93,10 @@ public Long getTargetVideoEncodingBitRate(@NonNull Long identifier) { @NonNull @Override public Long prepareRecording(@NonNull Long identifier, @NonNull String path) { + if (context == null) { + throw new IllegalStateException("Context must be set to prepare recording."); + } + Recorder recorder = getRecorderFromInstanceId(identifier); File temporaryCaptureFile = openTempFile(path); FileOutputOptions fileOutputOptions = diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/SystemServicesHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/SystemServicesHostApiImpl.java index c85c9806be39..d058d62fe224 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/SystemServicesHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/SystemServicesHostApiImpl.java @@ -60,6 +60,10 @@ public void setPermissionsRegistry(@Nullable PermissionsRegistry permissionsRegi @Override public void requestCameraPermissions( @NonNull Boolean enableAudio, @NonNull Result result) { + if (activity == null) { + throw new IllegalStateException("Activity must be set to request camera permissions."); + } + CameraPermissionsManager cameraPermissionsManager = cameraXProxy.createCameraPermissionsManager(); cameraPermissionsManager.requestPermissions( @@ -85,6 +89,10 @@ public void requestCameraPermissions( @Override @NonNull public String getTempFilePath(@NonNull String prefix, @NonNull String suffix) { + if (context == null) { + throw new IllegalStateException("Context must be set to create a temporary file."); + } + try { File path = File.createTempFile(prefix, suffix, context.getCacheDir()); return path.toString(); 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 be7ed98dde81..e25b95202317 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 @@ -4,6 +4,8 @@ package io.flutter.plugins.camerax; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; @@ -14,11 +16,14 @@ import android.app.Activity; import android.app.Application; +import android.content.Context; import androidx.lifecycle.LifecycleOwner; import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; +import io.flutter.plugins.camerax.CameraPermissionsManager.PermissionsRegistry; 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; @@ -31,12 +36,12 @@ public class CameraAndroidCameraxPluginTest { @Test public void onAttachedToActivity_setsLifecycleOwnerAsActivityIfLifecycleOwnerAsNeeded() { - CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); - Activity mockActivity = + final CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); + final Activity mockActivity = mock(Activity.class, withSettings().extraInterfaces(LifecycleOwner.class)); - ProcessCameraProviderHostApiImpl mockProcessCameraProviderHostApiImpl = + final ProcessCameraProviderHostApiImpl mockProcessCameraProviderHostApiImpl = mock(ProcessCameraProviderHostApiImpl.class); - LiveDataHostApiImpl mockLiveDataHostApiImpl = mock(LiveDataHostApiImpl.class); + final LiveDataHostApiImpl mockLiveDataHostApiImpl = mock(LiveDataHostApiImpl.class); doNothing().when(plugin).setUp(any(), any(), any()); when(activityPluginBinding.getActivity()).thenReturn(mockActivity); @@ -56,11 +61,11 @@ public void onAttachedToActivity_setsLifecycleOwnerAsActivityIfLifecycleOwnerAsN @Test public void onAttachedToActivity_setsLifecycleOwnerAsProxyLifecycleProviderIfActivityNotLifecycleOwnerAsNeeded() { - CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); - Activity mockActivity = mock(Activity.class); - ProcessCameraProviderHostApiImpl mockProcessCameraProviderHostApiImpl = + final CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); + final Activity mockActivity = mock(Activity.class); + final ProcessCameraProviderHostApiImpl mockProcessCameraProviderHostApiImpl = mock(ProcessCameraProviderHostApiImpl.class); - LiveDataHostApiImpl mockLiveDataHostApiImpl = mock(LiveDataHostApiImpl.class); + final LiveDataHostApiImpl mockLiveDataHostApiImpl = mock(LiveDataHostApiImpl.class); doNothing().when(plugin).setUp(any(), any(), any()); when(activityPluginBinding.getActivity()).thenReturn(mockActivity); @@ -80,61 +85,185 @@ public void onAttachedToActivity_setsLifecycleOwnerAsActivityIfLifecycleOwnerAsN } @Test - public void onAttachedToActivity_setsActivityAsNeeded() { - CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); - Activity mockActivity = mock(Activity.class); - SystemServicesHostApiImpl mockSystemServicesHostApiImpl = mock(SystemServicesHostApiImpl.class); - DeviceOrientationManagerHostApiImpl mockDeviceOrientationManagerHostApiImpl = mock(DeviceOrientationManagerHostApiImpl.class); + public void onAttachedToActivity_setsActivityAsNeededAndPermissionsRegistry() { + final CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); + final Activity mockActivity = mock(Activity.class); + final SystemServicesHostApiImpl mockSystemServicesHostApiImpl = + mock(SystemServicesHostApiImpl.class); + final DeviceOrientationManagerHostApiImpl mockDeviceOrientationManagerHostApiImpl = + mock(DeviceOrientationManagerHostApiImpl.class); + final ArgumentCaptor permissionsRegistryCaptor = + ArgumentCaptor.forClass(PermissionsRegistry.class); doNothing().when(plugin).setUp(any(), any(), any()); when(activityPluginBinding.getActivity()).thenReturn(mockActivity); when(mockActivity.getApplication()).thenReturn(mock(Application.class)); + plugin.processCameraProviderHostApiImpl = mock(ProcessCameraProviderHostApiImpl.class); + plugin.liveDataHostApiImpl = mock(LiveDataHostApiImpl.class); plugin.systemServicesHostApiImpl = mockSystemServicesHostApiImpl; plugin.deviceOrientationManagerHostApiImpl = mockDeviceOrientationManagerHostApiImpl; plugin.onAttachedToEngine(flutterPluginBinding); plugin.onAttachedToActivity(activityPluginBinding); + // Check Activity references are set. verify(mockSystemServicesHostApiImpl).setActivity(mockActivity); verify(mockDeviceOrientationManagerHostApiImpl).setActivity(mockActivity); + + // Check permissions registry reference is set. + verify(mockSystemServicesHostApiImpl) + .setPermissionsRegistry(permissionsRegistryCaptor.capture()); + assertNotNull(permissionsRegistryCaptor.getValue()); + assertTrue(permissionsRegistryCaptor.getValue() instanceof PermissionsRegistry); } @Test - public void onDetachedFromActivityForConfigChanges_removesReferencesToActivityPluginBindingAndActivity() { + public void + onDetachedFromActivityForConfigChanges_removesReferencesToActivityPluginBindingAndActivity() { + final CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); + final ProcessCameraProviderHostApiImpl mockProcessCameraProviderHostApiImpl = + mock(ProcessCameraProviderHostApiImpl.class); + final LiveDataHostApiImpl mockLiveDataHostApiImpl = mock(LiveDataHostApiImpl.class); + final SystemServicesHostApiImpl mockSystemServicesHostApiImpl = + mock(SystemServicesHostApiImpl.class); + final DeviceOrientationManagerHostApiImpl mockDeviceOrientationManagerHostApiImpl = + mock(DeviceOrientationManagerHostApiImpl.class); + plugin.processCameraProviderHostApiImpl = mockProcessCameraProviderHostApiImpl; + plugin.liveDataHostApiImpl = mockLiveDataHostApiImpl; + plugin.systemServicesHostApiImpl = mockSystemServicesHostApiImpl; + plugin.deviceOrientationManagerHostApiImpl = mockDeviceOrientationManagerHostApiImpl; - verify(mockProcessCameraProviderHostApiImpl) - .setLifecycleOwner(null); + plugin.onAttachedToEngine(flutterPluginBinding); + plugin.onDetachedFromActivityForConfigChanges(); + + verify(mockProcessCameraProviderHostApiImpl).setLifecycleOwner(null); verify(mockLiveDataHostApiImpl).setLifecycleOwner(null); verify(mockSystemServicesHostApiImpl).setActivity(null); verify(mockDeviceOrientationManagerHostApiImpl).setActivity(null); } @Test - public void onReattachedToActivityForConfigChanges_setsLifecycleOwnerAsActivityIfLifecycleOwnerAsNeeded() { + public void + onDetachedFromActivityForConfigChanges_setsContextReferencesBasedOnFlutterPluginBinding() { + final CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); + final Context mockContext = mock(Context.class); + final ProcessCameraProviderHostApiImpl mockProcessCameraProviderHostApiImpl = + mock(ProcessCameraProviderHostApiImpl.class); + final RecorderHostApiImpl mockRecorderHostApiImpl = mock(RecorderHostApiImpl.class); + final PendingRecordingHostApiImpl mockPendingRecordingHostApiImpl = + mock(PendingRecordingHostApiImpl.class); + final SystemServicesHostApiImpl mockSystemServicesHostApiImpl = + mock(SystemServicesHostApiImpl.class); + final ImageCaptureHostApiImpl mockImageCaptureHostApiImpl = + mock(ImageCaptureHostApiImpl.class); + final ImageAnalysisHostApiImpl mockImageAnalysisHostApiImpl = mock(ImageAnalysisHostApiImpl.class); + final CameraControlHostApiImpl mockCameraControlHostApiImpl = mock(CameraControlHostApiImpl.class); + + when(flutterPluginBinding.getApplicationContext()).thenReturn(mockContext); + + plugin.processCameraProviderHostApiImpl = mockProcessCameraProviderHostApiImpl; + plugin.recorderHostApiImpl = mockRecorderHostApiImpl; + plugin.pendingRecordingHostApiImpl = mockPendingRecordingHostApiImpl; + plugin.systemServicesHostApiImpl = mockSystemServicesHostApiImpl; + plugin.imageCaptureHostApiImpl = mockImageCaptureHostApiImpl; + plugin.imageAnalysisHostApiImpl = mockImageAnalysisHostApiImpl; + plugin.cameraControlHostApiImpl = mockCameraControlHostApiImpl; + plugin.liveDataHostApiImpl = mock(LiveDataHostApiImpl.class); + + plugin.onAttachedToEngine(flutterPluginBinding); + plugin.onDetachedFromActivityForConfigChanges(); + + verify(mockProcessCameraProviderHostApiImpl).setContext(mockContext); + verify(mockRecorderHostApiImpl).setContext(mockContext); + verify(mockPendingRecordingHostApiImpl).setContext(mockContext); + verify(mockSystemServicesHostApiImpl).setContext(mockContext); + verify(mockImageCaptureHostApiImpl).setContext(mockContext); + verify(mockImageAnalysisHostApiImpl).setContext(mockContext); + verify(mockCameraControlHostApiImpl).setContext(mockContext); + } + + @Test + public void + onReattachedToActivityForConfigChanges_setsLifecycleOwnerAsActivityIfLifecycleOwnerAsNeeded() { + final CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); + final Activity mockActivity = + mock(Activity.class, withSettings().extraInterfaces(LifecycleOwner.class)); + final ProcessCameraProviderHostApiImpl mockProcessCameraProviderHostApiImpl = + mock(ProcessCameraProviderHostApiImpl.class); + final LiveDataHostApiImpl mockLiveDataHostApiImpl = mock(LiveDataHostApiImpl.class); + + when(activityPluginBinding.getActivity()).thenReturn(mockActivity); + plugin.processCameraProviderHostApiImpl = mockProcessCameraProviderHostApiImpl; + plugin.liveDataHostApiImpl = mockLiveDataHostApiImpl; + plugin.systemServicesHostApiImpl = mock(SystemServicesHostApiImpl.class); + plugin.deviceOrientationManagerHostApiImpl = mock(DeviceOrientationManagerHostApiImpl.class); + + plugin.onReattachedToActivityForConfigChanges(activityPluginBinding); + + verify(mockProcessCameraProviderHostApiImpl).setLifecycleOwner(any(LifecycleOwner.class)); + verify(mockLiveDataHostApiImpl).setLifecycleOwner(any(LifecycleOwner.class)); } - @Test - public void onReattachedToActivityForConfigChanges_setsLifecycleOwnerAsProxyLifecycleProviderIfActivityNotLifecycleOwnerAsNeeded() { - + @Test + public void + onReattachedToActivityForConfigChanges_setsLifecycleOwnerAsProxyLifecycleProviderIfActivityNotLifecycleOwnerAsNeeded() { + final CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); + final Activity mockActivity = mock(Activity.class); + final ProcessCameraProviderHostApiImpl mockProcessCameraProviderHostApiImpl = + mock(ProcessCameraProviderHostApiImpl.class); + final LiveDataHostApiImpl mockLiveDataHostApiImpl = mock(LiveDataHostApiImpl.class); + + when(activityPluginBinding.getActivity()).thenReturn(mockActivity); + when(mockActivity.getApplication()).thenReturn(mock(Application.class)); + + plugin.processCameraProviderHostApiImpl = mockProcessCameraProviderHostApiImpl; + plugin.liveDataHostApiImpl = mockLiveDataHostApiImpl; + plugin.systemServicesHostApiImpl = mock(SystemServicesHostApiImpl.class); + plugin.deviceOrientationManagerHostApiImpl = mock(DeviceOrientationManagerHostApiImpl.class); + + plugin.onAttachedToEngine(flutterPluginBinding); + plugin.onReattachedToActivityForConfigChanges(activityPluginBinding); + + verify(mockProcessCameraProviderHostApiImpl) + .setLifecycleOwner(any(ProxyLifecycleProvider.class)); + verify(mockLiveDataHostApiImpl).setLifecycleOwner(any(ProxyLifecycleProvider.class)); } @Test public void onReattachedToActivityForConfigChanges_setsActivityAndPermissionsRegistryAsNeeded() { - CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); - Activity mockActivity = mock(Activity.class); - SystemServicesHostApiImpl mockSystemServicesHostApiImpl = mock(SystemServicesHostApiImpl.class); - DeviceOrientationManagerHostApiImpl mockDeviceOrientationManagerHostApiImpl = mock(DeviceOrientationManagerHostApiImpl.class); - ??? mockPermissionsRegistry = mock(???.class); + final CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); + final Activity mockActivity = mock(Activity.class); + final ProcessCameraProviderHostApiImpl mockProcessCameraProviderHostApiImpl = + mock(ProcessCameraProviderHostApiImpl.class); + final RecorderHostApiImpl mockRecorderHostApiImpl = mock(RecorderHostApiImpl.class); + final PendingRecordingHostApiImpl mockPendingRecordingHostApiImpl = + mock(PendingRecordingHostApiImpl.class); + final SystemServicesHostApiImpl mockSystemServicesHostApiImpl = + mock(SystemServicesHostApiImpl.class); + final ImageAnalysisHostApiImpl mockImageAnalysisHostApiImpl = + mock(ImageAnalysisHostApiImpl.class); + final ImageCaptureHostApiImpl mockImageCaptureHostApiImpl = mock(ImageCaptureHostApiImpl.class); + final CameraControlHostApiImpl mockCameraControlHostApiImpl = mock(CameraControlHostApiImpl.class); + final DeviceOrientationManagerHostApiImpl mockDeviceOrientationManagerHostApiImpl = + mock(DeviceOrientationManagerHostApiImpl.class); + final ArgumentCaptor permissionsRegistryCaptor = + ArgumentCaptor.forClass(PermissionsRegistry.class); - doNothing().when(plugin).setUp(any(), any(), any()); when(activityPluginBinding.getActivity()).thenReturn(mockActivity); when(mockActivity.getApplication()).thenReturn(mock(Application.class)); + plugin.processCameraProviderHostApiImpl = mockProcessCameraProviderHostApiImpl; + plugin.recorderHostApiImpl = mockRecorderHostApiImpl; + plugin.pendingRecordingHostApiImpl = mockPendingRecordingHostApiImpl; plugin.systemServicesHostApiImpl = mockSystemServicesHostApiImpl; + plugin.imageCaptureHostApiImpl = mockImageCaptureHostApiImpl; + plugin.imageAnalysisHostApiImpl = mockImageAnalysisHostApiImpl; + plugin.cameraControlHostApiImpl = mockCameraControlHostApiImpl; plugin.deviceOrientationManagerHostApiImpl = mockDeviceOrientationManagerHostApiImpl; + plugin.liveDataHostApiImpl = mock(LiveDataHostApiImpl.class); plugin.onAttachedToEngine(flutterPluginBinding); plugin.onReattachedToActivityForConfigChanges(activityPluginBinding); @@ -144,19 +273,84 @@ public void onReattachedToActivityForConfigChanges_setsActivityAndPermissionsReg verify(mockDeviceOrientationManagerHostApiImpl).setActivity(mockActivity); // Check Activity as Context references are set. + verify(mockProcessCameraProviderHostApiImpl).setContext(mockActivity); + verify(mockRecorderHostApiImpl).setContext(mockActivity); + verify(mockPendingRecordingHostApiImpl).setContext(mockActivity); + verify(mockSystemServicesHostApiImpl).setContext(mockActivity); + verify(mockImageCaptureHostApiImpl).setContext(mockActivity); + verify(mockImageAnalysisHostApiImpl).setContext(mockActivity); + verify(mockCameraControlHostApiImpl).setContext(mockActivity); // Check permissions registry reference is set. - verify(mockSystemServicesHostApiImpl).setPermissionsRegistry(mockPermissionsRegistry); - + verify(mockSystemServicesHostApiImpl) + .setPermissionsRegistry(permissionsRegistryCaptor.capture()); + assertNotNull(permissionsRegistryCaptor.getValue()); + assertTrue(permissionsRegistryCaptor.getValue() instanceof PermissionsRegistry); } @Test public void onDetachedFromActivity_removesReferencesToActivityPluginBindingAndActivity() { + final CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); + final ProcessCameraProviderHostApiImpl mockProcessCameraProviderHostApiImpl = + mock(ProcessCameraProviderHostApiImpl.class); + final SystemServicesHostApiImpl mockSystemServicesHostApiImpl = + mock(SystemServicesHostApiImpl.class); + final LiveDataHostApiImpl mockLiveDataHostApiImpl = mock(LiveDataHostApiImpl.class); + final DeviceOrientationManagerHostApiImpl mockDeviceOrientationManagerHostApiImpl = + mock(DeviceOrientationManagerHostApiImpl.class); - verify(mockProcessCameraProviderHostApiImpl) - .setLifecycleOwner(null); + plugin.processCameraProviderHostApiImpl = mockProcessCameraProviderHostApiImpl; + plugin.liveDataHostApiImpl = mockLiveDataHostApiImpl; + plugin.systemServicesHostApiImpl = mockSystemServicesHostApiImpl; + plugin.deviceOrientationManagerHostApiImpl = mockDeviceOrientationManagerHostApiImpl; + + plugin.onAttachedToEngine(flutterPluginBinding); + plugin.onDetachedFromActivityForConfigChanges(); + + verify(mockProcessCameraProviderHostApiImpl).setLifecycleOwner(null); verify(mockLiveDataHostApiImpl).setLifecycleOwner(null); verify(mockSystemServicesHostApiImpl).setActivity(null); verify(mockDeviceOrientationManagerHostApiImpl).setActivity(null); } + + @Test + public void onDetachedFromActivity_setsContextReferencesBasedOnFlutterPluginBinding() { + final CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); + final Context mockContext = mock(Context.class); + final ProcessCameraProviderHostApiImpl mockProcessCameraProviderHostApiImpl = + mock(ProcessCameraProviderHostApiImpl.class); + final RecorderHostApiImpl mockRecorderHostApiImpl = mock(RecorderHostApiImpl.class); + final PendingRecordingHostApiImpl mockPendingRecordingHostApiImpl = + mock(PendingRecordingHostApiImpl.class); + final SystemServicesHostApiImpl mockSystemServicesHostApiImpl = + mock(SystemServicesHostApiImpl.class); + final ImageAnalysisHostApiImpl mockImageAnalysisHostApiImpl = + mock(ImageAnalysisHostApiImpl.class); + final ImageCaptureHostApiImpl mockImageCaptureHostApiImpl = mock(ImageCaptureHostApiImpl.class); + final CameraControlHostApiImpl mockCameraControlHostApiImpl = mock(CameraControlHostApiImpl.class); + final ArgumentCaptor permissionsRegistryCaptor = + ArgumentCaptor.forClass(PermissionsRegistry.class); + + when(flutterPluginBinding.getApplicationContext()).thenReturn(mockContext); + + plugin.processCameraProviderHostApiImpl = mockProcessCameraProviderHostApiImpl; + plugin.recorderHostApiImpl = mockRecorderHostApiImpl; + plugin.pendingRecordingHostApiImpl = mockPendingRecordingHostApiImpl; + plugin.systemServicesHostApiImpl = mockSystemServicesHostApiImpl; + plugin.imageCaptureHostApiImpl = mockImageCaptureHostApiImpl; + plugin.imageAnalysisHostApiImpl = mockImageAnalysisHostApiImpl; + plugin.cameraControlHostApiImpl = mockCameraControlHostApiImpl; + plugin.liveDataHostApiImpl = mock(LiveDataHostApiImpl.class); + + plugin.onAttachedToEngine(flutterPluginBinding); + plugin.onDetachedFromActivity(); + + verify(mockProcessCameraProviderHostApiImpl).setContext(mockContext); + verify(mockRecorderHostApiImpl).setContext(mockContext); + verify(mockPendingRecordingHostApiImpl).setContext(mockContext); + verify(mockSystemServicesHostApiImpl).setContext(mockContext); + verify(mockImageCaptureHostApiImpl).setContext(mockContext); + verify(mockImageAnalysisHostApiImpl).setContext(mockContext); + verify(mockCameraControlHostApiImpl).setContext(mockContext); + } } diff --git a/packages/camera/camera_android_camerax/pubspec.yaml b/packages/camera/camera_android_camerax/pubspec.yaml index e4332e9e54e2..8ec9f0369a41 100644 --- a/packages/camera/camera_android_camerax/pubspec.yaml +++ b/packages/camera/camera_android_camerax/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_android_camerax description: Android implementation of the camera plugin using the CameraX library. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_android_camerax issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.5.0+25 +version: 0.5.0+26 environment: sdk: ">=3.0.0 <4.0.0" From d9646ba7e4a3b2ff0ea09ba81447553eca33ee85 Mon Sep 17 00:00:00 2001 From: camsim99 Date: Thu, 11 Jan 2024 14:02:18 -0800 Subject: [PATCH 6/7] Formatting --- .../camerax/CameraAndroidCameraxPlugin.java | 4 +++- .../plugins/camerax/CameraControlHostApiImpl.java | 12 ++++++------ .../DeviceOrientationManagerHostApiImpl.java | 3 ++- .../camerax/ProcessCameraProviderHostApiImpl.java | 3 ++- .../camerax/CameraAndroidCameraxPluginTest.java | 15 +++++++++------ 5 files changed, 22 insertions(+), 15 deletions(-) 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 83f912871f42..d068fd0e7602 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 @@ -27,7 +27,9 @@ public final class CameraAndroidCameraxPlugin implements FlutterPlugin, Activity @VisibleForTesting public ImageCaptureHostApiImpl imageCaptureHostApiImpl; @VisibleForTesting public CameraControlHostApiImpl cameraControlHostApiImpl; @VisibleForTesting public @Nullable SystemServicesHostApiImpl systemServicesHostApiImpl; - @VisibleForTesting public @Nullable DeviceOrientationManagerHostApiImpl deviceOrientationManagerHostApiImpl; + + @VisibleForTesting + public @Nullable DeviceOrientationManagerHostApiImpl deviceOrientationManagerHostApiImpl; @VisibleForTesting public @Nullable ProcessCameraProviderHostApiImpl processCameraProviderHostApiImpl; diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraControlHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraControlHostApiImpl.java index 3e0bf7b9997c..2524d503af4b 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraControlHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraControlHostApiImpl.java @@ -36,9 +36,9 @@ public void enableTorch( @NonNull CameraControl cameraControl, @NonNull Boolean torch, @NonNull GeneratedCameraXLibrary.Result result) { - if (context == null) { - throw new IllegalStateException("Context must be set to enable the torch."); - } + if (context == null) { + throw new IllegalStateException("Context must be set to enable the torch."); + } ListenableFuture enableTorchFuture = cameraControl.enableTorch(torch); @@ -62,9 +62,9 @@ public void setZoomRatio( @NonNull CameraControl cameraControl, @NonNull Double ratio, @NonNull GeneratedCameraXLibrary.Result result) { - if (context == null) { - throw new IllegalStateException("Context must be set to set zoom ratio."); - } + if (context == null) { + throw new IllegalStateException("Context must be set to set zoom ratio."); + } float ratioAsFloat = ratio.floatValue(); ListenableFuture setZoomRatioFuture = cameraControl.setZoomRatio(ratioAsFloat); diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/DeviceOrientationManagerHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/DeviceOrientationManagerHostApiImpl.java index a6c0ffb91618..22bba48e1bad 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/DeviceOrientationManagerHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/DeviceOrientationManagerHostApiImpl.java @@ -49,7 +49,8 @@ public void setActivity(@NonNull Activity activity) { public void startListeningForDeviceOrientationChange( @NonNull Boolean isFrontFacing, @NonNull Long sensorOrientation) { if (activity == null) { - throw new IllegalStateException("Activity must be set to start listening for device orientation changes."); + throw new IllegalStateException( + "Activity must be set to start listening for device orientation changes."); } deviceOrientationManager = diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java index 47b01121ca1c..0e22e1aa5a5f 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ProcessCameraProviderHostApiImpl.java @@ -116,7 +116,8 @@ public List getAvailableCameraInfos(@NonNull Long identifier) { @NonNull Long cameraSelectorIdentifier, @NonNull List useCaseIds) { if (lifecycleOwner == null) { - throw new IllegalStateException("LifecycleOwner must be set to get ProcessCameraProvider instance."); + throw new IllegalStateException( + "LifecycleOwner must be set to get ProcessCameraProvider instance."); } ProcessCameraProvider processCameraProvider = 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 e25b95202317..8c9daf8e0143 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 @@ -156,10 +156,11 @@ public void onAttachedToActivity_setsActivityAsNeededAndPermissionsRegistry() { mock(PendingRecordingHostApiImpl.class); final SystemServicesHostApiImpl mockSystemServicesHostApiImpl = mock(SystemServicesHostApiImpl.class); - final ImageCaptureHostApiImpl mockImageCaptureHostApiImpl = - mock(ImageCaptureHostApiImpl.class); - final ImageAnalysisHostApiImpl mockImageAnalysisHostApiImpl = mock(ImageAnalysisHostApiImpl.class); - final CameraControlHostApiImpl mockCameraControlHostApiImpl = mock(CameraControlHostApiImpl.class); + final ImageCaptureHostApiImpl mockImageCaptureHostApiImpl = mock(ImageCaptureHostApiImpl.class); + final ImageAnalysisHostApiImpl mockImageAnalysisHostApiImpl = + mock(ImageAnalysisHostApiImpl.class); + final CameraControlHostApiImpl mockCameraControlHostApiImpl = + mock(CameraControlHostApiImpl.class); when(flutterPluginBinding.getApplicationContext()).thenReturn(mockContext); @@ -246,7 +247,8 @@ public void onReattachedToActivityForConfigChanges_setsActivityAndPermissionsReg final ImageAnalysisHostApiImpl mockImageAnalysisHostApiImpl = mock(ImageAnalysisHostApiImpl.class); final ImageCaptureHostApiImpl mockImageCaptureHostApiImpl = mock(ImageCaptureHostApiImpl.class); - final CameraControlHostApiImpl mockCameraControlHostApiImpl = mock(CameraControlHostApiImpl.class); + final CameraControlHostApiImpl mockCameraControlHostApiImpl = + mock(CameraControlHostApiImpl.class); final DeviceOrientationManagerHostApiImpl mockDeviceOrientationManagerHostApiImpl = mock(DeviceOrientationManagerHostApiImpl.class); final ArgumentCaptor permissionsRegistryCaptor = @@ -327,7 +329,8 @@ public void onDetachedFromActivity_setsContextReferencesBasedOnFlutterPluginBind final ImageAnalysisHostApiImpl mockImageAnalysisHostApiImpl = mock(ImageAnalysisHostApiImpl.class); final ImageCaptureHostApiImpl mockImageCaptureHostApiImpl = mock(ImageCaptureHostApiImpl.class); - final CameraControlHostApiImpl mockCameraControlHostApiImpl = mock(CameraControlHostApiImpl.class); + final CameraControlHostApiImpl mockCameraControlHostApiImpl = + mock(CameraControlHostApiImpl.class); final ArgumentCaptor permissionsRegistryCaptor = ArgumentCaptor.forClass(PermissionsRegistry.class); From d76972adbd04635027c1c2cd399424f7cd51d83b Mon Sep 17 00:00:00 2001 From: camsim99 Date: Thu, 11 Jan 2024 14:16:00 -0800 Subject: [PATCH 7/7] lint --- .../camerax/CameraAndroidCameraxPlugin.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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 d068fd0e7602..6781e85212ec 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 @@ -20,13 +20,13 @@ public final class CameraAndroidCameraxPlugin implements FlutterPlugin, ActivityAware { private InstanceManager instanceManager; private FlutterPluginBinding pluginBinding; - @VisibleForTesting public PendingRecordingHostApiImpl pendingRecordingHostApiImpl; - @VisibleForTesting public RecorderHostApiImpl recorderHostApiImpl; - @VisibleForTesting public VideoCaptureHostApiImpl videoCaptureHostApiImpl; - @VisibleForTesting public ImageAnalysisHostApiImpl imageAnalysisHostApiImpl; - @VisibleForTesting public ImageCaptureHostApiImpl imageCaptureHostApiImpl; - @VisibleForTesting public CameraControlHostApiImpl cameraControlHostApiImpl; - @VisibleForTesting public @Nullable SystemServicesHostApiImpl systemServicesHostApiImpl; + @VisibleForTesting @Nullable public PendingRecordingHostApiImpl pendingRecordingHostApiImpl; + @VisibleForTesting @Nullable public RecorderHostApiImpl recorderHostApiImpl; + @VisibleForTesting @Nullable public VideoCaptureHostApiImpl videoCaptureHostApiImpl; + @VisibleForTesting @Nullable public ImageAnalysisHostApiImpl imageAnalysisHostApiImpl; + @VisibleForTesting @Nullable public ImageCaptureHostApiImpl imageCaptureHostApiImpl; + @VisibleForTesting @Nullable public CameraControlHostApiImpl cameraControlHostApiImpl; + @VisibleForTesting @Nullable public SystemServicesHostApiImpl systemServicesHostApiImpl; @VisibleForTesting public @Nullable DeviceOrientationManagerHostApiImpl deviceOrientationManagerHostApiImpl;