Skip to content

Commit 545c97f

Browse files
authored
[camera_platform_interface] Migrate to null safety (flutter#3497)
1 parent 2b6addf commit 545c97f

File tree

13 files changed

+205
-108
lines changed

13 files changed

+205
-108
lines changed

packages/camera/camera_platform_interface/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.0.0-nullsafety
2+
3+
- Migrate to null safety.
4+
15
## 1.6.0
26

37
- Added VideoRecordedEvent to support ending a video recording in the native implementation.

packages/camera/camera_platform_interface/lib/src/events/camera_event.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,12 @@ class CameraInitializedEvent extends CameraEvent {
7070
CameraInitializedEvent(
7171
int cameraId,
7272
this.previewWidth,
73-
this.previewHeight, [
73+
this.previewHeight,
7474
this.exposureMode,
75-
this.exposurePointSupported = false,
75+
this.exposurePointSupported,
7676
this.focusMode,
77-
this.focusPointSupported = false,
78-
]) : super(cameraId);
77+
this.focusPointSupported,
78+
) : super(cameraId);
7979

8080
/// Converts the supplied [Map] to an instance of the [CameraInitializedEvent]
8181
/// class.
@@ -242,7 +242,7 @@ class VideoRecordedEvent extends CameraEvent {
242242
final XFile file;
243243

244244
/// Maximum duration of the recorded video.
245-
final Duration maxVideoDuration;
245+
final Duration? maxVideoDuration;
246246

247247
/// Build a VideoRecordedEvent triggered from the camera with the `cameraId`.
248248
///

packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart

Lines changed: 106 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'package:camera_platform_interface/src/types/focus_mode.dart';
1111
import 'package:camera_platform_interface/src/types/image_format_group.dart';
1212
import 'package:camera_platform_interface/src/utils/utils.dart';
1313
import 'package:cross_file/cross_file.dart';
14+
import 'package:flutter/foundation.dart';
1415
import 'package:flutter/services.dart';
1516
import 'package:flutter/widgets.dart';
1617
import 'package:meta/meta.dart';
@@ -58,8 +59,13 @@ class MethodChannelCamera extends CameraPlatform {
5859
@override
5960
Future<List<CameraDescription>> availableCameras() async {
6061
try {
61-
final List<Map<dynamic, dynamic>> cameras = await _channel
62+
final cameras = await _channel
6263
.invokeListMethod<Map<dynamic, dynamic>>('availableCameras');
64+
65+
if (cameras == null) {
66+
return <CameraDescription>[];
67+
}
68+
6369
return cameras.map((Map<dynamic, dynamic> camera) {
6470
return CameraDescription(
6571
name: camera['name'],
@@ -75,30 +81,30 @@ class MethodChannelCamera extends CameraPlatform {
7581
@override
7682
Future<int> createCamera(
7783
CameraDescription cameraDescription,
78-
ResolutionPreset resolutionPreset, {
79-
bool enableAudio,
84+
ResolutionPreset? resolutionPreset, {
85+
bool enableAudio = true,
8086
}) async {
8187
try {
82-
final Map<String, dynamic> reply =
83-
await _channel.invokeMapMethod<String, dynamic>(
84-
'create',
85-
<String, dynamic>{
86-
'cameraName': cameraDescription.name,
87-
'resolutionPreset': resolutionPreset != null
88-
? _serializeResolutionPreset(resolutionPreset)
89-
: null,
90-
'enableAudio': enableAudio,
91-
},
92-
);
93-
return reply['cameraId'];
88+
final reply = await _channel
89+
.invokeMapMethod<String, dynamic>('create', <String, dynamic>{
90+
'cameraName': cameraDescription.name,
91+
'resolutionPreset': resolutionPreset != null
92+
? _serializeResolutionPreset(resolutionPreset)
93+
: null,
94+
'enableAudio': enableAudio,
95+
});
96+
97+
return reply!['cameraId'];
9498
} on PlatformException catch (e) {
9599
throw CameraException(e.code, e.message);
96100
}
97101
}
98102

99103
@override
100-
Future<void> initializeCamera(int cameraId,
101-
{ImageFormatGroup imageFormatGroup}) {
104+
Future<void> initializeCamera(
105+
int cameraId, {
106+
ImageFormatGroup imageFormatGroup = ImageFormatGroup.unknown,
107+
}) {
102108
_channels.putIfAbsent(cameraId, () {
103109
final channel = MethodChannel('flutter.io/cameraPlugin/camera$cameraId');
104110
channel.setMethodCallHandler(
@@ -125,15 +131,16 @@ class MethodChannelCamera extends CameraPlatform {
125131

126132
@override
127133
Future<void> dispose(int cameraId) async {
134+
if (_channels.containsKey(cameraId)) {
135+
final cameraChannel = _channels[cameraId];
136+
cameraChannel?.setMethodCallHandler(null);
137+
_channels.remove(cameraId);
138+
}
139+
128140
await _channel.invokeMethod<void>(
129141
'dispose',
130142
<String, dynamic>{'cameraId': cameraId},
131143
);
132-
133-
if (_channels.containsKey(cameraId)) {
134-
_channels[cameraId].setMethodCallHandler(null);
135-
_channels.remove(cameraId);
136-
}
137144
}
138145

139146
@override
@@ -169,7 +176,9 @@ class MethodChannelCamera extends CameraPlatform {
169176

170177
@override
171178
Future<void> lockCaptureOrientation(
172-
int cameraId, DeviceOrientation orientation) async {
179+
int cameraId,
180+
DeviceOrientation orientation,
181+
) async {
173182
await _channel.invokeMethod<String>(
174183
'lockCaptureOrientation',
175184
<String, dynamic>{
@@ -189,10 +198,18 @@ class MethodChannelCamera extends CameraPlatform {
189198

190199
@override
191200
Future<XFile> takePicture(int cameraId) async {
192-
String path = await _channel.invokeMethod<String>(
201+
final path = await _channel.invokeMethod<String>(
193202
'takePicture',
194203
<String, dynamic>{'cameraId': cameraId},
195204
);
205+
206+
if (path == null) {
207+
throw CameraException(
208+
'INVALID_PATH',
209+
'The platform "$defaultTargetPlatform" did not return a path while reporting success. The platform should always return a valid path or report an error.',
210+
);
211+
}
212+
196213
return XFile(path);
197214
}
198215

@@ -202,7 +219,7 @@ class MethodChannelCamera extends CameraPlatform {
202219

203220
@override
204221
Future<void> startVideoRecording(int cameraId,
205-
{Duration maxVideoDuration}) async {
222+
{Duration? maxVideoDuration}) async {
206223
await _channel.invokeMethod<void>(
207224
'startVideoRecording',
208225
<String, dynamic>{
@@ -214,10 +231,18 @@ class MethodChannelCamera extends CameraPlatform {
214231

215232
@override
216233
Future<XFile> stopVideoRecording(int cameraId) async {
217-
String path = await _channel.invokeMethod<String>(
234+
final path = await _channel.invokeMethod<String>(
218235
'stopVideoRecording',
219236
<String, dynamic>{'cameraId': cameraId},
220237
);
238+
239+
if (path == null) {
240+
throw CameraException(
241+
'INVALID_PATH',
242+
'The platform "$defaultTargetPlatform" did not return a path while reporting success. The platform should always return a valid path or report an error.',
243+
);
244+
}
245+
221246
return XFile(path);
222247
}
223248

@@ -255,9 +280,10 @@ class MethodChannelCamera extends CameraPlatform {
255280
);
256281

257282
@override
258-
Future<void> setExposurePoint(int cameraId, Point<double> point) {
283+
Future<void> setExposurePoint(int cameraId, Point<double>? point) {
259284
assert(point == null || point.x >= 0 && point.x <= 1);
260285
assert(point == null || point.y >= 0 && point.y <= 1);
286+
261287
return _channel.invokeMethod<void>(
262288
'setExposurePoint',
263289
<String, dynamic>{
@@ -270,35 +296,47 @@ class MethodChannelCamera extends CameraPlatform {
270296
}
271297

272298
@override
273-
Future<double> getMinExposureOffset(int cameraId) =>
274-
_channel.invokeMethod<double>(
275-
'getMinExposureOffset',
276-
<String, dynamic>{'cameraId': cameraId},
277-
);
299+
Future<double> getMinExposureOffset(int cameraId) async {
300+
final minExposureOffset = await _channel.invokeMethod<double>(
301+
'getMinExposureOffset',
302+
<String, dynamic>{'cameraId': cameraId},
303+
);
304+
305+
return minExposureOffset!;
306+
}
278307

279308
@override
280-
Future<double> getMaxExposureOffset(int cameraId) =>
281-
_channel.invokeMethod<double>(
282-
'getMaxExposureOffset',
283-
<String, dynamic>{'cameraId': cameraId},
284-
);
309+
Future<double> getMaxExposureOffset(int cameraId) async {
310+
final maxExposureOffset = await _channel.invokeMethod<double>(
311+
'getMaxExposureOffset',
312+
<String, dynamic>{'cameraId': cameraId},
313+
);
314+
315+
return maxExposureOffset!;
316+
}
285317

286318
@override
287-
Future<double> getExposureOffsetStepSize(int cameraId) =>
288-
_channel.invokeMethod<double>(
289-
'getExposureOffsetStepSize',
290-
<String, dynamic>{'cameraId': cameraId},
291-
);
319+
Future<double> getExposureOffsetStepSize(int cameraId) async {
320+
final stepSize = await _channel.invokeMethod<double>(
321+
'getExposureOffsetStepSize',
322+
<String, dynamic>{'cameraId': cameraId},
323+
);
324+
325+
return stepSize!;
326+
}
292327

293328
@override
294-
Future<double> setExposureOffset(int cameraId, double offset) =>
295-
_channel.invokeMethod<double>(
296-
'setExposureOffset',
297-
<String, dynamic>{
298-
'cameraId': cameraId,
299-
'offset': offset,
300-
},
301-
);
329+
Future<double> setExposureOffset(int cameraId, double offset) async {
330+
final appliedOffset = await _channel.invokeMethod<double>(
331+
'setExposureOffset',
332+
<String, dynamic>{
333+
'cameraId': cameraId,
334+
'offset': offset,
335+
},
336+
);
337+
338+
return appliedOffset!;
339+
}
302340

303341
@override
304342
Future<void> setFocusMode(int cameraId, FocusMode mode) =>
@@ -311,9 +349,10 @@ class MethodChannelCamera extends CameraPlatform {
311349
);
312350

313351
@override
314-
Future<void> setFocusPoint(int cameraId, Point<double> point) {
352+
Future<void> setFocusPoint(int cameraId, Point<double>? point) {
315353
assert(point == null || point.x >= 0 && point.x <= 1);
316354
assert(point == null || point.y >= 0 && point.y <= 1);
355+
317356
return _channel.invokeMethod<void>(
318357
'setFocusPoint',
319358
<String, dynamic>{
@@ -326,16 +365,24 @@ class MethodChannelCamera extends CameraPlatform {
326365
}
327366

328367
@override
329-
Future<double> getMaxZoomLevel(int cameraId) => _channel.invokeMethod<double>(
330-
'getMaxZoomLevel',
331-
<String, dynamic>{'cameraId': cameraId},
332-
);
368+
Future<double> getMaxZoomLevel(int cameraId) async {
369+
final maxZoomLevel = await _channel.invokeMethod<double>(
370+
'getMaxZoomLevel',
371+
<String, dynamic>{'cameraId': cameraId},
372+
);
373+
374+
return maxZoomLevel!;
375+
}
333376

334377
@override
335-
Future<double> getMinZoomLevel(int cameraId) => _channel.invokeMethod<double>(
336-
'getMinZoomLevel',
337-
<String, dynamic>{'cameraId': cameraId},
338-
);
378+
Future<double> getMinZoomLevel(int cameraId) async {
379+
final minZoomLevel = await _channel.invokeMethod<double>(
380+
'getMinZoomLevel',
381+
<String, dynamic>{'cameraId': cameraId},
382+
);
383+
384+
return minZoomLevel!;
385+
}
339386

340387
@override
341388
Future<void> setZoomLevel(int cameraId, double zoom) async {

packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ abstract class CameraPlatform extends PlatformInterface {
5151
/// Creates an uninitialized camera instance and returns the cameraId.
5252
Future<int> createCamera(
5353
CameraDescription cameraDescription,
54-
ResolutionPreset resolutionPreset, {
55-
bool enableAudio,
54+
ResolutionPreset? resolutionPreset, {
55+
bool enableAudio = true,
5656
}) {
5757
throw UnimplementedError('createCamera() is not implemented.');
5858
}
@@ -62,8 +62,10 @@ abstract class CameraPlatform extends PlatformInterface {
6262
/// [imageFormatGroup] is used to specify the image formatting used.
6363
/// On Android this defaults to ImageFormat.YUV_420_888 and applies only to the imageStream.
6464
/// On iOS this defaults to kCVPixelFormatType_32BGRA.
65-
Future<void> initializeCamera(int cameraId,
66-
{ImageFormatGroup imageFormatGroup}) {
65+
Future<void> initializeCamera(
66+
int cameraId, {
67+
ImageFormatGroup imageFormatGroup = ImageFormatGroup.unknown,
68+
}) {
6769
throw UnimplementedError('initializeCamera() is not implemented.');
6870
}
6971

@@ -130,7 +132,7 @@ abstract class CameraPlatform extends PlatformInterface {
130132
/// meaning the recording will continue until manually stopped.
131133
/// With [maxVideoDuration] set the video is returned in a [VideoRecordedEvent]
132134
/// through the [onVideoRecordedEvent] stream when the set duration is reached.
133-
Future<void> startVideoRecording(int cameraId, {Duration maxVideoDuration}) {
135+
Future<void> startVideoRecording(int cameraId, {Duration? maxVideoDuration}) {
134136
throw UnimplementedError('startVideoRecording() is not implemented.');
135137
}
136138

@@ -160,7 +162,10 @@ abstract class CameraPlatform extends PlatformInterface {
160162
}
161163

162164
/// Sets the exposure point for automatically determining the exposure values.
163-
Future<void> setExposurePoint(int cameraId, Point<double> point) {
165+
///
166+
/// Supplying `null` for the [point] argument will result in resetting to the
167+
/// original exposure point value.
168+
Future<void> setExposurePoint(int cameraId, Point<double>? point) {
164169
throw UnimplementedError('setExposurePoint() is not implemented.');
165170
}
166171

@@ -202,7 +207,10 @@ abstract class CameraPlatform extends PlatformInterface {
202207
}
203208

204209
/// Sets the focus point for automatically determining the focus values.
205-
Future<void> setFocusPoint(int cameraId, Point<double> point) {
210+
///
211+
/// Supplying `null` for the [point] argument will result in resetting to the
212+
/// original focus point value.
213+
Future<void> setFocusPoint(int cameraId, Point<double>? point) {
206214
throw UnimplementedError('setFocusPoint() is not implemented.');
207215
}
208216

packages/camera/camera_platform_interface/lib/src/types/camera_description.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ enum CameraLensDirection {
1717
/// Properties of a camera device.
1818
class CameraDescription {
1919
/// Creates a new camera description with the given properties.
20-
CameraDescription({this.name, this.lensDirection, this.sensorOrientation});
20+
CameraDescription({
21+
required this.name,
22+
required this.lensDirection,
23+
required this.sensorOrientation,
24+
});
2125

2226
/// The name of the camera device.
2327
final String name;

packages/camera/camera_platform_interface/lib/src/types/camera_exception.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class CameraException implements Exception {
1313
String code;
1414

1515
/// Textual description of the error.
16-
String description;
16+
String? description;
1717

1818
@override
1919
String toString() => 'CameraException($code, $description)';

0 commit comments

Comments
 (0)