-
Notifications
You must be signed in to change notification settings - Fork 9.8k
[camera] Add CameraSelector class to CameraX plugin #6348
Conversation
e3cf18f
to
28a9247
Compare
} | ||
|
||
List<CameraInfo> filteredCameraInfos = cameraSelector.filter(cameraInfosForFilter); | ||
final CameraInfoFlutterApiImpl cameraInfoFlutterApiImpl = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this class is used in multiple methods, you could make it a private field in the constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other method uses CameraSelectorFlutterApiImpl
. I don't plan on implementing any other methods in this class for now (flutter/flutter#111124), so I'l leave them as local variables, but can definitely change that if I end up reusing either!
...roid_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraSelectorHostApiImpl.java
Show resolved
Hide resolved
} | ||
|
||
@Override | ||
public Long requireLensFacing(@NonNull Long lensDirection) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a better pattern would be to change this to a create
method with this value as a parameter. And then the Dart class would have an additional normal constructor that sets this field. e.g.
class CameraSelector extends JavaObject {
CameraSelector({
int lensFacing,
super.binaryMessenger,
super.instanceManager,
}) : _api = CameraSelectorHostApiImpl(
binaryMessenger: binaryMessenger,
instanceManager: instanceManager,
),
super.detached() {
AndroidCameraXCameraFlutterApis.instance.ensureSetUp();
_api.createFromInstances(this, lensFacing);
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And the create
method
- Create the builder
- set the lens facing.
- Build the selector
- add the selector to the instancemanager
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the pattern you've typically followed for the builder pattern? I think this makes sense but just wondering about the context on moving away from the Android Api.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So in most situations, we do want to follow the Java API because it makes our wrapper API more resistant to changes of the Java API. However, the pattern explained above is often considered, unofficially, as the "Dart equivalent" to the Java Builder Pattern. The main reason you never see the builder pattern in Dart is because Dart has language features that makes it obsolete.
So in situations like this, where a superior Dart equivalent pattern exists, we can go with the "Dartier" pattern. It should also probably be considered case by case. As far as I can tell, I don't see any downsides to doing it for CameraSelector
.
static const int LENS_FACING_BACK = 1; | ||
|
||
/// Selector for default front facing camera. | ||
static final Future<CameraSelector> defaultFrontCamera = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if this is guaranteed to be correct that the Java:
DEFAULT_BACK_CAMERA == new CameraSelector.Builder().requireLensFacing(LENS_FACING_BACK).build()
I think this method could use the attach
pattern from the Wrapping Native Api
s doc. It would also make it synchronous. e.g.
static CameraSelector defaultFrontCamera({
BinaryMessenger? binaryMessenger,
InstanceManager? instanceManager,
}) {
final CameraSelector cameraSelector = CameraSelector.detached();
CameraSelectorHostApiImpl(
binaryMessenger: binaryMessenger,
instanceManager: instanceManager,
).attachDefaultFrontCameraFromInstances(cameraSelector);
return cameraSelector;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
@Override | ||
public List<Long> filter(@NonNull Long identifier, @NonNull List<Long> cameraInfoIds) { | ||
CameraSelector cameraSelector = (CameraSelector) instanceManager.getInstance(identifier); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method implementation is a good sign for me to make improvements to this design. Nothing needs to be done for this comment, I'm just letting you know that I'm going to work on helper methods for InstanceManager to improve working with Lists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha. I agree that would be super useful!
...roid_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraSelectorHostApiImpl.java
Outdated
Show resolved
Hide resolved
...camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/InstanceManager.java
Outdated
Show resolved
Hide resolved
packages/camera/camera_android_camerax/lib/src/camera_selector.dart
Outdated
Show resolved
Hide resolved
packages/camera/camera_android_camerax/pigeons/camerax_library.dart
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
private final BinaryMessenger binaryMessenger; | ||
private final InstanceManager instanceManager; | ||
|
||
@VisibleForTesting public CameraSelector.Builder cameraSelectorBuilder; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional:
So having a settable parameter like this is pretty typical for testing the create
methods in host apis. However, most classes don't use builders and you will have to test the constructor. It's worth considering using a proxy class to handle all your class instantiations and static methods. For example
class CameraXProxy {
CameraSelector createCameraSelector(lensFacing) {
// build and return
}
ACameraXClass createACameraXClass() {
return new ACameraXClass();
}
void staticMethodForACameraXClass() {
ACameraXClass.staticMethod();
}
}
And then you can add this value to any HostApi
that has a create
method. And mock it in tests.
You could also create a separate proxy for each host api. (e.g. CameraSelectorProxy
).
Adds
CameraSelector
class wrapper to CameraX plugin.Part of flutter/flutter#111124.
Pre-launch Checklist
dart format
.)[shared_preferences]
pubspec.yaml
with an appropriate new version according to the pub versioning philosophy, or this PR is exempt from version changes.CHANGELOG.md
to add a description of the change, following repository CHANGELOG style.///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.