[camera] Added timeout to Android pre-capture sequence (#3558)

* Added timeout for waiting pre-capture state Android

* Fix analysis warning and bumped version
diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md
index aee3774..7391f30 100644
--- a/packages/camera/camera/CHANGELOG.md
+++ b/packages/camera/camera/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.8.0-nullsafety.1
+
+* Added a timeout to the pre-capture sequence on Android to prevent crashes when the camera cannot get a focus.
+
 ## 0.8.0-nullsafety
 
 * Migrated to null safety.
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 a5f8647..5169a3b 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
@@ -36,6 +36,7 @@
 import android.os.Build.VERSION_CODES;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.SystemClock;
 import android.util.Log;
 import android.util.Range;
 import android.util.Rational;
@@ -73,6 +74,9 @@
 public class Camera {
   private static final String TAG = "Camera";
 
+  /** Timeout for the pre-capture sequence. */
+  private static final long PRECAPTURE_TIMEOUT_MS = 1000;
+
   private final SurfaceTextureEntry flutterTexture;
   private final CameraManager cameraManager;
   private final DeviceOrientationManager deviceOrientationListener;
@@ -105,6 +109,7 @@
   private boolean useAutoFocus = true;
   private Range<Integer> fpsRange;
   private PlatformChannel.DeviceOrientation lockedCaptureOrientation;
+  private long preCaptureStartTime;
 
   private static final HashMap<String, Integer> supportedImageFormats;
   // Current supported outputs
@@ -503,11 +508,16 @@
                   || aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED
                   || aeState == CaptureRequest.CONTROL_AE_STATE_CONVERGED) {
                 pictureCaptureRequest.setState(State.waitingPreCaptureReady);
+                setPreCaptureStartTime();
               }
               break;
             case waitingPreCaptureReady:
               if (aeState == null || aeState != CaptureRequest.CONTROL_AE_STATE_PRECAPTURE) {
                 runPictureCapture();
+              } else {
+                if (hitPreCaptureTimeout()) {
+                  unlockAutoFocus();
+                }
               }
           }
         }
@@ -1142,6 +1152,20 @@
     startPreview();
   }
 
+  /** Sets the time the pre-capture sequence started. */
+  private void setPreCaptureStartTime() {
+    preCaptureStartTime = SystemClock.elapsedRealtime();
+  }
+
+  /**
+   * Check if the timeout for the pre-capture sequence has been reached.
+   *
+   * @return true if the timeout is reached; otherwise false is returned.
+   */
+  private boolean hitPreCaptureTimeout() {
+    return (SystemClock.elapsedRealtime() - preCaptureStartTime) > PRECAPTURE_TIMEOUT_MS;
+  }
+
   private void closeCaptureSession() {
     if (cameraCaptureSession != null) {
       cameraCaptureSession.close();
diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml
index 7ed08d8..5b98c39 100644
--- a/packages/camera/camera/pubspec.yaml
+++ b/packages/camera/camera/pubspec.yaml
@@ -2,7 +2,7 @@
 description: A Flutter plugin for getting information about and controlling the
   camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video,
   and streaming image buffers to dart.
-version: 0.8.0-nullsafety
+version: 0.8.0-nullsafety.1
 homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera
 
 dependencies:
diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart
index b37b770..40ce29e 100644
--- a/packages/camera/camera/test/camera_test.dart
+++ b/packages/camera/camera/test/camera_test.dart
@@ -1268,7 +1268,7 @@
   Future<int> createCamera(
     CameraDescription description,
     ResolutionPreset? resolutionPreset, {
-    bool enableAudio = true,
+    bool enableAudio = false,
   }) =>
       mockPlatformException
           ? throw PlatformException(code: 'foo', message: 'bar')