Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 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
4 changes: 4 additions & 0 deletions packages/camera/camera_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.10.9+14

* Converts native to Dart platform calls to Pigeon.

## 0.10.9+13

* Converts `getAvailableCameras` to Pigeon.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import android.hardware.camera2.CameraMetadata;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
import io.flutter.plugins.camera.features.autofocus.FocusMode;
import io.flutter.plugins.camera.features.exposurelock.ExposureMode;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -143,4 +145,62 @@ public static List<Messages.PlatformCameraDescription> getAvailableCameras(
}
return cameras;
}

/**
* Converts a DeviceOrientation from the systemchannels package to a PlatformDeviceOrientation
* from Pigeon.
*
* @param orientation A DeviceOrientation.
* @return The corresponding PlatformDeviceOrientation.
*/
@NonNull
public static Messages.PlatformDeviceOrientation orientationToPigeon(
@NonNull PlatformChannel.DeviceOrientation orientation) {
switch (orientation) {
case PORTRAIT_UP:
return Messages.PlatformDeviceOrientation.PORTRAIT_UP;
case PORTRAIT_DOWN:
return Messages.PlatformDeviceOrientation.PORTRAIT_DOWN;
case LANDSCAPE_LEFT:
return Messages.PlatformDeviceOrientation.LANDSCAPE_LEFT;
case LANDSCAPE_RIGHT:
return Messages.PlatformDeviceOrientation.LANDSCAPE_RIGHT;
}
return Messages.PlatformDeviceOrientation.PORTRAIT_UP;
}

/**
* Converts a FocusMode from the autofocus package to a PlatformFocusMode from Pigeon.
*
* @param focusMode A FocusMode.
* @return The corresponding PlatformFocusMode.
*/
@NonNull
public static Messages.PlatformFocusMode focusModeToPigeon(@NonNull FocusMode focusMode) {
switch (focusMode) {
case auto:
return Messages.PlatformFocusMode.AUTO;
case locked:
return Messages.PlatformFocusMode.LOCKED;
}
return Messages.PlatformFocusMode.AUTO;
}

/**
* Converts an ExposureMode from the exposurelock package to a PlatformExposureMode from Pigeon.
*
* @param exposureMode An ExposureMode.
* @return The corresponding PlatformExposureMode.
*/
@NonNull
public static Messages.PlatformExposureMode exposureModeToPigeon(
@NonNull ExposureMode exposureMode) {
switch (exposureMode) {
case auto:
return Messages.PlatformExposureMode.AUTO;
case locked:
return Messages.PlatformExposureMode.LOCKED;
}
return Messages.PlatformExposureMode.AUTO;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,69 +5,36 @@
package io.flutter.plugins.camera;

import android.os.Handler;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.camera.features.autofocus.FocusMode;
import io.flutter.plugins.camera.features.exposurelock.ExposureMode;
import java.util.HashMap;
import java.util.Map;

/** Utility class that facilitates communication to the Flutter client */
public class DartMessenger {
@NonNull private final Handler handler;
@Nullable MethodChannel cameraChannel;
@Nullable MethodChannel deviceChannel;

/** Specifies the different device related message types. */
enum DeviceEventType {
/** Indicates the device's orientation has changed. */
ORIENTATION_CHANGED("orientation_changed");
final String method;

DeviceEventType(String method) {
this.method = method;
}
}

/** Specifies the different camera related message types. */
enum CameraEventType {
/** Indicates that an error occurred while interacting with the camera. */
ERROR("error"),
/** Indicates that the camera is closing. */
CLOSING("camera_closing"),
/** Indicates that the camera is initialized. */
INITIALIZED("initialized");

final String method;

/**
* Converts the supplied method name to the matching {@link CameraEventType}.
*
* @param method name to be converted into a {@link CameraEventType}.
*/
CameraEventType(String method) {
this.method = method;
}
}
Messages.CameraGlobalEventApi globalEventApi;
Messages.CameraEventApi eventApi;

/**
* Creates a new instance of the {@link DartMessenger} class.
*
* @param messenger is the {@link BinaryMessenger} that is used to communicate with Flutter.
* @param cameraId identifies the camera which is the source of the communication.
* @param handler the handler used to manage the thread's message queue. This should always be a
* handler managing the main thread since communication with Flutter should always happen on
* the main thread. The handler is mainly supplied so it will be easier test this class.
* @param globalEventApi the API used to consume calls to dart that are not tied to a specific
* camera instance.
* @param eventApi the API used to consume calls to dart that are tied to this specific camera.
*/
DartMessenger(BinaryMessenger messenger, long cameraId, @NonNull Handler handler) {
cameraChannel =
new MethodChannel(messenger, "plugins.flutter.io/camera_android/camera" + cameraId);
deviceChannel = new MethodChannel(messenger, "plugins.flutter.io/camera_android/fromPlatform");
DartMessenger(
@NonNull Handler handler,
Messages.CameraGlobalEventApi globalEventApi,
Messages.CameraEventApi eventApi) {
this.handler = handler;
this.globalEventApi = globalEventApi;
this.eventApi = eventApi;
}

/**
Expand All @@ -77,13 +44,10 @@ enum CameraEventType {
*/
public void sendDeviceOrientationChangeEvent(
@NonNull PlatformChannel.DeviceOrientation orientation) {
this.send(
DeviceEventType.ORIENTATION_CHANGED,
new HashMap<String, Object>() {
{
put("orientation", CameraUtils.serializeDeviceOrientation(orientation));
}
});
handler.post(
() ->
globalEventApi.deviceOrientationChanged(
CameraUtils.orientationToPigeon(orientation), new NoOpVoidResult()));
}

/**
Expand All @@ -109,23 +73,26 @@ void sendCameraInitializedEvent(
assert (focusMode != null);
assert (exposurePointSupported != null);
assert (focusPointSupported != null);
this.send(
CameraEventType.INITIALIZED,
new HashMap<String, Object>() {
{
put("previewWidth", previewWidth.doubleValue());
put("previewHeight", previewHeight.doubleValue());
put("exposureMode", exposureMode.toString());
put("focusMode", focusMode.toString());
put("exposurePointSupported", exposurePointSupported);
put("focusPointSupported", focusPointSupported);
}
});
handler.post(
() ->
eventApi.initialized(
new Messages.PlatformCameraState.Builder()
.setPreviewSize(
new Messages.PlatformSize.Builder()
.setWidth(previewWidth.doubleValue())
.setHeight(previewHeight.doubleValue())
.build())
.setExposurePointSupported(exposurePointSupported)
.setFocusPointSupported(focusPointSupported)
.setExposureMode(CameraUtils.exposureModeToPigeon(exposureMode))
.setFocusMode(CameraUtils.focusModeToPigeon(focusMode))
.build(),
new NoOpVoidResult()));
}

/** Sends a message to the Flutter client informing that the camera is closing. */
void sendCameraClosingEvent() {
send(CameraEventType.CLOSING);
handler.post(() -> eventApi.closed(new NoOpVoidResult()));
}

/**
Expand All @@ -135,43 +102,8 @@ void sendCameraClosingEvent() {
* @param description contains details regarding the error that occurred.
*/
void sendCameraErrorEvent(@Nullable String description) {
this.send(
CameraEventType.ERROR,
new HashMap<String, Object>() {
{
if (!TextUtils.isEmpty(description)) put("description", description);
}
});
}

private void send(CameraEventType eventType) {
send(eventType, new HashMap<>());
}

private void send(CameraEventType eventType, Map<String, Object> args) {
if (cameraChannel == null) {
return;
}

handler.post(
new Runnable() {
@Override
public void run() {
cameraChannel.invokeMethod(eventType.method, args);
}
});
}

private void send(DeviceEventType eventType) {
send(eventType, new HashMap<>());
}

private void send(DeviceEventType eventType, Map<String, Object> args) {
if (deviceChannel == null) {
return;
}

handler.post(() -> deviceChannel.invokeMethod(eventType.method, args));
String errorMessage = (description == null) ? "" : description;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minimal null check as description is Nullable.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you put a TODO (with an issue link) on this line to fix description being nullable and update any failing call sites? Actually fixing it is out of scope of this PR, but the fact that we need this line is a significant problem since there's no other content in the message, so if we ever actually do this, the plugin client will get absolutely no actionable information.

handler.post(() -> eventApi.error(errorMessage, new NoOpVoidResult()));
}

/**
Expand Down
Loading