-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[camera] Initial iOS Pigeon conversion #6553
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,8 +15,7 @@ @implementation AvailableCamerasTest | |
|
||
- (void)testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone { | ||
CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil]; | ||
XCTestExpectation *expectation = | ||
[[XCTestExpectation alloc] initWithDescription:@"Result finished"]; | ||
XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; | ||
|
||
// iPhone 13 Cameras: | ||
AVCaptureDevice *wideAngleCamera = OCMClassMock([AVCaptureDevice class]); | ||
|
@@ -55,29 +54,26 @@ - (void)testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone { | |
} | ||
OCMStub([discoverySessionMock devices]).andReturn([NSArray arrayWithArray:cameras]); | ||
|
||
// Set up method call | ||
FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"availableCameras" | ||
arguments:nil]; | ||
|
||
__block id resultValue; | ||
[camera handleMethodCallAsync:call | ||
result:^(id _Nullable result) { | ||
resultValue = result; | ||
[expectation fulfill]; | ||
}]; | ||
__block NSArray<FCPPlatformCameraDescription *> *resultValue; | ||
[camera | ||
availableCamerasWithCompletion:^(NSArray<FCPPlatformCameraDescription *> *_Nullable result, | ||
FlutterError *_Nullable error) { | ||
XCTAssertNil(error); | ||
resultValue = result; | ||
[expectation fulfill]; | ||
}]; | ||
[self waitForExpectationsWithTimeout:30 handler:nil]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure why we weren't actually using the expectation before, but now it's necessary because the queue dispatch isn't being bypassed in the test like it was before, so the block above is no longer run synchronously in the test. |
||
|
||
// Verify the result | ||
NSDictionary *dictionaryResult = (NSDictionary *)resultValue; | ||
if (@available(iOS 13.0, *)) { | ||
XCTAssertTrue([dictionaryResult count] == 4); | ||
XCTAssertEqual(resultValue.count, 4); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is just a quality of life improvement for when the test fails. (I had a failure initially because I didn't add the |
||
} else { | ||
XCTAssertTrue([dictionaryResult count] == 3); | ||
XCTAssertEqual(resultValue.count, 3); | ||
} | ||
} | ||
- (void)testAvailableCamerasShouldReturnOneCameraOnSingleCameraIPhone { | ||
CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil]; | ||
XCTestExpectation *expectation = | ||
[[XCTestExpectation alloc] initWithDescription:@"Result finished"]; | ||
XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; | ||
|
||
// iPhone 8 Cameras: | ||
AVCaptureDevice *wideAngleCamera = OCMClassMock([AVCaptureDevice class]); | ||
|
@@ -105,20 +101,19 @@ - (void)testAvailableCamerasShouldReturnOneCameraOnSingleCameraIPhone { | |
[cameras addObjectsFromArray:@[ wideAngleCamera, frontFacingCamera ]]; | ||
OCMStub([discoverySessionMock devices]).andReturn([NSArray arrayWithArray:cameras]); | ||
|
||
// Set up method call | ||
FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"availableCameras" | ||
arguments:nil]; | ||
|
||
__block id resultValue; | ||
[camera handleMethodCallAsync:call | ||
result:^(id _Nullable result) { | ||
resultValue = result; | ||
[expectation fulfill]; | ||
}]; | ||
__block NSArray<FCPPlatformCameraDescription *> *resultValue; | ||
[camera | ||
availableCamerasWithCompletion:^(NSArray<FCPPlatformCameraDescription *> *_Nullable result, | ||
FlutterError *_Nullable error) { | ||
XCTAssertNil(error); | ||
resultValue = result; | ||
[expectation fulfill]; | ||
}]; | ||
[self waitForExpectationsWithTimeout:30 handler:nil]; | ||
|
||
// Verify the result | ||
NSDictionary *dictionaryResult = (NSDictionary *)resultValue; | ||
XCTAssertTrue([dictionaryResult count] == 2); | ||
XCTAssertEqual(resultValue.count, 2); | ||
; | ||
} | ||
|
||
@end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
// Autogenerated from Pigeon (v18.0.0), do not edit directly. | ||
// See also: https://pub.dev/packages/pigeon | ||
|
||
#import <Foundation/Foundation.h> | ||
|
||
@protocol FlutterBinaryMessenger; | ||
@protocol FlutterMessageCodec; | ||
@class FlutterError; | ||
@class FlutterStandardTypedData; | ||
|
||
NS_ASSUME_NONNULL_BEGIN | ||
|
||
typedef NS_ENUM(NSUInteger, FCPPlatformCameraLensDirection) { | ||
/// Front facing camera (a user looking at the screen is seen by the camera). | ||
FCPPlatformCameraLensDirectionFront = 0, | ||
/// Back facing camera (a user looking at the screen is not seen by the camera). | ||
FCPPlatformCameraLensDirectionBack = 1, | ||
/// External camera which may not be mounted to the device. | ||
FCPPlatformCameraLensDirectionExternal = 2, | ||
}; | ||
|
||
/// Wrapper for FCPPlatformCameraLensDirection to allow for nullability. | ||
@interface FCPPlatformCameraLensDirectionBox : NSObject | ||
@property(nonatomic, assign) FCPPlatformCameraLensDirection value; | ||
- (instancetype)initWithValue:(FCPPlatformCameraLensDirection)value; | ||
@end | ||
|
||
@class FCPPlatformCameraDescription; | ||
|
||
@interface FCPPlatformCameraDescription : NSObject | ||
/// `init` unavailable to enforce nonnull fields, see the `make` class method. | ||
- (instancetype)init NS_UNAVAILABLE; | ||
+ (instancetype)makeWithName:(NSString *)name | ||
lensDirection:(FCPPlatformCameraLensDirection)lensDirection; | ||
/// The name of the camera device. | ||
@property(nonatomic, copy) NSString *name; | ||
/// The direction the camera is facing. | ||
@property(nonatomic, assign) FCPPlatformCameraLensDirection lensDirection; | ||
@end | ||
|
||
/// The codec used by FCPCameraApi. | ||
NSObject<FlutterMessageCodec> *FCPCameraApiGetCodec(void); | ||
|
||
@protocol FCPCameraApi | ||
/// Returns the list of available cameras. | ||
- (void)availableCamerasWithCompletion:(void (^)(NSArray<FCPPlatformCameraDescription *> *_Nullable, | ||
FlutterError *_Nullable))completion; | ||
@end | ||
|
||
extern void SetUpFCPCameraApi(id<FlutterBinaryMessenger> binaryMessenger, | ||
NSObject<FCPCameraApi> *_Nullable api); | ||
|
||
extern void SetUpFCPCameraApiWithSuffix(id<FlutterBinaryMessenger> binaryMessenger, | ||
NSObject<FCPCameraApi> *_Nullable api, | ||
NSString *messageChannelSuffix); | ||
|
||
NS_ASSUME_NONNULL_END |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
// Autogenerated from Pigeon (v18.0.0), do not edit directly. | ||
// See also: https://pub.dev/packages/pigeon | ||
|
||
#import "messages.g.h" | ||
|
||
#if TARGET_OS_OSX | ||
#import <FlutterMacOS/FlutterMacOS.h> | ||
#else | ||
#import <Flutter/Flutter.h> | ||
#endif | ||
|
||
#if !__has_feature(objc_arc) | ||
#error File requires ARC to be enabled. | ||
#endif | ||
|
||
static NSArray *wrapResult(id result, FlutterError *error) { | ||
if (error) { | ||
return @[ | ||
error.code ?: [NSNull null], error.message ?: [NSNull null], error.details ?: [NSNull null] | ||
]; | ||
} | ||
return @[ result ?: [NSNull null] ]; | ||
} | ||
|
||
static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) { | ||
id result = array[key]; | ||
return (result == [NSNull null]) ? nil : result; | ||
} | ||
|
||
@implementation FCPPlatformCameraLensDirectionBox | ||
- (instancetype)initWithValue:(FCPPlatformCameraLensDirection)value { | ||
self = [super init]; | ||
if (self) { | ||
_value = value; | ||
} | ||
return self; | ||
} | ||
@end | ||
|
||
@interface FCPPlatformCameraDescription () | ||
+ (FCPPlatformCameraDescription *)fromList:(NSArray *)list; | ||
+ (nullable FCPPlatformCameraDescription *)nullableFromList:(NSArray *)list; | ||
- (NSArray *)toList; | ||
@end | ||
|
||
@implementation FCPPlatformCameraDescription | ||
+ (instancetype)makeWithName:(NSString *)name | ||
lensDirection:(FCPPlatformCameraLensDirection)lensDirection { | ||
FCPPlatformCameraDescription *pigeonResult = [[FCPPlatformCameraDescription alloc] init]; | ||
pigeonResult.name = name; | ||
pigeonResult.lensDirection = lensDirection; | ||
return pigeonResult; | ||
} | ||
+ (FCPPlatformCameraDescription *)fromList:(NSArray *)list { | ||
FCPPlatformCameraDescription *pigeonResult = [[FCPPlatformCameraDescription alloc] init]; | ||
pigeonResult.name = GetNullableObjectAtIndex(list, 0); | ||
pigeonResult.lensDirection = [GetNullableObjectAtIndex(list, 1) integerValue]; | ||
return pigeonResult; | ||
} | ||
+ (nullable FCPPlatformCameraDescription *)nullableFromList:(NSArray *)list { | ||
return (list) ? [FCPPlatformCameraDescription fromList:list] : nil; | ||
} | ||
- (NSArray *)toList { | ||
return @[ | ||
self.name ?: [NSNull null], | ||
@(self.lensDirection), | ||
]; | ||
} | ||
@end | ||
|
||
@interface FCPCameraApiCodecReader : FlutterStandardReader | ||
@end | ||
@implementation FCPCameraApiCodecReader | ||
- (nullable id)readValueOfType:(UInt8)type { | ||
switch (type) { | ||
case 128: | ||
return [FCPPlatformCameraDescription fromList:[self readValue]]; | ||
default: | ||
return [super readValueOfType:type]; | ||
} | ||
} | ||
@end | ||
|
||
@interface FCPCameraApiCodecWriter : FlutterStandardWriter | ||
@end | ||
@implementation FCPCameraApiCodecWriter | ||
- (void)writeValue:(id)value { | ||
if ([value isKindOfClass:[FCPPlatformCameraDescription class]]) { | ||
[self writeByte:128]; | ||
[self writeValue:[value toList]]; | ||
} else { | ||
[super writeValue:value]; | ||
} | ||
} | ||
@end | ||
|
||
@interface FCPCameraApiCodecReaderWriter : FlutterStandardReaderWriter | ||
@end | ||
@implementation FCPCameraApiCodecReaderWriter | ||
- (FlutterStandardWriter *)writerWithData:(NSMutableData *)data { | ||
return [[FCPCameraApiCodecWriter alloc] initWithData:data]; | ||
} | ||
- (FlutterStandardReader *)readerWithData:(NSData *)data { | ||
return [[FCPCameraApiCodecReader alloc] initWithData:data]; | ||
} | ||
@end | ||
|
||
NSObject<FlutterMessageCodec> *FCPCameraApiGetCodec(void) { | ||
static FlutterStandardMessageCodec *sSharedObject = nil; | ||
static dispatch_once_t sPred = 0; | ||
dispatch_once(&sPred, ^{ | ||
FCPCameraApiCodecReaderWriter *readerWriter = [[FCPCameraApiCodecReaderWriter alloc] init]; | ||
sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter]; | ||
}); | ||
return sSharedObject; | ||
} | ||
|
||
void SetUpFCPCameraApi(id<FlutterBinaryMessenger> binaryMessenger, NSObject<FCPCameraApi> *api) { | ||
SetUpFCPCameraApiWithSuffix(binaryMessenger, api, @""); | ||
} | ||
|
||
void SetUpFCPCameraApiWithSuffix(id<FlutterBinaryMessenger> binaryMessenger, | ||
NSObject<FCPCameraApi> *api, NSString *messageChannelSuffix) { | ||
messageChannelSuffix = messageChannelSuffix.length > 0 | ||
? [NSString stringWithFormat:@".%@", messageChannelSuffix] | ||
: @""; | ||
/// Returns the list of available cameras. | ||
{ | ||
FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] | ||
initWithName:[NSString stringWithFormat:@"%@%@", | ||
@"dev.flutter.pigeon.camera_avfoundation." | ||
@"CameraApi.getAvailableCameras", | ||
messageChannelSuffix] | ||
binaryMessenger:binaryMessenger | ||
codec:FCPCameraApiGetCodec()]; | ||
if (api) { | ||
NSCAssert( | ||
[api respondsToSelector:@selector(availableCamerasWithCompletion:)], | ||
@"FCPCameraApi api (%@) doesn't respond to @selector(availableCamerasWithCompletion:)", | ||
api); | ||
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { | ||
[api availableCamerasWithCompletion:^( | ||
NSArray<FCPPlatformCameraDescription *> *_Nullable output, | ||
FlutterError *_Nullable error) { | ||
callback(wrapResult(output, error)); | ||
}]; | ||
}]; | ||
} else { | ||
[channel setMessageHandler:nil]; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change to the utility method allows using
waitForExpectationsWithTimeout:
instead of having to list every expectation.