Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit fb966fb

Browse files
author
Chris Yang
committed
Merge branch 'master' into gmap_custom_tiles_platform_interface
2 parents 83dc4ea + 0434f06 commit fb966fb

32 files changed

+1271
-145
lines changed

packages/camera/camera/CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## 0.7.0
2+
3+
* Added support for capture orientation locking on Android and iOS.
4+
* Fixed camera preview not rotating correctly on Android and iOS.
5+
* Fixed camera preview sometimes appearing stretched on Android and iOS.
6+
* Fixed videos & photos saving with the incorrect rotation on iOS.
7+
* BREAKING CHANGE: `CameraValue.aspectRatio` now returns `width / height` rather than `height / width`.
8+
19
## 0.6.6
210

311
* Adds auto focus support for Android and iOS implementations.
@@ -20,7 +28,7 @@
2028

2129
## 0.6.4+2
2230

23-
* Set ImageStreamReader listener to null to prevent stale images when streaming images.
31+
* Set ImageStreamReader listener to null to prevent stale images when streaming images.
2432

2533
## 0.6.4+1
2634

packages/camera/camera/android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ project.getTasks().withType(JavaCompile){
2727
apply plugin: 'com.android.library'
2828

2929
android {
30-
compileSdkVersion 29
30+
compileSdkVersion 30
3131

3232
defaultConfig {
3333
minSdkVersion 21

packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
package io.flutter.plugins.camera;
66

7-
import static android.view.OrientationEventListener.ORIENTATION_UNKNOWN;
87
import static io.flutter.plugins.camera.CameraUtils.computeBestPreviewSize;
98

109
import android.annotation.SuppressLint;
@@ -41,10 +40,10 @@
4140
import android.util.Range;
4241
import android.util.Rational;
4342
import android.util.Size;
44-
import android.view.OrientationEventListener;
4543
import android.view.Surface;
4644
import androidx.annotation.NonNull;
4745
import androidx.annotation.Nullable;
46+
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
4847
import io.flutter.plugin.common.EventChannel;
4948
import io.flutter.plugin.common.MethodChannel.Result;
5049
import io.flutter.plugins.camera.PictureCaptureRequest.State;
@@ -76,7 +75,7 @@ public class Camera {
7675

7776
private final SurfaceTextureEntry flutterTexture;
7877
private final CameraManager cameraManager;
79-
private final OrientationEventListener orientationEventListener;
78+
private final DeviceOrientationManager deviceOrientationListener;
8079
private final boolean isFrontFacing;
8180
private final int sensorOrientation;
8281
private final String cameraName;
@@ -97,7 +96,6 @@ public class Camera {
9796
private MediaRecorder mediaRecorder;
9897
private boolean recordingVideo;
9998
private File videoRecordingFile;
100-
private int currentOrientation = ORIENTATION_UNKNOWN;
10199
private FlashMode flashMode;
102100
private ExposureMode exposureMode;
103101
private FocusMode focusMode;
@@ -106,6 +104,7 @@ public class Camera {
106104
private int exposureOffset;
107105
private boolean useAutoFocus = true;
108106
private Range<Integer> fpsRange;
107+
private PlatformChannel.DeviceOrientation lockedCaptureOrientation;
109108

110109
private static final HashMap<String, Integer> supportedImageFormats;
111110
// Current supported outputs
@@ -136,18 +135,6 @@ public Camera(
136135
this.exposureMode = ExposureMode.auto;
137136
this.focusMode = FocusMode.auto;
138137
this.exposureOffset = 0;
139-
orientationEventListener =
140-
new OrientationEventListener(activity.getApplicationContext()) {
141-
@Override
142-
public void onOrientationChanged(int i) {
143-
if (i == ORIENTATION_UNKNOWN) {
144-
return;
145-
}
146-
// Convert the raw deg angle to the nearest multiple of 90.
147-
currentOrientation = (int) Math.round(i / 90.0) * 90;
148-
}
149-
};
150-
orientationEventListener.enable();
151138

152139
cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraName);
153140
initFps(cameraCharacteristics);
@@ -164,6 +151,10 @@ public void onOrientationChanged(int i) {
164151
new CameraZoom(
165152
cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE),
166153
cameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM));
154+
155+
deviceOrientationListener =
156+
new DeviceOrientationManager(activity, dartMessenger, isFrontFacing, sensorOrientation);
157+
deviceOrientationListener.start();
167158
}
168159

169160
private void initFps(CameraCharacteristics cameraCharacteristics) {
@@ -195,7 +186,10 @@ private void prepareMediaRecorder(String outputFilePath) throws IOException {
195186
mediaRecorder =
196187
new MediaRecorderBuilder(recordingProfile, outputFilePath)
197188
.setEnableAudio(enableAudio)
198-
.setMediaOrientation(getMediaOrientation())
189+
.setMediaOrientation(
190+
lockedCaptureOrientation == null
191+
? deviceOrientationListener.getMediaOrientation()
192+
: deviceOrientationListener.getMediaOrientation(lockedCaptureOrientation))
199193
.build();
200194
}
201195

@@ -545,7 +539,11 @@ private void runPictureCapture() {
545539
final CaptureRequest.Builder captureBuilder =
546540
cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
547541
captureBuilder.addTarget(pictureImageReader.getSurface());
548-
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getMediaOrientation());
542+
captureBuilder.set(
543+
CaptureRequest.JPEG_ORIENTATION,
544+
lockedCaptureOrientation == null
545+
? deviceOrientationListener.getMediaOrientation()
546+
: deviceOrientationListener.getMediaOrientation(lockedCaptureOrientation));
549547
switch (flashMode) {
550548
case off:
551549
captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
@@ -968,6 +966,14 @@ public void setZoomLevel(@NonNull final Result result, float zoom) throws Camera
968966
result.success(null);
969967
}
970968

969+
public void lockCaptureOrientation(PlatformChannel.DeviceOrientation orientation) {
970+
this.lockedCaptureOrientation = orientation;
971+
}
972+
973+
public void unlockCaptureOrientation() {
974+
this.lockedCaptureOrientation = null;
975+
}
976+
971977
private void updateFpsRange() {
972978
if (fpsRange == null) {
973979
return;
@@ -1160,14 +1166,6 @@ public void close() {
11601166
public void dispose() {
11611167
close();
11621168
flutterTexture.release();
1163-
orientationEventListener.disable();
1164-
}
1165-
1166-
private int getMediaOrientation() {
1167-
final int sensorOrientationOffset =
1168-
(currentOrientation == ORIENTATION_UNKNOWN)
1169-
? 0
1170-
: (isFrontFacing) ? -currentOrientation : currentOrientation;
1171-
return (sensorOrientationOffset + sensorOrientation + 360) % 360;
1169+
deviceOrientationListener.stop();
11721170
}
11731171
}

packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import android.hardware.camera2.params.StreamConfigurationMap;
1515
import android.media.CamcorderProfile;
1616
import android.util.Size;
17+
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
1718
import io.flutter.plugins.camera.types.ResolutionPreset;
1819
import java.util.ArrayList;
1920
import java.util.Arrays;
@@ -28,6 +29,59 @@ public final class CameraUtils {
2829

2930
private CameraUtils() {}
3031

32+
static PlatformChannel.DeviceOrientation getDeviceOrientationFromDegrees(int degrees) {
33+
// Round to the nearest 90 degrees.
34+
degrees = (int) (Math.round(degrees / 90.0) * 90) % 360;
35+
// Determine the corresponding device orientation.
36+
switch (degrees) {
37+
case 90:
38+
return PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT;
39+
case 180:
40+
return PlatformChannel.DeviceOrientation.PORTRAIT_DOWN;
41+
case 270:
42+
return PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT;
43+
case 0:
44+
default:
45+
return PlatformChannel.DeviceOrientation.PORTRAIT_UP;
46+
}
47+
}
48+
49+
static String serializeDeviceOrientation(PlatformChannel.DeviceOrientation orientation) {
50+
if (orientation == null)
51+
throw new UnsupportedOperationException("Could not serialize null device orientation.");
52+
switch (orientation) {
53+
case PORTRAIT_UP:
54+
return "portraitUp";
55+
case PORTRAIT_DOWN:
56+
return "portraitDown";
57+
case LANDSCAPE_LEFT:
58+
return "landscapeLeft";
59+
case LANDSCAPE_RIGHT:
60+
return "landscapeRight";
61+
default:
62+
throw new UnsupportedOperationException(
63+
"Could not serialize device orientation: " + orientation.toString());
64+
}
65+
}
66+
67+
static PlatformChannel.DeviceOrientation deserializeDeviceOrientation(String orientation) {
68+
if (orientation == null)
69+
throw new UnsupportedOperationException("Could not deserialize null device orientation.");
70+
switch (orientation) {
71+
case "portraitUp":
72+
return PlatformChannel.DeviceOrientation.PORTRAIT_UP;
73+
case "portraitDown":
74+
return PlatformChannel.DeviceOrientation.PORTRAIT_DOWN;
75+
case "landscapeLeft":
76+
return PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT;
77+
case "landscapeRight":
78+
return PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT;
79+
default:
80+
throw new UnsupportedOperationException(
81+
"Could not deserialize device orientation: " + orientation);
82+
}
83+
}
84+
3185
static Size computeBestPreviewSize(String cameraName, ResolutionPreset preset) {
3286
if (preset.ordinal() > ResolutionPreset.high.ordinal()) {
3387
preset = ResolutionPreset.high;

packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import android.text.TextUtils;
88
import androidx.annotation.Nullable;
9+
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
910
import io.flutter.plugin.common.BinaryMessenger;
1011
import io.flutter.plugin.common.MethodChannel;
1112
import io.flutter.plugins.camera.types.ExposureMode;
@@ -14,16 +15,44 @@
1415
import java.util.Map;
1516

1617
class DartMessenger {
17-
@Nullable private MethodChannel channel;
18+
@Nullable private MethodChannel cameraChannel;
19+
@Nullable private MethodChannel deviceChannel;
1820

19-
enum EventType {
20-
ERROR,
21-
CAMERA_CLOSING,
22-
INITIALIZED,
21+
enum DeviceEventType {
22+
ORIENTATION_CHANGED("orientation_changed");
23+
private final String method;
24+
25+
DeviceEventType(String method) {
26+
this.method = method;
27+
}
28+
}
29+
30+
enum CameraEventType {
31+
ERROR("error"),
32+
CLOSING("camera_closing"),
33+
INITIALIZED("initialized");
34+
35+
private final String method;
36+
37+
CameraEventType(String method) {
38+
this.method = method;
39+
}
2340
}
2441

2542
DartMessenger(BinaryMessenger messenger, long cameraId) {
26-
channel = new MethodChannel(messenger, "flutter.io/cameraPlugin/camera" + cameraId);
43+
cameraChannel = new MethodChannel(messenger, "flutter.io/cameraPlugin/camera" + cameraId);
44+
deviceChannel = new MethodChannel(messenger, "flutter.io/cameraPlugin/device");
45+
}
46+
47+
void sendDeviceOrientationChangeEvent(PlatformChannel.DeviceOrientation orientation) {
48+
assert (orientation != null);
49+
this.send(
50+
DeviceEventType.ORIENTATION_CHANGED,
51+
new HashMap<String, Object>() {
52+
{
53+
put("orientation", CameraUtils.serializeDeviceOrientation(orientation));
54+
}
55+
});
2756
}
2857

2958
void sendCameraInitializedEvent(
@@ -40,7 +69,7 @@ void sendCameraInitializedEvent(
4069
assert (exposurePointSupported != null);
4170
assert (focusPointSupported != null);
4271
this.send(
43-
EventType.INITIALIZED,
72+
CameraEventType.INITIALIZED,
4473
new HashMap<String, Object>() {
4574
{
4675
put("previewWidth", previewWidth.doubleValue());
@@ -54,27 +83,38 @@ void sendCameraInitializedEvent(
5483
}
5584

5685
void sendCameraClosingEvent() {
57-
send(EventType.CAMERA_CLOSING);
86+
send(CameraEventType.CLOSING);
5887
}
5988

6089
void sendCameraErrorEvent(@Nullable String description) {
6190
this.send(
62-
EventType.ERROR,
91+
CameraEventType.ERROR,
6392
new HashMap<String, Object>() {
6493
{
6594
if (!TextUtils.isEmpty(description)) put("description", description);
6695
}
6796
});
6897
}
6998

70-
void send(EventType eventType) {
99+
void send(CameraEventType eventType) {
100+
send(eventType, new HashMap<>());
101+
}
102+
103+
void send(CameraEventType eventType, Map<String, Object> args) {
104+
if (cameraChannel == null) {
105+
return;
106+
}
107+
cameraChannel.invokeMethod(eventType.method, args);
108+
}
109+
110+
void send(DeviceEventType eventType) {
71111
send(eventType, new HashMap<>());
72112
}
73113

74-
void send(EventType eventType, Map<String, Object> args) {
75-
if (channel == null) {
114+
void send(DeviceEventType eventType, Map<String, Object> args) {
115+
if (deviceChannel == null) {
76116
return;
77117
}
78-
channel.invokeMethod(eventType.toString().toLowerCase(), args);
118+
deviceChannel.invokeMethod(eventType.method, args);
79119
}
80120
}

0 commit comments

Comments
 (0)