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

[image_picker] Image picker fix camera device #3898

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
fd62211
Fix handler method to get preferred camera device
ydag May 17, 2021
aaa4a39
Update the version number
ydag May 17, 2021
9c021ad
Add description into the CHANGELOG.md file
ydag May 17, 2021
877b0d8
Fix an issue when camera is chosen
ydag May 17, 2021
3a75fe8
Merge branch 'master' into image_picker_fix_camera_device
ydag May 18, 2021
00213eb
Update the version number
ydag May 18, 2021
5b7ff47
Add helper method to get camera device
ydag May 19, 2021
b548492
Refactor to get preferred camera device
ydag May 19, 2021
9b8b882
Fix team selection in XCTest signing
ydag May 19, 2021
4ffe307
Merge branch 'master' into image_picker_fix_camera_device
ydag May 20, 2021
2313548
Update the version number
ydag May 20, 2021
00ae1ff
Remove unnecessary curly brackets
ydag May 26, 2021
30d61c7
Remove unnecessary curly brackets
ydag May 26, 2021
ceb2577
Add local variable to call method only once
ydag May 26, 2021
4398ae6
Add a declaration comment
ydag May 27, 2021
22b684a
Fix the method call
ydag May 27, 2021
c93a157
Revert "Fix an issue when camera is chosen"
ydag May 27, 2021
3760e13
Merge branch 'master' into image_picker_fix_camera_device
ydag Jun 1, 2021
72bdca4
Merge branch 'master' into image_picker_fix_camera_device
ydag Jun 3, 2021
23f4d8a
Update the comment
ydag Jun 3, 2021
f8fa19d
Add OCMock to the RunnerUITests
ydag Jun 3, 2021
b5710fb
Refactor unit tests with OCMock implementation
ydag Jun 3, 2021
dc7c3b6
Update the podfile
ydag Jun 3, 2021
8ef3516
Add libOCMock.a in Link Binary With Libraries
ydag Jun 3, 2021
3f7d062
Revert "Add libOCMock.a in Link Binary With Libraries"
ydag Jun 3, 2021
311caf5
Merge branch 'master' into image_picker_fix_camera_device
ydag Jun 3, 2021
04b8e74
Update CHANGELOG file
ydag Jun 3, 2021
46c1e7d
Refactor Podfile to add OCMock under RunnerTests
ydag Jun 3, 2021
c27a3f3
Add AVCaptureDevice mock
ydag Jun 4, 2021
397f053
Merge branch 'master' into image_picker_fix_camera_device
ydag Jun 8, 2021
27df40e
Update version number
ydag Jun 8, 2021
b24e5c0
Merge branch 'master' into image_picker_fix_camera_device
ydag Jun 8, 2021
1c3db4c
Update version number
ydag Jun 8, 2021
9277b82
Merge branch 'master' into image_picker_fix_camera_device
ydag Jun 21, 2021
290ca88
Remove self-explanatory comments
ydag Jun 21, 2021
7467883
Merge branch 'master' into image_picker_fix_camera_device
ydag Jun 22, 2021
0ec6cc8
Update the version number
ydag Jun 22, 2021
6b82355
Merge branch 'master' into image_picker_fix_camera_device
ydag Jun 23, 2021
9ffa039
Merge branch 'master' into image_picker_fix_camera_device
ydag Jun 25, 2021
bf8bd36
Update the version number
ydag Jun 25, 2021
5a14280
Remove tearDown method
ydag Jun 28, 2021
6fe570f
Convert true to YES
ydag Jun 28, 2021
4927206
Add blank after pragma mark
ydag Jun 28, 2021
84b3e65
Refactor to return AVAuthorizationStatus constant
ydag Jun 28, 2021
6294377
Fix the comment
ydag Jun 28, 2021
2800919
Add a comment
ydag Jun 30, 2021
b0022f6
Merge branch 'master' into image_picker_fix_camera_device
ydag Jun 30, 2021
8108389
Update the version number
ydag Jun 30, 2021
5d7181b
Fix comments
ydag Jun 30, 2021
e65ce44
Merge branch 'master' into image_picker_fix_camera_device
ydag Jun 30, 2021
8634c68
Update version number
ydag Jun 30, 2021
307757c
Update the comment
ydag Jul 9, 2021
a2b22d6
Merge branch 'master' into image_picker_fix_camera_device
ydag Jul 12, 2021
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
6 changes: 5 additions & 1 deletion packages/image_picker/image_picker/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
## 0.8.1+4

* Fixes an issue where `preferredCameraDevice` option is not working for `getVideo` method.
* Refactor unit tests that were device-only before.

## 0.8.1+3

* Fix image picker causing a crash when the cache directory is deleted.

## 0.8.1+2

* Update the example app to support the multi-image feature.

## 0.8.1+1
Expand Down
3 changes: 3 additions & 0 deletions packages/image_picker/image_picker/example/ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ target 'Runner' do
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))

target 'RunnerTests' do
platform :ios, '9.0'
inherit! :search_paths
# Pods for testing
pod 'OCMock', '~> 3.8.1'
end
target 'RunnerUITests' do
inherit! :search_paths
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -877,7 +877,7 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = NHAKRD9N7D;
DEVELOPMENT_TEAM = "";
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = RunnerUITestiOS14/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

@import image_picker;
@import XCTest;
#import <OCMock/OCMock.h>

@interface MockViewController : UIViewController
@property(nonatomic, retain) UIViewController *mockPresented;
Expand All @@ -27,90 +28,152 @@ - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker;
@end

@interface ImagePickerPluginTests : XCTestCase
@property(readonly, nonatomic) id mockUIImagePicker;
@property(readonly, nonatomic) id mockAVCaptureDevice;
@end

@implementation ImagePickerPluginTests

#pragma mark - Test camera devices, no op on simulators
- (void)setUp {
_mockUIImagePicker = OCMClassMock([UIImagePickerController class]);
_mockAVCaptureDevice = OCMClassMock([AVCaptureDevice class]);
}

- (void)testPluginPickImageDeviceBack {
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
return;
}
// UIImagePickerControllerSourceTypeCamera is supported
OCMStub(ClassMethod(
[_mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]))
.andReturn(YES);

// UIImagePickerControllerCameraDeviceRear is supported
OCMStub(ClassMethod(
[_mockUIImagePicker isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear]))
.andReturn(YES);

// AVAuthorizationStatusAuthorized is supported
OCMStub([_mockAVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo])
.andReturn(AVAuthorizationStatusAuthorized);

// Run test
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
FlutterMethodCall *call =
[FlutterMethodCall methodCallWithMethodName:@"pickImage"
arguments:@{@"source" : @(0), @"cameraDevice" : @(0)}];
[plugin handleMethodCall:call
result:^(id _Nullable r){
}];

XCTAssertEqual([plugin getImagePickerController].cameraDevice,
UIImagePickerControllerCameraDeviceRear);
}

- (void)testPluginPickImageDeviceFront {
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
return;
}
// UIImagePickerControllerSourceTypeCamera is supported
OCMStub(ClassMethod(
[_mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]))
.andReturn(YES);

// UIImagePickerControllerCameraDeviceFront is supported
OCMStub(ClassMethod([_mockUIImagePicker
isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront]))
.andReturn(YES);

// AVAuthorizationStatusAuthorized is supported
OCMStub([_mockAVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo])
.andReturn(AVAuthorizationStatusAuthorized);

// Run test
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
FlutterMethodCall *call =
[FlutterMethodCall methodCallWithMethodName:@"pickImage"
arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}];
[plugin handleMethodCall:call
result:^(id _Nullable r){
}];

XCTAssertEqual([plugin getImagePickerController].cameraDevice,
UIImagePickerControllerCameraDeviceFront);
}

- (void)testPluginPickVideoDeviceBack {
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
return;
}
// UIImagePickerControllerSourceTypeCamera is supported
OCMStub(ClassMethod(
[_mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]))
.andReturn(YES);

// UIImagePickerControllerCameraDeviceRear is supported
OCMStub(ClassMethod(
[_mockUIImagePicker isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear]))
.andReturn(YES);

// AVAuthorizationStatusAuthorized is supported
OCMStub([_mockAVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo])
.andReturn(AVAuthorizationStatusAuthorized);

// Run test
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
FlutterMethodCall *call =
[FlutterMethodCall methodCallWithMethodName:@"pickVideo"
arguments:@{@"source" : @(0), @"cameraDevice" : @(0)}];
[plugin handleMethodCall:call
result:^(id _Nullable r){
}];

XCTAssertEqual([plugin getImagePickerController].cameraDevice,
UIImagePickerControllerCameraDeviceRear);
}

- (void)testPluginPickImageDeviceCancelClickMultipleTimes {
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
return;
}
- (void)testPluginPickVideoDeviceFront {
// UIImagePickerControllerSourceTypeCamera is supported
OCMStub(ClassMethod(
[_mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]))
.andReturn(YES);

// UIImagePickerControllerCameraDeviceFront is supported
OCMStub(ClassMethod([_mockUIImagePicker
isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront]))
.andReturn(YES);

// AVAuthorizationStatusAuthorized is supported
OCMStub([_mockAVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo])
.andReturn(AVAuthorizationStatusAuthorized);

// Run test
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
FlutterMethodCall *call =
[FlutterMethodCall methodCallWithMethodName:@"pickImage"
[FlutterMethodCall methodCallWithMethodName:@"pickVideo"
arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}];
[plugin handleMethodCall:call
result:^(id _Nullable r){
}];
plugin.result = ^(id result) {

};
[plugin imagePickerControllerDidCancel:[plugin getImagePickerController]];
[plugin imagePickerControllerDidCancel:[plugin getImagePickerController]];
XCTAssertEqual([plugin getImagePickerController].cameraDevice,
UIImagePickerControllerCameraDeviceFront);
}

- (void)testPluginPickVideoDeviceFront {
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
#pragma mark - Test camera devices, no op on simulators

- (void)testPluginPickImageDeviceCancelClickMultipleTimes {
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are you aborting the test if the camera is available?

Copy link
Contributor Author

@ydag ydag Jun 28, 2021

Choose a reason for hiding this comment

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

Hi Stuart,
This change made by this commit and it already exists in master as well and got merged in my PR. Do you think we should remove it? Or do you think we should ask what was this test about and try to fix it?

Copy link
Contributor

Choose a reason for hiding this comment

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

@cyanglaz Was this a bug, or is this intentionally only supposed to run on simulator? That seems bizarre.

return;
}
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
FlutterMethodCall *call =
[FlutterMethodCall methodCallWithMethodName:@"pickVideo"
[FlutterMethodCall methodCallWithMethodName:@"pickImage"
arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}];
[plugin handleMethodCall:call
result:^(id _Nullable r){
}];
XCTAssertEqual([plugin getImagePickerController].cameraDevice,
UIImagePickerControllerCameraDeviceFront);
plugin.result = ^(id result) {

};
// To ensure the flow does not crash by multiple cancel call
[plugin imagePickerControllerDidCancel:[plugin getImagePickerController]];
[plugin imagePickerControllerDidCancel:[plugin getImagePickerController]];
}

#pragma mark - Test video duration

- (void)testPickingVideoWithDuration {
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
FlutterMethodCall *call = [FlutterMethodCall
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ @interface FLTImagePickerPlugin () <UINavigationControllerDelegate,

@implementation FLTImagePickerPlugin {
UIImagePickerController *_imagePickerController;
UIImagePickerControllerCameraDevice _device;
}

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
Expand Down Expand Up @@ -70,6 +69,21 @@ - (UIViewController *)viewControllerWithWindow:(UIWindow *)window {
return topController;
}

/**
* Returns the UIImagePickerControllerCameraDevice to use given [arguments].
*
* If the cameraDevice value that is fetched from arguments is 1 then returns
* UIImagePickerControllerCameraDeviceFront. If the cameraDevice value that is fetched
* from arguments is 0 then returns UIImagePickerControllerCameraDeviceRear.
*
* @param arguments that should be used to get cameraDevice value.
*/
- (UIImagePickerControllerCameraDevice)getCameraDeviceFromArguments:(NSDictionary *)arguments {
NSInteger cameraDevice = [[arguments objectForKey:@"cameraDevice"] intValue];
return (cameraDevice == 1) ? UIImagePickerControllerCameraDeviceFront
: UIImagePickerControllerCameraDeviceRear;
}

- (void)pickImageWithPHPicker:(int)maxImagesAllowed API_AVAILABLE(ios(14)) {
PHPickerConfiguration *config =
[[PHPickerConfiguration alloc] initWithPhotoLibrary:PHPhotoLibrary.sharedPhotoLibrary];
Expand All @@ -95,13 +109,9 @@ - (void)pickImageWithUIImagePicker {
self.maxImagesAllowed = 1;

switch (imageSource) {
case SOURCE_CAMERA: {
NSInteger cameraDevice = [[_arguments objectForKey:@"cameraDevice"] intValue];
_device = (cameraDevice == 1) ? UIImagePickerControllerCameraDeviceFront
: UIImagePickerControllerCameraDeviceRear;
case SOURCE_CAMERA:
[self checkCameraAuthorization];
break;
}
case SOURCE_GALLERY:
[self checkPhotoAuthorization];
break;
Expand Down Expand Up @@ -188,11 +198,12 @@ - (void)showCamera {
return;
}
}
UIImagePickerControllerCameraDevice device = [self getCameraDeviceFromArguments:_arguments];
// Camera is not available on simulators
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] &&
[UIImagePickerController isCameraDeviceAvailable:_device]) {
[UIImagePickerController isCameraDeviceAvailable:device]) {
_imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
_imagePickerController.cameraDevice = _device;
_imagePickerController.cameraDevice = device;
[[self viewControllerWithWindow:nil] presentViewController:_imagePickerController
animated:YES
completion:nil];
Expand Down Expand Up @@ -406,8 +417,8 @@ - (void)picker:(PHPickerViewController *)picker
* The difference with initWithCapacity is that initWithCapacity still gives an empty array making
* it impossible to add objects on an index larger than the size.
*
* @param @size The length of the required array
* @return @NSMutableArray An array of a specified size
* @param size The length of the required array
* @return NSMutableArray An array of a specified size
*/
- (NSMutableArray *)createNSMutableArrayWithSize:(NSUInteger)size {
NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithCapacity:size];
Expand Down Expand Up @@ -528,14 +539,14 @@ - (void)saveImageWithPickerInfo:(NSDictionary *)info
* Applies NSMutableArray on the FLutterResult.
*
* NSString must be returned by FlutterResult if the single image
* mode is active. It is checked by @c maxImagesAllowed and
* returns the first object of the @c pathlist.
* mode is active. It is checked by maxImagesAllowed and
* returns the first object of the pathlist.
*
* NSMutableArray must be returned by FlutterResult if the multi-image
* mode is active. After the @c pathlist count is checked then it returns
* the @c pathlist.
* mode is active. After the pathlist count is checked then it returns
* the pathlist.
*
* @param @pathList that should be applied to FlutterResult.
* @param pathList that should be applied to FlutterResult.
*/
- (void)handleSavedPathList:(NSArray *)pathList {
if (!self.result) {
Expand Down
2 changes: 1 addition & 1 deletion packages/image_picker/image_picker/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Flutter plugin for selecting images from the Android and iOS image
library, and taking new pictures with the camera.
repository: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22
version: 0.8.1+3
version: 0.8.1+4

environment:
sdk: ">=2.12.0 <3.0.0"
Expand Down