Skip to content

Commit

Permalink
[camera_android] Begin conversion to Pigeon (#7755)
Browse files Browse the repository at this point in the history
Convert one method to use Pigeon to setup the backbone of future
conversions. Android analog of
#6553

Part of flutter/flutter#117905

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] page, which explains my
responsibilities.
- [x] I read and followed the [relevant style guides] and ran the
auto-formatter. (Unlike the flutter/flutter repo, the flutter/packages
repo does use `dart format`.)
- [ ] I signed the [CLA].
- [x] The title of the PR starts with the name of the package surrounded
by square brackets, e.g. `[shared_preferences]`
- [x] I [linked to at least one issue that this PR fixes] in the
description above.
- [x] I updated `pubspec.yaml` with an appropriate new version according
to the [pub versioning philosophy], or this PR is [exempt from version
changes].
- [x] I updated `CHANGELOG.md` to add a description of the change,
[following repository CHANGELOG style], or this PR is [exempt from
CHANGELOG changes].
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/packages/blob/main/CONTRIBUTING.md
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md
[relevant style guides]:
https://github.com/flutter/packages/blob/main/CONTRIBUTING.md#style
[CLA]: https://cla.developers.google.com/
[Discord]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Chat.md
[linked to at least one issue that this PR fixes]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#overview
[pub versioning philosophy]: https://dart.dev/tools/pub/versioning
[exempt from version changes]:
https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#version
[following repository CHANGELOG style]:
https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changelog-style
[exempt from CHANGELOG changes]:
https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changelog
[test-exempt]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#tests
  • Loading branch information
yaakovschectman authored Oct 9, 2024
1 parent 44e7d73 commit d3bfaff
Show file tree
Hide file tree
Showing 14 changed files with 628 additions and 103 deletions.
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+13

* Converts `getAvailableCameras` to Pigeon.

## 0.10.9+12

* Updates Java compatibility version to 11.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/** Provides various utilities for camera. */
public final class CameraUtils {
Expand Down Expand Up @@ -85,6 +83,27 @@ static PlatformChannel.DeviceOrientation deserializeDeviceOrientation(String ori
}
}

/**
* Converts a raw integer to a PlatformCameraLensDirection enum.
*
* @param lensDirection One of CameraMetadata.LENS_FACING_FRONT, LENS_FACING_BACK, or
* LENS_FACING_EXTERNAL.
* @return One of Messages.PlatformCameraLensDirection.FRONT, BACK, or EXTERNAL.
*/
static Messages.PlatformCameraLensDirection lensDirectionFromInteger(int lensDirection) {
switch (lensDirection) {
case CameraMetadata.LENS_FACING_FRONT:
return Messages.PlatformCameraLensDirection.FRONT;
case CameraMetadata.LENS_FACING_BACK:
return Messages.PlatformCameraLensDirection.BACK;
case CameraMetadata.LENS_FACING_EXTERNAL:
return Messages.PlatformCameraLensDirection.EXTERNAL;
}
// CameraMetadata is defined in the Android API. In the event that a new value is added, a
// default fallback value of FRONT is returned.
return Messages.PlatformCameraLensDirection.FRONT;
}

/**
* Gets all the available cameras for the device.
*
Expand All @@ -93,11 +112,11 @@ static PlatformChannel.DeviceOrientation deserializeDeviceOrientation(String ori
* @throws CameraAccessException when the camera could not be accessed.
*/
@NonNull
public static List<Map<String, Object>> getAvailableCameras(@NonNull Activity activity)
throws CameraAccessException {
public static List<Messages.PlatformCameraDescription> getAvailableCameras(
@NonNull Activity activity) throws CameraAccessException {
CameraManager cameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
String[] cameraNames = cameraManager.getCameraIdList();
List<Map<String, Object>> cameras = new ArrayList<>();
List<Messages.PlatformCameraDescription> cameras = new ArrayList<>();
for (String cameraName : cameraNames) {
int cameraId;
try {
Expand All @@ -109,24 +128,17 @@ public static List<Map<String, Object>> getAvailableCameras(@NonNull Activity ac
continue;
}

HashMap<String, Object> details = new HashMap<>();
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraName);
details.put("name", cameraName);
int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
details.put("sensorOrientation", sensorOrientation);

int lensFacing = characteristics.get(CameraCharacteristics.LENS_FACING);
switch (lensFacing) {
case CameraMetadata.LENS_FACING_FRONT:
details.put("lensFacing", "front");
break;
case CameraMetadata.LENS_FACING_BACK:
details.put("lensFacing", "back");
break;
case CameraMetadata.LENS_FACING_EXTERNAL:
details.put("lensFacing", "external");
break;
}
Messages.PlatformCameraLensDirection lensDirection = lensDirectionFromInteger(lensFacing);
Messages.PlatformCameraDescription details =
new Messages.PlatformCameraDescription.Builder()
.setName(cameraName)
.setSensorOrientation((long) sensorOrientation)
.setLensDirection(lensDirection)
.build();
cameras.add(details);
}
return cameras;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
// 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.
// Autogenerated from Pigeon (v22.4.1), do not edit directly.
// See also: https://pub.dev/packages/pigeon

package io.flutter.plugins.camera;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.CLASS;

import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.plugin.common.BasicMessageChannel;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MessageCodec;
import io.flutter.plugin.common.StandardMessageCodec;
import java.io.ByteArrayOutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/** Generated class from Pigeon. */
@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression", "serial"})
public class Messages {

/** Error class for passing custom error details to Flutter via a thrown PlatformException. */
public static class FlutterError extends RuntimeException {

/** The error code. */
public final String code;

/** The error details. Must be a datatype supported by the api codec. */
public final Object details;

public FlutterError(@NonNull String code, @Nullable String message, @Nullable Object details) {
super(message);
this.code = code;
this.details = details;
}
}

@NonNull
protected static ArrayList<Object> wrapError(@NonNull Throwable exception) {
ArrayList<Object> errorList = new ArrayList<>(3);
if (exception instanceof FlutterError) {
FlutterError error = (FlutterError) exception;
errorList.add(error.code);
errorList.add(error.getMessage());
errorList.add(error.details);
} else {
errorList.add(exception.toString());
errorList.add(exception.getClass().getSimpleName());
errorList.add(
"Cause: " + exception.getCause() + ", Stacktrace: " + Log.getStackTraceString(exception));
}
return errorList;
}

@Target(METHOD)
@Retention(CLASS)
@interface CanIgnoreReturnValue {}

public enum PlatformCameraLensDirection {
FRONT(0),
BACK(1),
EXTERNAL(2);

final int index;

PlatformCameraLensDirection(final int index) {
this.index = index;
}
}

/** Generated class from Pigeon that represents data sent in messages. */
public static final class PlatformCameraDescription {
private @NonNull String name;

public @NonNull String getName() {
return name;
}

public void setName(@NonNull String setterArg) {
if (setterArg == null) {
throw new IllegalStateException("Nonnull field \"name\" is null.");
}
this.name = setterArg;
}

private @NonNull PlatformCameraLensDirection lensDirection;

public @NonNull PlatformCameraLensDirection getLensDirection() {
return lensDirection;
}

public void setLensDirection(@NonNull PlatformCameraLensDirection setterArg) {
if (setterArg == null) {
throw new IllegalStateException("Nonnull field \"lensDirection\" is null.");
}
this.lensDirection = setterArg;
}

private @NonNull Long sensorOrientation;

public @NonNull Long getSensorOrientation() {
return sensorOrientation;
}

public void setSensorOrientation(@NonNull Long setterArg) {
if (setterArg == null) {
throw new IllegalStateException("Nonnull field \"sensorOrientation\" is null.");
}
this.sensorOrientation = setterArg;
}

/** Constructor is non-public to enforce null safety; use Builder. */
PlatformCameraDescription() {}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
PlatformCameraDescription that = (PlatformCameraDescription) o;
return name.equals(that.name)
&& lensDirection.equals(that.lensDirection)
&& sensorOrientation.equals(that.sensorOrientation);
}

@Override
public int hashCode() {
return Objects.hash(name, lensDirection, sensorOrientation);
}

public static final class Builder {

private @Nullable String name;

@CanIgnoreReturnValue
public @NonNull Builder setName(@NonNull String setterArg) {
this.name = setterArg;
return this;
}

private @Nullable PlatformCameraLensDirection lensDirection;

@CanIgnoreReturnValue
public @NonNull Builder setLensDirection(@NonNull PlatformCameraLensDirection setterArg) {
this.lensDirection = setterArg;
return this;
}

private @Nullable Long sensorOrientation;

@CanIgnoreReturnValue
public @NonNull Builder setSensorOrientation(@NonNull Long setterArg) {
this.sensorOrientation = setterArg;
return this;
}

public @NonNull PlatformCameraDescription build() {
PlatformCameraDescription pigeonReturn = new PlatformCameraDescription();
pigeonReturn.setName(name);
pigeonReturn.setLensDirection(lensDirection);
pigeonReturn.setSensorOrientation(sensorOrientation);
return pigeonReturn;
}
}

@NonNull
ArrayList<Object> toList() {
ArrayList<Object> toListResult = new ArrayList<>(3);
toListResult.add(name);
toListResult.add(lensDirection);
toListResult.add(sensorOrientation);
return toListResult;
}

static @NonNull PlatformCameraDescription fromList(@NonNull ArrayList<Object> pigeonVar_list) {
PlatformCameraDescription pigeonResult = new PlatformCameraDescription();
Object name = pigeonVar_list.get(0);
pigeonResult.setName((String) name);
Object lensDirection = pigeonVar_list.get(1);
pigeonResult.setLensDirection((PlatformCameraLensDirection) lensDirection);
Object sensorOrientation = pigeonVar_list.get(2);
pigeonResult.setSensorOrientation((Long) sensorOrientation);
return pigeonResult;
}
}

private static class PigeonCodec extends StandardMessageCodec {
public static final PigeonCodec INSTANCE = new PigeonCodec();

private PigeonCodec() {}

@Override
protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) {
switch (type) {
case (byte) 129:
{
Object value = readValue(buffer);
return value == null
? null
: PlatformCameraLensDirection.values()[((Long) value).intValue()];
}
case (byte) 130:
return PlatformCameraDescription.fromList((ArrayList<Object>) readValue(buffer));
default:
return super.readValueOfType(type, buffer);
}
}

@Override
protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) {
if (value instanceof PlatformCameraLensDirection) {
stream.write(129);
writeValue(stream, value == null ? null : ((PlatformCameraLensDirection) value).index);
} else if (value instanceof PlatformCameraDescription) {
stream.write(130);
writeValue(stream, ((PlatformCameraDescription) value).toList());
} else {
super.writeValue(stream, value);
}
}
}

/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface CameraApi {

@NonNull
List<PlatformCameraDescription> getAvailableCameras();

/** The codec used by CameraApi. */
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);
}

static void setUp(
@NonNull BinaryMessenger binaryMessenger,
@NonNull String messageChannelSuffix,
@Nullable CameraApi api) {
messageChannelSuffix = messageChannelSuffix.isEmpty() ? "" : "." + messageChannelSuffix;
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.camera_android.CameraApi.getAvailableCameras"
+ messageChannelSuffix,
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<>();
try {
List<PlatformCameraDescription> output = api.getAvailableCameras();
wrapped.add(0, output);
} catch (Throwable exception) {
wrapped = wrapError(exception);
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
}
}
}
Loading

0 comments on commit d3bfaff

Please sign in to comment.