From ab492d2a9471dd5bdeb4227b224f5c2ec203f20a Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Tue, 7 Sep 2021 15:45:41 +0200 Subject: [PATCH 1/6] [camera] Fixed IllegalStateException being thrown on activity switch. --- packages/camera/camera/CHANGELOG.md | 4 ++++ .../io/flutter/plugins/camera/Camera.java | 22 ++++++++----------- .../flutter/plugins/camera/CameraPlugin.java | 18 ++++----------- .../plugins/camera/MethodCallHandlerImpl.java | 17 ++------------ packages/camera/camera/pubspec.yaml | 2 +- 5 files changed, 20 insertions(+), 43 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 62b5f1f9bd4c..b2dda9a52436 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.4+1 + +* Fixed Android implementation throwing IllegalStateException when switching to a different activity. + ## 0.9.4 * Add web support by endorsing `package:camera_web`. diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 4601e7d34d69..51009716f56d 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -35,9 +35,6 @@ import android.view.Surface; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.lifecycle.Lifecycle; -import androidx.lifecycle.LifecycleObserver; -import androidx.lifecycle.OnLifecycleEvent; import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.MethodChannel; @@ -82,8 +79,7 @@ interface ErrorCallback { class Camera implements CameraCaptureCallback.CameraCaptureStateListener, - ImageReader.OnImageAvailableListener, - LifecycleObserver { + ImageReader.OnImageAvailableListener { private static final String TAG = "Camera"; private static final HashMap supportedImageFormats; @@ -576,19 +572,19 @@ private Display getDefaultDisplay() { } /** Starts a background thread and its {@link Handler}. */ - @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) public void startBackgroundThread() { - backgroundHandlerThread = new HandlerThread("CameraBackground"); - try { - backgroundHandlerThread.start(); - } catch (IllegalThreadStateException e) { - // Ignore exception in case the thread has already started. + if (backgroundHandlerThread == null) { + backgroundHandlerThread = new HandlerThread("CameraBackground"); + try { + backgroundHandlerThread.start(); + } catch (IllegalThreadStateException e) { + // Ignore exception in case the thread has already started. + } + backgroundHandler = new Handler(backgroundHandlerThread.getLooper()); } - backgroundHandler = new Handler(backgroundHandlerThread.getLooper()); } /** Stops the background thread and its {@link Handler}. */ - @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) public void stopBackgroundThread() { if (backgroundHandlerThread != null) { backgroundHandlerThread.quitSafely(); diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java index ef3a2b9b5d83..067ed0295e2e 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java @@ -8,11 +8,9 @@ import android.os.Build; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.lifecycle.Lifecycle; import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.embedding.engine.plugins.activity.ActivityAware; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; -import io.flutter.embedding.engine.plugins.lifecycle.FlutterLifecycleAdapter; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugins.camera.CameraPermissions.PermissionsRegistry; import io.flutter.view.TextureRegistry; @@ -53,8 +51,7 @@ public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registra registrar.activity(), registrar.messenger(), registrar::addRequestPermissionsResultListener, - registrar.view(), - null); + registrar.view()); } @Override @@ -73,8 +70,7 @@ public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { binding.getActivity(), flutterPluginBinding.getBinaryMessenger(), binding::addRequestPermissionsResultListener, - flutterPluginBinding.getTextureRegistry(), - FlutterLifecycleAdapter.getActivityLifecycle(binding)); + flutterPluginBinding.getTextureRegistry()); } @Override @@ -100,8 +96,7 @@ private void maybeStartListening( Activity activity, BinaryMessenger messenger, PermissionsRegistry permissionsRegistry, - TextureRegistry textureRegistry, - @Nullable Lifecycle lifecycle) { + TextureRegistry textureRegistry) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { // If the sdk is less than 21 (min sdk for Camera2) we don't register the plugin. return; @@ -109,11 +104,6 @@ private void maybeStartListening( methodCallHandler = new MethodCallHandlerImpl( - activity, - messenger, - new CameraPermissions(), - permissionsRegistry, - textureRegistry, - lifecycle); + activity, messenger, new CameraPermissions(), permissionsRegistry, textureRegistry); } } diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java index 5e25353cbca9..35cc2b081bae 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java @@ -10,8 +10,6 @@ import android.os.Looper; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.lifecycle.Lifecycle; -import androidx.lifecycle.LifecycleObserver; import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.EventChannel; @@ -29,7 +27,7 @@ import java.util.HashMap; import java.util.Map; -final class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler, LifecycleObserver { +final class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler { private final Activity activity; private final BinaryMessenger messenger; private final CameraPermissions cameraPermissions; @@ -37,7 +35,6 @@ final class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler, Li private final TextureRegistry textureRegistry; private final MethodChannel methodChannel; private final EventChannel imageStreamChannel; - private final Lifecycle lifecycle; private @Nullable Camera camera; MethodCallHandlerImpl( @@ -45,14 +42,12 @@ final class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler, Li BinaryMessenger messenger, CameraPermissions cameraPermissions, PermissionsRegistry permissionsAdder, - TextureRegistry textureRegistry, - @Nullable Lifecycle lifecycle) { + TextureRegistry textureRegistry) { this.activity = activity; this.messenger = messenger; this.cameraPermissions = cameraPermissions; this.permissionsRegistry = permissionsAdder; this.textureRegistry = textureRegistry; - this.lifecycle = lifecycle; methodChannel = new MethodChannel(messenger, "plugins.flutter.io/camera"); imageStreamChannel = new EventChannel(messenger, "plugins.flutter.io/camera/imageStream"); @@ -387,10 +382,6 @@ private void instantiateCamera(MethodCall call, Result result) throws CameraAcce new CameraPropertiesImpl(cameraName, CameraUtils.getCameraManager(activity)); ResolutionPreset resolutionPreset = ResolutionPreset.valueOf(preset); - if (camera != null && lifecycle != null) { - lifecycle.removeObserver(camera); - } - camera = new Camera( activity, @@ -401,10 +392,6 @@ private void instantiateCamera(MethodCall call, Result result) throws CameraAcce resolutionPreset, enableAudio); - if (lifecycle != null) { - lifecycle.addObserver(camera); - } - Map reply = new HashMap<>(); reply.put("cameraId", flutterSurfaceTexture.id()); result.success(reply); diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index b8894d58ac3a..5c225eaee48f 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -4,7 +4,7 @@ description: A Flutter plugin for getting information about and controlling the and streaming image buffers to dart. repository: https://github.com/flutter/plugins/tree/master/packages/camera/camera issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.4 +version: 0.9.4+1 environment: sdk: ">=2.14.0 <3.0.0" From 6dd242a113f91e22042031b86968e821cc0da629 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Tue, 7 Sep 2021 15:46:46 +0200 Subject: [PATCH 2/6] Fix test --- .../io/flutter/plugins/camera/MethodCallHandlerImplTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/MethodCallHandlerImplTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/MethodCallHandlerImplTest.java index 35eed7a66a1a..4211bf1dbabb 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/MethodCallHandlerImplTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/MethodCallHandlerImplTest.java @@ -33,8 +33,7 @@ public void setUp() { mock(BinaryMessenger.class), mock(CameraPermissions.class), mock(CameraPermissions.PermissionsRegistry.class), - mock(TextureRegistry.class), - null); + mock(TextureRegistry.class)); mockResult = mock(MethodChannel.Result.class); mockCamera = mock(Camera.class); TestUtils.setPrivateField(handler, "camera", mockCamera); From 6361b4dc5dffa4223e3cd405b7902ea79ba116ef Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Wed, 8 Sep 2021 10:29:14 +0200 Subject: [PATCH 3/6] Added test --- .../io/flutter/plugins/camera/Camera.java | 39 ++++++++++++++++++- .../io/flutter/plugins/camera/CameraTest.java | 30 ++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 51009716f56d..ef23c547cec1 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -35,6 +35,7 @@ import android.view.Surface; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.MethodChannel; @@ -574,13 +575,13 @@ private Display getDefaultDisplay() { /** Starts a background thread and its {@link Handler}. */ public void startBackgroundThread() { if (backgroundHandlerThread == null) { - backgroundHandlerThread = new HandlerThread("CameraBackground"); + backgroundHandlerThread = HandlerThreadFactory.create("CameraBackground"); try { backgroundHandlerThread.start(); } catch (IllegalThreadStateException e) { // Ignore exception in case the thread has already started. } - backgroundHandler = new Handler(backgroundHandlerThread.getLooper()); + backgroundHandler = HandlerFactory.create(backgroundHandlerThread.getLooper()); } } @@ -1116,4 +1117,38 @@ public void dispose() { flutterTexture.release(); getDeviceOrientationManager().stop(); } + + /** Factory class that assists in creating a {@link HandlerThread} instance. */ + static class HandlerThreadFactory { + /** + * Creates a new instance of the {@link HandlerThread} class. + * + *

This method is visible for testing purposes only and should never be used outside this * + * class. + * + * @param name to give to the HandlerThread. + * @return new instance of the {@link HandlerThread} class. + */ + @VisibleForTesting + public static HandlerThread create(String name) { + return new HandlerThread(name); + } + } + + /** Factory class that assists in creating a {@link Handler} instance. */ + static class HandlerFactory { + /** + * Creates a new instance of the {@link Handler} class. + * + *

This method is visible for testing purposes only and should never be used outside this * + * class. + * + * @param looper to give to the Handler. + * @return new instance of the {@link Handler} class. + */ + @VisibleForTesting + public static Handler create(Looper looper) { + return new Handler(looper); + } + } } diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java index fbed28bc11fc..4e90eef0632c 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java @@ -10,6 +10,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -23,6 +24,9 @@ import android.media.CamcorderProfile; import android.media.MediaRecorder; import android.os.Build; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; import androidx.annotation.NonNull; import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.plugin.common.MethodChannel; @@ -49,6 +53,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.mockito.MockedStatic; public class CameraTest { private CameraProperties mockCameraProperties; @@ -57,6 +62,10 @@ public class CameraTest { private Camera camera; private CameraCaptureSession mockCaptureSession; private CaptureRequest.Builder mockPreviewRequestBuilder; + private MockedStatic mockHandlerThreadFactory; + private HandlerThread mockHandlerThread; + private MockedStatic mockHandlerFactory; + private Handler mockHandler; @Before public void before() { @@ -65,6 +74,10 @@ public void before() { mockDartMessenger = mock(DartMessenger.class); mockCaptureSession = mock(CameraCaptureSession.class); mockPreviewRequestBuilder = mock(CaptureRequest.Builder.class); + mockHandlerThreadFactory = mockStatic(Camera.HandlerThreadFactory.class); + mockHandlerThread = mock(HandlerThread.class); + mockHandlerFactory = mockStatic(Camera.HandlerFactory.class); + mockHandler = mock(Handler.class); final Activity mockActivity = mock(Activity.class); final TextureRegistry.SurfaceTextureEntry mockFlutterTexture = @@ -74,6 +87,10 @@ public void before() { final boolean enableAudio = false; when(mockCameraProperties.getCameraName()).thenReturn(cameraName); + mockHandlerFactory.when(() -> Camera.HandlerFactory.create(any())).thenReturn(mockHandler); + mockHandlerThreadFactory + .when(() -> Camera.HandlerThreadFactory.create(any())) + .thenReturn(mockHandlerThread); camera = new Camera( @@ -92,6 +109,8 @@ public void before() { @After public void after() { TestUtils.setFinalStatic(Build.VERSION.class, "SDK_INT", 0); + mockHandlerThreadFactory.close(); + mockHandlerFactory.close(); } @Test @@ -773,6 +792,17 @@ public void resumePreview_shouldSendErrorEventOnCameraAccessException() verify(mockDartMessenger, times(1)).sendCameraErrorEvent(any()); } + @Test + public void startBackgroundThread_shouldStartNewThread() { + Looper mockLooper = mock(Looper.class); + when(mockHandlerThread.getLooper()).thenReturn(mockLooper); + + camera.startBackgroundThread(); + + verify(mockHandlerThread).start(); + assertEquals(mockHandler, TestUtils.getPrivateField(camera, "backgroundHandler")); + } + private static class TestCameraFeatureFactory implements CameraFeatureFactory { private final AutoFocusFeature mockAutoFocusFeature; private final ExposureLockFeature mockExposureLockFeature; From 6361c6e180d21f87791d4e151eb36fe332803e67 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Wed, 8 Sep 2021 11:08:20 +0200 Subject: [PATCH 4/6] Update tests --- packages/camera/camera/android/build.gradle | 2 +- .../java/io/flutter/plugins/camera/CameraTest.java | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/camera/camera/android/build.gradle b/packages/camera/camera/android/build.gradle index 61d13e5579cc..633efd0b284a 100644 --- a/packages/camera/camera/android/build.gradle +++ b/packages/camera/camera/android/build.gradle @@ -60,7 +60,7 @@ android { dependencies { compileOnly 'androidx.annotation:annotation:1.1.0' testImplementation 'junit:junit:4.12' - testImplementation 'org.mockito:mockito-inline:3.11.1' + testImplementation 'org.mockito:mockito-inline:3.12.4' testImplementation 'androidx.test:core:1.3.0' testImplementation 'org.robolectric:robolectric:4.3' } diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java index 4e90eef0632c..9c99c3840345 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java @@ -26,7 +26,6 @@ import android.os.Build; import android.os.Handler; import android.os.HandlerThread; -import android.os.Looper; import androidx.annotation.NonNull; import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.plugin.common.MethodChannel; @@ -794,15 +793,20 @@ public void resumePreview_shouldSendErrorEventOnCameraAccessException() @Test public void startBackgroundThread_shouldStartNewThread() { - Looper mockLooper = mock(Looper.class); - when(mockHandlerThread.getLooper()).thenReturn(mockLooper); - camera.startBackgroundThread(); - verify(mockHandlerThread).start(); + verify(mockHandlerThread, times(1)).start(); assertEquals(mockHandler, TestUtils.getPrivateField(camera, "backgroundHandler")); } + @Test + public void startBackgroundThread_shouldNotStartNewThreadWhenAlreadyCreated() { + camera.startBackgroundThread(); + camera.startBackgroundThread(); + + verify(mockHandlerThread, times(1)).start(); + } + private static class TestCameraFeatureFactory implements CameraFeatureFactory { private final AutoFocusFeature mockAutoFocusFeature; private final ExposureLockFeature mockExposureLockFeature; From 467661e1c9e57d43593f8add47faeaff31369618 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 23 Sep 2021 12:10:58 +0200 Subject: [PATCH 5/6] Added tests to assert when LifecycleObserver is implemented. --- .../test/java/io/flutter/plugins/camera/CameraTest.java | 9 +++++++++ .../plugins/camera/MethodCallHandlerImplTest.java | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java index 9c99c3840345..9d973195435e 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java @@ -5,6 +5,7 @@ package io.flutter.plugins.camera; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -27,6 +28,7 @@ import android.os.Handler; import android.os.HandlerThread; import androidx.annotation.NonNull; +import androidx.lifecycle.LifecycleObserver; import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugins.camera.features.CameraFeatureFactory; @@ -112,6 +114,13 @@ public void after() { mockHandlerFactory.close(); } + @Test + public void shouldNotImplementLifecycleObserverInterface() { + Class cameraClass = Camera.class; + + assertFalse(LifecycleObserver.class.isAssignableFrom(cameraClass)); + } + @Test public void shouldCreateCameraPluginAndSetAllFeatures() { final Activity mockActivity = mock(Activity.class); diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/MethodCallHandlerImplTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/MethodCallHandlerImplTest.java index 4211bf1dbabb..868e2e9e6d57 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/MethodCallHandlerImplTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/MethodCallHandlerImplTest.java @@ -4,6 +4,7 @@ package io.flutter.plugins.camera; +import static org.junit.Assert.assertFalse; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -11,6 +12,7 @@ import android.app.Activity; import android.hardware.camera2.CameraAccessException; +import androidx.lifecycle.LifecycleObserver; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; @@ -39,6 +41,13 @@ public void setUp() { TestUtils.setPrivateField(handler, "camera", mockCamera); } + @Test + public void shouldNotImplementLifecycleObserverInterface() { + Class methodCallHandlerClass = MethodCallHandlerImpl.class; + + assertFalse(LifecycleObserver.class.isAssignableFrom(methodCallHandlerClass)); + } + @Test public void onMethodCall_pausePreview_shouldPausePreviewAndSendSuccessResult() throws CameraAccessException { From 95619933bedfd8e848a71583a33d9ff41a867538 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Fri, 24 Sep 2021 08:55:35 +0200 Subject: [PATCH 6/6] Process feedback on PR According to feedback from @blasten on PR, the following changes are made: - Removed an obsolete empty line in the CHANGELOG.md; - Return early from the `startBackgroundThread` function when the `backgroundHandlerThread is not `null`. This simplifies the method making it easier to read and understand. --- .../java/io/flutter/plugins/camera/Camera.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index ef23c547cec1..75ced531b08a 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -574,15 +574,17 @@ private Display getDefaultDisplay() { /** Starts a background thread and its {@link Handler}. */ public void startBackgroundThread() { - if (backgroundHandlerThread == null) { - backgroundHandlerThread = HandlerThreadFactory.create("CameraBackground"); - try { - backgroundHandlerThread.start(); - } catch (IllegalThreadStateException e) { - // Ignore exception in case the thread has already started. - } - backgroundHandler = HandlerFactory.create(backgroundHandlerThread.getLooper()); + if (backgroundHandlerThread != null) { + return; + } + + backgroundHandlerThread = HandlerThreadFactory.create("CameraBackground"); + try { + backgroundHandlerThread.start(); + } catch (IllegalThreadStateException e) { + // Ignore exception in case the thread has already started. } + backgroundHandler = HandlerFactory.create(backgroundHandlerThread.getLooper()); } /** Stops the background thread and its {@link Handler}. */