Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[camerax] Wrap Android classes/methods required to set the exposure mode #5966

Merged
merged 25 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e71fefc
Dart side
camsim99 Jan 23, 2024
916a0ae
Java side
camsim99 Jan 24, 2024
2267138
Commit generated tests for fixing
camsim99 Jan 24, 2024
5de43ae
Update packages/camera/camera_android_camerax/lib/src/camera2_camera_…
camsim99 Jan 24, 2024
26500e6
Run build_runner
camsim99 Jan 24, 2024
f5c0647
Dart tests
camsim99 Jan 24, 2024
5bf2a13
Change dart side to use map + refactor dart tests
camsim99 Jan 24, 2024
1ac6a56
Change java side to use maps
camsim99 Jan 25, 2024
ac0af9c
Format + add 1/2 java tests
camsim99 Jan 26, 2024
96c3624
Add 2/2 java tests
camsim99 Jan 26, 2024
29009a2
Merge remote-tracking branch 'upstream/main' into camx_cam2
camsim99 Jan 26, 2024
e7cb2c3
fix analyze
camsim99 Jan 26, 2024
cef639b
Fix android lint and bump version
camsim99 Jan 26, 2024
0ad3b16
Self review
camsim99 Jan 29, 2024
d35b58f
Add comment to pigeon
camsim99 Jan 29, 2024
6e71a37
Merge remote-tracking branch 'upstream/main' into camx_cam2
camsim99 Jan 29, 2024
b4743cc
Modify generated proxy comments
camsim99 Feb 5, 2024
05d41f4
Update packages/camera/camera_android_camerax/android/src/main/java/i…
camsim99 Feb 5, 2024
6deea90
Update packages/camera/camera_android_camerax/lib/src/camera2_camera_…
camsim99 Feb 5, 2024
0f140c4
Update packages/camera/camera_android_camerax/lib/src/camera2_camera_…
camsim99 Feb 5, 2024
35db695
Update packages/camera/camera_android_camerax/lib/src/capture_request…
camsim99 Feb 5, 2024
a3e9fb4
Update packages/camera/camera_android_camerax/pigeons/camerax_library…
camsim99 Feb 5, 2024
46076be
Merge remote-tracking branch 'refs/remotes/origin/camx_cam2' into cam…
camsim99 Feb 5, 2024
84280c7
Finish addressing review
camsim99 Feb 5, 2024
7483bde
Merge remote-tracking branch 'upstream/main' into camx_cam2
camsim99 Feb 5, 2024
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
4 changes: 4 additions & 0 deletions packages/camera/camera_android_camerax/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.5.0+31

* Wraps CameraX classes needed to set capture request options, which is needed to implement setting the exposure mode.

## 0.5.0+30

* Adds documentation to clarify how the plugin uses resolution presets as target resolutions for CameraX.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class AnalyzerHostApiImpl implements AnalyzerHostApi {
private final InstanceManager instanceManager;
private final AnalyzerProxy proxy;

/** Proxy for constructors and static method of {@link ImageAnalysis.Analyzer}. */
/** Proxy for constructor of {@link ImageAnalysis.Analyzer}. */
@VisibleForTesting
public static class AnalyzerProxy {

Expand Down Expand Up @@ -95,7 +95,7 @@ public AnalyzerHostApiImpl(
*
* @param binaryMessenger used to communicate with Dart over asynchronous messages
* @param instanceManager maintains instances stored to communicate with attached Dart objects
* @param proxy proxy for constructors and static method of {@link ImageAnalysis.Analyzer}
* @param proxy proxy for constructor of {@link ImageAnalysis.Analyzer}
*/
@VisibleForTesting
AnalyzerHostApiImpl(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class AspectRatioStrategyHostApiImpl implements AspectRatioStrategyHostAp
private final InstanceManager instanceManager;
private final AspectRatioStrategyProxy proxy;

/** Proxy for constructors and static method of {@link AspectRatioStrategy}. */
/** Proxy for constructor of {@link AspectRatioStrategy}. */
@VisibleForTesting
public static class AspectRatioStrategyProxy {
/** Creates an instance of {@link AspectRatioStrategy}. */
Expand All @@ -43,7 +43,7 @@ public AspectRatioStrategyHostApiImpl(@NonNull InstanceManager instanceManager)
* Constructs an {@link AspectRatioStrategyHostApiImpl}.
*
* @param instanceManager maintains instances stored to communicate with attached Dart objects
* @param proxy proxy for constructors and static method of {@link AspectRatioStrategy}
* @param proxy proxy for constructor of {@link AspectRatioStrategy}
*/
@VisibleForTesting
AspectRatioStrategyHostApiImpl(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.camerax;

import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.OptIn;
import androidx.annotation.VisibleForTesting;
import androidx.camera.camera2.interop.Camera2CameraControl;
import androidx.camera.camera2.interop.CaptureRequestOptions;
import androidx.camera.core.CameraControl;
import androidx.core.content.ContextCompat;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import io.flutter.plugins.camerax.GeneratedCameraXLibrary.Camera2CameraControlHostApi;
import java.util.Objects;

/**
* Host API implementation for {@link Camera2CameraControl}.
*
* <p>This class may handle instantiating and adding native object instances that are attached to a
* Dart instance or handle method calls on the associated native class or an instance of the class.
*/
public class Camera2CameraControlHostApiImpl implements Camera2CameraControlHostApi {
private final InstanceManager instanceManager;
private final Camera2CameraControlProxy proxy;

/** Proxy for constructor and methods of {@link Camera2CameraControl}. */
@VisibleForTesting
public static class Camera2CameraControlProxy {
Context context;

/**
* Creates an instance of {@link Camera2CameraControl} derived from specified {@link
* CameraControl} instance.
*/
@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)
public @NonNull Camera2CameraControl create(@NonNull CameraControl cameraControl) {
return Camera2CameraControl.from(cameraControl);
}

/**
* Adds a {@link CaptureRequestOptions} to update the capture session with the options it
* contains.
*/
@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)
public void addCaptureRequestOptions(
@NonNull Camera2CameraControl camera2CameraControl,
@NonNull CaptureRequestOptions bundle,
@NonNull GeneratedCameraXLibrary.Result<Void> result) {
if (context == null) {
throw new IllegalStateException("Context must be set to add capture request options.");
}

ListenableFuture<Void> addCaptureRequestOptionsFuture =
camera2CameraControl.addCaptureRequestOptions(bundle);

Futures.addCallback(
addCaptureRequestOptionsFuture,
new FutureCallback<Void>() {
public void onSuccess(Void voidResult) {
result.success(null);
}

public void onFailure(Throwable t) {
result.error(t);
}
},
ContextCompat.getMainExecutor(context));
}
}

/**
* Constructs a {@link Camera2CameraControlHostApiImpl}.
*
* @param instanceManager maintains instances stored to communicate with attached Dart objects
* @param context {@link Context} used to retrieve {@code Executor}
*/
public Camera2CameraControlHostApiImpl(
@NonNull InstanceManager instanceManager, @NonNull Context context) {
this(instanceManager, new Camera2CameraControlProxy(), context);
}

/**
* Constructs a {@link Camera2CameraControlHostApiImpl}.
*
* @param instanceManager maintains instances stored to communicate with attached Dart objects
* @param proxy proxy for constructor and methods of {@link Camera2CameraControl}
* @param context {@link Context} used to retrieve {@code Executor}
*/
@VisibleForTesting
Camera2CameraControlHostApiImpl(
@NonNull InstanceManager instanceManager,
@NonNull Camera2CameraControlProxy proxy,
@NonNull Context context) {
this.instanceManager = instanceManager;
this.proxy = proxy;
proxy.context = context;
}

/**
* Sets the context that the {@code Camera2CameraControl} will use to listen for the result of
* setting capture request options.
*
* <p>If using the camera plugin in an add-to-app context, ensure that this is called anytime that
* the context changes.
*/
public void setContext(@NonNull Context context) {
this.proxy.context = context;
}

@Override
public void create(@NonNull Long identifier, @NonNull Long cameraControlIdentifier) {
instanceManager.addDartCreatedInstance(
proxy.create(Objects.requireNonNull(instanceManager.getInstance(cameraControlIdentifier))),
identifier);
}

@Override
public void addCaptureRequestOptions(
@NonNull Long identifier,
@NonNull Long captureRequestOptionsIdentifier,
@NonNull GeneratedCameraXLibrary.Result<Void> result) {
proxy.addCaptureRequestOptions(
getCamera2CameraControlInstance(identifier),
Objects.requireNonNull(instanceManager.getInstance(captureRequestOptionsIdentifier)),
result);
}

/**
* Retrieves the {@link Camera2CameraControl} instance associated with the specified {@code
* identifier}.
*/
private Camera2CameraControl getCamera2CameraControlInstance(@NonNull Long identifier) {
return Objects.requireNonNull(instanceManager.getInstance(identifier));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class CameraControlHostApiImpl implements CameraControlHostApi {
private final InstanceManager instanceManager;
private final CameraControlProxy proxy;

/** Proxy for constructors and static method of {@link CameraControl}. */
/** Proxy for methods of {@link CameraControl}. */
@VisibleForTesting
public static class CameraControlProxy {
Context context;
Expand Down Expand Up @@ -99,6 +99,10 @@ public void startFocusAndMetering(
@NonNull CameraControl cameraControl,
@NonNull FocusMeteringAction focusMeteringAction,
@NonNull GeneratedCameraXLibrary.Result<Long> result) {
if (context == null) {
throw new IllegalStateException("Context must be set to set zoom ratio.");
}

ListenableFuture<FocusMeteringResult> focusMeteringResultFuture =
cameraControl.startFocusAndMetering(focusMeteringAction);

Expand Down Expand Up @@ -173,6 +177,7 @@ public void onFailure(Throwable t) {
* Constructs an {@link CameraControlHostApiImpl}.
*
* @param instanceManager maintains instances stored to communicate with attached Dart objects
* @param context {@link Context} used to retrieve {@code Executor}
*/
public CameraControlHostApiImpl(
@NonNull BinaryMessenger binaryMessenger,
Expand All @@ -185,8 +190,8 @@ public CameraControlHostApiImpl(
* Constructs an {@link CameraControlHostApiImpl}.
*
* @param instanceManager maintains instances stored to communicate with attached Dart objects
* @param proxy proxy for constructors and static method of {@link CameraControl}
* @param context {@link Context} used to retrieve {@code Executor} used to enable torch mode
* @param proxy proxy for methods of {@link CameraControl}
* @param context {@link Context} used to retrieve {@code Executor}
*/
@VisibleForTesting
CameraControlHostApiImpl(
Expand All @@ -203,11 +208,11 @@ public CameraControlHostApiImpl(
}

/**
* Sets the context that the {@code ProcessCameraProvider} will use to enable/disable torch mode
* and set the zoom ratio.
* Sets the context that the {@code CameraControl} will use to enable/disable torch mode and set
* the zoom ratio.
*
* <p>If using the camera plugin in an add-to-app context, ensure that a new instance of the
* {@code CameraControl} is fetched via {@code #enableTorch} anytime the context changes.
* <p>If using the camera plugin in an add-to-app context, ensure that this is called anytime that
* the context changes.
*/
public void setContext(@NonNull Context context) {
this.proxy.context = context;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.camerax;

import android.hardware.camera2.CaptureRequest;
import androidx.annotation.NonNull;
import androidx.annotation.OptIn;
import androidx.annotation.VisibleForTesting;
import androidx.camera.camera2.interop.CaptureRequestOptions;
import io.flutter.plugins.camerax.GeneratedCameraXLibrary.CaptureRequestKeySupportedType;
import io.flutter.plugins.camerax.GeneratedCameraXLibrary.CaptureRequestOptionsHostApi;
import java.util.HashMap;
import java.util.Map;

/**
* Host API implementation for {@link CaptureRequestOptions}.
*
* <p>This class may handle instantiating and adding native object instances that are attached to a
* Dart instance or handle method calls on the associated native class or an instance of the class.
*/
public class CaptureRequestOptionsHostApiImpl implements CaptureRequestOptionsHostApi {
private final InstanceManager instanceManager;
private final CaptureRequestOptionsProxy proxy;

/** Proxy for constructor of {@link CaptureRequestOptions}. */
@VisibleForTesting
public static class CaptureRequestOptionsProxy {
/** Creates an instance of {@link CaptureRequestOptions}. */
// Suppression is safe because the type shared between the key and value pairs that
// represent capture request options is checked on the Dart side.
@SuppressWarnings("unchecked")
@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)
public @NonNull CaptureRequestOptions create(
@NonNull Map<CaptureRequestKeySupportedType, Object> options) {
CaptureRequestOptions.Builder builder = getCaptureRequestOptionsBuilder();

for (Map.Entry<CaptureRequestKeySupportedType, Object> option : options.entrySet()) {
CaptureRequestKeySupportedType optionKeyType = option.getKey();
CaptureRequest.Key<? extends Object> optionKey = getCaptureRequestKey(optionKeyType);
Object optionValue = option.getValue();

if (optionValue == null) {
builder.clearCaptureRequestOption(optionKey);
continue;
}

switch (optionKeyType) {
case CONTROL_AE_LOCK:
builder.setCaptureRequestOption(
(CaptureRequest.Key<Boolean>) optionKey, (Boolean) optionValue);
break;
default:
throw new IllegalArgumentException(
"The capture request key "
+ optionKeyType.toString()
+ "is not currently supported by the plugin.");
}
}

return builder.build();
}

private CaptureRequest.Key<? extends Object> getCaptureRequestKey(
CaptureRequestKeySupportedType type) {
CaptureRequest.Key<? extends Object> key;
switch (type) {
case CONTROL_AE_LOCK:
key = CaptureRequest.CONTROL_AE_LOCK;
break;
default:
throw new IllegalArgumentException(
"The capture request key is not currently supported by the plugin.");
}
return key;
}

@VisibleForTesting
@OptIn(markerClass = androidx.camera.camera2.interop.ExperimentalCamera2Interop.class)
public @NonNull CaptureRequestOptions.Builder getCaptureRequestOptionsBuilder() {
return new CaptureRequestOptions.Builder();
}
}

/**
* Constructs a {@link CaptureRequestOptionsHostApiImpl}.
*
* @param instanceManager maintains instances stored to communicate with attached Dart objects
*/
public CaptureRequestOptionsHostApiImpl(@NonNull InstanceManager instanceManager) {
this(instanceManager, new CaptureRequestOptionsProxy());
}

/**
* Constructs a {@link CaptureRequestOptionsHostApiImpl}.
*
* @param instanceManager maintains instances stored to communicate with attached Dart objects
* @param proxy proxy for constructor of {@link CaptureRequestOptions}
*/
@VisibleForTesting
CaptureRequestOptionsHostApiImpl(
@NonNull InstanceManager instanceManager, @NonNull CaptureRequestOptionsProxy proxy) {
this.instanceManager = instanceManager;
this.proxy = proxy;
}

@Override
public void create(@NonNull Long identifier, @NonNull Map<Long, Object> options) {
Map<CaptureRequestKeySupportedType, Object> decodedOptions =
new HashMap<CaptureRequestKeySupportedType, Object>();
for (Map.Entry<Long, Object> option : options.entrySet()) {
decodedOptions.put(
CaptureRequestKeySupportedType.values()[option.getKey().intValue()], option.getValue());
}
instanceManager.addDartCreatedInstance(proxy.create(decodedOptions), identifier);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class FallbackStrategyHostApiImpl implements FallbackStrategyHostApi {

private final FallbackStrategyProxy proxy;

/** Proxy for constructors and static method of {@link FallbackStrategy}. */
/** Proxy for constructor of {@link FallbackStrategy}. */
@VisibleForTesting
public static class FallbackStrategyProxy {
/** Creates an instance of {@link FallbackStrategy}. */
Expand Down Expand Up @@ -59,7 +59,7 @@ public FallbackStrategyHostApiImpl(@NonNull InstanceManager instanceManager) {
* Constructs a {@link FallbackStrategyHostApiImpl}.
*
* @param instanceManager maintains instances stored to communicate with attached Dart objects
* @param proxy proxy for constructors and static method of {@link FallbackStrategy}
* @param proxy proxy for constructor of {@link FallbackStrategy}
*/
FallbackStrategyHostApiImpl(
@NonNull InstanceManager instanceManager, @NonNull FallbackStrategyProxy proxy) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class FocusMeteringActionHostApiImpl implements FocusMeteringActionHostAp

private final FocusMeteringActionProxy proxy;

/** Proxy for constructors and static method of {@link FocusMeteringAction}. */
/** Proxy for constructor of {@link FocusMeteringAction}. */
@VisibleForTesting
public static class FocusMeteringActionProxy {
/** Creates an instance of {@link FocusMeteringAction}. */
Expand Down Expand Up @@ -90,7 +90,7 @@ public FocusMeteringActionHostApiImpl(@NonNull InstanceManager instanceManager)
* Constructs a {@link FocusMeteringActionHostApiImpl}.
*
* @param instanceManager maintains instances stored to communicate with attached Dart objects
* @param proxy proxy for constructors and static method of {@link FocusMeteringAction}
* @param proxy proxy for constructor of {@link FocusMeteringAction}
*/
FocusMeteringActionHostApiImpl(
@NonNull InstanceManager instanceManager, @NonNull FocusMeteringActionProxy proxy) {
Expand Down
Loading