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

[image_picker] Default to gallery instead of camera when picking multiple images on pre-iOS 14 devices. #4718

Merged
merged 22 commits into from
Feb 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b1dfdcf
Default to image gallery when picking multiple images
mvanbeusekom Feb 1, 2022
9d15c59
Add additional unit-tests
mvanbeusekom Feb 1, 2022
bd955e9
Refactored tests to expose private interface in separate test header.
mvanbeusekom Feb 2, 2022
e8333f8
Adds declaration comments.
mvanbeusekom Feb 2, 2022
f60f73d
Fix spelling error in changelog
mvanbeusekom Feb 2, 2022
3921f8d
Fix formatting
mvanbeusekom Feb 3, 2022
2b5555a
Merged in unit test refactoring
mvanbeusekom Feb 3, 2022
8707cd8
Applied feedback from PR
mvanbeusekom Feb 3, 2022
441dea1
Refactored tests to expose private interface in separate test header.
mvanbeusekom Feb 2, 2022
6fc92d6
Adds declaration comments.
mvanbeusekom Feb 2, 2022
3a6d1b5
Fix spelling error in changelog
mvanbeusekom Feb 2, 2022
69a41d8
Fix formatting
mvanbeusekom Feb 3, 2022
31442f3
Remove private headers from umbrella
mvanbeusekom Feb 7, 2022
86a2987
Merge branch 'image_picker_test_header' into issue/96903
mvanbeusekom Feb 8, 2022
9b71661
Removes the pickImageWithUIImagePicker trampoline method.
mvanbeusekom Feb 8, 2022
76131a7
Use call.arguments instead of self.arguments.
mvanbeusekom Feb 8, 2022
84abc6f
Merge remote-tracking branch 'upstream/main' into issue/96903
mvanbeusekom Feb 8, 2022
35dc1ab
Merge remote-tracking branch 'upstream/main' into issue/96903
mvanbeusekom Feb 9, 2022
5ea21c7
Apply feedback on PR
mvanbeusekom Feb 9, 2022
134ba8b
Refactored FLTImagePickerPlugin not to be stateful
mvanbeusekom Feb 9, 2022
6bbd53c
Added declaration comments as required by style
mvanbeusekom Feb 9, 2022
f9bfe66
Apply fixes for nits
mvanbeusekom Feb 10, 2022
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
5 changes: 5 additions & 0 deletions packages/image_picker/image_picker/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 0.8.4+8

* Configures the `UIImagePicker` to default to gallery instead of camera when
picking multiple images on pre-iOS 14 devices.

## 0.8.4+7

* Refactors unit test to expose private interface via a separate test header instead of the inline declaration.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,127 +23,161 @@ - (UIViewController *)presentedViewController {
@end

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

@end

@implementation ImagePickerPluginTests

- (void)setUp {
_mockUIImagePicker = OCMClassMock([UIImagePickerController class]);
_mockAVCaptureDevice = OCMClassMock([AVCaptureDevice class]);
}

- (void)testPluginPickImageDeviceBack {
id mockUIImagePicker = OCMClassMock([UIImagePickerController class]);
id mockAVCaptureDevice = OCMClassMock([AVCaptureDevice class]);
// UIImagePickerControllerSourceTypeCamera is supported
OCMStub(ClassMethod(
[_mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]))
[mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]))
.andReturn(YES);

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

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

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

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

- (void)testPluginPickImageDeviceFront {
id mockUIImagePicker = OCMClassMock([UIImagePickerController class]);
id mockAVCaptureDevice = OCMClassMock([AVCaptureDevice class]);
// UIImagePickerControllerSourceTypeCamera is supported
OCMStub(ClassMethod(
[_mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]))
[mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]))
.andReturn(YES);

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

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

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

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

- (void)testPluginPickVideoDeviceBack {
id mockUIImagePicker = OCMClassMock([UIImagePickerController class]);
id mockAVCaptureDevice = OCMClassMock([AVCaptureDevice class]);
// UIImagePickerControllerSourceTypeCamera is supported
OCMStub(ClassMethod(
[_mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]))
[mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]))
.andReturn(YES);

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

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

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

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

- (void)testPluginPickVideoDeviceFront {
id mockUIImagePicker = OCMClassMock([UIImagePickerController class]);
id mockAVCaptureDevice = OCMClassMock([AVCaptureDevice class]);

// UIImagePickerControllerSourceTypeCamera is supported
OCMStub(ClassMethod(
[_mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]))
[mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]))
.andReturn(YES);

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

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

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

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

- (void)testPickMultiImageShouldUseUIImagePickerControllerOnPreiOS14 {
if (@available(iOS 14, *)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

@jmagman Relevant to our discussions about test matrixes in this repository: we won't ever actually test this in CI currently.

return;
}

id mockUIImagePicker = OCMClassMock([UIImagePickerController class]);
id photoLibrary = OCMClassMock([PHPhotoLibrary class]);
OCMStub(ClassMethod([photoLibrary authorizationStatus]))
.andReturn(PHAuthorizationStatusAuthorized);

FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
[plugin setImagePickerControllerOverrides:@[ mockUIImagePicker ]];
FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickMultiImage"
arguments:@{
@"maxWidth" : @(100),
@"maxHeight" : @(200),
@"imageQuality" : @(50),
}];

[plugin handleMethodCall:call
result:^(id _Nullable r){
}];

OCMVerify(times(1),
[mockUIImagePicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary]);
}

#pragma mark - Test camera devices, no op on simulators
Expand All @@ -156,15 +190,18 @@ - (void)testPluginPickImageDeviceCancelClickMultipleTimes {
FlutterMethodCall *call =
[FlutterMethodCall methodCallWithMethodName:@"pickImage"
arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}];
UIImagePickerController *controller = [[UIImagePickerController alloc] init];
plugin.imagePickerControllerOverrides = @[ controller ];
[plugin handleMethodCall:call
result:^(id _Nullable r){
}];
plugin.result = ^(id result) {

};

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

#pragma mark - Test video duration
Expand All @@ -174,10 +211,12 @@ - (void)testPickingVideoWithDuration {
FlutterMethodCall *call = [FlutterMethodCall
methodCallWithMethodName:@"pickVideo"
arguments:@{@"source" : @(0), @"cameraDevice" : @(0), @"maxDuration" : @95}];
UIImagePickerController *controller = [[UIImagePickerController alloc] init];
[plugin setImagePickerControllerOverrides:@[ controller ]];
[plugin handleMethodCall:call
result:^(id _Nullable r){
}];
XCTAssertEqual([plugin getImagePickerController].videoMaximumDuration, 95);
XCTAssertEqual(controller.videoMaximumDuration, 95);
}

- (void)testViewController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
@interface FLTImagePickerPlugin : NSObject <FlutterPlugin>

// For testing only.
- (UIImagePickerController *)getImagePickerController;
- (UIViewController *)viewControllerWithWindow:(UIWindow *)window;

@end
Loading