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

Commit 193bbe9

Browse files
Merge branch 'main' into ios-optional-permissions
2 parents 8ff7492 + 3fb9e2c commit 193bbe9

38 files changed

+1029
-164
lines changed

packages/camera/camera/CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
## 0.9.4+5
1+
## NEXT
2+
3+
* Minor internal code cleanup.
4+
5+
## 0.9.4+6
6+
7+
* Fixes a crash in iOS when using image stream due to calling Flutter engine API on non-main thread.
8+
9+
## 0.9.4+5
210

311
* Fixes bug where calling a method after the camera was closed resulted in a Java `IllegalStateException` exception.
412
* Fixes integration tests.

packages/camera/camera/example/ios/Runner.xcodeproj/project.pbxproj

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
2121
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
2222
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
23+
E01EE4A82799F3A5008C1950 /* QueueHelperTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E01EE4A72799F3A5008C1950 /* QueueHelperTests.m */; };
24+
E0C6E2002770F01A00EA6AA3 /* ThreadSafeMethodChannelTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0C6E1FD2770F01A00EA6AA3 /* ThreadSafeMethodChannelTests.m */; };
25+
E0C6E2012770F01A00EA6AA3 /* ThreadSafeTextureRegistryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0C6E1FE2770F01A00EA6AA3 /* ThreadSafeTextureRegistryTests.m */; };
26+
E0C6E2022770F01A00EA6AA3 /* ThreadSafeEventChannelTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0C6E1FF2770F01A00EA6AA3 /* ThreadSafeEventChannelTests.m */; };
2327
E487C86026D686A10034AC92 /* CameraPreviewPauseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E487C85F26D686A10034AC92 /* CameraPreviewPauseTests.m */; };
2428
F6EE622F2710A6FC00905E4A /* MockFLTThreadSafeFlutterResult.m in Sources */ = {isa = PBXBuildFile; fileRef = F6EE622E2710A6FC00905E4A /* MockFLTThreadSafeFlutterResult.m */; };
2529
/* End PBXBuildFile section */
@@ -74,6 +78,10 @@
7478
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
7579
9C5CC6CAD53AD388B2694F3A /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
7680
A24F9E418BA48BCC7409B117 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
81+
E01EE4A72799F3A5008C1950 /* QueueHelperTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QueueHelperTests.m; sourceTree = "<group>"; };
82+
E0C6E1FD2770F01A00EA6AA3 /* ThreadSafeMethodChannelTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ThreadSafeMethodChannelTests.m; sourceTree = "<group>"; };
83+
E0C6E1FE2770F01A00EA6AA3 /* ThreadSafeTextureRegistryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ThreadSafeTextureRegistryTests.m; sourceTree = "<group>"; };
84+
E0C6E1FF2770F01A00EA6AA3 /* ThreadSafeEventChannelTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ThreadSafeEventChannelTests.m; sourceTree = "<group>"; };
7785
E487C85F26D686A10034AC92 /* CameraPreviewPauseTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CameraPreviewPauseTests.m; sourceTree = "<group>"; };
7886
F63F9EED27143B19002479BF /* MockFLTThreadSafeFlutterResult.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockFLTThreadSafeFlutterResult.h; sourceTree = "<group>"; };
7987
F6EE622E2710A6FC00905E4A /* MockFLTThreadSafeFlutterResult.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockFLTThreadSafeFlutterResult.m; sourceTree = "<group>"; };
@@ -107,6 +115,10 @@
107115
03BB766C2665316900CE5A93 /* Info.plist */,
108116
033B94BD269C40A200B4DF97 /* CameraMethodChannelTests.m */,
109117
03F6F8B126CBB4670024B8D3 /* ThreadSafeFlutterResultTests.m */,
118+
E0C6E1FF2770F01A00EA6AA3 /* ThreadSafeEventChannelTests.m */,
119+
E0C6E1FD2770F01A00EA6AA3 /* ThreadSafeMethodChannelTests.m */,
120+
E0C6E1FE2770F01A00EA6AA3 /* ThreadSafeTextureRegistryTests.m */,
121+
E01EE4A72799F3A5008C1950 /* QueueHelperTests.m */,
110122
E487C85F26D686A10034AC92 /* CameraPreviewPauseTests.m */,
111123
F6EE622E2710A6FC00905E4A /* MockFLTThreadSafeFlutterResult.m */,
112124
F63F9EED27143B19002479BF /* MockFLTThreadSafeFlutterResult.h */,
@@ -239,7 +251,7 @@
239251
97C146E61CF9000F007C117D /* Project object */ = {
240252
isa = PBXProject;
241253
attributes = {
242-
LastUpgradeCheck = 1100;
254+
LastUpgradeCheck = 1300;
243255
ORGANIZATIONNAME = "The Flutter Authors";
244256
TargetAttributes = {
245257
03BB76672665316900CE5A93 = {
@@ -378,6 +390,10 @@
378390
E487C86026D686A10034AC92 /* CameraPreviewPauseTests.m in Sources */,
379391
F6EE622F2710A6FC00905E4A /* MockFLTThreadSafeFlutterResult.m in Sources */,
380392
334733EA2668111C00DCC49E /* CameraOrientationTests.m in Sources */,
393+
E0C6E2022770F01A00EA6AA3 /* ThreadSafeEventChannelTests.m in Sources */,
394+
E0C6E2012770F01A00EA6AA3 /* ThreadSafeTextureRegistryTests.m in Sources */,
395+
E0C6E2002770F01A00EA6AA3 /* ThreadSafeMethodChannelTests.m in Sources */,
396+
E01EE4A82799F3A5008C1950 /* QueueHelperTests.m in Sources */,
381397
);
382398
runOnlyForDeploymentPostprocessing = 0;
383399
};

packages/camera/camera/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "1100"
3+
LastUpgradeVersion = "1300"
44
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
@import camera;
6+
@import XCTest;
7+
8+
@interface QueueHelperTests : XCTestCase
9+
10+
@end
11+
12+
@implementation QueueHelperTests
13+
14+
- (void)testShouldStayOnMainQueueIfCalledFromMainQueue {
15+
XCTestExpectation *expectation =
16+
[self expectationWithDescription:@"Block must be run on the main queue."];
17+
[QueueHelper ensureToRunOnMainQueue:^{
18+
if (NSThread.isMainThread) {
19+
[expectation fulfill];
20+
}
21+
}];
22+
[self waitForExpectationsWithTimeout:1 handler:nil];
23+
}
24+
25+
- (void)testShouldDispatchToMainQueueIfCalledFromBackgroundQueue {
26+
XCTestExpectation *expectation =
27+
[self expectationWithDescription:@"Block must be run on the main queue."];
28+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
29+
[QueueHelper ensureToRunOnMainQueue:^{
30+
if (NSThread.isMainThread) {
31+
[expectation fulfill];
32+
}
33+
}];
34+
});
35+
[self waitForExpectationsWithTimeout:1 handler:nil];
36+
}
37+
38+
@end
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
@import camera;
6+
@import XCTest;
7+
#import <OCMock/OCMock.h>
8+
9+
@interface ThreadSafeEventChannelTests : XCTestCase
10+
@end
11+
12+
@implementation ThreadSafeEventChannelTests
13+
14+
- (void)testSetStreamHandler_shouldStayOnMainThreadIfCalledFromMainThread {
15+
FlutterEventChannel *mockEventChannel = OCMClassMock([FlutterEventChannel class]);
16+
FLTThreadSafeEventChannel *threadSafeEventChannel =
17+
[[FLTThreadSafeEventChannel alloc] initWithEventChannel:mockEventChannel];
18+
19+
XCTestExpectation *mainThreadExpectation =
20+
[self expectationWithDescription:@"setStreamHandler must be called on the main thread"];
21+
XCTestExpectation *mainThreadCompletionExpectation =
22+
[self expectationWithDescription:
23+
@"setStreamHandler's completion block must be called on the main thread"];
24+
OCMStub([mockEventChannel setStreamHandler:[OCMArg any]]).andDo(^(NSInvocation *invocation) {
25+
if (NSThread.isMainThread) {
26+
[mainThreadExpectation fulfill];
27+
}
28+
});
29+
30+
[threadSafeEventChannel setStreamHandler:nil
31+
completion:^{
32+
if (NSThread.isMainThread) {
33+
[mainThreadCompletionExpectation fulfill];
34+
}
35+
}];
36+
[self waitForExpectationsWithTimeout:1 handler:nil];
37+
}
38+
39+
- (void)testSetStreamHandler_shouldDispatchToMainThreadIfCalledFromBackgroundThread {
40+
FlutterEventChannel *mockEventChannel = OCMClassMock([FlutterEventChannel class]);
41+
FLTThreadSafeEventChannel *threadSafeEventChannel =
42+
[[FLTThreadSafeEventChannel alloc] initWithEventChannel:mockEventChannel];
43+
44+
XCTestExpectation *mainThreadExpectation =
45+
[self expectationWithDescription:@"setStreamHandler must be called on the main thread"];
46+
XCTestExpectation *mainThreadCompletionExpectation =
47+
[self expectationWithDescription:
48+
@"setStreamHandler's completion block must be called on the main thread"];
49+
OCMStub([mockEventChannel setStreamHandler:[OCMArg any]]).andDo(^(NSInvocation *invocation) {
50+
if (NSThread.isMainThread) {
51+
[mainThreadExpectation fulfill];
52+
}
53+
});
54+
55+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
56+
[threadSafeEventChannel setStreamHandler:nil
57+
completion:^{
58+
if (NSThread.isMainThread) {
59+
[mainThreadCompletionExpectation fulfill];
60+
}
61+
}];
62+
});
63+
[self waitForExpectationsWithTimeout:1 handler:nil];
64+
}
65+
66+
@end

packages/camera/camera/example/ios/RunnerTests/ThreadSafeFlutterResultTests.m

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ @interface ThreadSafeFlutterResultTests : XCTestCase
1010

1111
@implementation ThreadSafeFlutterResultTests
1212
- (void)testAsyncSendSuccess_ShouldCallResultOnMainThread {
13-
XCTestExpectation* expectation =
14-
[[XCTestExpectation alloc] initWithDescription:@"Result finished"];
13+
XCTestExpectation* expectation = [self expectationWithDescription:@"Result finished"];
1514

1615
FLTThreadSafeFlutterResult* threadSafeFlutterResult =
1716
[[FLTThreadSafeFlutterResult alloc] initWithResult:^(id _Nullable result) {
@@ -23,25 +22,23 @@ - (void)testAsyncSendSuccess_ShouldCallResultOnMainThread {
2322
[threadSafeFlutterResult sendSuccess];
2423
});
2524

26-
[self waitForExpectations:[NSArray arrayWithObject:expectation] timeout:1];
25+
[self waitForExpectationsWithTimeout:1 handler:nil];
2726
}
2827

2928
- (void)testSyncSendSuccess_ShouldCallResultOnMainThread {
30-
XCTestExpectation* expectation =
31-
[[XCTestExpectation alloc] initWithDescription:@"Result finished"];
29+
XCTestExpectation* expectation = [self expectationWithDescription:@"Result finished"];
3230

3331
FLTThreadSafeFlutterResult* threadSafeFlutterResult =
3432
[[FLTThreadSafeFlutterResult alloc] initWithResult:^(id _Nullable result) {
3533
XCTAssert(NSThread.isMainThread);
3634
[expectation fulfill];
3735
}];
3836
[threadSafeFlutterResult sendSuccess];
39-
[self waitForExpectations:[NSArray arrayWithObject:expectation] timeout:1];
37+
[self waitForExpectationsWithTimeout:1 handler:nil];
4038
}
4139

4240
- (void)testSendNotImplemented_ShouldSendNotImplementedToFlutterResult {
43-
XCTestExpectation* expectation =
44-
[[XCTestExpectation alloc] initWithDescription:@"Result finished"];
41+
XCTestExpectation* expectation = [self expectationWithDescription:@"Result finished"];
4542

4643
FLTThreadSafeFlutterResult* threadSafeFlutterResult =
4744
[[FLTThreadSafeFlutterResult alloc] initWithResult:^(id _Nullable result) {
@@ -53,15 +50,14 @@ - (void)testSendNotImplemented_ShouldSendNotImplementedToFlutterResult {
5350
[threadSafeFlutterResult sendNotImplemented];
5451
});
5552

56-
[self waitForExpectations:[NSArray arrayWithObject:expectation] timeout:1];
53+
[self waitForExpectationsWithTimeout:1 handler:nil];
5754
}
5855

5956
- (void)testSendErrorDetails_ShouldSendErrorToFlutterResult {
6057
NSString* errorCode = @"errorCode";
6158
NSString* errorMessage = @"message";
6259
NSString* errorDetails = @"error details";
63-
XCTestExpectation* expectation =
64-
[[XCTestExpectation alloc] initWithDescription:@"Result finished"];
60+
XCTestExpectation* expectation = [self expectationWithDescription:@"Result finished"];
6561

6662
FLTThreadSafeFlutterResult* threadSafeFlutterResult =
6763
[[FLTThreadSafeFlutterResult alloc] initWithResult:^(id _Nullable result) {
@@ -77,13 +73,12 @@ - (void)testSendErrorDetails_ShouldSendErrorToFlutterResult {
7773
[threadSafeFlutterResult sendErrorWithCode:errorCode message:errorMessage details:errorDetails];
7874
});
7975

80-
[self waitForExpectations:[NSArray arrayWithObject:expectation] timeout:1];
76+
[self waitForExpectationsWithTimeout:1 handler:nil];
8177
}
8278

8379
- (void)testSendNSError_ShouldSendErrorToFlutterResult {
8480
NSError* originalError = [[NSError alloc] initWithDomain:NSURLErrorDomain code:404 userInfo:nil];
85-
XCTestExpectation* expectation =
86-
[[XCTestExpectation alloc] initWithDescription:@"Result finished"];
81+
XCTestExpectation* expectation = [self expectationWithDescription:@"Result finished"];
8782

8883
FLTThreadSafeFlutterResult* threadSafeFlutterResult =
8984
[[FLTThreadSafeFlutterResult alloc] initWithResult:^(id _Nullable result) {
@@ -99,13 +94,12 @@ - (void)testSendNSError_ShouldSendErrorToFlutterResult {
9994
[threadSafeFlutterResult sendError:originalError];
10095
});
10196

102-
[self waitForExpectations:[NSArray arrayWithObject:expectation] timeout:1];
97+
[self waitForExpectationsWithTimeout:1 handler:nil];
10398
}
10499

105100
- (void)testSendResult_ShouldSendResultToFlutterResult {
106101
NSString* resultData = @"resultData";
107-
XCTestExpectation* expectation =
108-
[[XCTestExpectation alloc] initWithDescription:@"Result finished"];
102+
XCTestExpectation* expectation = [self expectationWithDescription:@"Result finished"];
109103

110104
FLTThreadSafeFlutterResult* threadSafeFlutterResult =
111105
[[FLTThreadSafeFlutterResult alloc] initWithResult:^(id _Nullable result) {
@@ -117,6 +111,6 @@ - (void)testSendResult_ShouldSendResultToFlutterResult {
117111
[threadSafeFlutterResult sendSuccessWithData:resultData];
118112
});
119113

120-
[self waitForExpectations:[NSArray arrayWithObject:expectation] timeout:1];
114+
[self waitForExpectationsWithTimeout:1 handler:nil];
121115
}
122116
@end
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
@import camera;
6+
@import XCTest;
7+
#import <OCMock/OCMock.h>
8+
9+
@interface ThreadSafeMethodChannelTests : XCTestCase
10+
@end
11+
12+
@implementation ThreadSafeMethodChannelTests
13+
14+
- (void)testInvokeMethod_shouldStayOnMainThreadIfCalledFromMainThread {
15+
FlutterMethodChannel *mockMethodChannel = OCMClassMock([FlutterMethodChannel class]);
16+
FLTThreadSafeMethodChannel *threadSafeMethodChannel =
17+
[[FLTThreadSafeMethodChannel alloc] initWithMethodChannel:mockMethodChannel];
18+
19+
XCTestExpectation *mainThreadExpectation =
20+
[self expectationWithDescription:@"invokeMethod must be called on the main thread"];
21+
22+
OCMStub([mockMethodChannel invokeMethod:[OCMArg any] arguments:[OCMArg any]])
23+
.andDo(^(NSInvocation *invocation) {
24+
if (NSThread.isMainThread) {
25+
[mainThreadExpectation fulfill];
26+
}
27+
});
28+
29+
[threadSafeMethodChannel invokeMethod:@"foo" arguments:nil];
30+
[self waitForExpectationsWithTimeout:1 handler:nil];
31+
}
32+
33+
- (void)testInvokeMethod__shouldDispatchToMainThreadIfCalledFromBackgroundThread {
34+
FlutterMethodChannel *mockMethodChannel = OCMClassMock([FlutterMethodChannel class]);
35+
FLTThreadSafeMethodChannel *threadSafeMethodChannel =
36+
[[FLTThreadSafeMethodChannel alloc] initWithMethodChannel:mockMethodChannel];
37+
38+
XCTestExpectation *mainThreadExpectation =
39+
[self expectationWithDescription:@"invokeMethod must be called on the main thread"];
40+
41+
OCMStub([mockMethodChannel invokeMethod:[OCMArg any] arguments:[OCMArg any]])
42+
.andDo(^(NSInvocation *invocation) {
43+
if (NSThread.isMainThread) {
44+
[mainThreadExpectation fulfill];
45+
}
46+
});
47+
48+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
49+
[threadSafeMethodChannel invokeMethod:@"foo" arguments:nil];
50+
});
51+
[self waitForExpectationsWithTimeout:1 handler:nil];
52+
}
53+
54+
@end

0 commit comments

Comments
 (0)