diff --git a/AUTHORS b/AUTHORS index ffc4e5a468f0..7a426e7b9746 100644 --- a/AUTHORS +++ b/AUTHORS @@ -44,6 +44,7 @@ Lukasz Piliszczuk SoundReply Solutions GmbH Rafal Wachol Pau Picas +Alexandru Tuca Rhodes Davis Jr. Luigi Agosti Quentin Le Guennec diff --git a/packages/image_picker/CHANGELOG.md b/packages/image_picker/CHANGELOG.md index 0cd83a0503d6..394c0e9e94dc 100644 --- a/packages/image_picker/CHANGELOG.md +++ b/packages/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.4 + +* Set maximum duration for video recording. + ## 0.6.3+2 * Bump RoboElectric dependency to 4.3.1 and update resource usage. @@ -12,11 +16,13 @@ * Migrate to using the new e2e test binding. ## 0.6.2+3 + * Remove the deprecated `author:` field from pubspec.yaml * Migrate the plugin to the pubspec platforms manifest. * Require Flutter SDK 1.10.0 or greater. ## 0.6.2+2 + * Android: Revert the image file return logic when the image doesn't have to be scaled. Fix a rotation regression caused by 0.6.2+1 * Example App: Add a dialog to enter `maxWidth`, `maxHeight` or `quality` when picking image. diff --git a/packages/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java b/packages/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java index f2a0b02c821d..72ea3f3c0a03 100644 --- a/packages/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java +++ b/packages/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java @@ -274,6 +274,10 @@ public void takeVideoWithCamera(MethodCall methodCall, MethodChannel.Result resu private void launchTakeVideoWithCameraIntent() { Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); + if (this.methodCall != null && this.methodCall.argument("maxDuration") != null) { + int maxSeconds = this.methodCall.argument("maxDuration"); + intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, maxSeconds); + } boolean canTakePhotos = intentResolver.resolveActivity(intent); if (!canTakePhotos) { diff --git a/packages/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java b/packages/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java index 88fa3372766f..aa9b00521f53 100644 --- a/packages/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java +++ b/packages/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java @@ -26,6 +26,7 @@ public class ImagePickerDelegateTest { private static final Double WIDTH = 10.0; private static final Double HEIGHT = 10.0; + private static final Double MAX_DURATION = 10.0; private static final Integer IMAGE_QUALITY = 90; @Mock Activity mockActivity; @@ -373,6 +374,19 @@ public void onActivityResult_WhenImageTakenWithCamera_AndNoResizeNeeded_Finishes verifyNoMoreInteractions(mockResult); } + @Test + public void + onActivityResult_WhenVideoTakenWithCamera_AndMaxDurationParametersSupplied_FinishesWithFilePath() { + when(mockMethodCall.argument("maxDuration")).thenReturn(MAX_DURATION); + + ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + delegate.onActivityResult( + ImagePickerDelegate.REQUEST_CODE_TAKE_VIDEO_WITH_CAMERA, Activity.RESULT_OK, mockIntent); + + verify(mockResult).success("pathFromUri"); + verifyNoMoreInteractions(mockResult); + } + private ImagePickerDelegate createDelegate() { return new ImagePickerDelegate( mockActivity, diff --git a/packages/image_picker/example/lib/main.dart b/packages/image_picker/example/lib/main.dart index 919c8388266f..29781f7df449 100755 --- a/packages/image_picker/example/lib/main.dart +++ b/packages/image_picker/example/lib/main.dart @@ -64,7 +64,8 @@ class _MyHomePageState extends State { await _controller.setVolume(0.0); } if (isVideo) { - final File file = await ImagePicker.pickVideo(source: source); + final File file = await ImagePicker.pickVideo( + source: source, maxDuration: const Duration(seconds: 10)); await _playVideo(file); } else { await _displayPickImageDialog(context, diff --git a/packages/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/ios/Classes/FLTImagePickerPlugin.m index 127b119543fa..c9ea53f86efe 100644 --- a/packages/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -93,6 +93,10 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result _arguments = call.arguments; int imageSource = [[_arguments objectForKey:@"source"] intValue]; + if ([[_arguments objectForKey:@"maxDuration"] isKindOfClass:[NSNumber class]]) { + NSTimeInterval max = [[_arguments objectForKey:@"maxDuration"] doubleValue]; + _imagePickerController.videoMaximumDuration = max; + } switch (imageSource) { case SOURCE_CAMERA: diff --git a/packages/image_picker/lib/image_picker.dart b/packages/image_picker/lib/image_picker.dart index 19cd0752ced3..f8b43203df55 100755 --- a/packages/image_picker/lib/image_picker.dart +++ b/packages/image_picker/lib/image_picker.dart @@ -79,16 +79,19 @@ class ImagePicker { /// The [source] argument controls where the video comes from. This can /// be either [ImageSource.camera] or [ImageSource.gallery]. /// + /// The [maxDuration] argument specifies the maximum duration of the captured video. If no [maxDuration] is specified, + /// the maximum duration will be infinite. + /// /// In Android, the MainActivity can be destroyed for various fo reasons. If that happens, the result will be lost /// in this call. You can then call [retrieveLostData] when your app relaunches to retrieve the lost data. - static Future pickVideo({ - @required ImageSource source, - }) async { + static Future pickVideo( + {@required ImageSource source, Duration maxDuration}) async { assert(source != null); final String path = await _channel.invokeMethod( 'pickVideo', { 'source': source.index, + 'maxDuration': maxDuration?.inSeconds, }, ); return path == null ? null : File(path); diff --git a/packages/image_picker/pubspec.yaml b/packages/image_picker/pubspec.yaml index a9a300063e2a..0d99970d4fbe 100755 --- a/packages/image_picker/pubspec.yaml +++ b/packages/image_picker/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker -version: 0.6.3+2 +version: 0.6.4 flutter: plugin: diff --git a/packages/image_picker/test/image_picker_test.dart b/packages/image_picker/test/image_picker_test.dart index 28eae8eaa46d..505ad3051e0a 100644 --- a/packages/image_picker/test/image_picker_test.dart +++ b/packages/image_picker/test/image_picker_test.dart @@ -151,17 +151,40 @@ void main() { expect( log, [ - isMethodCall('pickVideo', arguments: { - 'source': 0, - }), - isMethodCall('pickVideo', arguments: { - 'source': 1, - }), + isMethodCall('pickVideo', + arguments: {'source': 0, 'maxDuration': null}), + isMethodCall('pickVideo', + arguments: {'source': 1, 'maxDuration': null}), ], ); }); - test('handles a null image path response gracefully', () async { + test('passes the duration argument correctly', () async { + await ImagePicker.pickVideo(source: ImageSource.camera); + await ImagePicker.pickVideo( + source: ImageSource.camera, + maxDuration: const Duration(seconds: 10)); + await ImagePicker.pickVideo( + source: ImageSource.camera, + maxDuration: const Duration(minutes: 1)); + await ImagePicker.pickVideo( + source: ImageSource.camera, maxDuration: const Duration(hours: 1)); + expect( + log, + [ + isMethodCall('pickVideo', + arguments: {'source': 0, 'maxDuration': null}), + isMethodCall('pickVideo', + arguments: {'source': 0, 'maxDuration': 10}), + isMethodCall('pickVideo', + arguments: {'source': 0, 'maxDuration': 60}), + isMethodCall('pickVideo', + arguments: {'source': 0, 'maxDuration': 3600}), + ], + ); + }); + + test('handles a null video path response gracefully', () async { channel.setMockMethodCallHandler((MethodCall methodCall) => null); expect(