Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,10 @@ class Camera
private CameraProperties cameraProperties;
private final CameraFeatureFactory cameraFeatureFactory;
private final Activity activity;

/** A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture. */
private final CameraCaptureCallback cameraCaptureCallback;

/** A {@link Handler} for running tasks in the background. */
Handler backgroundHandler;

Expand All @@ -119,19 +121,23 @@ class Camera
CameraCaptureSession captureSession;
@VisibleForTesting ImageReader pictureImageReader;
ImageStreamReader imageStreamReader;

/** {@link CaptureRequest.Builder} for the camera preview */
CaptureRequest.Builder previewRequestBuilder;

@VisibleForTesting MediaRecorder mediaRecorder;

/** True when recording video. */
boolean recordingVideo;

/** True when the preview is paused. */
@VisibleForTesting boolean pausedPreview;

private File captureFile;

/** Holds the current capture timeouts */
private CaptureTimeoutsWrapper captureTimeouts;

/** Holds the last known capture properties */
private CameraCaptureProperties captureProps;

Expand Down Expand Up @@ -271,8 +277,9 @@ private void prepareMediaRecorder(String outputFilePath) throws IOException {

MediaRecorderBuilder mediaRecorderBuilder;

// TODO(camsim99): Revert changes that allow legacy code to be used when recordingProfile is null
// once this has largely been fixed on the Android side. https://github.com/flutter/flutter/issues/119668
// TODO(camsim99): Revert changes that allow legacy code to be used when recordingProfile
// is null once this has largely been fixed on the Android side.
// https://github.com/flutter/flutter/issues/119668
if (SdkCapabilityChecker.supportsEncoderProfiles() && getRecordingProfile() != null) {
mediaRecorderBuilder =
new MediaRecorderBuilder(
Expand Down Expand Up @@ -1157,7 +1164,8 @@ public void resumePreview() {

public void startPreview(@Nullable Runnable onSuccessCallback)
throws CameraAccessException, InterruptedException {
// If recording is already in progress, the camera is being flipped, so send it through the VideoRenderer to keep the correct orientation.
// If recording is already in progress, the camera is being flipped, so send it through the
// VideoRenderer to keep the correct orientation.
if (recordingVideo) {
startPreviewWithVideoRendererStream(onSuccessCallback);
} else {
Expand Down Expand Up @@ -1379,7 +1387,8 @@ public void setDescriptionWhileRecording(CameraProperties properties) {
"setDescriptionWhileRecordingFailed", "Device was not recording", null);
}

// See VideoRenderer.java; support for this EGL extension is required to switch camera while recording.
// See VideoRenderer.java; support for this EGL extension is required to switch camera while
// recording.
if (!SdkCapabilityChecker.supportsEglRecordableAndroid()) {
throw new Messages.FlutterError(
"setDescriptionWhileRecordingFailed",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,9 @@ private Long instantiateCamera(String cameraName, Messages.PlatformMediaSettings
@SuppressWarnings("ConstantConditions")
private <T> void handleException(Exception exception, Messages.Result<T> result) {
// The code below exactly preserves the format of the native exceptions generated by pre-Pigeon
// code. Since `camera` currently leaks the raw platform exceptions to clients, there may be client
// code that relies on specific string values here, so these should not be changed. See
// code. Since `camera` currently leaks the raw platform exceptions to clients, there may
// be client code that relies on specific string values here, so these should not be changed.
// See
// https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#platform-exception-handling
// for longer-term solutions to this.
if (exception instanceof CameraAccessException) {
Expand All @@ -102,8 +103,9 @@ private <T> void handleException(Exception exception, Messages.Result<T> result)

private void handleException(Exception exception, Messages.VoidResult result) {
// The code below exactly preserves the format of the native exceptions generated by pre-Pigeon
// code. Since `camera` currently leaks the raw platform exceptions to clients, there may be client
// code that relies on specific string values here, so these should not be changed. See
// code. Since `camera` currently leaks the raw platform exceptions to clients, there may
// be client code that relies on specific string values here, so these should not be changed.
// See
// https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#platform-exception-handling
// for longer-term solutions to this.
if (exception instanceof CameraAccessException) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,7 @@ public interface Result<T> {
/** Failure case callback method for handling errors. */
void error(@NonNull Throwable error);
}

/** Asynchronous error handling return type for nullable API method returns. */
public interface NullableResult<T> {
/** Success case callback method for handling returns. */
Expand All @@ -950,6 +951,7 @@ public interface NullableResult<T> {
/** Failure case callback method for handling errors. */
void error(@NonNull Throwable error);
}

/** Asynchronous error handling return type for void API method returns. */
public interface VoidResult {
/** Success case callback method for handling returns. */
Expand All @@ -958,6 +960,7 @@ public interface VoidResult {
/** Failure case callback method for handling errors. */
void error(@NonNull Throwable error);
}

/**
* Handles calls from Dart to the native side.
*
Expand All @@ -967,81 +970,108 @@ public interface CameraApi {
/** Returns the list of available cameras. */
@NonNull
List<PlatformCameraDescription> getAvailableCameras();

/** Creates a new camera with the given name and settings and returns its ID. */
void create(
@NonNull String cameraName,
@NonNull PlatformMediaSettings mediaSettings,
@NonNull Result<Long> result);

/** Initializes the camera with the given ID for the given image format. */
void initialize(@NonNull PlatformImageFormatGroup imageFormat);

/** Disposes of the camera with the given ID. */
void dispose();

/** Locks the camera with the given ID to the given orientation. */
void lockCaptureOrientation(@NonNull PlatformDeviceOrientation orientation);

/** Unlocks the orientation for the camera with the given ID. */
void unlockCaptureOrientation();

/** Takes a picture on the camera with the given ID and returns a path to the resulting file. */
void takePicture(@NonNull Result<String> result);

/** Starts recording a video on the camera with the given ID. */
void startVideoRecording(@NonNull Boolean enableStream);

/**
* Ends video recording on the camera with the given ID and returns the path to the resulting
* file.
*/
@NonNull
String stopVideoRecording();

/** Pauses video recording on the camera with the given ID. */
void pauseVideoRecording();

/** Resumes previously paused video recording on the camera with the given ID. */
void resumeVideoRecording();

/** Begins streaming frames from the camera. */
void startImageStream();

/** Stops streaming frames from the camera. */
void stopImageStream();

/** Sets the flash mode of the camera with the given ID. */
void setFlashMode(@NonNull PlatformFlashMode flashMode, @NonNull VoidResult result);

/** Sets the exposure mode of the camera with the given ID. */
void setExposureMode(@NonNull PlatformExposureMode exposureMode, @NonNull VoidResult result);

/**
* Sets the exposure point of the camera with the given ID.
*
* <p>A null value resets to the default exposure point.
*/
void setExposurePoint(@Nullable PlatformPoint point, @NonNull VoidResult result);

/** Returns the minimum exposure offset of the camera with the given ID. */
@NonNull
Double getMinExposureOffset();

/** Returns the maximum exposure offset of the camera with the given ID. */
@NonNull
Double getMaxExposureOffset();

/** Returns the exposure step size of the camera with the given ID. */
@NonNull
Double getExposureOffsetStepSize();

/**
* Sets the exposure offset of the camera with the given ID and returns the actual exposure
* offset.
*/
void setExposureOffset(@NonNull Double offset, @NonNull Result<Double> result);

/** Sets the focus mode of the camera with the given ID. */
void setFocusMode(@NonNull PlatformFocusMode focusMode);

/**
* Sets the focus point of the camera with the given ID.
*
* <p>A null value resets to the default focus point.
*/
void setFocusPoint(@Nullable PlatformPoint point, @NonNull VoidResult result);

/** Returns the maximum zoom level of the camera with the given ID. */
@NonNull
Double getMaxZoomLevel();

/** Returns the minimum zoom level of the camera with the given ID. */
@NonNull
Double getMinZoomLevel();

/** Sets the zoom level of the camera with the given ID. */
void setZoomLevel(@NonNull Double zoom, @NonNull VoidResult result);

/** Pauses streaming of preview frames. */
void pausePreview();

/** Resumes previously paused streaming of preview frames. */
void resumePreview();

/**
* Changes the camera while recording video.
*
Expand All @@ -1053,6 +1083,7 @@ void create(
static @NonNull MessageCodec<Object> getCodec() {
return PigeonCodec.INSTANCE;
}

/** Sets up an instance of `CameraApi` to handle messages through the `binaryMessenger`. */
static void setUp(@NonNull BinaryMessenger binaryMessenger, @Nullable CameraApi api) {
setUp(binaryMessenger, "", api);
Expand Down Expand Up @@ -1780,6 +1811,7 @@ public void error(Throwable error) {
}
}
}

/**
* Handles calls from native side to Dart that are not camera-specific.
*
Expand All @@ -1803,6 +1835,7 @@ public CameraGlobalEventApi(
static @NonNull MessageCodec<Object> getCodec() {
return PigeonCodec.INSTANCE;
}

/** Called when the device's physical orientation changes. */
public void deviceOrientationChanged(
@NonNull PlatformDeviceOrientation orientationArg, @NonNull VoidResult result) {
Expand All @@ -1829,6 +1862,7 @@ public void deviceOrientationChanged(
});
}
}

/**
* Handles device-specific calls from native side to Dart.
*
Expand All @@ -1852,6 +1886,7 @@ public CameraEventApi(
static @NonNull MessageCodec<Object> getCodec() {
return PigeonCodec.INSTANCE;
}

/** Called when the camera is initialized. */
public void initialized(
@NonNull PlatformCameraState initialStateArg, @NonNull VoidResult result) {
Expand All @@ -1876,6 +1911,7 @@ public void initialized(
}
});
}

/** Called when an error occurs in the camera. */
public void error(@NonNull String messageArg, @NonNull VoidResult result) {
final String channelName =
Expand All @@ -1899,6 +1935,7 @@ public void error(@NonNull String messageArg, @NonNull VoidResult result) {
}
});
}

/** Called when the camera closes. */
public void closed(@NonNull VoidResult result) {
final String channelName =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ public class SdkCapabilityChecker {

@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.P)
public static boolean supportsDistortionCorrection() {
// See https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES
// See
// https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES
return SDK_VERSION >= Build.VERSION_CODES.P;
}

Expand All @@ -36,13 +37,15 @@ public static boolean supportsEncoderProfiles() {

@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.P)
public static boolean supportsSessionConfiguration() {
// See https://developer.android.com/reference/android/hardware/camera2/params/SessionConfiguration
// See
// https://developer.android.com/reference/android/hardware/camera2/params/SessionConfiguration
return SDK_VERSION >= Build.VERSION_CODES.P;
}

@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.R)
public static boolean supportsZoomRatio() {
// See https://developer.android.com/reference/android/hardware/camera2/CaptureRequest#CONTROL_ZOOM_RATIO
// See
// https://developer.android.com/reference/android/hardware/camera2/CaptureRequest#CONTROL_ZOOM_RATIO
return SDK_VERSION >= Build.VERSION_CODES.R;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ public boolean checkIsSupported() {
final Float minFocus = cameraProperties.getLensInfoMinimumFocusDistance();

// Check if the focal length of the lens is fixed. If the minimum focus distance == 0, then the
// focal length is fixed. The minimum focus distance can be null on some devices: https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE
// focal length is fixed. The minimum focus distance can be null on some devices:
// https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE
boolean isFixedLength = minFocus == null || minFocus == 0;

return !isFixedLength
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ public void updateBuilder(@NonNull CaptureRequest.Builder requestBuilder) {
private void buildExposureRectangle() {
if (this.cameraBoundaries == null) {
throw new AssertionError(
"The cameraBoundaries should be set (using `ExposurePointFeature.setCameraBoundaries(Size)`) before updating the exposure point.");
"The cameraBoundaries should be set (using"
+ " `ExposurePointFeature.setCameraBoundaries(Size)`) before updating the exposure"
+ " point.");
}
if (this.exposurePoint == null) {
this.exposureRectangle = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ public void updateBuilder(@NonNull CaptureRequest.Builder requestBuilder) {
private void buildFocusRectangle() {
if (this.cameraBoundaries == null) {
throw new AssertionError(
"The cameraBoundaries should be set (using `FocusPointFeature.setCameraBoundaries(Size)`) before updating the focus point.");
"The cameraBoundaries should be set (using `FocusPointFeature.setCameraBoundaries(Size)`)"
+ " before updating the focus point.");
}
if (this.focusPoint == null) {
this.focusRectangle = null;
Expand Down
Loading
Loading