From 50705367ce6fcdaefb725c022d1169b82b67dbbf Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Fri, 27 Dec 2024 14:07:32 +0100 Subject: [PATCH 01/31] Introduce protocols and remove OCMock from CameraFocusTests --- .../ios/Runner.xcodeproj/project.pbxproj | 81 ++++++--- .../xcshareddata/swiftpm/Package.resolved | 14 ++ .../ios/RunnerTests/CameraFocusTests.m | 135 ++++++++------ .../ios/RunnerTests/CameraPreviewPauseTests.m | 1 - .../example/ios/RunnerTests/CameraTestUtils.m | 9 +- .../ios/RunnerTests/FLTCamPhotoCaptureTests.m | 7 +- .../RunnerTests/MockCaptureDeviceController.h | 80 +++++++++ .../RunnerTests/MockCaptureDeviceController.m | 127 +++++++++++++ .../MockDeviceOrientationProvider.h | 17 ++ .../MockDeviceOrientationProvider.m | 14 ++ .../RunnerTests/Mocks/MockDeviceController.m | 6 + .../Sources/camera_avfoundation/FLTCam.m | 21 ++- .../FLTCamMediaSettingsAVWrapper.m | 9 +- .../Protocols/FLTCaptureDeviceControlling.m | 170 ++++++++++++++++++ .../Protocols/FLTDeviceOrientationProviding.m | 13 ++ .../include/CameraPlugin.modulemap | 2 + .../include/camera_avfoundation/FLTCam.h | 5 +- .../FLTCamMediaSettingsAVWrapper.h | 10 +- .../include/camera_avfoundation/FLTCam_Test.h | 3 +- .../Protocols/FLTCaptureDeviceControlling.h | 72 ++++++++ .../Protocols/FLTDeviceOrientationProviding.h | 17 ++ 21 files changed, 709 insertions(+), 104 deletions(-) create mode 100644 packages/camera/camera_avfoundation/example/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.h create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.m create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceController.m create mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m create mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m create mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.h create mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.h diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj index 041d918da5b..04b0b3c4550 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,22 +3,25 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 60; objects = { /* Begin PBXBuildFile section */ 033B94BE269C40A200B4DF97 /* CameraMethodChannelTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 033B94BD269C40A200B4DF97 /* CameraMethodChannelTests.m */; }; 03BB766B2665316900CE5A93 /* CameraFocusTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 03BB766A2665316900CE5A93 /* CameraFocusTests.m */; }; + 1000364CB781922C6D6AAA4A /* libPods-RunnerTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9DDC4CE84A8B378AE4A8CD9C /* libPods-RunnerTests.a */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 236906D1621AE863A5B2E770 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 89D82918721FABF772705DB0 /* libPods-Runner.a */; }; - 25C3919135C3D981E6F800D0 /* libPods-RunnerTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1944D8072499F3B5E7653D44 /* libPods-RunnerTests.a */; }; 334733EA2668111C00DCC49E /* CameraOrientationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 03BB767226653ABE00CE5A93 /* CameraOrientationTests.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 408D7A792C3C9CD000B71F9A /* OCMock in Frameworks */ = {isa = PBXBuildFile; productRef = 408D7A782C3C9CD000B71F9A /* OCMock */; }; 43ED1537282570DE00EB00DE /* AvailableCamerasTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 43ED1536282570DE00EB00DE /* AvailableCamerasTest.m */; }; + 54D650172516862D30686934 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ECAF63F924EFA2D68883BA85 /* libPods-Runner.a */; }; 788A065A27B0E02900533D74 /* StreamingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 788A065927B0E02900533D74 /* StreamingTest.m */; }; 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; 7D5FCCD42AEF9D0200FB7108 /* CameraSettingsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D5FCCD32AEF9D0200FB7108 /* CameraSettingsTests.m */; }; + 7F56D0382D1EDDCE005676A5 /* CameraPermissionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0B0D2BA27DFF2AF00E71E4B /* CameraPermissionTests.m */; }; + 7F87E8022D01FD6F00A3549C /* MockCaptureDeviceController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */; }; + 7F87E80C2D0325D900A3549C /* MockDeviceOrientationProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F87E80B2D0325D700A3549C /* MockDeviceOrientationProvider.m */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; @@ -30,7 +33,6 @@ E04F108627A87CA600573D0C /* FLTSavePhotoDelegateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E04F108527A87CA600573D0C /* FLTSavePhotoDelegateTests.m */; }; E071CF7227B3061B006EF3BA /* FLTCamPhotoCaptureTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E071CF7127B3061B006EF3BA /* FLTCamPhotoCaptureTests.m */; }; E071CF7427B31DE4006EF3BA /* FLTCamSampleBufferTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E071CF7327B31DE4006EF3BA /* FLTCamSampleBufferTests.m */; }; - E0B0D2BB27DFF2AF00E71E4B /* CameraPermissionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0B0D2BA27DFF2AF00E71E4B /* CameraPermissionTests.m */; }; E0C6E2022770F01A00EA6AA3 /* ThreadSafeEventChannelTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0C6E1FF2770F01A00EA6AA3 /* ThreadSafeEventChannelTests.m */; }; E0CDBAC227CD9729002561D9 /* CameraTestUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = E0CDBAC127CD9729002561D9 /* CameraTestUtils.m */; }; E0F95E3D27A32AB900699390 /* CameraPropertiesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0F95E3C27A32AB900699390 /* CameraPropertiesTests.m */; }; @@ -68,17 +70,18 @@ 03BB767226653ABE00CE5A93 /* CameraOrientationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CameraOrientationTests.m; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 14AE82C910C2A12F2ECB2094 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 1944D8072499F3B5E7653D44 /* libPods-RunnerTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RunnerTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 43ED1536282570DE00EB00DE /* AvailableCamerasTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AvailableCamerasTest.m; sourceTree = ""; }; - 59848A7CA98C1FADF8840207 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 4A191381C3593DF1AC4E7559 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 788A065927B0E02900533D74 /* StreamingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StreamingTest.m; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 7D5FCCD32AEF9D0200FB7108 /* CameraSettingsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CameraSettingsTests.m; sourceTree = ""; }; - 89D82918721FABF772705DB0 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCaptureDeviceController.m; sourceTree = ""; }; + 7F87E8032D02FF8C00A3549C /* MockCaptureDeviceController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCaptureDeviceController.h; sourceTree = ""; }; + 7F87E80A2D0325B200A3549C /* MockDeviceOrientationProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockDeviceOrientationProvider.h; sourceTree = ""; }; + 7F87E80B2D0325D700A3549C /* MockDeviceOrientationProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockDeviceOrientationProvider.m; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -87,8 +90,9 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 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 = ""; }; - 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 = ""; }; + 9DDC4CE84A8B378AE4A8CD9C /* libPods-RunnerTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RunnerTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + A8F314CD1C64E9257EBC811D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + B61D98BBC8FB276D1C4A7BB2 /* 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 = ""; }; CEF661192B5E36A500D33FD4 /* CameraSessionPresetsTests.m */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = CameraSessionPresetsTests.m; sourceTree = ""; }; E01EE4A72799F3A5008C1950 /* QueueUtilsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QueueUtilsTests.m; sourceTree = ""; }; E032F24F279F5E94009E9028 /* CameraCaptureSessionQueueRaceConditionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CameraCaptureSessionQueueRaceConditionTests.m; sourceTree = ""; }; @@ -101,6 +105,8 @@ E0CDBAC127CD9729002561D9 /* CameraTestUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CameraTestUtils.m; sourceTree = ""; }; E0F95E3C27A32AB900699390 /* CameraPropertiesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CameraPropertiesTests.m; sourceTree = ""; }; E487C85F26D686A10034AC92 /* CameraPreviewPauseTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CameraPreviewPauseTests.m; sourceTree = ""; }; + E67C6DBF6478BE708993169F /* 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 = ""; }; + ECAF63F924EFA2D68883BA85 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -109,7 +115,7 @@ buildActionMask = 2147483647; files = ( 408D7A792C3C9CD000B71F9A /* OCMock in Frameworks */, - 25C3919135C3D981E6F800D0 /* libPods-RunnerTests.a in Frameworks */, + 1000364CB781922C6D6AAA4A /* libPods-RunnerTests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -118,7 +124,7 @@ buildActionMask = 2147483647; files = ( 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, - 236906D1621AE863A5B2E770 /* libPods-Runner.a in Frameworks */, + 54D650172516862D30686934 /* libPods-Runner.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -128,6 +134,10 @@ 03BB76692665316900CE5A93 /* RunnerTests */ = { isa = PBXGroup; children = ( + 7F87E80B2D0325D700A3549C /* MockDeviceOrientationProvider.m */, + 7F87E80A2D0325B200A3549C /* MockDeviceOrientationProvider.h */, + 7F87E8032D02FF8C00A3549C /* MockCaptureDeviceController.h */, + 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */, 7D5FCCD32AEF9D0200FB7108 /* CameraSettingsTests.m */, 03BB766A2665316900CE5A93 /* CameraFocusTests.m */, 03BB767226653ABE00CE5A93 /* CameraOrientationTests.m */, @@ -154,8 +164,8 @@ 3242FD2B467C15C62200632F /* Frameworks */ = { isa = PBXGroup; children = ( - 89D82918721FABF772705DB0 /* libPods-Runner.a */, - 1944D8072499F3B5E7653D44 /* libPods-RunnerTests.a */, + ECAF63F924EFA2D68883BA85 /* libPods-Runner.a */, + 9DDC4CE84A8B378AE4A8CD9C /* libPods-RunnerTests.a */, ); name = Frameworks; sourceTree = ""; @@ -219,10 +229,10 @@ FD386F00E98D73419C929072 /* Pods */ = { isa = PBXGroup; children = ( - 59848A7CA98C1FADF8840207 /* Pods-Runner.debug.xcconfig */, - 14AE82C910C2A12F2ECB2094 /* Pods-Runner.release.xcconfig */, - 9C5CC6CAD53AD388B2694F3A /* Pods-RunnerTests.debug.xcconfig */, - A24F9E418BA48BCC7409B117 /* Pods-RunnerTests.release.xcconfig */, + A8F314CD1C64E9257EBC811D /* Pods-Runner.debug.xcconfig */, + 4A191381C3593DF1AC4E7559 /* Pods-Runner.release.xcconfig */, + B61D98BBC8FB276D1C4A7BB2 /* Pods-RunnerTests.debug.xcconfig */, + E67C6DBF6478BE708993169F /* Pods-RunnerTests.release.xcconfig */, ); path = Pods; sourceTree = ""; @@ -263,6 +273,7 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 2B62C73988DE02487EF557D4 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -305,7 +316,7 @@ ); mainGroup = 97C146E51CF9000F007C117D; packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, 408D7A772C3C9CD000B71F9A /* XCRemoteSwiftPackageReference "ocmock" */, ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; @@ -340,6 +351,28 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 2B62C73988DE02487EF557D4 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/camera_avfoundation/camera_avfoundation_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/path_provider_foundation/path_provider_foundation_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/video_player_avfoundation/video_player_avfoundation_privacy.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/camera_avfoundation_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/path_provider_foundation_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/video_player_avfoundation_privacy.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -424,10 +457,13 @@ files = ( 033B94BE269C40A200B4DF97 /* CameraMethodChannelTests.m in Sources */, E071CF7227B3061B006EF3BA /* FLTCamPhotoCaptureTests.m in Sources */, + 7F56D0382D1EDDCE005676A5 /* CameraPermissionTests.m in Sources */, E0F95E3D27A32AB900699390 /* CameraPropertiesTests.m in Sources */, 03BB766B2665316900CE5A93 /* CameraFocusTests.m in Sources */, + 7F87E8022D01FD6F00A3549C /* MockCaptureDeviceController.m in Sources */, 7D5FCCD42AEF9D0200FB7108 /* CameraSettingsTests.m in Sources */, E487C86026D686A10034AC92 /* CameraPreviewPauseTests.m in Sources */, + 7F87E80C2D0325D900A3549C /* MockDeviceOrientationProvider.m in Sources */, E071CF7427B31DE4006EF3BA /* FLTCamSampleBufferTests.m in Sources */, E04F108627A87CA600573D0C /* FLTSavePhotoDelegateTests.m in Sources */, 43ED1537282570DE00EB00DE /* AvailableCamerasTest.m in Sources */, @@ -437,7 +473,6 @@ E032F250279F5E94009E9028 /* CameraCaptureSessionQueueRaceConditionTests.m in Sources */, 788A065A27B0E02900533D74 /* StreamingTest.m in Sources */, E0C6E2022770F01A00EA6AA3 /* ThreadSafeEventChannelTests.m in Sources */, - E0B0D2BB27DFF2AF00E71E4B /* CameraPermissionTests.m in Sources */, E01EE4A82799F3A5008C1950 /* QueueUtilsTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -484,7 +519,7 @@ /* Begin XCBuildConfiguration section */ 03BB766F2665316900CE5A93 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9C5CC6CAD53AD388B2694F3A /* Pods-RunnerTests.debug.xcconfig */; + baseConfigurationReference = B61D98BBC8FB276D1C4A7BB2 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; @@ -513,7 +548,7 @@ }; 03BB76702665316900CE5A93 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = A24F9E418BA48BCC7409B117 /* Pods-RunnerTests.release.xcconfig */; + baseConfigurationReference = E67C6DBF6478BE708993169F /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; @@ -726,7 +761,7 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { isa = XCLocalSwiftPackageReference; relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; }; diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved b/packages/camera/camera_avfoundation/example/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 00000000000..a8d31f4703e --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,14 @@ +{ + "originHash" : "20e8ffe6c32a926c4f00e4e9a967104dab3f8007aacc282029f03ed5f5f2e183", + "pins" : [ + { + "identity" : "ocmock", + "kind" : "remoteSourceControl", + "location" : "https://github.com/erikdoe/ocmock", + "state" : { + "revision" : "fe1661a3efed11831a6452f4b1a0c5e6ddc08c3d" + } + } + ], + "version" : 3 +} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m index 0cb8333345a..edcd7c4795c 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m @@ -8,120 +8,149 @@ #endif @import XCTest; @import AVFoundation; -#import + +#import "MockCaptureDeviceController.h" +#import "MockDeviceOrientationProvider.h" @interface CameraFocusTests : XCTestCase @property(readonly, nonatomic) FLTCam *camera; -@property(readonly, nonatomic) id mockDevice; -@property(readonly, nonatomic) id mockUIDevice; +@property(readonly, nonatomic) MockCaptureDeviceController *mockDevice; +@property(readonly, nonatomic) MockDeviceOrientationProvider *mockDeviceOrientationProvider; @end @implementation CameraFocusTests - (void)setUp { _camera = [[FLTCam alloc] init]; - _mockDevice = OCMClassMock([AVCaptureDevice class]); - _mockUIDevice = OCMPartialMock([UIDevice currentDevice]); -} - -- (void)tearDown { - [_mockDevice stopMocking]; - [_mockUIDevice stopMocking]; + _mockDevice = [[MockCaptureDeviceController alloc] init]; + _mockDeviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; } - (void)testAutoFocusWithContinuousModeSupported_ShouldSetContinuousAutoFocus { - // AVCaptureFocusModeContinuousAutoFocus is supported - OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]).andReturn(true); - // AVCaptureFocusModeContinuousAutoFocus is supported - OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]).andReturn(true); - - // Don't expect setFocusMode:AVCaptureFocusModeAutoFocus - [[_mockDevice reject] setFocusMode:AVCaptureFocusModeAutoFocus]; + // AVCaptureFocusModeContinuousAutoFocus and AVCaptureFocusModeContinuousAutoFocus are supported + _mockDevice.isFocusModeSupportedStub = ^BOOL(AVCaptureFocusMode mode) { + return mode == AVCaptureFocusModeContinuousAutoFocus || mode == AVCaptureFocusModeAutoFocus; + }; + + __block BOOL setFocusModeContinuousAutoFocusCalled = NO; + + _mockDevice.setFocusModeStub = ^(AVCaptureFocusMode mode) { + // Don't expect setFocusMode:AVCaptureFocusModeAutoFocus + if (mode == AVCaptureFocusModeAutoFocus) { + XCTFail(@"Unexpected call to setFocusMode"); + } else if (mode == AVCaptureFocusModeContinuousAutoFocus) { + setFocusModeContinuousAutoFocusCalled = YES; + } + }; // Run test [_camera applyFocusMode:FCPPlatformFocusModeAuto onDevice:_mockDevice]; // Expect setFocusMode:AVCaptureFocusModeContinuousAutoFocus - OCMVerify([_mockDevice setFocusMode:AVCaptureFocusModeContinuousAutoFocus]); + XCTAssertTrue(setFocusModeContinuousAutoFocusCalled); } - (void)testAutoFocusWithContinuousModeNotSupported_ShouldSetAutoFocus { // AVCaptureFocusModeContinuousAutoFocus is not supported - OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) - .andReturn(false); - // AVCaptureFocusModeContinuousAutoFocus is supported - OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]).andReturn(true); - + // AVCaptureFocusModeAutoFocus is supported + _mockDevice.isFocusModeSupportedStub = ^BOOL(AVCaptureFocusMode mode) { + return mode == AVCaptureFocusModeAutoFocus; + }; + + __block BOOL setFocusModeAutoFocusCalled = NO; + // Don't expect setFocusMode:AVCaptureFocusModeContinuousAutoFocus - [[_mockDevice reject] setFocusMode:AVCaptureFocusModeContinuousAutoFocus]; - + _mockDevice.setFocusModeStub = ^(AVCaptureFocusMode mode) { + if (mode == AVCaptureFocusModeContinuousAutoFocus) { + XCTFail(@"Unexpected call to setFocusMode"); + } else if (mode == AVCaptureFocusModeAutoFocus) { + setFocusModeAutoFocusCalled = YES; + } + }; + // Run test [_camera applyFocusMode:FCPPlatformFocusModeAuto onDevice:_mockDevice]; - + // Expect setFocusMode:AVCaptureFocusModeAutoFocus - OCMVerify([_mockDevice setFocusMode:AVCaptureFocusModeAutoFocus]); + XCTAssertTrue(setFocusModeAutoFocusCalled); } - (void)testAutoFocusWithNoModeSupported_ShouldSetNothing { - // AVCaptureFocusModeContinuousAutoFocus is not supported - OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) - .andReturn(false); - // AVCaptureFocusModeContinuousAutoFocus is not supported - OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]).andReturn(false); + // No modes are supported + _mockDevice.isFocusModeSupportedStub = ^BOOL(AVCaptureFocusMode mode) { + return NO; + }; // Don't expect any setFocus - [[_mockDevice reject] setFocusMode:AVCaptureFocusModeContinuousAutoFocus]; - [[_mockDevice reject] setFocusMode:AVCaptureFocusModeAutoFocus]; + _mockDevice.setFocusModeStub = ^(AVCaptureFocusMode mode) { + XCTFail(@"Unexpected call to setFocusMode"); + }; // Run test [_camera applyFocusMode:FCPPlatformFocusModeAuto onDevice:_mockDevice]; } - (void)testLockedFocusWithModeSupported_ShouldSetModeAutoFocus { - // AVCaptureFocusModeContinuousAutoFocus is supported - OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]).andReturn(true); - // AVCaptureFocusModeContinuousAutoFocus is supported - OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]).andReturn(true); - - // Don't expect any setFocus - [[_mockDevice reject] setFocusMode:AVCaptureFocusModeContinuousAutoFocus]; - + // AVCaptureFocusModeContinuousAutoFocus and AVCaptureFocusModeAutoFocus are supported + _mockDevice.isFocusModeSupportedStub = ^BOOL(AVCaptureFocusMode mode) { + return mode == AVCaptureFocusModeContinuousAutoFocus || mode == AVCaptureFocusModeAutoFocus; + }; + + __block BOOL setFocusModeAutoFocusCalled = NO; + + // Expect only setFocusMode:AVCaptureFocusModeAutoFocus + _mockDevice.setFocusModeStub = ^(AVCaptureFocusMode mode) { + if (mode == AVCaptureFocusModeContinuousAutoFocus) { + XCTFail(@"Unexpected call to setFocusMode"); + } else if (mode == AVCaptureFocusModeAutoFocus) { + setFocusModeAutoFocusCalled = YES; + } + }; + // Run test [_camera applyFocusMode:FCPPlatformFocusModeLocked onDevice:_mockDevice]; - // Expect setFocusMode:AVCaptureFocusModeAutoFocus - OCMVerify([_mockDevice setFocusMode:AVCaptureFocusModeAutoFocus]); + XCTAssertTrue(setFocusModeAutoFocusCalled); } - (void)testLockedFocusWithModeNotSupported_ShouldSetNothing { - // AVCaptureFocusModeContinuousAutoFocus is supported - OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]).andReturn(true); - // AVCaptureFocusModeContinuousAutoFocus is not supported - OCMStub([_mockDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]).andReturn(false); + _mockDevice.isFocusModeSupportedStub = ^BOOL(AVCaptureFocusMode mode) { + return mode == AVCaptureFocusModeContinuousAutoFocus; + }; // Don't expect any setFocus - [[_mockDevice reject] setFocusMode:AVCaptureFocusModeContinuousAutoFocus]; - [[_mockDevice reject] setFocusMode:AVCaptureFocusModeAutoFocus]; + _mockDevice.setFocusModeStub = ^(AVCaptureFocusMode mode) { + XCTFail(@"Unexpected call to setFocusMode"); + }; // Run test [_camera applyFocusMode:FCPPlatformFocusModeLocked onDevice:_mockDevice]; } +// TODO(mchudy): replace setValue with proper DI - (void)testSetFocusPointWithResult_SetsFocusPointOfInterest { // UI is currently in landscape left orientation - OCMStub([(UIDevice *)_mockUIDevice orientation]).andReturn(UIDeviceOrientationLandscapeLeft); + [_camera setValue:_mockDeviceOrientationProvider forKey:@"deviceOrientationProvider"]; + _mockDeviceOrientationProvider.orientation = UIDeviceOrientationLandscapeLeft; // Focus point of interest is supported - OCMStub([_mockDevice isFocusPointOfInterestSupported]).andReturn(true); + _mockDevice.isFocusPointOfInterestSupported = YES; // Set mock device as the current capture device [_camera setValue:_mockDevice forKey:@"captureDevice"]; + __block BOOL setFocusPointOfInterestCalled = NO; + _mockDevice.setFocusPointOfInterestStub = ^(CGPoint point) { + if (point.x == 1 && point.y == 1) { + setFocusPointOfInterestCalled = YES; + } + }; + // Run test [_camera setFocusPoint:[FCPPlatformPoint makeWithX:1 y:1] withCompletion:^(FlutterError *_Nullable error){ }]; // Verify the focus point of interest has been set - OCMVerify([_mockDevice setFocusPointOfInterest:CGPointMake(1, 1)]); + XCTAssertTrue(setFocusPointOfInterestCalled); } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPreviewPauseTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPreviewPauseTests.m index 04bdd0795da..60dfca54168 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPreviewPauseTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPreviewPauseTests.m @@ -8,7 +8,6 @@ #endif @import XCTest; @import AVFoundation; -#import @interface CameraPreviewPauseTests : XCTestCase @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m index 503a5c255c5..501498d6382 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m @@ -88,8 +88,8 @@ videoCaptureSession:videoSessionMock audioCaptureSession:audioSessionMock captureSessionQueue:captureSessionQueue - captureDeviceFactory:captureDeviceFactory ?: ^AVCaptureDevice *(void) { - return captureDeviceMock; + captureDeviceFactory:captureDeviceFactory ?: ^id(void) { + return [[FLTDefaultCaptureDeviceController alloc] initWithDevice:captureDeviceMock]; } videoDimensionsForFormat:^CMVideoDimensions(AVCaptureDeviceFormat *format) { return CMVideoFormatDescriptionGetDimensions(format.formatDescription); @@ -161,9 +161,8 @@ videoCaptureSession:captureSession audioCaptureSession:audioSessionMock captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL) - captureDeviceFactory:^AVCaptureDevice *(void) { - return captureDevice; - } + captureDeviceFactory:^id(void) { + return [[FLTDefaultCaptureDeviceController alloc] initWithDevice:captureDevice]; } videoDimensionsForFormat:videoDimensionsForFormat error:nil]; } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m index 7f17e39a6b0..31711f065ef 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m @@ -171,7 +171,7 @@ - (void)testCaptureToFile_mustReportFileExtensionWithJpgWhenHEVCNotAvailableAndF }); [self waitForExpectationsWithTimeout:1 handler:nil]; } - +// - (void)testCaptureToFile_handlesTorchMode { XCTestExpectation *pathExpectation = [self expectationWithDescription: @@ -188,8 +188,9 @@ - (void)testCaptureToFile_handlesTorchMode { (void *)FLTCaptureSessionQueueSpecific, NULL); FLTCam *cam = FLTCreateCamWithCaptureSessionQueueAndMediaSettings(captureSessionQueue, nil, nil, - ^AVCaptureDevice *(void) { - return captureDeviceMock; + ^id(void) { + return + [[FLTDefaultCaptureDeviceController alloc] initWithDevice:captureDeviceMock]; }); AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettings]; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h new file mode 100644 index 00000000000..8723b191024 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h @@ -0,0 +1,80 @@ +// 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. + +@import camera_avfoundation; +#if __has_include() +@import camera_avfoundation.Test; +#endif +@import AVFoundation; + +NS_ASSUME_NONNULL_BEGIN + +@interface MockCaptureDeviceController : NSObject +// Position/Orientation +@property(nonatomic, assign) AVCaptureDevicePosition position; + +// Format/Configuration +@property(nonatomic, strong) AVCaptureDeviceFormat *activeFormat; +@property(nonatomic, strong) NSArray *formats; +@property(nonatomic, copy) void (^setActiveFormatStub)(AVCaptureDeviceFormat *format); + +// Flash/Torch +@property(nonatomic, assign) BOOL hasFlash; +@property(nonatomic, assign) BOOL hasTorch; +@property(nonatomic, assign) BOOL isTorchAvailable; +@property(nonatomic, assign) AVCaptureTorchMode torchMode; +@property(nonatomic, copy) void (^setTorchModeStub)(AVCaptureTorchMode mode); +@property(nonatomic, assign) BOOL flashModeSupported; + +// Focus +@property(nonatomic, assign) BOOL focusPointOfInterestSupported; +@property(nonatomic, copy) BOOL (^isFocusModeSupportedStub)(AVCaptureFocusMode mode); +@property(nonatomic, assign) AVCaptureFocusMode focusMode; +@property(nonatomic, copy) void (^setFocusModeStub)(AVCaptureFocusMode mode); +@property(nonatomic, assign) CGPoint focusPointOfInterest; +@property(nonatomic, copy) void (^setFocusPointOfInterestStub)(CGPoint point); + +// Exposure +@property(nonatomic, assign) BOOL exposurePointOfInterestSupported; +@property(nonatomic, assign) AVCaptureExposureMode exposureMode; +@property(nonatomic, assign) BOOL exposureModeSupported; +@property(nonatomic, copy) void (^setExposureModeStub)(AVCaptureExposureMode mode); +@property(nonatomic, assign) CGPoint exposurePointOfInterest; +@property(nonatomic, copy) void (^setExposurePointOfInterestStub)(CGPoint point); +@property(nonatomic, assign) float minExposureTargetBias; +@property(nonatomic, assign) float maxExposureTargetBias; +@property(nonatomic, copy) void (^setExposureTargetBiasStub)(float bias, void (^_Nullable handler)(CMTime)); + +// Zoom +@property(nonatomic, assign) float maxAvailableVideoZoomFactor; +@property(nonatomic, assign) float minAvailableVideoZoomFactor; +@property(nonatomic, assign) float videoZoomFactor; +@property(nonatomic, copy) void (^setVideoZoomFactorStub)(float factor); + +// Camera Properties +@property(nonatomic, assign) float lensAperture; +@property(nonatomic, assign) CMTime exposureDuration; +@property(nonatomic, assign) float ISO; + +// Configuration Lock +@property(nonatomic, assign) BOOL shouldFailConfiguration; +@property(nonatomic, copy) void (^lockForConfigurationStub)(NSError **error); +@property(nonatomic, copy) void (^unlockForConfigurationStub)(void); + +// Frame Duration +@property(nonatomic, assign) CMTime activeVideoMinFrameDuration; +@property(nonatomic, assign) CMTime activeVideoMaxFrameDuration; +@property(nonatomic, copy) void (^setActiveVideoMinFrameDurationStub)(CMTime duration); +@property(nonatomic, copy) void (^setActiveVideoMaxFrameDurationStub)(CMTime duration); + +// Input Creation +@property(nonatomic, strong) AVCaptureInput *inputToReturn; +@property(nonatomic, copy) void (^createInputStub)(NSError **error); + +@property(nonatomic, assign) BOOL isExposurePointOfInterestSupported; +@property(nonatomic, assign) BOOL isFocusPointOfInterestSupported; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m new file mode 100644 index 00000000000..c1659d36f07 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m @@ -0,0 +1,127 @@ +// 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. + +@import camera_avfoundation; +#if __has_include() +@import camera_avfoundation.Test; +#endif +@import AVFoundation; + +#import "MockCaptureDeviceController.h" + +@implementation MockCaptureDeviceController + +- (void)setActiveFormat:(AVCaptureDeviceFormat *)format { + _activeFormat = format; + if (self.setActiveFormatStub) { + self.setActiveFormatStub(format); + } +} + +- (BOOL)isFlashModeSupported:(AVCaptureFlashMode)mode { + return self.flashModeSupported; +} + +- (void)setTorchMode:(AVCaptureTorchMode)mode { + _torchMode = mode; + if (self.setTorchModeStub) { + self.setTorchModeStub(mode); + } +} + +- (BOOL)isFocusModeSupported:(AVCaptureFocusMode)mode { + if (self.isFocusModeSupportedStub) { + return self.isFocusModeSupportedStub(mode); + } + return NO; +} + +- (void)setFocusMode:(AVCaptureFocusMode)mode { + _focusMode = mode; + if (self.setFocusModeStub) { + self.setFocusModeStub(mode); + } +} + +- (void)setFocusPointOfInterest:(CGPoint)point { + _focusPointOfInterest = point; + if (self.setFocusPointOfInterestStub) { + self.setFocusPointOfInterestStub(point); + } +} + +- (void)setExposureMode:(AVCaptureExposureMode)mode { + _exposureMode = mode; + if (self.setExposureModeStub) { + self.setExposureModeStub(mode); + } +} + +- (void)setExposurePointOfInterest:(CGPoint)point { + _exposurePointOfInterest = point; + if (self.setExposurePointOfInterestStub) { + self.setExposurePointOfInterestStub(point); + } +} + +- (void)setExposureTargetBias:(float)bias completionHandler:(void (^)(CMTime))handler { + if (self.setExposureTargetBiasStub) { + self.setExposureTargetBiasStub(bias, handler); + } +} + +- (void)setVideoZoomFactor:(float)factor { + _videoZoomFactor = factor; + if (self.setVideoZoomFactorStub) { + self.setVideoZoomFactorStub(factor); + } +} + +- (BOOL)lockForConfiguration:(NSError **)error { + if (self.lockForConfigurationStub) { + self.lockForConfigurationStub(error); + return !self.shouldFailConfiguration; + } + if (self.shouldFailConfiguration) { + if (error) { + *error = [NSError errorWithDomain:@"test" code:0 userInfo:nil]; + } + return NO; + } + return YES; +} + +- (void)unlockForConfiguration { + if (self.unlockForConfigurationStub) { + self.unlockForConfigurationStub(); + } +} + +- (void)setActiveVideoMinFrameDuration:(CMTime)duration { + _activeVideoMinFrameDuration = duration; + if (self.setActiveVideoMinFrameDurationStub) { + self.setActiveVideoMinFrameDurationStub(duration); + } +} + +- (void)setActiveVideoMaxFrameDuration:(CMTime)duration { + _activeVideoMaxFrameDuration = duration; + if (self.setActiveVideoMaxFrameDurationStub) { + self.setActiveVideoMaxFrameDurationStub(duration); + } +} + +- (BOOL)isExposureModeSupported:(AVCaptureExposureMode)mode { + return self.exposureModeSupported; +} + +- (AVCaptureInput *)createInput:(NSError *_Nullable *_Nullable)error { + if (self.createInputStub) { + self.createInputStub(error); + } + return self.inputToReturn; +} + + +@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.h new file mode 100644 index 00000000000..0421ec66529 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.h @@ -0,0 +1,17 @@ +// 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. + +@import camera_avfoundation; +#if __has_include() +@import camera_avfoundation.Test; +#endif +@import AVFoundation; + +NS_ASSUME_NONNULL_BEGIN + +@interface MockDeviceOrientationProvider : NSObject +@property(nonatomic, assign) UIDeviceOrientation orientation; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.m new file mode 100644 index 00000000000..963cb7e96ff --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.m @@ -0,0 +1,14 @@ +// 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. + +@import camera_avfoundation; +#if __has_include() +@import camera_avfoundation.Test; +#endif +@import AVFoundation; + +#import "MockDeviceOrientationProvider.h" + +@implementation MockDeviceOrientationProvider +@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceController.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceController.m new file mode 100644 index 00000000000..27cc985d7d2 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceController.m @@ -0,0 +1,6 @@ +// 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. + + +@interface FLTMockCaptureDeviceController : NSObject diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 0b065026f10..2174f699869 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -13,6 +13,8 @@ #import "./include/camera_avfoundation/FLTThreadSafeEventChannel.h" #import "./include/camera_avfoundation/QueueUtils.h" #import "./include/camera_avfoundation/messages.g.h" +#import "./include/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.h" +#import "./include/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.h" static FlutterError *FlutterErrorFromNSError(NSError *error) { return [FlutterError errorWithCode:[NSString stringWithFormat:@"Error %d", (int)error.code] @@ -103,7 +105,7 @@ @interface FLTCam () deviceOrientationProvider; /// Reports the given error message to the Dart side of the plugin. /// /// Can be called from any thread. @@ -144,8 +146,9 @@ - (instancetype)initWithCameraName:(NSString *)cameraName videoCaptureSession:videoCaptureSession audioCaptureSession:videoCaptureSession captureSessionQueue:captureSessionQueue - captureDeviceFactory:^AVCaptureDevice *(void) { - return [AVCaptureDevice deviceWithUniqueID:cameraName]; + captureDeviceFactory:^id (void) { + AVCaptureDevice *device = [AVCaptureDevice deviceWithUniqueID:cameraName]; + return [[FLTDefaultCaptureDeviceController alloc] initWithDevice:device]; } videoDimensionsForFormat:^CMVideoDimensions(AVCaptureDeviceFormat *format) { return CMVideoFormatDescriptionGetDimensions(format.formatDescription); @@ -262,6 +265,8 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings _motionManager = [[CMMotionManager alloc] init]; [_motionManager startAccelerometerUpdates]; + + _deviceOrientationProvider = [[FLTDefaultDeviceOrientationProvider alloc] init]; if (_mediaSettings.framesPerSecond) { // The frame rate can be changed only on a locked for configuration device. @@ -309,7 +314,7 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings - (AVCaptureConnection *)createConnection:(NSError **)error { // Setup video capture input. - _captureVideoInput = [AVCaptureDeviceInput deviceInputWithDevice:_captureDevice error:error]; + _captureVideoInput = [_captureDevice createInput:error]; // Test the return value of the `deviceInputWithDevice` method to see whether an error occurred. // Don’t just test to see whether the error pointer was set to point to an error. @@ -344,8 +349,8 @@ - (void)reportInitializationState { height:self.previewSize.height] exposureMode:self.exposureMode focusMode:self.focusMode - exposurePointSupported:self.captureDevice.exposurePointOfInterestSupported - focusPointSupported:self.captureDevice.focusPointOfInterestSupported]; + exposurePointSupported:self.captureDevice.isExposurePointOfInterestSupported + focusPointSupported:self.captureDevice.isFocusPointOfInterestSupported]; __weak typeof(self) weakSelf = self; FLTEnsureToRunOnMainQueue(^{ @@ -1038,7 +1043,7 @@ - (void)applyFocusMode { [self applyFocusMode:_focusMode onDevice:_captureDevice]; } -- (void)applyFocusMode:(FCPPlatformFocusMode)focusMode onDevice:(AVCaptureDevice *)captureDevice { +- (void)applyFocusMode:(FCPPlatformFocusMode)focusMode onDevice:(id)captureDevice { [captureDevice lockForConfiguration:nil]; switch (focusMode) { case FCPPlatformFocusModeLocked: @@ -1175,7 +1180,7 @@ - (void)setFocusPoint:(FCPPlatformPoint *)point details:nil]); return; } - UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; + UIDeviceOrientation orientation = [_deviceOrientationProvider orientation]; [_captureDevice lockForConfiguration:nil]; // A nil point resets to the center. [_captureDevice diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m index b975daa4b5c..c712245a6ce 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m @@ -3,14 +3,15 @@ // found in the LICENSE file. #import "./include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h" +#import "./include/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.h" @implementation FLTCamMediaSettingsAVWrapper -- (BOOL)lockDevice:(AVCaptureDevice *)captureDevice error:(NSError *_Nullable *_Nullable)outError { +- (BOOL)lockDevice:(id)captureDevice error:(NSError *_Nullable *_Nullable)outError { return [captureDevice lockForConfiguration:outError]; } -- (void)unlockDevice:(AVCaptureDevice *)captureDevice { +- (void)unlockDevice:(id)captureDevice { return [captureDevice unlockForConfiguration]; } @@ -22,11 +23,11 @@ - (void)commitConfigurationForSession:(AVCaptureSession *)videoCaptureSession { [videoCaptureSession commitConfiguration]; } -- (void)setMinFrameDuration:(CMTime)duration onDevice:(AVCaptureDevice *)captureDevice { +- (void)setMinFrameDuration:(CMTime)duration onDevice:(id)captureDevice { captureDevice.activeVideoMinFrameDuration = duration; } -- (void)setMaxFrameDuration:(CMTime)duration onDevice:(AVCaptureDevice *)captureDevice { +- (void)setMaxFrameDuration:(CMTime)duration onDevice:(id)captureDevice { captureDevice.activeVideoMaxFrameDuration = duration; } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m new file mode 100644 index 00000000000..f89e44920f4 --- /dev/null +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m @@ -0,0 +1,170 @@ +// 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. + +#import "../include/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.h" + +@interface FLTDefaultCaptureDeviceController () +@property(nonatomic, strong) AVCaptureDevice *device; +@end + +@implementation FLTDefaultCaptureDeviceController + +- (instancetype)initWithDevice:(AVCaptureDevice *)device { + self = [super init]; + if (self) { + _device = device; + } + return self; +} + +// Position/Orientation +- (AVCaptureDevicePosition)position { + return self.device.position; +} + +// Format/Configuration +- (AVCaptureDeviceFormat *)activeFormat { + return self.device.activeFormat; +} + +- (NSArray *)formats { + return self.device.formats; +} + +- (void)setActiveFormat:(AVCaptureDeviceFormat *)format { + self.device.activeFormat = format; +} + +// Flash/Torch +- (BOOL)hasFlash { + return self.device.hasFlash; +} + +- (BOOL)hasTorch { + return self.device.hasTorch; +} + +- (BOOL)isTorchAvailable { + return self.device.isTorchAvailable; +} + +- (AVCaptureTorchMode)torchMode { + return self.device.torchMode; +} + +- (void)setTorchMode:(AVCaptureTorchMode)torchMode { + self.device.torchMode = torchMode; +} + +- (BOOL)isFlashModeSupported:(AVCaptureFlashMode)mode { + return [self.device isFlashModeSupported:mode]; +} + +// Focus +- (BOOL)isFocusPointOfInterestSupported { + return self.device.isFocusPointOfInterestSupported; +} + +- (BOOL)isFocusModeSupported:(AVCaptureFocusMode)mode { + return [self.device isFocusModeSupported:mode]; +} + +- (void)setFocusMode:(AVCaptureFocusMode)focusMode { + self.device.focusMode = focusMode; +} + +- (void)setFocusPointOfInterest:(CGPoint)point { + self.device.focusPointOfInterest = point; +} + +// Exposure +- (BOOL)isExposurePointOfInterestSupported { + return self.device.isExposurePointOfInterestSupported; +} + +- (void)setExposureMode:(AVCaptureExposureMode)exposureMode { + self.device.exposureMode = exposureMode; +} + +- (void)setExposurePointOfInterest:(CGPoint)point { + self.device.exposurePointOfInterest = point; +} + +- (float)minExposureTargetBias { + return self.device.minExposureTargetBias; +} + +- (float)maxExposureTargetBias { + return self.device.maxExposureTargetBias; +} + +- (void)setExposureTargetBias:(float)bias completionHandler:(void (^)(CMTime))handler { + [self.device setExposureTargetBias:bias completionHandler:handler]; +} + +- (BOOL)isExposureModeSupported:(AVCaptureExposureMode)mode { + return [self.device isExposureModeSupported:mode]; +} + +// Zoom +- (float)maxAvailableVideoZoomFactor { + return self.device.maxAvailableVideoZoomFactor; +} + +- (float)minAvailableVideoZoomFactor { + return self.device.minAvailableVideoZoomFactor; +} + +- (float)videoZoomFactor { + return self.device.videoZoomFactor; +} + +- (void)setVideoZoomFactor:(float)factor { + self.device.videoZoomFactor = factor; +} + +// Camera Properties +- (float)lensAperture { + return self.device.lensAperture; +} + +- (CMTime)exposureDuration { + return self.device.exposureDuration; +} + +- (float)ISO { + return self.device.ISO; +} + +// Configuration Lock +- (BOOL)lockForConfiguration:(NSError **)error { + return [self.device lockForConfiguration:error]; +} + +- (void)unlockForConfiguration { + [self.device unlockForConfiguration]; +} + +- (CMTime)activeVideoMinFrameDuration { + return self.device.activeVideoMinFrameDuration; +} + +- (void)setActiveVideoMinFrameDuration:(CMTime)duration { + self.device.activeVideoMinFrameDuration = duration; +} + +- (CMTime)activeVideoMaxFrameDuration { + return self.device.activeVideoMaxFrameDuration; +} + +- (void)setActiveVideoMaxFrameDuration:(CMTime)duration { + self.device.activeVideoMaxFrameDuration = duration; +} + +- (AVCaptureInput *)createInput:(NSError * _Nullable * _Nullable)error { + return [AVCaptureDeviceInput deviceInputWithDevice:_device error:error]; +} + + +@end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m new file mode 100644 index 00000000000..7b10f09109d --- /dev/null +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m @@ -0,0 +1,13 @@ +// 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. + +#import "../include/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.h" + +@implementation FLTDefaultDeviceOrientationProvider + +- (UIDeviceOrientation)orientation { + return [[UIDevice currentDevice] orientation]; +} + +@end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap index 57d858f894f..af0c9bee47f 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap @@ -13,6 +13,8 @@ framework module camera_avfoundation { header "FLTThreadSafeEventChannel.h" header "FLTPermissionServicing.h" header "FLTCameraPermissionManager.h" + header "FLTCaptureDeviceControlling.h" + header "FLTDeviceOrientationProviding.h" header "QueueUtils.h" } } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h index d8f97926b77..9fee90390a2 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h @@ -8,6 +8,7 @@ #import "CameraProperties.h" #import "FLTCamMediaSettingsAVWrapper.h" +#import "FLTCaptureDeviceControlling.h" #import "messages.g.h" NS_ASSUME_NONNULL_BEGIN @@ -15,7 +16,7 @@ NS_ASSUME_NONNULL_BEGIN /// A class that manages camera's state and performs camera operations. @interface FLTCam : NSObject -@property(readonly, nonatomic) AVCaptureDevice *captureDevice; +@property(readonly, nonatomic) id captureDevice; @property(readonly, nonatomic) CGSize previewSize; @property(assign, nonatomic) BOOL isPreviewPaused; @property(nonatomic, copy) void (^onFrameAvailable)(void); @@ -92,7 +93,7 @@ NS_ASSUME_NONNULL_BEGIN /// /// @param focusMode The focus mode that should be applied to the @captureDevice instance. /// @param captureDevice The AVCaptureDevice to which the @focusMode will be applied. -- (void)applyFocusMode:(FCPPlatformFocusMode)focusMode onDevice:(AVCaptureDevice *)captureDevice; +- (void)applyFocusMode:(FCPPlatformFocusMode)focusMode onDevice:(id)captureDevice; - (void)pausePreview; - (void)resumePreview; - (void)setDescriptionWhileRecording:(NSString *)cameraName diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h index 144a84eac13..4e8d9d15cd8 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h @@ -5,6 +5,8 @@ @import AVFoundation; @import Foundation; +#import "FLTCaptureDeviceControlling.h" + NS_ASSUME_NONNULL_BEGIN /** @@ -25,14 +27,14 @@ NS_ASSUME_NONNULL_BEGIN * @param outError The optional error. * @result A BOOL indicating whether the device was successfully locked for configuration. */ -- (BOOL)lockDevice:(AVCaptureDevice *)captureDevice error:(NSError *_Nullable *_Nullable)outError; +- (BOOL)lockDevice:(id)captureDevice error:(NSError *_Nullable *_Nullable)outError; /** * @method unlockDevice: * @abstract Release exclusive control over device hardware properties. * @param captureDevice The capture device. */ -- (void)unlockDevice:(AVCaptureDevice *)captureDevice; +- (void)unlockDevice:(id)captureDevice; /** * @method beginConfigurationForSession: @@ -57,7 +59,7 @@ NS_ASSUME_NONNULL_BEGIN * @param duration The frame duration. * @param captureDevice The capture device */ -- (void)setMinFrameDuration:(CMTime)duration onDevice:(AVCaptureDevice *)captureDevice; +- (void)setMinFrameDuration:(CMTime)duration onDevice:(id)captureDevice; /** * @method setMaxFrameDuration:onDevice: @@ -66,7 +68,7 @@ NS_ASSUME_NONNULL_BEGIN * @param duration The frame duration. * @param captureDevice The capture device */ -- (void)setMaxFrameDuration:(CMTime)duration onDevice:(AVCaptureDevice *)captureDevice; +- (void)setMaxFrameDuration:(CMTime)duration onDevice:(id)captureDevice; /** * @method assetWriterAudioInputWithOutputSettings: diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h index d05838f49a7..65bf90a70b6 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h @@ -4,6 +4,7 @@ #import "FLTCam.h" #import "FLTSavePhotoDelegate.h" +#import "FLTCaptureDeviceControlling.h" /// Determines the video dimensions (width and height) for a given capture device format. /// Used in tests to mock CMVideoFormatDescriptionGetDimensions. @@ -11,7 +12,7 @@ typedef CMVideoDimensions (^VideoDimensionsForFormat)(AVCaptureDeviceFormat *); /// Factory block returning an AVCaptureDevice. /// Used in tests to inject a device into FLTCam. -typedef AVCaptureDevice * (^CaptureDeviceFactory)(void); +typedef id (^CaptureDeviceFactory)(void); @interface FLTImageStreamHandler : NSObject diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.h new file mode 100644 index 00000000000..5603055865a --- /dev/null +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.h @@ -0,0 +1,72 @@ +// 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. + +@import AVFoundation; +@import Foundation; + +NS_ASSUME_NONNULL_BEGIN + +@protocol FLTCaptureDeviceControlling + +// Position/Orientation +- (AVCaptureDevicePosition)position; + +// Format/Configuration +- (AVCaptureDeviceFormat *)activeFormat; +- (NSArray *)formats; +- (void)setActiveFormat:(AVCaptureDeviceFormat *)format; + +// Flash/Torch +- (BOOL)hasFlash; +- (BOOL)hasTorch; +- (BOOL)isTorchAvailable; +- (AVCaptureTorchMode)torchMode; +- (void)setTorchMode:(AVCaptureTorchMode)torchMode; +- (BOOL)isFlashModeSupported:(AVCaptureFlashMode)mode; + +// Focus +- (BOOL)isFocusPointOfInterestSupported; +- (BOOL)isFocusModeSupported:(AVCaptureFocusMode)mode; +- (void)setFocusMode:(AVCaptureFocusMode)focusMode; +- (void)setFocusPointOfInterest:(CGPoint)point; + +// Exposure +- (BOOL)isExposurePointOfInterestSupported; +- (void)setExposureMode:(AVCaptureExposureMode)exposureMode; +- (void)setExposurePointOfInterest:(CGPoint)point; +- (float)minExposureTargetBias; +- (float)maxExposureTargetBias; +- (void)setExposureTargetBias:(float)bias completionHandler:(void (^ _Nullable)(CMTime))handler; +- (BOOL)isExposureModeSupported:(AVCaptureExposureMode)mode; + +// Zoom +- (float)maxAvailableVideoZoomFactor; +- (float)minAvailableVideoZoomFactor; +- (float)videoZoomFactor; +- (void)setVideoZoomFactor:(float)factor; + +// Camera Properties +- (float)lensAperture; +- (CMTime)exposureDuration; +- (float)ISO; + +// Configuration Lock +- (BOOL)lockForConfiguration:(NSError **)error; +- (void)unlockForConfiguration; + +// Frame Duration +- (CMTime)activeVideoMinFrameDuration; +- (void)setActiveVideoMinFrameDuration:(CMTime)duration; +- (CMTime)activeVideoMaxFrameDuration; +- (void)setActiveVideoMaxFrameDuration:(CMTime)duration; + +- (AVCaptureInput *)createInput:(NSError * _Nullable * _Nullable)error; + +@end + +@interface FLTDefaultCaptureDeviceController : NSObject +- (instancetype)initWithDevice:(AVCaptureDevice *)device; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.h new file mode 100644 index 00000000000..e0b39f9b9e2 --- /dev/null +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.h @@ -0,0 +1,17 @@ +// 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. + +@import AVFoundation; +@import Foundation; + +NS_ASSUME_NONNULL_BEGIN + +@protocol FLTDeviceOrientationProviding +- (UIDeviceOrientation)orientation; +@end + +@interface FLTDefaultDeviceOrientationProvider : NSObject +@end + +NS_ASSUME_NONNULL_END From 335deed5335a51a50f0ecc28c624f77059381c18 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Fri, 6 Dec 2024 17:14:26 +0100 Subject: [PATCH 02/31] Migrate CameraExposureTests --- .../xcshareddata/swiftpm/Package.resolved | 14 ---- .../ios/RunnerTests/CameraExposureTests.m | 78 ++++++++++++------- .../ios/RunnerTests/CameraFocusTests.m | 28 ++++++- .../ios/RunnerTests/CameraOrientationTests.m | 15 +++- .../ios/RunnerTests/FLTCamPhotoCaptureTests.m | 2 +- .../RunnerTests/MockCaptureDeviceController.h | 7 +- .../RunnerTests/MockCaptureDeviceController.m | 3 +- .../RunnerTests/Mocks/MockDeviceController.m | 6 -- .../Protocols/FLTCaptureDeviceControlling.m | 2 +- 9 files changed, 94 insertions(+), 61 deletions(-) delete mode 100644 packages/camera/camera_avfoundation/example/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceController.m diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved b/packages/camera/camera_avfoundation/example/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index a8d31f4703e..00000000000 --- a/packages/camera/camera_avfoundation/example/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,14 +0,0 @@ -{ - "originHash" : "20e8ffe6c32a926c4f00e4e9a967104dab3f8007aacc282029f03ed5f5f2e183", - "pins" : [ - { - "identity" : "ocmock", - "kind" : "remoteSourceControl", - "location" : "https://github.com/erikdoe/ocmock", - "state" : { - "revision" : "fe1661a3efed11831a6452f4b1a0c5e6ddc08c3d" - } - } - ], - "version" : 3 -} diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m index 7b641a5746c..bbe3cf055a9 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m @@ -5,51 +5,73 @@ @import camera_avfoundation; @import XCTest; @import AVFoundation; -#import -@interface FLTCam : NSObject - -- (void)setExposurePointWithResult:(FlutterResult)result x:(double)x y:(double)y; -@end +#import "MockCaptureDeviceController.h" +#import "MockDeviceOrientationProvider.h" @interface CameraExposureTests : XCTestCase @property(readonly, nonatomic) FLTCam *camera; -@property(readonly, nonatomic) id mockDevice; -@property(readonly, nonatomic) id mockUIDevice; +@property(readonly, nonatomic) MockCaptureDeviceController *mockDevice; +@property(readonly, nonatomic) MockDeviceOrientationProvider *mockDeviceOrientationProvider; @end @implementation CameraExposureTests - (void)setUp { _camera = [[FLTCam alloc] init]; - _mockDevice = OCMClassMock([AVCaptureDevice class]); - _mockUIDevice = OCMPartialMock([UIDevice currentDevice]); -} - -- (void)tearDown { - [_mockDevice stopMocking]; - [_mockUIDevice stopMocking]; + _mockDevice = [[MockCaptureDeviceController alloc] init]; + _mockDeviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; + + [_camera setValue:_mockDevice forKey:@"captureDevice"]; + [_camera setValue:_mockDeviceOrientationProvider forKey:@"deviceOrientationProvider"]; } -- (void)testSetExpsourePointWithResult_SetsExposurePointOfInterest { +- (void)testSetExposurePointWithResult_SetsExposurePointOfInterest { // UI is currently in landscape left orientation - OCMStub([(UIDevice *)_mockUIDevice orientation]).andReturn(UIDeviceOrientationLandscapeLeft); + _mockDeviceOrientationProvider.orientation = UIDeviceOrientationLandscapeLeft; // Exposure point of interest is supported - OCMStub([_mockDevice isExposurePointOfInterestSupported]).andReturn(true); - // Set mock device as the current capture device - [_camera setValue:_mockDevice forKey:@"captureDevice"]; + _mockDevice.isExposurePointOfInterestSupported = YES; + + // Verify the focus point of interest has been set + __block CGPoint setPoint = CGPointZero; + _mockDevice.setExposurePointOfInterestStub = ^(CGPoint point) { + if (CGPointEqualToPoint(CGPointMake(1, 1), point)) { + setPoint = point; + } + }; // Run test - [_camera - setExposurePointWithResult:^void(id _Nullable result) { - } - x:1 - y:1]; + XCTestExpectation *completionExpectation = [self expectationWithDescription:@"Completion called"]; + [_camera setExposurePoint:[FCPPlatformPoint makeWithX:1 y:1] + withCompletion:^(FlutterError * _Nullable error) { + XCTAssertNil(error); + [completionExpectation fulfill]; + }]; - // Verify the focus point of interest has been set - OCMVerify([_mockDevice setExposurePointOfInterest:CGPointMake(1, 1)]); + [self waitForExpectationsWithTimeout:1 handler:nil]; + XCTAssertEqual(setPoint.x, 1.0); + XCTAssertEqual(setPoint.y, 1.0); +} + +- (void)testSetExposurePoint_WhenNotSupported_ReturnsError { + // UI is currently in landscape left orientation + _mockDeviceOrientationProvider.orientation = UIDeviceOrientationLandscapeLeft; + // Exposure point of interest is not supported + _mockDevice.isExposurePointOfInterestSupported = NO; + + XCTestExpectation *expectation = [self expectationWithDescription:@"Completion with error"]; + + // Run + [_camera setExposurePoint:[FCPPlatformPoint makeWithX:1 y:1] + withCompletion:^(FlutterError *_Nullable error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.code, @"setExposurePointFailed"); + XCTAssertEqualObjects(error.message, @"Device does not have exposure point capabilities"); + [expectation fulfill]; + }]; + + // Verify + [self waitForExpectationsWithTimeout:1 handler:nil]; } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m index edcd7c4795c..27f5e21bdfa 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m @@ -24,6 +24,9 @@ - (void)setUp { _camera = [[FLTCam alloc] init]; _mockDevice = [[MockCaptureDeviceController alloc] init]; _mockDeviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; + + [_camera setValue:_mockDevice forKey:@"captureDevice"]; + [_camera setValue:_mockDeviceOrientationProvider forKey:@"deviceOrientationProvider"]; } - (void)testAutoFocusWithContinuousModeSupported_ShouldSetContinuousAutoFocus { @@ -127,15 +130,11 @@ - (void)testLockedFocusWithModeNotSupported_ShouldSetNothing { [_camera applyFocusMode:FCPPlatformFocusModeLocked onDevice:_mockDevice]; } -// TODO(mchudy): replace setValue with proper DI - (void)testSetFocusPointWithResult_SetsFocusPointOfInterest { // UI is currently in landscape left orientation - [_camera setValue:_mockDeviceOrientationProvider forKey:@"deviceOrientationProvider"]; _mockDeviceOrientationProvider.orientation = UIDeviceOrientationLandscapeLeft; // Focus point of interest is supported _mockDevice.isFocusPointOfInterestSupported = YES; - // Set mock device as the current capture device - [_camera setValue:_mockDevice forKey:@"captureDevice"]; __block BOOL setFocusPointOfInterestCalled = NO; _mockDevice.setFocusPointOfInterestStub = ^(CGPoint point) { @@ -153,4 +152,25 @@ - (void)testSetFocusPointWithResult_SetsFocusPointOfInterest { XCTAssertTrue(setFocusPointOfInterestCalled); } +- (void)testSetFocusPoint_WhenNotSupported_ReturnsError { + // UI is currently in landscape left orientation + _mockDeviceOrientationProvider.orientation = UIDeviceOrientationLandscapeLeft; + // Exposure point of interest is not supported + _mockDevice.isFocusPointOfInterestSupported = NO; + + XCTestExpectation *expectation = [self expectationWithDescription:@"Completion with error"]; + + // Run + [_camera setFocusPoint:[FCPPlatformPoint makeWithX:1 y:1] + withCompletion:^(FlutterError *_Nullable error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.code, @"setFocusPointFailed"); + XCTAssertEqualObjects(error.message, @"Device does not have focus point capabilities"); + [expectation fulfill]; + }]; + + // Verify + [self waitForExpectationsWithTimeout:1 handler:nil]; +} + @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m index e6ce8d48bc5..6ced4fa4c4e 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m @@ -11,6 +11,8 @@ #import +#import "MockCaptureDeviceController.h" + @interface StubGlobalEventApi : FCPCameraGlobalEventApi @property(nonatomic) BOOL called; @property(nonatomic) FCPPlatformDeviceOrientation lastOrientation; @@ -35,10 +37,21 @@ - (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(nonnull NSString #pragma mark - @interface CameraOrientationTests : XCTestCase +@property(readonly, nonatomic) FLTCam *camera; +@property(readonly, nonatomic) MockCaptureDeviceController *mockDevice; +@property(readonly, nonatomic) StubGlobalEventApi *eventAPI; @end @implementation CameraOrientationTests +- (void)setUp { + [super setUp]; + _mockDevice = [[MockCaptureDeviceController alloc] init]; + _camera = [[FLTCam alloc] init]; + + [_camera setValue:_mockDevice forKey:@"captureDevice"]; +} + // Ensure that the given queue and then the main queue have both cycled, to wait for any pending // async events that may have been bounced between them. - (void)waitForRoundTripWithQueue:(dispatch_queue_t)queue { @@ -97,13 +110,13 @@ - (void)testOrientationNotificationsNotCalledForFaceDown { - (void)testOrientationUpdateMustBeOnCaptureSessionQueue { XCTestExpectation *queueExpectation = [self expectationWithDescription:@"Orientation update must happen on the capture session queue"]; - CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil]; const char *captureSessionQueueSpecific = "capture_session_queue"; dispatch_queue_set_specific(camera.captureSessionQueue, captureSessionQueueSpecific, (void *)captureSessionQueueSpecific, NULL); FLTCam *mockCam = OCMClassMock([FLTCam class]); camera.camera = mockCam; + OCMStub([mockCam setDeviceOrientation:UIDeviceOrientationLandscapeLeft]) .andDo(^(NSInvocation *invocation) { if (dispatch_get_specific(captureSessionQueueSpecific)) { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m index 31711f065ef..bc7e224e549 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m @@ -171,7 +171,7 @@ - (void)testCaptureToFile_mustReportFileExtensionWithJpgWhenHEVCNotAvailableAndF }); [self waitForExpectationsWithTimeout:1 handler:nil]; } -// + - (void)testCaptureToFile_handlesTorchMode { XCTestExpectation *pathExpectation = [self expectationWithDescription: diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h index 8723b191024..901bcc60c7b 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h @@ -28,7 +28,7 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, assign) BOOL flashModeSupported; // Focus -@property(nonatomic, assign) BOOL focusPointOfInterestSupported; +@property(nonatomic, assign) BOOL isFocusPointOfInterestSupported; @property(nonatomic, copy) BOOL (^isFocusModeSupportedStub)(AVCaptureFocusMode mode); @property(nonatomic, assign) AVCaptureFocusMode focusMode; @property(nonatomic, copy) void (^setFocusModeStub)(AVCaptureFocusMode mode); @@ -36,7 +36,7 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, copy) void (^setFocusPointOfInterestStub)(CGPoint point); // Exposure -@property(nonatomic, assign) BOOL exposurePointOfInterestSupported; +@property(nonatomic, assign) BOOL isExposurePointOfInterestSupported; @property(nonatomic, assign) AVCaptureExposureMode exposureMode; @property(nonatomic, assign) BOOL exposureModeSupported; @property(nonatomic, copy) void (^setExposureModeStub)(AVCaptureExposureMode mode); @@ -72,9 +72,6 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, strong) AVCaptureInput *inputToReturn; @property(nonatomic, copy) void (^createInputStub)(NSError **error); -@property(nonatomic, assign) BOOL isExposurePointOfInterestSupported; -@property(nonatomic, assign) BOOL isFocusPointOfInterestSupported; - @end NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m index c1659d36f07..548cea98bb9 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m @@ -68,6 +68,8 @@ - (void)setExposurePointOfInterest:(CGPoint)point { - (void)setExposureTargetBias:(float)bias completionHandler:(void (^)(CMTime))handler { if (self.setExposureTargetBiasStub) { self.setExposureTargetBiasStub(bias, handler); + } else if (handler) { + handler(kCMTimeZero); } } @@ -123,5 +125,4 @@ - (AVCaptureInput *)createInput:(NSError *_Nullable *_Nullable)error { return self.inputToReturn; } - @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceController.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceController.m deleted file mode 100644 index 27cc985d7d2..00000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceController.m +++ /dev/null @@ -1,6 +0,0 @@ -// 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. - - -@interface FLTMockCaptureDeviceController : NSObject diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m index f89e44920f4..1483620039b 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m @@ -63,7 +63,7 @@ - (BOOL)isFlashModeSupported:(AVCaptureFlashMode)mode { // Focus - (BOOL)isFocusPointOfInterestSupported { - return self.device.isFocusPointOfInterestSupported; + return self.device.isFocusPointOfInterestSupported; } - (BOOL)isFocusModeSupported:(AVCaptureFocusMode)mode { From ca581d79a80667f5dca7f1492364433c452aecbe Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Fri, 27 Dec 2024 14:26:42 +0100 Subject: [PATCH 03/31] Format code --- .../ios/RunnerTests/CameraExposureTests.m | 31 ++--- .../ios/RunnerTests/CameraFocusTests.m | 38 +++--- .../ios/RunnerTests/CameraOrientationTests.m | 2 +- .../example/ios/RunnerTests/CameraTestUtils.m | 22 ++-- .../ios/RunnerTests/FLTCamPhotoCaptureTests.m | 9 +- .../RunnerTests/MockCaptureDeviceController.h | 3 +- .../RunnerTests/MockCaptureDeviceController.m | 120 +++++++++--------- .../Sources/camera_avfoundation/FLTCam.m | 15 ++- .../FLTCamMediaSettingsAVWrapper.m | 9 +- .../Protocols/FLTCaptureDeviceControlling.m | 77 ++++++----- .../Protocols/FLTDeviceOrientationProviding.m | 2 +- .../include/camera_avfoundation/FLTCam.h | 3 +- .../FLTCamMediaSettingsAVWrapper.h | 9 +- .../include/camera_avfoundation/FLTCam_Test.h | 2 +- .../Protocols/FLTCaptureDeviceControlling.h | 4 +- .../include/camera_avfoundation/QueueUtils.h | 2 +- 16 files changed, 179 insertions(+), 169 deletions(-) diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m index bbe3cf055a9..28a5f7e1fcc 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m @@ -21,7 +21,7 @@ - (void)setUp { _camera = [[FLTCam alloc] init]; _mockDevice = [[MockCaptureDeviceController alloc] init]; _mockDeviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; - + [_camera setValue:_mockDevice forKey:@"captureDevice"]; [_camera setValue:_mockDeviceOrientationProvider forKey:@"deviceOrientationProvider"]; } @@ -31,7 +31,7 @@ - (void)testSetExposurePointWithResult_SetsExposurePointOfInterest { _mockDeviceOrientationProvider.orientation = UIDeviceOrientationLandscapeLeft; // Exposure point of interest is supported _mockDevice.isExposurePointOfInterestSupported = YES; - + // Verify the focus point of interest has been set __block CGPoint setPoint = CGPointZero; _mockDevice.setExposurePointOfInterestStub = ^(CGPoint point) { @@ -43,9 +43,9 @@ - (void)testSetExposurePointWithResult_SetsExposurePointOfInterest { // Run test XCTestExpectation *completionExpectation = [self expectationWithDescription:@"Completion called"]; [_camera setExposurePoint:[FCPPlatformPoint makeWithX:1 y:1] - withCompletion:^(FlutterError * _Nullable error) { - XCTAssertNil(error); - [completionExpectation fulfill]; + withCompletion:^(FlutterError *_Nullable error) { + XCTAssertNil(error); + [completionExpectation fulfill]; }]; [self waitForExpectationsWithTimeout:1 handler:nil]; @@ -58,18 +58,19 @@ - (void)testSetExposurePoint_WhenNotSupported_ReturnsError { _mockDeviceOrientationProvider.orientation = UIDeviceOrientationLandscapeLeft; // Exposure point of interest is not supported _mockDevice.isExposurePointOfInterestSupported = NO; - + XCTestExpectation *expectation = [self expectationWithDescription:@"Completion with error"]; - + // Run - [_camera setExposurePoint:[FCPPlatformPoint makeWithX:1 y:1] - withCompletion:^(FlutterError *_Nullable error) { - XCTAssertNotNil(error); - XCTAssertEqualObjects(error.code, @"setExposurePointFailed"); - XCTAssertEqualObjects(error.message, @"Device does not have exposure point capabilities"); - [expectation fulfill]; - }]; - + [_camera + setExposurePoint:[FCPPlatformPoint makeWithX:1 y:1] + withCompletion:^(FlutterError *_Nullable error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.code, @"setExposurePointFailed"); + XCTAssertEqualObjects(error.message, @"Device does not have exposure point capabilities"); + [expectation fulfill]; + }]; + // Verify [self waitForExpectationsWithTimeout:1 handler:nil]; } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m index 27f5e21bdfa..f7d96c3aa75 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m @@ -24,7 +24,7 @@ - (void)setUp { _camera = [[FLTCam alloc] init]; _mockDevice = [[MockCaptureDeviceController alloc] init]; _mockDeviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; - + [_camera setValue:_mockDevice forKey:@"captureDevice"]; [_camera setValue:_mockDeviceOrientationProvider forKey:@"deviceOrientationProvider"]; } @@ -34,7 +34,7 @@ - (void)testAutoFocusWithContinuousModeSupported_ShouldSetContinuousAutoFocus { _mockDevice.isFocusModeSupportedStub = ^BOOL(AVCaptureFocusMode mode) { return mode == AVCaptureFocusModeContinuousAutoFocus || mode == AVCaptureFocusModeAutoFocus; }; - + __block BOOL setFocusModeContinuousAutoFocusCalled = NO; _mockDevice.setFocusModeStub = ^(AVCaptureFocusMode mode) { @@ -59,9 +59,9 @@ - (void)testAutoFocusWithContinuousModeNotSupported_ShouldSetAutoFocus { _mockDevice.isFocusModeSupportedStub = ^BOOL(AVCaptureFocusMode mode) { return mode == AVCaptureFocusModeAutoFocus; }; - + __block BOOL setFocusModeAutoFocusCalled = NO; - + // Don't expect setFocusMode:AVCaptureFocusModeContinuousAutoFocus _mockDevice.setFocusModeStub = ^(AVCaptureFocusMode mode) { if (mode == AVCaptureFocusModeContinuousAutoFocus) { @@ -70,10 +70,10 @@ - (void)testAutoFocusWithContinuousModeNotSupported_ShouldSetAutoFocus { setFocusModeAutoFocusCalled = YES; } }; - + // Run test [_camera applyFocusMode:FCPPlatformFocusModeAuto onDevice:_mockDevice]; - + // Expect setFocusMode:AVCaptureFocusModeAutoFocus XCTAssertTrue(setFocusModeAutoFocusCalled); } @@ -86,7 +86,7 @@ - (void)testAutoFocusWithNoModeSupported_ShouldSetNothing { // Don't expect any setFocus _mockDevice.setFocusModeStub = ^(AVCaptureFocusMode mode) { - XCTFail(@"Unexpected call to setFocusMode"); + XCTFail(@"Unexpected call to setFocusMode"); }; // Run test @@ -98,7 +98,7 @@ - (void)testLockedFocusWithModeSupported_ShouldSetModeAutoFocus { _mockDevice.isFocusModeSupportedStub = ^BOOL(AVCaptureFocusMode mode) { return mode == AVCaptureFocusModeContinuousAutoFocus || mode == AVCaptureFocusModeAutoFocus; }; - + __block BOOL setFocusModeAutoFocusCalled = NO; // Expect only setFocusMode:AVCaptureFocusModeAutoFocus @@ -109,7 +109,7 @@ - (void)testLockedFocusWithModeSupported_ShouldSetModeAutoFocus { setFocusModeAutoFocusCalled = YES; } }; - + // Run test [_camera applyFocusMode:FCPPlatformFocusModeLocked onDevice:_mockDevice]; @@ -123,7 +123,7 @@ - (void)testLockedFocusWithModeNotSupported_ShouldSetNothing { // Don't expect any setFocus _mockDevice.setFocusModeStub = ^(AVCaptureFocusMode mode) { - XCTFail(@"Unexpected call to setFocusMode"); + XCTFail(@"Unexpected call to setFocusMode"); }; // Run test @@ -157,18 +157,18 @@ - (void)testSetFocusPoint_WhenNotSupported_ReturnsError { _mockDeviceOrientationProvider.orientation = UIDeviceOrientationLandscapeLeft; // Exposure point of interest is not supported _mockDevice.isFocusPointOfInterestSupported = NO; - + XCTestExpectation *expectation = [self expectationWithDescription:@"Completion with error"]; - + // Run [_camera setFocusPoint:[FCPPlatformPoint makeWithX:1 y:1] - withCompletion:^(FlutterError *_Nullable error) { - XCTAssertNotNil(error); - XCTAssertEqualObjects(error.code, @"setFocusPointFailed"); - XCTAssertEqualObjects(error.message, @"Device does not have focus point capabilities"); - [expectation fulfill]; - }]; - + withCompletion:^(FlutterError *_Nullable error) { + XCTAssertNotNil(error); + XCTAssertEqualObjects(error.code, @"setFocusPointFailed"); + XCTAssertEqualObjects(error.message, @"Device does not have focus point capabilities"); + [expectation fulfill]; + }]; + // Verify [self waitForExpectationsWithTimeout:1 handler:nil]; } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m index 6ced4fa4c4e..b1547c53212 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m @@ -116,7 +116,7 @@ - (void)testOrientationUpdateMustBeOnCaptureSessionQueue { (void *)captureSessionQueueSpecific, NULL); FLTCam *mockCam = OCMClassMock([FLTCam class]); camera.camera = mockCam; - + OCMStub([mockCam setDeviceOrientation:UIDeviceOrientationLandscapeLeft]) .andDo(^(NSInvocation *invocation) { if (dispatch_get_specific(captureSessionQueueSpecific)) { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m index 501498d6382..f82bbf1aedc 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m @@ -155,16 +155,18 @@ OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]); OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - return [[FLTCam alloc] initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) - mediaSettingsAVWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] - orientation:UIDeviceOrientationPortrait - videoCaptureSession:captureSession - audioCaptureSession:audioSessionMock - captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL) - captureDeviceFactory:^id(void) { - return [[FLTDefaultCaptureDeviceController alloc] initWithDevice:captureDevice]; } - videoDimensionsForFormat:videoDimensionsForFormat - error:nil]; + return [[FLTCam alloc] + initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) + mediaSettingsAVWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] + orientation:UIDeviceOrientationPortrait + videoCaptureSession:captureSession + audioCaptureSession:audioSessionMock + captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL) + captureDeviceFactory:^id(void) { + return [[FLTDefaultCaptureDeviceController alloc] initWithDevice:captureDevice]; + } + videoDimensionsForFormat:videoDimensionsForFormat + error:nil]; } CMSampleBufferRef FLTCreateTestSampleBuffer(void) { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m index bc7e224e549..75a4f3abd7d 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m @@ -187,11 +187,10 @@ - (void)testCaptureToFile_handlesTorchMode { dispatch_queue_set_specific(captureSessionQueue, FLTCaptureSessionQueueSpecific, (void *)FLTCaptureSessionQueueSpecific, NULL); - FLTCam *cam = FLTCreateCamWithCaptureSessionQueueAndMediaSettings(captureSessionQueue, nil, nil, - ^id(void) { - return - [[FLTDefaultCaptureDeviceController alloc] initWithDevice:captureDeviceMock]; - }); + FLTCam *cam = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( + captureSessionQueue, nil, nil, ^id(void) { + return [[FLTDefaultCaptureDeviceController alloc] initWithDevice:captureDeviceMock]; + }); AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettings]; id mockSettings = OCMClassMock([AVCapturePhotoSettings class]); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h index 901bcc60c7b..af28d652734 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h @@ -44,7 +44,8 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, copy) void (^setExposurePointOfInterestStub)(CGPoint point); @property(nonatomic, assign) float minExposureTargetBias; @property(nonatomic, assign) float maxExposureTargetBias; -@property(nonatomic, copy) void (^setExposureTargetBiasStub)(float bias, void (^_Nullable handler)(CMTime)); +@property(nonatomic, copy) void (^setExposureTargetBiasStub) + (float bias, void (^_Nullable handler)(CMTime)); // Zoom @property(nonatomic, assign) float maxAvailableVideoZoomFactor; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m index 548cea98bb9..cc89bb85abf 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m @@ -13,21 +13,21 @@ @implementation MockCaptureDeviceController - (void)setActiveFormat:(AVCaptureDeviceFormat *)format { - _activeFormat = format; - if (self.setActiveFormatStub) { - self.setActiveFormatStub(format); - } + _activeFormat = format; + if (self.setActiveFormatStub) { + self.setActiveFormatStub(format); + } } - (BOOL)isFlashModeSupported:(AVCaptureFlashMode)mode { - return self.flashModeSupported; + return self.flashModeSupported; } - (void)setTorchMode:(AVCaptureTorchMode)mode { - _torchMode = mode; - if (self.setTorchModeStub) { - self.setTorchModeStub(mode); - } + _torchMode = mode; + if (self.setTorchModeStub) { + self.setTorchModeStub(mode); + } } - (BOOL)isFocusModeSupported:(AVCaptureFocusMode)mode { @@ -38,91 +38,91 @@ - (BOOL)isFocusModeSupported:(AVCaptureFocusMode)mode { } - (void)setFocusMode:(AVCaptureFocusMode)mode { - _focusMode = mode; - if (self.setFocusModeStub) { - self.setFocusModeStub(mode); - } + _focusMode = mode; + if (self.setFocusModeStub) { + self.setFocusModeStub(mode); + } } - (void)setFocusPointOfInterest:(CGPoint)point { - _focusPointOfInterest = point; - if (self.setFocusPointOfInterestStub) { - self.setFocusPointOfInterestStub(point); - } + _focusPointOfInterest = point; + if (self.setFocusPointOfInterestStub) { + self.setFocusPointOfInterestStub(point); + } } - (void)setExposureMode:(AVCaptureExposureMode)mode { - _exposureMode = mode; - if (self.setExposureModeStub) { - self.setExposureModeStub(mode); - } + _exposureMode = mode; + if (self.setExposureModeStub) { + self.setExposureModeStub(mode); + } } - (void)setExposurePointOfInterest:(CGPoint)point { - _exposurePointOfInterest = point; - if (self.setExposurePointOfInterestStub) { - self.setExposurePointOfInterestStub(point); - } + _exposurePointOfInterest = point; + if (self.setExposurePointOfInterestStub) { + self.setExposurePointOfInterestStub(point); + } } - (void)setExposureTargetBias:(float)bias completionHandler:(void (^)(CMTime))handler { - if (self.setExposureTargetBiasStub) { - self.setExposureTargetBiasStub(bias, handler); - } else if (handler) { - handler(kCMTimeZero); - } + if (self.setExposureTargetBiasStub) { + self.setExposureTargetBiasStub(bias, handler); + } else if (handler) { + handler(kCMTimeZero); + } } - (void)setVideoZoomFactor:(float)factor { - _videoZoomFactor = factor; - if (self.setVideoZoomFactorStub) { - self.setVideoZoomFactorStub(factor); - } + _videoZoomFactor = factor; + if (self.setVideoZoomFactorStub) { + self.setVideoZoomFactorStub(factor); + } } - (BOOL)lockForConfiguration:(NSError **)error { - if (self.lockForConfigurationStub) { - self.lockForConfigurationStub(error); - return !self.shouldFailConfiguration; - } - if (self.shouldFailConfiguration) { - if (error) { - *error = [NSError errorWithDomain:@"test" code:0 userInfo:nil]; - } - return NO; + if (self.lockForConfigurationStub) { + self.lockForConfigurationStub(error); + return !self.shouldFailConfiguration; + } + if (self.shouldFailConfiguration) { + if (error) { + *error = [NSError errorWithDomain:@"test" code:0 userInfo:nil]; } - return YES; + return NO; + } + return YES; } - (void)unlockForConfiguration { - if (self.unlockForConfigurationStub) { - self.unlockForConfigurationStub(); - } + if (self.unlockForConfigurationStub) { + self.unlockForConfigurationStub(); + } } - (void)setActiveVideoMinFrameDuration:(CMTime)duration { - _activeVideoMinFrameDuration = duration; - if (self.setActiveVideoMinFrameDurationStub) { - self.setActiveVideoMinFrameDurationStub(duration); - } + _activeVideoMinFrameDuration = duration; + if (self.setActiveVideoMinFrameDurationStub) { + self.setActiveVideoMinFrameDurationStub(duration); + } } - (void)setActiveVideoMaxFrameDuration:(CMTime)duration { - _activeVideoMaxFrameDuration = duration; - if (self.setActiveVideoMaxFrameDurationStub) { - self.setActiveVideoMaxFrameDurationStub(duration); - } + _activeVideoMaxFrameDuration = duration; + if (self.setActiveVideoMaxFrameDurationStub) { + self.setActiveVideoMaxFrameDurationStub(duration); + } } - (BOOL)isExposureModeSupported:(AVCaptureExposureMode)mode { - return self.exposureModeSupported; + return self.exposureModeSupported; } - (AVCaptureInput *)createInput:(NSError *_Nullable *_Nullable)error { - if (self.createInputStub) { - self.createInputStub(error); - } - return self.inputToReturn; + if (self.createInputStub) { + self.createInputStub(error); + } + return self.inputToReturn; } @end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 2174f699869..ff9e23bc48d 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -11,10 +11,10 @@ #import "./include/camera_avfoundation/FLTSavePhotoDelegate.h" #import "./include/camera_avfoundation/FLTThreadSafeEventChannel.h" -#import "./include/camera_avfoundation/QueueUtils.h" -#import "./include/camera_avfoundation/messages.g.h" #import "./include/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.h" #import "./include/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.h" +#import "./include/camera_avfoundation/QueueUtils.h" +#import "./include/camera_avfoundation/messages.g.h" static FlutterError *FlutterErrorFromNSError(NSError *error) { return [FlutterError errorWithCode:[NSString stringWithFormat:@"Error %d", (int)error.code] @@ -146,7 +146,7 @@ - (instancetype)initWithCameraName:(NSString *)cameraName videoCaptureSession:videoCaptureSession audioCaptureSession:videoCaptureSession captureSessionQueue:captureSessionQueue - captureDeviceFactory:^id (void) { + captureDeviceFactory:^id(void) { AVCaptureDevice *device = [AVCaptureDevice deviceWithUniqueID:cameraName]; return [[FLTDefaultCaptureDeviceController alloc] initWithDevice:device]; } @@ -265,7 +265,7 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings _motionManager = [[CMMotionManager alloc] init]; [_motionManager startAccelerometerUpdates]; - + _deviceOrientationProvider = [[FLTDefaultDeviceOrientationProvider alloc] init]; if (_mediaSettings.framesPerSecond) { @@ -349,8 +349,8 @@ - (void)reportInitializationState { height:self.previewSize.height] exposureMode:self.exposureMode focusMode:self.focusMode - exposurePointSupported:self.captureDevice.isExposurePointOfInterestSupported - focusPointSupported:self.captureDevice.isFocusPointOfInterestSupported]; + exposurePointSupported:self.captureDevice.isExposurePointOfInterestSupported + focusPointSupported:self.captureDevice.isFocusPointOfInterestSupported]; __weak typeof(self) weakSelf = self; FLTEnsureToRunOnMainQueue(^{ @@ -1043,7 +1043,8 @@ - (void)applyFocusMode { [self applyFocusMode:_focusMode onDevice:_captureDevice]; } -- (void)applyFocusMode:(FCPPlatformFocusMode)focusMode onDevice:(id)captureDevice { +- (void)applyFocusMode:(FCPPlatformFocusMode)focusMode + onDevice:(id)captureDevice { [captureDevice lockForConfiguration:nil]; switch (focusMode) { case FCPPlatformFocusModeLocked: diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m index c712245a6ce..0ecf89a724c 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m @@ -7,7 +7,8 @@ @implementation FLTCamMediaSettingsAVWrapper -- (BOOL)lockDevice:(id)captureDevice error:(NSError *_Nullable *_Nullable)outError { +- (BOOL)lockDevice:(id)captureDevice + error:(NSError *_Nullable *_Nullable)outError { return [captureDevice lockForConfiguration:outError]; } @@ -23,11 +24,13 @@ - (void)commitConfigurationForSession:(AVCaptureSession *)videoCaptureSession { [videoCaptureSession commitConfiguration]; } -- (void)setMinFrameDuration:(CMTime)duration onDevice:(id)captureDevice { +- (void)setMinFrameDuration:(CMTime)duration + onDevice:(id)captureDevice { captureDevice.activeVideoMinFrameDuration = duration; } -- (void)setMaxFrameDuration:(CMTime)duration onDevice:(id)captureDevice { +- (void)setMaxFrameDuration:(CMTime)duration + onDevice:(id)captureDevice { captureDevice.activeVideoMaxFrameDuration = duration; } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m index 1483620039b..eaa4dfd250a 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m @@ -11,54 +11,54 @@ @interface FLTDefaultCaptureDeviceController () @implementation FLTDefaultCaptureDeviceController - (instancetype)initWithDevice:(AVCaptureDevice *)device { - self = [super init]; - if (self) { - _device = device; - } - return self; + self = [super init]; + if (self) { + _device = device; + } + return self; } // Position/Orientation - (AVCaptureDevicePosition)position { - return self.device.position; + return self.device.position; } // Format/Configuration - (AVCaptureDeviceFormat *)activeFormat { - return self.device.activeFormat; + return self.device.activeFormat; } - (NSArray *)formats { - return self.device.formats; + return self.device.formats; } - (void)setActiveFormat:(AVCaptureDeviceFormat *)format { - self.device.activeFormat = format; + self.device.activeFormat = format; } // Flash/Torch - (BOOL)hasFlash { - return self.device.hasFlash; + return self.device.hasFlash; } - (BOOL)hasTorch { - return self.device.hasTorch; + return self.device.hasTorch; } - (BOOL)isTorchAvailable { - return self.device.isTorchAvailable; + return self.device.isTorchAvailable; } - (AVCaptureTorchMode)torchMode { - return self.device.torchMode; + return self.device.torchMode; } - (void)setTorchMode:(AVCaptureTorchMode)torchMode { - self.device.torchMode = torchMode; + self.device.torchMode = torchMode; } - (BOOL)isFlashModeSupported:(AVCaptureFlashMode)mode { - return [self.device isFlashModeSupported:mode]; + return [self.device isFlashModeSupported:mode]; } // Focus @@ -67,40 +67,40 @@ - (BOOL)isFocusPointOfInterestSupported { } - (BOOL)isFocusModeSupported:(AVCaptureFocusMode)mode { - return [self.device isFocusModeSupported:mode]; + return [self.device isFocusModeSupported:mode]; } - (void)setFocusMode:(AVCaptureFocusMode)focusMode { - self.device.focusMode = focusMode; + self.device.focusMode = focusMode; } - (void)setFocusPointOfInterest:(CGPoint)point { - self.device.focusPointOfInterest = point; + self.device.focusPointOfInterest = point; } // Exposure - (BOOL)isExposurePointOfInterestSupported { - return self.device.isExposurePointOfInterestSupported; + return self.device.isExposurePointOfInterestSupported; } - (void)setExposureMode:(AVCaptureExposureMode)exposureMode { - self.device.exposureMode = exposureMode; + self.device.exposureMode = exposureMode; } - (void)setExposurePointOfInterest:(CGPoint)point { - self.device.exposurePointOfInterest = point; + self.device.exposurePointOfInterest = point; } - (float)minExposureTargetBias { - return self.device.minExposureTargetBias; + return self.device.minExposureTargetBias; } - (float)maxExposureTargetBias { - return self.device.maxExposureTargetBias; + return self.device.maxExposureTargetBias; } - (void)setExposureTargetBias:(float)bias completionHandler:(void (^)(CMTime))handler { - [self.device setExposureTargetBias:bias completionHandler:handler]; + [self.device setExposureTargetBias:bias completionHandler:handler]; } - (BOOL)isExposureModeSupported:(AVCaptureExposureMode)mode { @@ -109,62 +109,61 @@ - (BOOL)isExposureModeSupported:(AVCaptureExposureMode)mode { // Zoom - (float)maxAvailableVideoZoomFactor { - return self.device.maxAvailableVideoZoomFactor; + return self.device.maxAvailableVideoZoomFactor; } - (float)minAvailableVideoZoomFactor { - return self.device.minAvailableVideoZoomFactor; + return self.device.minAvailableVideoZoomFactor; } - (float)videoZoomFactor { - return self.device.videoZoomFactor; + return self.device.videoZoomFactor; } - (void)setVideoZoomFactor:(float)factor { - self.device.videoZoomFactor = factor; + self.device.videoZoomFactor = factor; } // Camera Properties - (float)lensAperture { - return self.device.lensAperture; + return self.device.lensAperture; } - (CMTime)exposureDuration { - return self.device.exposureDuration; + return self.device.exposureDuration; } - (float)ISO { - return self.device.ISO; + return self.device.ISO; } // Configuration Lock - (BOOL)lockForConfiguration:(NSError **)error { - return [self.device lockForConfiguration:error]; + return [self.device lockForConfiguration:error]; } - (void)unlockForConfiguration { - [self.device unlockForConfiguration]; + [self.device unlockForConfiguration]; } - (CMTime)activeVideoMinFrameDuration { - return self.device.activeVideoMinFrameDuration; + return self.device.activeVideoMinFrameDuration; } - (void)setActiveVideoMinFrameDuration:(CMTime)duration { - self.device.activeVideoMinFrameDuration = duration; + self.device.activeVideoMinFrameDuration = duration; } - (CMTime)activeVideoMaxFrameDuration { - return self.device.activeVideoMaxFrameDuration; + return self.device.activeVideoMaxFrameDuration; } - (void)setActiveVideoMaxFrameDuration:(CMTime)duration { - self.device.activeVideoMaxFrameDuration = duration; + self.device.activeVideoMaxFrameDuration = duration; } -- (AVCaptureInput *)createInput:(NSError * _Nullable * _Nullable)error { +- (AVCaptureInput *)createInput:(NSError *_Nullable *_Nullable)error { return [AVCaptureDeviceInput deviceInputWithDevice:_device error:error]; } - @end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m index 7b10f09109d..0f909b2a9fa 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m @@ -6,7 +6,7 @@ @implementation FLTDefaultDeviceOrientationProvider -- (UIDeviceOrientation)orientation { +- (UIDeviceOrientation)orientation { return [[UIDevice currentDevice] orientation]; } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h index 9fee90390a2..b5418124bf5 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h @@ -93,7 +93,8 @@ NS_ASSUME_NONNULL_BEGIN /// /// @param focusMode The focus mode that should be applied to the @captureDevice instance. /// @param captureDevice The AVCaptureDevice to which the @focusMode will be applied. -- (void)applyFocusMode:(FCPPlatformFocusMode)focusMode onDevice:(id)captureDevice; +- (void)applyFocusMode:(FCPPlatformFocusMode)focusMode + onDevice:(id)captureDevice; - (void)pausePreview; - (void)resumePreview; - (void)setDescriptionWhileRecording:(NSString *)cameraName diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h index 4e8d9d15cd8..8d95cf02afe 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h @@ -27,7 +27,8 @@ NS_ASSUME_NONNULL_BEGIN * @param outError The optional error. * @result A BOOL indicating whether the device was successfully locked for configuration. */ -- (BOOL)lockDevice:(id)captureDevice error:(NSError *_Nullable *_Nullable)outError; +- (BOOL)lockDevice:(id)captureDevice + error:(NSError *_Nullable *_Nullable)outError; /** * @method unlockDevice: @@ -59,7 +60,8 @@ NS_ASSUME_NONNULL_BEGIN * @param duration The frame duration. * @param captureDevice The capture device */ -- (void)setMinFrameDuration:(CMTime)duration onDevice:(id)captureDevice; +- (void)setMinFrameDuration:(CMTime)duration + onDevice:(id)captureDevice; /** * @method setMaxFrameDuration:onDevice: @@ -68,7 +70,8 @@ NS_ASSUME_NONNULL_BEGIN * @param duration The frame duration. * @param captureDevice The capture device */ -- (void)setMaxFrameDuration:(CMTime)duration onDevice:(id)captureDevice; +- (void)setMaxFrameDuration:(CMTime)duration + onDevice:(id)captureDevice; /** * @method assetWriterAudioInputWithOutputSettings: diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h index 65bf90a70b6..f643d335a4c 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h @@ -3,8 +3,8 @@ // found in the LICENSE file. #import "FLTCam.h" -#import "FLTSavePhotoDelegate.h" #import "FLTCaptureDeviceControlling.h" +#import "FLTSavePhotoDelegate.h" /// Determines the video dimensions (width and height) for a given capture device format. /// Used in tests to mock CMVideoFormatDescriptionGetDimensions. diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.h index 5603055865a..370f0e5df10 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.h @@ -37,7 +37,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)setExposurePointOfInterest:(CGPoint)point; - (float)minExposureTargetBias; - (float)maxExposureTargetBias; -- (void)setExposureTargetBias:(float)bias completionHandler:(void (^ _Nullable)(CMTime))handler; +- (void)setExposureTargetBias:(float)bias completionHandler:(void (^_Nullable)(CMTime))handler; - (BOOL)isExposureModeSupported:(AVCaptureExposureMode)mode; // Zoom @@ -61,7 +61,7 @@ NS_ASSUME_NONNULL_BEGIN - (CMTime)activeVideoMaxFrameDuration; - (void)setActiveVideoMaxFrameDuration:(CMTime)duration; -- (AVCaptureInput *)createInput:(NSError * _Nullable * _Nullable)error; +- (AVCaptureInput *)createInput:(NSError *_Nullable *_Nullable)error; @end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/QueueUtils.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/QueueUtils.h index a7e22da716d..e230a53508f 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/QueueUtils.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/QueueUtils.h @@ -7,7 +7,7 @@ NS_ASSUME_NONNULL_BEGIN /// Queue-specific context data to be associated with the capture session queue. -extern const char* FLTCaptureSessionQueueSpecific; +extern const char *FLTCaptureSessionQueueSpecific; /// Ensures the given block to be run on the main queue. /// If caller site is already on the main queue, the block will be run From 2e3c8e70b4c9b89f93f25aa006d305464f0774f8 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Mon, 30 Dec 2024 13:40:35 +0100 Subject: [PATCH 04/31] Use DI for mocking dependencies --- .../camera/camera_avfoundation/CHANGELOG.md | 4 ++ .../ios/Runner.xcodeproj/project.pbxproj | 4 ++ .../ios/RunnerTests/CameraExposureTests.m | 13 +++++-- .../ios/RunnerTests/CameraFocusTests.m | 13 +++++-- .../ios/RunnerTests/CameraSettingsTests.m | 4 +- .../example/ios/RunnerTests/CameraTestUtils.h | 3 +- .../example/ios/RunnerTests/CameraTestUtils.m | 37 ++++++++++++------- .../ios/RunnerTests/FLTCamPhotoCaptureTests.m | 6 ++- .../Sources/camera_avfoundation/FLTCam.m | 4 +- .../include/camera_avfoundation/FLTCam_Test.h | 2 + .../include/camera_avfoundation/QueueUtils.h | 2 +- .../camera/camera_avfoundation/pubspec.yaml | 2 +- 12 files changed, 64 insertions(+), 30 deletions(-) diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index f0f4a302ae5..4ed3637776f 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.17+7 + +* Introduces new protocols `FLTCaptureDeviceControlling` and `FLTDeviceOrientationProviding` + ## 0.9.17+6 * Updates minimum supported SDK version to Flutter 3.22/Dart 3.4. diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj index 04b0b3c4550..8dd444160cb 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 7F56D0382D1EDDCE005676A5 /* CameraPermissionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0B0D2BA27DFF2AF00E71E4B /* CameraPermissionTests.m */; }; 7F87E8022D01FD6F00A3549C /* MockCaptureDeviceController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */; }; 7F87E80C2D0325D900A3549C /* MockDeviceOrientationProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F87E80B2D0325D700A3549C /* MockDeviceOrientationProvider.m */; }; + 7FA99E592D22C75300582559 /* CameraExposureTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FA99E582D22C75300582559 /* CameraExposureTests.m */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; @@ -82,6 +83,7 @@ 7F87E8032D02FF8C00A3549C /* MockCaptureDeviceController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCaptureDeviceController.h; sourceTree = ""; }; 7F87E80A2D0325B200A3549C /* MockDeviceOrientationProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockDeviceOrientationProvider.h; sourceTree = ""; }; 7F87E80B2D0325D700A3549C /* MockDeviceOrientationProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockDeviceOrientationProvider.m; sourceTree = ""; }; + 7FA99E582D22C75300582559 /* CameraExposureTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CameraExposureTests.m; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -140,6 +142,7 @@ 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */, 7D5FCCD32AEF9D0200FB7108 /* CameraSettingsTests.m */, 03BB766A2665316900CE5A93 /* CameraFocusTests.m */, + 7FA99E582D22C75300582559 /* CameraExposureTests.m */, 03BB767226653ABE00CE5A93 /* CameraOrientationTests.m */, 03BB766C2665316900CE5A93 /* Info.plist */, 033B94BD269C40A200B4DF97 /* CameraMethodChannelTests.m */, @@ -462,6 +465,7 @@ 03BB766B2665316900CE5A93 /* CameraFocusTests.m in Sources */, 7F87E8022D01FD6F00A3549C /* MockCaptureDeviceController.m in Sources */, 7D5FCCD42AEF9D0200FB7108 /* CameraSettingsTests.m in Sources */, + 7FA99E592D22C75300582559 /* CameraExposureTests.m in Sources */, E487C86026D686A10034AC92 /* CameraPreviewPauseTests.m in Sources */, 7F87E80C2D0325D900A3549C /* MockDeviceOrientationProvider.m in Sources */, E071CF7427B31DE4006EF3BA /* FLTCamSampleBufferTests.m in Sources */, diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m index 28a5f7e1fcc..23f57358190 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m @@ -6,6 +6,7 @@ @import XCTest; @import AVFoundation; +#import "CameraTestUtils.h" #import "MockCaptureDeviceController.h" #import "MockDeviceOrientationProvider.h" @@ -18,12 +19,16 @@ @interface CameraExposureTests : XCTestCase @implementation CameraExposureTests - (void)setUp { - _camera = [[FLTCam alloc] init]; - _mockDevice = [[MockCaptureDeviceController alloc] init]; + MockCaptureDeviceController *mockDevice = [[MockCaptureDeviceController alloc] init]; _mockDeviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; + _mockDevice = mockDevice; - [_camera setValue:_mockDevice forKey:@"captureDevice"]; - [_camera setValue:_mockDeviceOrientationProvider forKey:@"deviceOrientationProvider"]; + _camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( + nil, nil, nil, + ^id(void) { + return mockDevice; + }, + _mockDeviceOrientationProvider); } - (void)testSetExposurePointWithResult_SetsExposurePointOfInterest { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m index f7d96c3aa75..18fd29d89f3 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m @@ -9,6 +9,7 @@ @import XCTest; @import AVFoundation; +#import "CameraTestUtils.h" #import "MockCaptureDeviceController.h" #import "MockDeviceOrientationProvider.h" @@ -21,12 +22,16 @@ @interface CameraFocusTests : XCTestCase @implementation CameraFocusTests - (void)setUp { - _camera = [[FLTCam alloc] init]; - _mockDevice = [[MockCaptureDeviceController alloc] init]; + MockCaptureDeviceController *mockDevice = [[MockCaptureDeviceController alloc] init]; + _mockDevice = mockDevice; _mockDeviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; - [_camera setValue:_mockDevice forKey:@"captureDevice"]; - [_camera setValue:_mockDeviceOrientationProvider forKey:@"deviceOrientationProvider"]; + _camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( + nil, nil, nil, + ^id(void) { + return mockDevice; + }, + _mockDeviceOrientationProvider); } - (void)testAutoFocusWithContinuousModeSupported_ShouldSetContinuousAutoFocus { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m index 9bed6bea488..98e12020b59 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m @@ -144,7 +144,7 @@ - (void)testSettings_shouldPassConfigurationToCameraDeviceAndWriter { [[TestMediaSettingsAVWrapper alloc] initWithTestCase:self]; FLTCam *camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( - dispatch_queue_create("test", NULL), settings, injectedWrapper, nil); + dispatch_queue_create("test", NULL), settings, injectedWrapper, nil, nil); // Expect FPS configuration is passed to camera device. [self waitForExpectations:@[ @@ -211,7 +211,7 @@ - (void)testSettings_ShouldSelectFormatWhichSupports60FPS { enableAudio:gTestEnableAudio]; FLTCam *camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( - dispatch_queue_create("test", NULL), settings, nil, nil); + dispatch_queue_create("test", NULL), settings, nil, nil, nil); AVFrameRateRange *range = camera.captureDevice.activeFormat.videoSupportedFrameRateRanges[0]; XCTAssertLessThanOrEqual(range.minFrameRate, 60); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h index 2bbb56c51a7..008ba9df48f 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h @@ -20,7 +20,8 @@ extern FLTCam *_Nullable FLTCreateCamWithCaptureSessionQueueAndMediaSettings( dispatch_queue_t _Nullable captureSessionQueue, FCPPlatformMediaSettings *_Nullable mediaSettings, FLTCamMediaSettingsAVWrapper *_Nullable mediaSettingsAVWrapper, - CaptureDeviceFactory _Nullable captureDeviceFactory); + CaptureDeviceFactory _Nullable captureDeviceFactory, + id _Nullable deviceOrientationProvider); extern FLTCam *FLTCreateCamWithCaptureSessionQueue(dispatch_queue_t captureSessionQueue); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m index f82bbf1aedc..f10a3b122d7 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m @@ -8,6 +8,8 @@ @import AVFoundation; @import camera_avfoundation; +#import "MockDeviceOrientationProvider.h" + static FCPPlatformMediaSettings *FCPGetDefaultMediaSettings( FCPPlatformResolutionPreset resolutionPreset) { return [FCPPlatformMediaSettings makeWithResolutionPreset:resolutionPreset @@ -18,13 +20,14 @@ } FLTCam *FLTCreateCamWithCaptureSessionQueue(dispatch_queue_t captureSessionQueue) { - return FLTCreateCamWithCaptureSessionQueueAndMediaSettings(captureSessionQueue, nil, nil, nil); + return FLTCreateCamWithCaptureSessionQueueAndMediaSettings(captureSessionQueue, nil, nil, nil, + nil); } FLTCam *FLTCreateCamWithCaptureSessionQueueAndMediaSettings( dispatch_queue_t captureSessionQueue, FCPPlatformMediaSettings *mediaSettings, - FLTCamMediaSettingsAVWrapper *mediaSettingsAVWrapper, - CaptureDeviceFactory captureDeviceFactory) { + FLTCamMediaSettingsAVWrapper *mediaSettingsAVWrapper, CaptureDeviceFactory captureDeviceFactory, + id deviceOrientationProvider) { if (!mediaSettings) { mediaSettings = FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetMedium); } @@ -33,6 +36,10 @@ mediaSettingsAVWrapper = [[FLTCamMediaSettingsAVWrapper alloc] init]; } + if (!deviceOrientationProvider) { + deviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; + } + id inputMock = OCMClassMock([AVCaptureDeviceInput class]); OCMStub([inputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg setTo:nil]]) .andReturn(inputMock); @@ -94,6 +101,7 @@ videoDimensionsForFormat:^CMVideoDimensions(AVCaptureDeviceFormat *format) { return CMVideoFormatDescriptionGetDimensions(format.formatDescription); } + deviceOrientationProvider:deviceOrientationProvider error:nil]; id captureVideoDataOutputMock = [OCMockObject niceMockForClass:[AVCaptureVideoDataOutput class]]; @@ -156,17 +164,18 @@ OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); return [[FLTCam alloc] - initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) - mediaSettingsAVWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] - orientation:UIDeviceOrientationPortrait - videoCaptureSession:captureSession - audioCaptureSession:audioSessionMock - captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL) - captureDeviceFactory:^id(void) { - return [[FLTDefaultCaptureDeviceController alloc] initWithDevice:captureDevice]; - } - videoDimensionsForFormat:videoDimensionsForFormat - error:nil]; + initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) + mediaSettingsAVWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] + orientation:UIDeviceOrientationPortrait + videoCaptureSession:captureSession + audioCaptureSession:audioSessionMock + captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL) + captureDeviceFactory:^id(void) { + return [[FLTDefaultCaptureDeviceController alloc] initWithDevice:captureDevice]; + } + videoDimensionsForFormat:videoDimensionsForFormat + deviceOrientationProvider:[[MockDeviceOrientationProvider alloc] init] + error:nil]; } CMSampleBufferRef FLTCreateTestSampleBuffer(void) { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m index 75a4f3abd7d..c1bfb6ad376 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m @@ -188,9 +188,11 @@ - (void)testCaptureToFile_handlesTorchMode { (void *)FLTCaptureSessionQueueSpecific, NULL); FLTCam *cam = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( - captureSessionQueue, nil, nil, ^id(void) { + captureSessionQueue, nil, nil, + ^id(void) { return [[FLTDefaultCaptureDeviceController alloc] initWithDevice:captureDeviceMock]; - }); + }, + nil); AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettings]; id mockSettings = OCMClassMock([AVCapturePhotoSettings class]); diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index ff9e23bc48d..ab85994a8ba 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -153,6 +153,7 @@ - (instancetype)initWithCameraName:(NSString *)cameraName videoDimensionsForFormat:^CMVideoDimensions(AVCaptureDeviceFormat *format) { return CMVideoFormatDescriptionGetDimensions(format.formatDescription); } + deviceOrientationProvider:[[FLTDefaultDeviceOrientationProvider alloc] init] error:error]; } @@ -217,6 +218,7 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings captureSessionQueue:(dispatch_queue_t)captureSessionQueue captureDeviceFactory:(CaptureDeviceFactory)captureDeviceFactory videoDimensionsForFormat:(VideoDimensionsForFormat)videoDimensionsForFormat + deviceOrientationProvider:(id)deviceOrientationProvider error:(NSError **)error { self = [super init]; NSAssert(self, @"super init cannot be nil"); @@ -266,7 +268,7 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings _motionManager = [[CMMotionManager alloc] init]; [_motionManager startAccelerometerUpdates]; - _deviceOrientationProvider = [[FLTDefaultDeviceOrientationProvider alloc] init]; + _deviceOrientationProvider = deviceOrientationProvider; if (_mediaSettings.framesPerSecond) { // The frame rate can be changed only on a locked for configuration device. diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h index f643d335a4c..7e27e31a888 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h @@ -4,6 +4,7 @@ #import "FLTCam.h" #import "FLTCaptureDeviceControlling.h" +#import "FLTDeviceOrientationProviding.h" #import "FLTSavePhotoDelegate.h" /// Determines the video dimensions (width and height) for a given capture device format. @@ -75,6 +76,7 @@ typedef id (^CaptureDeviceFactory)(void); captureSessionQueue:(dispatch_queue_t)captureSessionQueue captureDeviceFactory:(CaptureDeviceFactory)captureDeviceFactory videoDimensionsForFormat:(VideoDimensionsForFormat)videoDimensionsForFormat + deviceOrientationProvider:(id)deviceOrientationProvider error:(NSError **)error; /// Start streaming images. diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/QueueUtils.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/QueueUtils.h index e230a53508f..a7e22da716d 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/QueueUtils.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/QueueUtils.h @@ -7,7 +7,7 @@ NS_ASSUME_NONNULL_BEGIN /// Queue-specific context data to be associated with the capture session queue. -extern const char *FLTCaptureSessionQueueSpecific; +extern const char* FLTCaptureSessionQueueSpecific; /// Ensures the given block to be run on the main queue. /// If caller site is already on the main queue, the block will be run diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index 507011775bf..5b335cac022 100644 --- a/packages/camera/camera_avfoundation/pubspec.yaml +++ b/packages/camera/camera_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_avfoundation description: iOS implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.17+6 +version: 0.9.17+7 environment: sdk: ^3.4.0 From c96e9dac2265c748a3503fc911492d42634000d8 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Mon, 30 Dec 2024 13:58:49 +0100 Subject: [PATCH 05/31] Fix CI --- .../Protocols/FLTCaptureDeviceControlling.m | 3 +++ .../Protocols/FLTDeviceOrientationProviding.m | 1 + 2 files changed, 4 insertions(+) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m index eaa4dfd250a..89c72574a3d 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m @@ -57,9 +57,12 @@ - (void)setTorchMode:(AVCaptureTorchMode)torchMode { self.device.torchMode = torchMode; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" - (BOOL)isFlashModeSupported:(AVCaptureFlashMode)mode { return [self.device isFlashModeSupported:mode]; } +#pragma clang diagnostic pop // Focus - (BOOL)isFocusPointOfInterestSupported { diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m index 0f909b2a9fa..9592de77886 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m @@ -3,6 +3,7 @@ // found in the LICENSE file. #import "../include/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.h" +#import @implementation FLTDefaultDeviceOrientationProvider From 715583871faf22bf1f33d895bc31a68e72987994 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Mon, 30 Dec 2024 14:10:51 +0100 Subject: [PATCH 06/31] Fix imports --- .../Protocols/FLTDeviceOrientationProviding.m | 1 - .../Protocols/FLTDeviceOrientationProviding.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m index 9592de77886..0f909b2a9fa 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m @@ -3,7 +3,6 @@ // found in the LICENSE file. #import "../include/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.h" -#import @implementation FLTDefaultDeviceOrientationProvider diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.h index e0b39f9b9e2..afdb607228d 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import AVFoundation; @import Foundation; +#import NS_ASSUME_NONNULL_BEGIN From 3cd5341261002a802026096c0dfbdf5c6b61c4b3 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Mon, 30 Dec 2024 14:21:18 +0100 Subject: [PATCH 07/31] Fix imports --- .../camera_avfoundation/include/camera_avfoundation/FLTCam.h | 2 +- .../camera_avfoundation/FLTCamMediaSettingsAVWrapper.h | 2 +- .../include/camera_avfoundation/FLTCam_Test.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h index b5418124bf5..4f94b1a4662 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h @@ -8,7 +8,7 @@ #import "CameraProperties.h" #import "FLTCamMediaSettingsAVWrapper.h" -#import "FLTCaptureDeviceControlling.h" +#import "Protocols/FLTCaptureDeviceControlling.h" #import "messages.g.h" NS_ASSUME_NONNULL_BEGIN diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h index 8d95cf02afe..1d59c5d7d88 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h @@ -5,7 +5,7 @@ @import AVFoundation; @import Foundation; -#import "FLTCaptureDeviceControlling.h" +#import "Protocols/FLTCaptureDeviceControlling.h" NS_ASSUME_NONNULL_BEGIN diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h index 7e27e31a888..5db514cca45 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h @@ -3,8 +3,8 @@ // found in the LICENSE file. #import "FLTCam.h" -#import "FLTCaptureDeviceControlling.h" -#import "FLTDeviceOrientationProviding.h" +#import "Protocols/FLTCaptureDeviceControlling.h" +#import "Protocols/FLTDeviceOrientationProviding.h" #import "FLTSavePhotoDelegate.h" /// Determines the video dimensions (width and height) for a given capture device format. From 8256579dfa2fe02b18aea90ec8cf15fef17dc597 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Mon, 30 Dec 2024 14:39:58 +0100 Subject: [PATCH 08/31] Another try to fix imports --- .../camera_avfoundation/include/camera_avfoundation/FLTCam.h | 3 ++- .../camera_avfoundation/FLTCamMediaSettingsAVWrapper.h | 2 +- .../include/camera_avfoundation/FLTCam_Test.h | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h index 4f94b1a4662..0752f84c4f9 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h @@ -6,9 +6,10 @@ @import Foundation; @import Flutter; +#import "FLTCaptureDeviceControlling.h" + #import "CameraProperties.h" #import "FLTCamMediaSettingsAVWrapper.h" -#import "Protocols/FLTCaptureDeviceControlling.h" #import "messages.g.h" NS_ASSUME_NONNULL_BEGIN diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h index 1d59c5d7d88..8d95cf02afe 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h @@ -5,7 +5,7 @@ @import AVFoundation; @import Foundation; -#import "Protocols/FLTCaptureDeviceControlling.h" +#import "FLTCaptureDeviceControlling.h" NS_ASSUME_NONNULL_BEGIN diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h index 5db514cca45..7e27e31a888 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h @@ -3,8 +3,8 @@ // found in the LICENSE file. #import "FLTCam.h" -#import "Protocols/FLTCaptureDeviceControlling.h" -#import "Protocols/FLTDeviceOrientationProviding.h" +#import "FLTCaptureDeviceControlling.h" +#import "FLTDeviceOrientationProviding.h" #import "FLTSavePhotoDelegate.h" /// Determines the video dimensions (width and height) for a given capture device format. From 27f31c0b2ce2cf4608572b377388a0a2d46a5514 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Mon, 30 Dec 2024 23:56:29 +0100 Subject: [PATCH 09/31] Change order in modulemap --- .../camera_avfoundation/include/CameraPlugin.modulemap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap index af0c9bee47f..f7ba3069d6b 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap @@ -5,6 +5,8 @@ framework module camera_avfoundation { module * { export * } explicit module Test { + header "FLTCaptureDeviceControlling.h" + header "FLTDeviceOrientationProviding.h" header "CameraPlugin_Test.h" header "CameraProperties.h" header "FLTCam.h" @@ -13,8 +15,6 @@ framework module camera_avfoundation { header "FLTThreadSafeEventChannel.h" header "FLTPermissionServicing.h" header "FLTCameraPermissionManager.h" - header "FLTCaptureDeviceControlling.h" - header "FLTDeviceOrientationProviding.h" header "QueueUtils.h" } } From 7a259095ac732d18334421f9800707c5bb8432a1 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Tue, 31 Dec 2024 00:15:54 +0100 Subject: [PATCH 10/31] Add FLTCamMediaSettingsAVWrapper to module map --- .../Sources/camera_avfoundation/include/CameraPlugin.modulemap | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap index f7ba3069d6b..6ba6e7b34c9 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap @@ -7,6 +7,7 @@ framework module camera_avfoundation { explicit module Test { header "FLTCaptureDeviceControlling.h" header "FLTDeviceOrientationProviding.h" + header "FLTCamMediaSettingsAVWrapper.h" header "CameraPlugin_Test.h" header "CameraProperties.h" header "FLTCam.h" From cdb1578989b83878f04265efa6ab841fe102ef1b Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Tue, 31 Dec 2024 11:42:51 +0100 Subject: [PATCH 11/31] Remove new protocols from modulemap --- .../Sources/camera_avfoundation/include/CameraPlugin.modulemap | 3 +-- .../camera_avfoundation/include/camera_avfoundation/FLTCam.h | 3 +-- .../include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h | 2 +- .../include/camera_avfoundation/FLTCam_Test.h | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap index 6ba6e7b34c9..df1f2e957dd 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap @@ -6,15 +6,14 @@ framework module camera_avfoundation { explicit module Test { header "FLTCaptureDeviceControlling.h" + header "FLTPermissionServicing.h" header "FLTDeviceOrientationProviding.h" - header "FLTCamMediaSettingsAVWrapper.h" header "CameraPlugin_Test.h" header "CameraProperties.h" header "FLTCam.h" header "FLTCam_Test.h" header "FLTSavePhotoDelegate_Test.h" header "FLTThreadSafeEventChannel.h" - header "FLTPermissionServicing.h" header "FLTCameraPermissionManager.h" header "QueueUtils.h" } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h index 0752f84c4f9..671c10a0654 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h @@ -6,11 +6,10 @@ @import Foundation; @import Flutter; -#import "FLTCaptureDeviceControlling.h" - #import "CameraProperties.h" #import "FLTCamMediaSettingsAVWrapper.h" #import "messages.g.h" +#import "Protocols/FLTCaptureDeviceControlling.h" NS_ASSUME_NONNULL_BEGIN diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h index 8d95cf02afe..1d59c5d7d88 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h @@ -5,7 +5,7 @@ @import AVFoundation; @import Foundation; -#import "FLTCaptureDeviceControlling.h" +#import "Protocols/FLTCaptureDeviceControlling.h" NS_ASSUME_NONNULL_BEGIN diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h index 7e27e31a888..558d3e77783 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h @@ -3,9 +3,9 @@ // found in the LICENSE file. #import "FLTCam.h" -#import "FLTCaptureDeviceControlling.h" #import "FLTDeviceOrientationProviding.h" #import "FLTSavePhotoDelegate.h" +#import "Protocols/FLTCaptureDeviceControlling.h" /// Determines the video dimensions (width and height) for a given capture device format. /// Used in tests to mock CMVideoFormatDescriptionGetDimensions. From 486686ac6f4ebce5e9c9251979ae0c1f05f6dd67 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Tue, 31 Dec 2024 12:21:55 +0100 Subject: [PATCH 12/31] Add header search path --- .../camera_avfoundation/ios/camera_avfoundation/Package.swift | 1 + .../camera_avfoundation/include/camera_avfoundation/FLTCam.h | 2 +- .../include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h | 2 +- .../include/camera_avfoundation/FLTCam_Test.h | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Package.swift b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Package.swift index 48050b6b788..3ea113b3a11 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Package.swift +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Package.swift @@ -25,6 +25,7 @@ let package = Package( ], cSettings: [ .headerSearchPath("include/camera_avfoundation") + .headerSearchPath("include/camera_avfoundation/Protocols") ] ) ] diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h index 671c10a0654..ee5b406647b 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h @@ -9,7 +9,7 @@ #import "CameraProperties.h" #import "FLTCamMediaSettingsAVWrapper.h" #import "messages.g.h" -#import "Protocols/FLTCaptureDeviceControlling.h" +#import "FLTCaptureDeviceControlling.h" NS_ASSUME_NONNULL_BEGIN diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h index 1d59c5d7d88..8d95cf02afe 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h @@ -5,7 +5,7 @@ @import AVFoundation; @import Foundation; -#import "Protocols/FLTCaptureDeviceControlling.h" +#import "FLTCaptureDeviceControlling.h" NS_ASSUME_NONNULL_BEGIN diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h index 558d3e77783..7e27e31a888 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h @@ -3,9 +3,9 @@ // found in the LICENSE file. #import "FLTCam.h" +#import "FLTCaptureDeviceControlling.h" #import "FLTDeviceOrientationProviding.h" #import "FLTSavePhotoDelegate.h" -#import "Protocols/FLTCaptureDeviceControlling.h" /// Determines the video dimensions (width and height) for a given capture device format. /// Used in tests to mock CMVideoFormatDescriptionGetDimensions. From 2a070caea9aa3db7891d4a67083820cbbab72e80 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Tue, 31 Dec 2024 12:27:02 +0100 Subject: [PATCH 13/31] Fix formatting --- .../camera_avfoundation/ios/camera_avfoundation/Package.swift | 1 - .../camera_avfoundation/include/CameraPlugin.modulemap | 4 ++-- .../camera_avfoundation/include/camera_avfoundation/FLTCam.h | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Package.swift b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Package.swift index 3ea113b3a11..48050b6b788 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Package.swift +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Package.swift @@ -25,7 +25,6 @@ let package = Package( ], cSettings: [ .headerSearchPath("include/camera_avfoundation") - .headerSearchPath("include/camera_avfoundation/Protocols") ] ) ] diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap index df1f2e957dd..4f2c934be24 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap @@ -5,9 +5,9 @@ framework module camera_avfoundation { module * { export * } explicit module Test { - header "FLTCaptureDeviceControlling.h" + header "Protocols/FLTCaptureDeviceControlling.h" + header "Protocols/FLTDeviceOrientationProviding.h" header "FLTPermissionServicing.h" - header "FLTDeviceOrientationProviding.h" header "CameraPlugin_Test.h" header "CameraProperties.h" header "FLTCam.h" diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h index ee5b406647b..b5418124bf5 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h @@ -8,8 +8,8 @@ #import "CameraProperties.h" #import "FLTCamMediaSettingsAVWrapper.h" -#import "messages.g.h" #import "FLTCaptureDeviceControlling.h" +#import "messages.g.h" NS_ASSUME_NONNULL_BEGIN From 04f1e8bdf0064646d19dbbceec33ff0b2996ab17 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Thu, 2 Jan 2025 10:04:21 +0100 Subject: [PATCH 14/31] Flatten the structure --- .../camera_avfoundation/Sources/camera_avfoundation/FLTCam.m | 4 ++-- .../camera_avfoundation/FLTCamMediaSettingsAVWrapper.m | 2 +- .../{Protocols => }/FLTCaptureDeviceControlling.m | 2 +- .../{Protocols => }/FLTDeviceOrientationProviding.m | 2 +- .../camera_avfoundation/include/CameraPlugin.modulemap | 4 ++-- .../{Protocols => }/FLTCaptureDeviceControlling.h | 0 .../{Protocols => }/FLTDeviceOrientationProviding.h | 0 7 files changed, 7 insertions(+), 7 deletions(-) rename packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/{Protocols => }/FLTCaptureDeviceControlling.m (97%) rename packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/{Protocols => }/FLTDeviceOrientationProviding.m (79%) rename packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/{Protocols => }/FLTCaptureDeviceControlling.h (100%) rename packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/{Protocols => }/FLTDeviceOrientationProviding.h (100%) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index ab85994a8ba..7612f2bca36 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -9,10 +9,10 @@ @import Flutter; #import +#import "./include/camera_avfoundation/FLTCaptureDeviceControlling.h" +#import "./include/camera_avfoundation/FLTDeviceOrientationProviding.h" #import "./include/camera_avfoundation/FLTSavePhotoDelegate.h" #import "./include/camera_avfoundation/FLTThreadSafeEventChannel.h" -#import "./include/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.h" -#import "./include/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.h" #import "./include/camera_avfoundation/QueueUtils.h" #import "./include/camera_avfoundation/messages.g.h" diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m index 0ecf89a724c..21a0d9a68ee 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m @@ -3,7 +3,7 @@ // found in the LICENSE file. #import "./include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h" -#import "./include/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.h" +#import "./include/camera_avfoundation/FLTCaptureDeviceControlling.h" @implementation FLTCamMediaSettingsAVWrapper diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m similarity index 97% rename from packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m rename to packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m index 89c72574a3d..658e0a0fedb 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "../include/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.h" +#import "./include/camera_avfoundation/FLTCaptureDeviceControlling.h" @interface FLTDefaultCaptureDeviceController () @property(nonatomic, strong) AVCaptureDevice *device; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTDeviceOrientationProviding.m similarity index 79% rename from packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m rename to packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTDeviceOrientationProviding.m index 0f909b2a9fa..5419eb0a358 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTDeviceOrientationProviding.m @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "../include/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.h" +#import "./include/camera_avfoundation/FLTDeviceOrientationProviding.h" @implementation FLTDefaultDeviceOrientationProvider diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap index 4f2c934be24..899a43a3cab 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap @@ -5,8 +5,8 @@ framework module camera_avfoundation { module * { export * } explicit module Test { - header "Protocols/FLTCaptureDeviceControlling.h" - header "Protocols/FLTDeviceOrientationProviding.h" + header "FLTCaptureDeviceControlling.h" + header "FLTDeviceOrientationProviding.h" header "FLTPermissionServicing.h" header "CameraPlugin_Test.h" header "CameraProperties.h" diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h similarity index 100% rename from packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTCaptureDeviceControlling.h rename to packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTDeviceOrientationProviding.h similarity index 100% rename from packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/Protocols/FLTDeviceOrientationProviding.h rename to packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTDeviceOrientationProviding.h From 0d81c7f1099c3a67f1132187e67484d1412401e5 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Thu, 2 Jan 2025 11:06:20 +0100 Subject: [PATCH 15/31] Remove OCMock from CameraOrientationTests --- .../ios/RunnerTests/CameraOrientationTests.m | 137 +++++++++++------- 1 file changed, 83 insertions(+), 54 deletions(-) diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m index b1547c53212..4badf8e85b0 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m @@ -9,9 +9,8 @@ @import XCTest; @import Flutter; -#import - #import "MockCaptureDeviceController.h" +#import "MockDeviceOrientationProvider.h" @interface StubGlobalEventApi : FCPCameraGlobalEventApi @property(nonatomic) BOOL called; @@ -34,22 +33,56 @@ - (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(nonnull NSString @end +@interface MockCamera : FLTCam +@property(nonatomic, copy) void (^setDeviceOrientationStub)(UIDeviceOrientation orientation); +@end + +@implementation MockCamera +- (void)setDeviceOrientation:(UIDeviceOrientation)orientation { + if (self.setDeviceOrientationStub) { + self.setDeviceOrientationStub(orientation); + } +} + +- (void)setCaptureDevice:(id)device { + self.captureDevice = device; +} + +@end + +@interface MockUIDevice : UIDevice +@property (nonatomic, assign) UIDeviceOrientation mockOrientation; +@end + +@implementation MockUIDevice +- (UIDeviceOrientation)orientation { + return self.mockOrientation; +} + +@end + #pragma mark - @interface CameraOrientationTests : XCTestCase -@property(readonly, nonatomic) FLTCam *camera; +@property(readonly, nonatomic) MockCamera *camera; @property(readonly, nonatomic) MockCaptureDeviceController *mockDevice; @property(readonly, nonatomic) StubGlobalEventApi *eventAPI; +@property(readonly, nonatomic) CameraPlugin *cameraPlugin; @end @implementation CameraOrientationTests - (void)setUp { [super setUp]; - _mockDevice = [[MockCaptureDeviceController alloc] init]; - _camera = [[FLTCam alloc] init]; - - [_camera setValue:_mockDevice forKey:@"captureDevice"]; + MockCaptureDeviceController *mockDevice = [[MockCaptureDeviceController alloc] init]; + _camera = [[MockCamera alloc] init]; + _eventAPI = [[StubGlobalEventApi alloc] init]; + _mockDevice = mockDevice; + + _cameraPlugin = [[CameraPlugin alloc] initWithRegistry:nil + messenger:nil + globalAPI:_eventAPI]; + _cameraPlugin.camera = _camera; } // Ensure that the given queue and then the main queue have both cycled, to wait for any pending @@ -70,30 +103,20 @@ - (void)sendOrientation:(UIDeviceOrientation)orientation toCamera:(CameraPlugin } - (void)testOrientationNotifications { - StubGlobalEventApi *eventAPI = [[StubGlobalEventApi alloc] init]; - CameraPlugin *cameraPlugin = [[CameraPlugin alloc] initWithRegistry:nil - messenger:nil - globalAPI:eventAPI]; - - [self sendOrientation:UIDeviceOrientationPortraitUpsideDown toCamera:cameraPlugin]; - XCTAssertEqual(eventAPI.lastOrientation, FCPPlatformDeviceOrientationPortraitDown); - [self sendOrientation:UIDeviceOrientationPortrait toCamera:cameraPlugin]; - XCTAssertEqual(eventAPI.lastOrientation, FCPPlatformDeviceOrientationPortraitUp); - [self sendOrientation:UIDeviceOrientationLandscapeLeft toCamera:cameraPlugin]; - XCTAssertEqual(eventAPI.lastOrientation, FCPPlatformDeviceOrientationLandscapeLeft); - [self sendOrientation:UIDeviceOrientationLandscapeRight toCamera:cameraPlugin]; - XCTAssertEqual(eventAPI.lastOrientation, FCPPlatformDeviceOrientationLandscapeRight); + [self sendOrientation:UIDeviceOrientationPortraitUpsideDown toCamera:_cameraPlugin]; + XCTAssertEqual(_eventAPI.lastOrientation, FCPPlatformDeviceOrientationPortraitDown); + [self sendOrientation:UIDeviceOrientationPortrait toCamera:_cameraPlugin]; + XCTAssertEqual(_eventAPI.lastOrientation, FCPPlatformDeviceOrientationPortraitUp); + [self sendOrientation:UIDeviceOrientationLandscapeLeft toCamera:_cameraPlugin]; + XCTAssertEqual(_eventAPI.lastOrientation, FCPPlatformDeviceOrientationLandscapeLeft); + [self sendOrientation:UIDeviceOrientationLandscapeRight toCamera:_cameraPlugin]; + XCTAssertEqual(_eventAPI.lastOrientation, FCPPlatformDeviceOrientationLandscapeRight); } - (void)testOrientationNotificationsNotCalledForFaceUp { - StubGlobalEventApi *eventAPI = [[StubGlobalEventApi alloc] init]; - CameraPlugin *cameraPlugin = [[CameraPlugin alloc] initWithRegistry:nil - messenger:nil - globalAPI:eventAPI]; + [self sendOrientation:UIDeviceOrientationFaceUp toCamera:_cameraPlugin]; - [self sendOrientation:UIDeviceOrientationFaceUp toCamera:cameraPlugin]; - - XCTAssertFalse(eventAPI.called); + XCTAssertFalse(_eventAPI.called); } - (void)testOrientationNotificationsNotCalledForFaceDown { @@ -110,53 +133,59 @@ - (void)testOrientationNotificationsNotCalledForFaceDown { - (void)testOrientationUpdateMustBeOnCaptureSessionQueue { XCTestExpectation *queueExpectation = [self expectationWithDescription:@"Orientation update must happen on the capture session queue"]; - CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil]; + + CameraPlugin *plugin = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil]; const char *captureSessionQueueSpecific = "capture_session_queue"; - dispatch_queue_set_specific(camera.captureSessionQueue, captureSessionQueueSpecific, + dispatch_queue_set_specific(plugin.captureSessionQueue, captureSessionQueueSpecific, (void *)captureSessionQueueSpecific, NULL); - FLTCam *mockCam = OCMClassMock([FLTCam class]); - camera.camera = mockCam; - - OCMStub([mockCam setDeviceOrientation:UIDeviceOrientationLandscapeLeft]) - .andDo(^(NSInvocation *invocation) { - if (dispatch_get_specific(captureSessionQueueSpecific)) { - [queueExpectation fulfill]; - } - }); - - [camera orientationChanged: + plugin.camera = _camera; + + _camera.setDeviceOrientationStub = ^(UIDeviceOrientation orientation) { + if (dispatch_get_specific(captureSessionQueueSpecific)) { + [queueExpectation fulfill]; + } + }; + + [plugin orientationChanged: [self createMockNotificationForOrientation:UIDeviceOrientationLandscapeLeft]]; [self waitForExpectationsWithTimeout:1 handler:nil]; } - (void)testOrientationChanged_noRetainCycle { dispatch_queue_t captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); - FLTCam *mockCam = OCMClassMock([FLTCam class]); - StubGlobalEventApi *stubAPI = [[StubGlobalEventApi alloc] init]; - __weak CameraPlugin *weakCamera; + __weak CameraPlugin *weakPlugin; @autoreleasepool { - CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil + CameraPlugin *plugin = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil - globalAPI:stubAPI]; - weakCamera = camera; - camera.captureSessionQueue = captureSessionQueue; - camera.camera = mockCam; + globalAPI:_eventAPI]; + weakPlugin = plugin; + plugin.captureSessionQueue = captureSessionQueue; + plugin.camera = _camera; - [camera orientationChanged: + [plugin orientationChanged: [self createMockNotificationForOrientation:UIDeviceOrientationLandscapeLeft]]; } // Sanity check - XCTAssertNil(weakCamera, @"Camera must have been deallocated."); + XCTAssertNil(weakPlugin, @"Camera must have been deallocated."); + + __block BOOL setDeviceOrientationCalled = NO; + _camera.setDeviceOrientationStub = ^(UIDeviceOrientation orientation) { + if (orientation == UIDeviceOrientationLandscapeLeft) { + setDeviceOrientationCalled = YES; + } + }; + + __weak StubGlobalEventApi *weakEventAPI = _eventAPI; // Must check in captureSessionQueue since orientationChanged dispatches to this queue. XCTestExpectation *expectation = [self expectationWithDescription:@"Dispatched to capture session queue"]; dispatch_async(captureSessionQueue, ^{ - OCMVerify(never(), [mockCam setDeviceOrientation:UIDeviceOrientationLandscapeLeft]); - XCTAssertFalse(stubAPI.called); + XCTAssertFalse(setDeviceOrientationCalled); + XCTAssertFalse(weakEventAPI.called); [expectation fulfill]; }); @@ -164,8 +193,8 @@ - (void)testOrientationChanged_noRetainCycle { } - (NSNotification *)createMockNotificationForOrientation:(UIDeviceOrientation)deviceOrientation { - UIDevice *mockDevice = OCMClassMock([UIDevice class]); - OCMStub([mockDevice orientation]).andReturn(deviceOrientation); + MockUIDevice *mockDevice = [[MockUIDevice alloc] init]; + mockDevice.mockOrientation = deviceOrientation; return [NSNotification notificationWithName:@"orientation_test" object:mockDevice]; } From bb1cf1a2835d36c8c44013164c7aafa808874968 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Thu, 2 Jan 2025 11:12:23 +0100 Subject: [PATCH 16/31] Add protocol for event channel --- .../ios/RunnerTests/MockEventChannel.h | 17 ++++++++++++ .../camera_avfoundation/FLTEventChannel.m | 27 +++++++++++++++++++ .../include/CameraPlugin.modulemap | 1 + .../camera_avfoundation/FLTEventChannel.h | 18 +++++++++++++ 4 files changed, 63 insertions(+) create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.h create mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTEventChannel.m create mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.h new file mode 100644 index 00000000000..d67c0782703 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.h @@ -0,0 +1,17 @@ +// 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. + +@import camera_avfoundation; +#if __has_include() +@import camera_avfoundation.Test; +#endif +@import Flutter; + +NS_ASSUME_NONNULL_BEGIN + +@interface MockEventChannel : NSObject +@property(nonatomic, copy) void (^setStreamHandlerStub)(NSObject *); +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTEventChannel.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTEventChannel.m new file mode 100644 index 00000000000..cc9f86d2d21 --- /dev/null +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTEventChannel.m @@ -0,0 +1,27 @@ +// 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. + + @import Flutter; + +#import "./include/camera_avfoundation/FLTEventChannel.h" + + @interface FLTDefaultEventChannel () + @property(nonatomic, strong) FlutterEventChannel *channel; + @end + + @implementation FLTDefaultEventChannel + + - (instancetype)initWithEventChannel:(FlutterEventChannel *)channel { + self = [super init]; + if (self) { + _channel = channel; + } + return self; + } + + - (void)setStreamHandler:(NSObject *)handler { + [self.channel setStreamHandler:handler]; + } + + @end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap index 899a43a3cab..6b58a7dc193 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap @@ -7,6 +7,7 @@ framework module camera_avfoundation { explicit module Test { header "FLTCaptureDeviceControlling.h" header "FLTDeviceOrientationProviding.h" + header "FLTMethodChannel.h" header "FLTPermissionServicing.h" header "CameraPlugin_Test.h" header "CameraProperties.h" diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h new file mode 100644 index 00000000000..9da05b1e644 --- /dev/null +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h @@ -0,0 +1,18 @@ +// 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. + + @import Flutter; + + NS_ASSUME_NONNULL_BEGIN + + @protocol FLTEventChannel + - (void)setStreamHandler:(nullable NSObject *)handler; + @end + + /// The default method channel that wraps FlutterMethodChannel + @interface FLTDefaultEventChannel : NSObject + - (instancetype)initWithEventChannel:(FlutterEventChannel *)channel; + @end + + NS_ASSUME_NONNULL_END From de26f9cb34b57e7120ee3c7d5c9fa1032fdefc73 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Thu, 2 Jan 2025 11:22:35 +0100 Subject: [PATCH 17/31] Remove OCMock from ThreadSafeEventChannelTests --- .../ios/RunnerTests/MockEventChannel.m | 15 +++++++ .../RunnerTests/ThreadSafeEventChannelTests.m | 44 +++++++++++-------- .../Sources/camera_avfoundation/FLTCam.m | 4 +- .../FLTThreadSafeEventChannel.m | 5 ++- .../include/CameraPlugin.modulemap | 2 +- .../camera_avfoundation/FLTEventChannel.h | 2 +- .../FLTThreadSafeEventChannel.h | 4 +- 7 files changed, 52 insertions(+), 24 deletions(-) create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.m diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.m new file mode 100644 index 00000000000..a128c2dcb3f --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.m @@ -0,0 +1,15 @@ +// 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. + +#import "MockEventChannel.h" + +@implementation MockEventChannel + +- (void)setStreamHandler:(NSObject *)handler { + if (self.setStreamHandlerStub) { + self.setStreamHandlerStub(handler); + } +} + +@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m index 169b75ddfbb..1f6562e2303 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m @@ -7,30 +7,37 @@ @import camera_avfoundation.Test; #endif @import XCTest; -#import + +#import "MockEventChannel.h" @interface ThreadSafeEventChannelTests : XCTestCase +@property(readonly, nonatomic) MockEventChannel *mockEventChannel; +@property(readonly, nonatomic) FLTThreadSafeEventChannel *threadSafeEventChannel; @end @implementation ThreadSafeEventChannelTests -- (void)testSetStreamHandler_shouldStayOnMainThreadIfCalledFromMainThread { - FlutterEventChannel *mockEventChannel = OCMClassMock([FlutterEventChannel class]); - FLTThreadSafeEventChannel *threadSafeEventChannel = - [[FLTThreadSafeEventChannel alloc] initWithEventChannel:mockEventChannel]; +- (void)setUp { + [super setUp]; + _mockEventChannel = [[MockEventChannel alloc] init]; + _threadSafeEventChannel = + [[FLTThreadSafeEventChannel alloc] initWithEventChannel:_mockEventChannel]; +} +- (void)testSetStreamHandler_shouldStayOnMainThreadIfCalledFromMainThread { XCTestExpectation *mainThreadExpectation = [self expectationWithDescription:@"setStreamHandler must be called on the main thread"]; XCTestExpectation *mainThreadCompletionExpectation = [self expectationWithDescription: @"setStreamHandler's completion block must be called on the main thread"]; - OCMStub([mockEventChannel setStreamHandler:[OCMArg any]]).andDo(^(NSInvocation *invocation) { + + [_mockEventChannel setSetStreamHandlerStub:^(NSObject *handler) { if (NSThread.isMainThread) { [mainThreadExpectation fulfill]; } - }); - - [threadSafeEventChannel setStreamHandler:nil + }]; + + [_threadSafeEventChannel setStreamHandler:nil completion:^{ if (NSThread.isMainThread) { [mainThreadCompletionExpectation fulfill]; @@ -40,23 +47,22 @@ - (void)testSetStreamHandler_shouldStayOnMainThreadIfCalledFromMainThread { } - (void)testSetStreamHandler_shouldDispatchToMainThreadIfCalledFromBackgroundThread { - FlutterEventChannel *mockEventChannel = OCMClassMock([FlutterEventChannel class]); - FLTThreadSafeEventChannel *threadSafeEventChannel = - [[FLTThreadSafeEventChannel alloc] initWithEventChannel:mockEventChannel]; - XCTestExpectation *mainThreadExpectation = [self expectationWithDescription:@"setStreamHandler must be called on the main thread"]; XCTestExpectation *mainThreadCompletionExpectation = [self expectationWithDescription: @"setStreamHandler's completion block must be called on the main thread"]; - OCMStub([mockEventChannel setStreamHandler:[OCMArg any]]).andDo(^(NSInvocation *invocation) { + + + [_mockEventChannel setSetStreamHandlerStub:^(NSObject *handler) { if (NSThread.isMainThread) { [mainThreadExpectation fulfill]; } - }); + }]; + __weak typeof(self) weakSelf = self; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [threadSafeEventChannel setStreamHandler:nil + [weakSelf.threadSafeEventChannel setStreamHandler:nil completion:^{ if (NSThread.isMainThread) { [mainThreadCompletionExpectation fulfill]; @@ -69,11 +75,13 @@ - (void)testSetStreamHandler_shouldDispatchToMainThreadIfCalledFromBackgroundThr - (void)testEventChannel_shouldBeKeptAliveWhenDispatchingBackToMainThread { XCTestExpectation *expectation = [self expectationWithDescription:@"Completion should be called."]; + + __weak typeof(self) weakSelf = self; dispatch_async(dispatch_queue_create("test", NULL), ^{ FLTThreadSafeEventChannel *channel = [[FLTThreadSafeEventChannel alloc] - initWithEventChannel:OCMClassMock([FlutterEventChannel class])]; + initWithEventChannel:weakSelf.mockEventChannel]; - [channel setStreamHandler:OCMOCK_ANY + [channel setStreamHandler:nil completion:^{ [expectation fulfill]; }]; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 7612f2bca36..9ca0884dacc 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -11,6 +11,7 @@ #import "./include/camera_avfoundation/FLTCaptureDeviceControlling.h" #import "./include/camera_avfoundation/FLTDeviceOrientationProviding.h" +#import "./include/camera_avfoundation/FLTEventChannel.h" #import "./include/camera_avfoundation/FLTSavePhotoDelegate.h" #import "./include/camera_avfoundation/FLTThreadSafeEventChannel.h" #import "./include/camera_avfoundation/QueueUtils.h" @@ -1214,8 +1215,9 @@ - (void)startImageStreamWithMessenger:(NSObject *)messen FlutterEventChannel *eventChannel = [FlutterEventChannel eventChannelWithName:@"plugins.flutter.io/camera_avfoundation/imageStream" binaryMessenger:messenger]; + id eventChannelProtocol = [[FLTDefaultEventChannel alloc] initWithEventChannel:eventChannel]; FLTThreadSafeEventChannel *threadSafeEventChannel = - [[FLTThreadSafeEventChannel alloc] initWithEventChannel:eventChannel]; + [[FLTThreadSafeEventChannel alloc] initWithEventChannel:eventChannelProtocol]; _imageStreamHandler = imageStreamHandler; __weak typeof(self) weakSelf = self; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTThreadSafeEventChannel.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTThreadSafeEventChannel.m index 53c7273a590..58f29038d0a 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTThreadSafeEventChannel.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTThreadSafeEventChannel.m @@ -2,16 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#import "./include/camera_avfoundation/FLTEventChannel.h" #import "./include/camera_avfoundation/FLTThreadSafeEventChannel.h" #import "./include/camera_avfoundation/QueueUtils.h" @interface FLTThreadSafeEventChannel () -@property(nonatomic, strong) FlutterEventChannel *channel; +@property(nonatomic, strong) id channel; @end @implementation FLTThreadSafeEventChannel -- (instancetype)initWithEventChannel:(FlutterEventChannel *)channel { +- (instancetype)initWithEventChannel:(id)channel { self = [super init]; if (self) { _channel = channel; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap index 6b58a7dc193..c4384df1a20 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap @@ -7,7 +7,7 @@ framework module camera_avfoundation { explicit module Test { header "FLTCaptureDeviceControlling.h" header "FLTDeviceOrientationProviding.h" - header "FLTMethodChannel.h" + header "FLTEventChannel.h" header "FLTPermissionServicing.h" header "CameraPlugin_Test.h" header "CameraProperties.h" diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h index 9da05b1e644..a75e4265a6f 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h @@ -11,7 +11,7 @@ @end /// The default method channel that wraps FlutterMethodChannel - @interface FLTDefaultEventChannel : NSObject +@interface FLTDefaultEventChannel : NSObject - (instancetype)initWithEventChannel:(FlutterEventChannel *)channel; @end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTThreadSafeEventChannel.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTThreadSafeEventChannel.h index 20a1d4023a3..b942b687dc6 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTThreadSafeEventChannel.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTThreadSafeEventChannel.h @@ -4,6 +4,8 @@ #import +#import "FLTEventChannel.h" + NS_ASSUME_NONNULL_BEGIN /// A thread safe wrapper for FlutterEventChannel that can be called from any thread, by dispatching @@ -12,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN /// Creates a FLTThreadSafeEventChannel by wrapping a FlutterEventChannel object. /// @param channel The FlutterEventChannel object to be wrapped. -- (instancetype)initWithEventChannel:(FlutterEventChannel *)channel; +- (instancetype)initWithEventChannel:(id)channel; /// Registers a handler on the main thread for stream setup requests from the Flutter side. /// The completion block runs on the main thread. From 4b45f30e8870bc57f17f352298688e2fdfb5b2d0 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Thu, 2 Jan 2025 11:52:01 +0100 Subject: [PATCH 18/31] Introduce FLTCameraDeviceDiscovering --- .../ios/Runner.xcodeproj/project.pbxproj | 12 +++ .../ios/RunnerTests/AvailableCamerasTest.m | 90 +++++++++++-------- .../ios/RunnerTests/CameraOrientationTests.m | 26 +++--- .../RunnerTests/MockCameraDeviceDiscoverer.h | 17 ++++ .../RunnerTests/MockCameraDeviceDiscoverer.m | 19 ++++ .../RunnerTests/MockCaptureDeviceController.h | 3 + .../ios/RunnerTests/MockEventChannel.h | 4 +- .../ios/RunnerTests/MockEventChannel.m | 6 +- .../RunnerTests/ThreadSafeEventChannelTests.m | 35 ++++---- .../camera_avfoundation/CameraPlugin.m | 25 +++--- .../Sources/camera_avfoundation/FLTCam.m | 3 +- .../FLTCameraDeviceDiscovering.m | 32 +++++++ .../FLTCaptureDeviceControlling.m | 4 + .../camera_avfoundation/FLTEventChannel.m | 36 ++++---- .../FLTThreadSafeEventChannel.m | 2 +- .../include/CameraPlugin.modulemap | 1 + .../camera_avfoundation/CameraPlugin_Test.h | 5 +- .../FLTCameraDeviceDiscovering.h | 21 +++++ .../FLTCaptureDeviceControlling.h | 2 + .../camera_avfoundation/FLTEventChannel.h | 22 ++--- 20 files changed, 252 insertions(+), 113 deletions(-) create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCameraDeviceDiscoverer.h create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCameraDeviceDiscoverer.m create mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m create mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCameraDeviceDiscovering.h diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj index 8dd444160cb..35450c16d15 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj @@ -19,6 +19,8 @@ 788A065A27B0E02900533D74 /* StreamingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 788A065927B0E02900533D74 /* StreamingTest.m */; }; 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; 7D5FCCD42AEF9D0200FB7108 /* CameraSettingsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D5FCCD32AEF9D0200FB7108 /* CameraSettingsTests.m */; }; + 7F29EB222D269ED500740257 /* MockEventChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F29EB212D269ED500740257 /* MockEventChannel.m */; }; + 7F29EB292D26A59000740257 /* MockCameraDeviceDiscoverer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F29EB282D26A59000740257 /* MockCameraDeviceDiscoverer.m */; }; 7F56D0382D1EDDCE005676A5 /* CameraPermissionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0B0D2BA27DFF2AF00E71E4B /* CameraPermissionTests.m */; }; 7F87E8022D01FD6F00A3549C /* MockCaptureDeviceController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */; }; 7F87E80C2D0325D900A3549C /* MockDeviceOrientationProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F87E80B2D0325D700A3549C /* MockDeviceOrientationProvider.m */; }; @@ -79,6 +81,10 @@ 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 7D5FCCD32AEF9D0200FB7108 /* CameraSettingsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CameraSettingsTests.m; sourceTree = ""; }; + 7F29EB202D269E4300740257 /* MockEventChannel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockEventChannel.h; sourceTree = ""; }; + 7F29EB212D269ED500740257 /* MockEventChannel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockEventChannel.m; sourceTree = ""; }; + 7F29EB272D26A55300740257 /* MockCameraDeviceDiscoverer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCameraDeviceDiscoverer.h; sourceTree = ""; }; + 7F29EB282D26A59000740257 /* MockCameraDeviceDiscoverer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCameraDeviceDiscoverer.m; sourceTree = ""; }; 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCaptureDeviceController.m; sourceTree = ""; }; 7F87E8032D02FF8C00A3549C /* MockCaptureDeviceController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCaptureDeviceController.h; sourceTree = ""; }; 7F87E80A2D0325B200A3549C /* MockDeviceOrientationProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockDeviceOrientationProvider.h; sourceTree = ""; }; @@ -138,8 +144,12 @@ children = ( 7F87E80B2D0325D700A3549C /* MockDeviceOrientationProvider.m */, 7F87E80A2D0325B200A3549C /* MockDeviceOrientationProvider.h */, + 7F29EB282D26A59000740257 /* MockCameraDeviceDiscoverer.m */, + 7F29EB272D26A55300740257 /* MockCameraDeviceDiscoverer.h */, 7F87E8032D02FF8C00A3549C /* MockCaptureDeviceController.h */, 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */, + 7F29EB202D269E4300740257 /* MockEventChannel.h */, + 7F29EB212D269ED500740257 /* MockEventChannel.m */, 7D5FCCD32AEF9D0200FB7108 /* CameraSettingsTests.m */, 03BB766A2665316900CE5A93 /* CameraFocusTests.m */, 7FA99E582D22C75300582559 /* CameraExposureTests.m */, @@ -469,12 +479,14 @@ E487C86026D686A10034AC92 /* CameraPreviewPauseTests.m in Sources */, 7F87E80C2D0325D900A3549C /* MockDeviceOrientationProvider.m in Sources */, E071CF7427B31DE4006EF3BA /* FLTCamSampleBufferTests.m in Sources */, + 7F29EB222D269ED500740257 /* MockEventChannel.m in Sources */, E04F108627A87CA600573D0C /* FLTSavePhotoDelegateTests.m in Sources */, 43ED1537282570DE00EB00DE /* AvailableCamerasTest.m in Sources */, E0CDBAC227CD9729002561D9 /* CameraTestUtils.m in Sources */, 334733EA2668111C00DCC49E /* CameraOrientationTests.m in Sources */, CEF6611A2B5E36A500D33FD4 /* CameraSessionPresetsTests.m in Sources */, E032F250279F5E94009E9028 /* CameraCaptureSessionQueueRaceConditionTests.m in Sources */, + 7F29EB292D26A59000740257 /* MockCameraDeviceDiscoverer.m in Sources */, 788A065A27B0E02900533D74 /* StreamingTest.m in Sources */, E0C6E2022770F01A00EA6AA3 /* ThreadSafeEventChannelTests.m in Sources */, E01EE4A82799F3A5008C1950 /* QueueUtilsTests.m in Sources */, diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m index f26a8dc48f1..a8628292c6d 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m @@ -8,33 +8,46 @@ #endif @import XCTest; @import AVFoundation; -#import + +#import "MockCameraDeviceDiscoverer.h" +#import "MockCaptureDeviceController.h" @interface AvailableCamerasTest : XCTestCase +@property(nonatomic, strong) MockCameraDeviceDiscoverer *mockDeviceDiscoverer; +@property(nonatomic, strong) CameraPlugin *cameraPlugin; @end @implementation AvailableCamerasTest +- (void)setUp { + [super setUp]; + + self.mockDeviceDiscoverer = [[MockCameraDeviceDiscoverer alloc] init]; + self.cameraPlugin = [[CameraPlugin alloc] initWithRegistry:nil + messenger:nil + globalAPI:nil + deviceDiscoverer:_mockDeviceDiscoverer]; +} + - (void)testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone { - CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil]; XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; // iPhone 13 Cameras: - AVCaptureDevice *wideAngleCamera = OCMClassMock([AVCaptureDevice class]); - OCMStub([wideAngleCamera uniqueID]).andReturn(@"0"); - OCMStub([wideAngleCamera position]).andReturn(AVCaptureDevicePositionBack); + MockCaptureDeviceController *wideAngleCamera = [[MockCaptureDeviceController alloc] init]; + wideAngleCamera.uniqueID = @"0"; + wideAngleCamera.position = AVCaptureDevicePositionBack; - AVCaptureDevice *frontFacingCamera = OCMClassMock([AVCaptureDevice class]); - OCMStub([frontFacingCamera uniqueID]).andReturn(@"1"); - OCMStub([frontFacingCamera position]).andReturn(AVCaptureDevicePositionFront); + MockCaptureDeviceController *frontFacingCamera = [[MockCaptureDeviceController alloc] init]; + frontFacingCamera.uniqueID = @"1"; + frontFacingCamera.position = AVCaptureDevicePositionFront; - AVCaptureDevice *ultraWideCamera = OCMClassMock([AVCaptureDevice class]); - OCMStub([ultraWideCamera uniqueID]).andReturn(@"2"); - OCMStub([ultraWideCamera position]).andReturn(AVCaptureDevicePositionBack); + MockCaptureDeviceController *ultraWideCamera = [[MockCaptureDeviceController alloc] init]; + ultraWideCamera.uniqueID = @"2"; + ultraWideCamera.position = AVCaptureDevicePositionBack; - AVCaptureDevice *telephotoCamera = OCMClassMock([AVCaptureDevice class]); - OCMStub([telephotoCamera uniqueID]).andReturn(@"3"); - OCMStub([telephotoCamera position]).andReturn(AVCaptureDevicePositionBack); + MockCaptureDeviceController *telephotoCamera = [[MockCaptureDeviceController alloc] init]; + telephotoCamera.uniqueID = @"3"; + telephotoCamera.position = AVCaptureDevicePositionBack; NSMutableArray *requiredTypes = [@[ AVCaptureDeviceTypeBuiltInWideAngleCamera, AVCaptureDeviceTypeBuiltInTelephotoCamera ] @@ -43,21 +56,23 @@ - (void)testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone { [requiredTypes addObject:AVCaptureDeviceTypeBuiltInUltraWideCamera]; } - id discoverySessionMock = OCMClassMock([AVCaptureDeviceDiscoverySession class]); - OCMStub([discoverySessionMock discoverySessionWithDeviceTypes:requiredTypes - mediaType:AVMediaTypeVideo - position:AVCaptureDevicePositionUnspecified]) - .andReturn(discoverySessionMock); - NSMutableArray *cameras = [NSMutableArray array]; [cameras addObjectsFromArray:@[ wideAngleCamera, frontFacingCamera, telephotoCamera ]]; if (@available(iOS 13.0, *)) { [cameras addObject:ultraWideCamera]; } - OCMStub([discoverySessionMock devices]).andReturn([NSArray arrayWithArray:cameras]); + + _mockDeviceDiscoverer.discoverySessionStub = ^NSArray> *_Nullable( + NSArray *_Nonnull deviceTypes, AVMediaType _Nonnull mediaType, + AVCaptureDevicePosition position) { + XCTAssertEqualObjects(deviceTypes, requiredTypes); + XCTAssertEqual(mediaType, AVMediaTypeVideo); + XCTAssertEqual(position, AVCaptureDevicePositionUnspecified); + return cameras; + }; __block NSArray *resultValue; - [camera + [_cameraPlugin availableCamerasWithCompletion:^(NSArray *_Nullable result, FlutterError *_Nullable error) { XCTAssertNil(error); @@ -74,17 +89,16 @@ - (void)testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone { } } - (void)testAvailableCamerasShouldReturnOneCameraOnSingleCameraIPhone { - CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil]; XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; // iPhone 8 Cameras: - AVCaptureDevice *wideAngleCamera = OCMClassMock([AVCaptureDevice class]); - OCMStub([wideAngleCamera uniqueID]).andReturn(@"0"); - OCMStub([wideAngleCamera position]).andReturn(AVCaptureDevicePositionBack); + MockCaptureDeviceController *wideAngleCamera = [[MockCaptureDeviceController alloc] init]; + wideAngleCamera.uniqueID = @"0"; + wideAngleCamera.position = AVCaptureDevicePositionBack; - AVCaptureDevice *frontFacingCamera = OCMClassMock([AVCaptureDevice class]); - OCMStub([frontFacingCamera uniqueID]).andReturn(@"1"); - OCMStub([frontFacingCamera position]).andReturn(AVCaptureDevicePositionFront); + MockCaptureDeviceController *frontFacingCamera = [[MockCaptureDeviceController alloc] init]; + frontFacingCamera.uniqueID = @"1"; + frontFacingCamera.position = AVCaptureDevicePositionFront; NSMutableArray *requiredTypes = [@[ AVCaptureDeviceTypeBuiltInWideAngleCamera, AVCaptureDeviceTypeBuiltInTelephotoCamera ] @@ -93,18 +107,20 @@ - (void)testAvailableCamerasShouldReturnOneCameraOnSingleCameraIPhone { [requiredTypes addObject:AVCaptureDeviceTypeBuiltInUltraWideCamera]; } - id discoverySessionMock = OCMClassMock([AVCaptureDeviceDiscoverySession class]); - OCMStub([discoverySessionMock discoverySessionWithDeviceTypes:requiredTypes - mediaType:AVMediaTypeVideo - position:AVCaptureDevicePositionUnspecified]) - .andReturn(discoverySessionMock); - NSMutableArray *cameras = [NSMutableArray array]; [cameras addObjectsFromArray:@[ wideAngleCamera, frontFacingCamera ]]; - OCMStub([discoverySessionMock devices]).andReturn([NSArray arrayWithArray:cameras]); + + _mockDeviceDiscoverer.discoverySessionStub = ^NSArray> *_Nullable( + NSArray *_Nonnull deviceTypes, AVMediaType _Nonnull mediaType, + AVCaptureDevicePosition position) { + XCTAssertEqualObjects(deviceTypes, requiredTypes); + XCTAssertEqual(mediaType, AVMediaTypeVideo); + XCTAssertEqual(position, AVCaptureDevicePositionUnspecified); + return cameras; + }; __block NSArray *resultValue; - [camera + [_cameraPlugin availableCamerasWithCompletion:^(NSArray *_Nullable result, FlutterError *_Nullable error) { XCTAssertNil(error); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m index 4badf8e85b0..2f2cb56820d 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m @@ -9,6 +9,7 @@ @import XCTest; @import Flutter; +#import "MockCameraDeviceDiscoverer.h" #import "MockCaptureDeviceController.h" #import "MockDeviceOrientationProvider.h" @@ -51,7 +52,7 @@ - (void)setCaptureDevice:(id)device { @end @interface MockUIDevice : UIDevice -@property (nonatomic, assign) UIDeviceOrientation mockOrientation; +@property(nonatomic, assign) UIDeviceOrientation mockOrientation; @end @implementation MockUIDevice @@ -68,6 +69,7 @@ @interface CameraOrientationTests : XCTestCase @property(readonly, nonatomic) MockCaptureDeviceController *mockDevice; @property(readonly, nonatomic) StubGlobalEventApi *eventAPI; @property(readonly, nonatomic) CameraPlugin *cameraPlugin; +@property(readonly, nonatomic) MockCameraDeviceDiscoverer *deviceDiscoverer; @end @implementation CameraOrientationTests @@ -78,10 +80,12 @@ - (void)setUp { _camera = [[MockCamera alloc] init]; _eventAPI = [[StubGlobalEventApi alloc] init]; _mockDevice = mockDevice; - + _deviceDiscoverer = [[MockCameraDeviceDiscoverer alloc] init]; + _cameraPlugin = [[CameraPlugin alloc] initWithRegistry:nil - messenger:nil - globalAPI:_eventAPI]; + messenger:nil + globalAPI:_eventAPI + deviceDiscoverer:_deviceDiscoverer]; _cameraPlugin.camera = _camera; } @@ -123,7 +127,8 @@ - (void)testOrientationNotificationsNotCalledForFaceDown { StubGlobalEventApi *eventAPI = [[StubGlobalEventApi alloc] init]; CameraPlugin *cameraPlugin = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil - globalAPI:eventAPI]; + globalAPI:eventAPI + deviceDiscoverer:_deviceDiscoverer]; [self sendOrientation:UIDeviceOrientationFaceDown toCamera:cameraPlugin]; @@ -139,8 +144,8 @@ - (void)testOrientationUpdateMustBeOnCaptureSessionQueue { dispatch_queue_set_specific(plugin.captureSessionQueue, captureSessionQueueSpecific, (void *)captureSessionQueueSpecific, NULL); plugin.camera = _camera; - - _camera.setDeviceOrientationStub = ^(UIDeviceOrientation orientation) { + + _camera.setDeviceOrientationStub = ^(UIDeviceOrientation orientation) { if (dispatch_get_specific(captureSessionQueueSpecific)) { [queueExpectation fulfill]; } @@ -159,7 +164,8 @@ - (void)testOrientationChanged_noRetainCycle { @autoreleasepool { CameraPlugin *plugin = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil - globalAPI:_eventAPI]; + globalAPI:_eventAPI + deviceDiscoverer:_deviceDiscoverer]; weakPlugin = plugin; plugin.captureSessionQueue = captureSessionQueue; plugin.camera = _camera; @@ -170,14 +176,14 @@ - (void)testOrientationChanged_noRetainCycle { // Sanity check XCTAssertNil(weakPlugin, @"Camera must have been deallocated."); - + __block BOOL setDeviceOrientationCalled = NO; _camera.setDeviceOrientationStub = ^(UIDeviceOrientation orientation) { if (orientation == UIDeviceOrientationLandscapeLeft) { setDeviceOrientationCalled = YES; } }; - + __weak StubGlobalEventApi *weakEventAPI = _eventAPI; // Must check in captureSessionQueue since orientationChanged dispatches to this queue. diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCameraDeviceDiscoverer.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCameraDeviceDiscoverer.h new file mode 100644 index 00000000000..87feaf3314d --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCameraDeviceDiscoverer.h @@ -0,0 +1,17 @@ +// 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. + +@import camera_avfoundation; +@import AVFoundation; + +NS_ASSUME_NONNULL_BEGIN + +@interface MockCameraDeviceDiscoverer : NSObject +@property(nonatomic, copy) + NSArray> *_Nullable (^discoverySessionStub) + (NSArray *deviceTypes, AVMediaType mediaType, + AVCaptureDevicePosition position); +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCameraDeviceDiscoverer.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCameraDeviceDiscoverer.m new file mode 100644 index 00000000000..bbc31702e59 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCameraDeviceDiscoverer.m @@ -0,0 +1,19 @@ +// 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. + +#import "MockCameraDeviceDiscoverer.h" + +@implementation MockCameraDeviceDiscoverer + +- (NSArray> *) + discoverySessionWithDeviceTypes:(NSArray *)deviceTypes + mediaType:(AVMediaType)mediaType + position:(AVCaptureDevicePosition)position { + if (self.discoverySessionStub) { + return self.discoverySessionStub(deviceTypes, mediaType, position); + } + return @[]; +} + +@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h index af28d652734..571bf811144 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h @@ -11,6 +11,9 @@ NS_ASSUME_NONNULL_BEGIN @interface MockCaptureDeviceController : NSObject + +@property(nonatomic, assign) NSString *uniqueID; + // Position/Orientation @property(nonatomic, assign) AVCaptureDevicePosition position; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.h index d67c0782703..baa69f8503c 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.h @@ -1,6 +1,6 @@ // 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. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. @import camera_avfoundation; #if __has_include() diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.m index a128c2dcb3f..7190cfb1771 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.m @@ -7,9 +7,9 @@ @implementation MockEventChannel - (void)setStreamHandler:(NSObject *)handler { - if (self.setStreamHandlerStub) { - self.setStreamHandlerStub(handler); - } + if (self.setStreamHandlerStub) { + self.setStreamHandlerStub(handler); + } } @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m index 1f6562e2303..dfd539ecfd3 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m @@ -21,7 +21,7 @@ - (void)setUp { [super setUp]; _mockEventChannel = [[MockEventChannel alloc] init]; _threadSafeEventChannel = - [[FLTThreadSafeEventChannel alloc] initWithEventChannel:_mockEventChannel]; + [[FLTThreadSafeEventChannel alloc] initWithEventChannel:_mockEventChannel]; } - (void)testSetStreamHandler_shouldStayOnMainThreadIfCalledFromMainThread { @@ -30,19 +30,19 @@ - (void)testSetStreamHandler_shouldStayOnMainThreadIfCalledFromMainThread { XCTestExpectation *mainThreadCompletionExpectation = [self expectationWithDescription: @"setStreamHandler's completion block must be called on the main thread"]; - + [_mockEventChannel setSetStreamHandlerStub:^(NSObject *handler) { if (NSThread.isMainThread) { [mainThreadExpectation fulfill]; } }]; - + [_threadSafeEventChannel setStreamHandler:nil - completion:^{ - if (NSThread.isMainThread) { - [mainThreadCompletionExpectation fulfill]; - } - }]; + completion:^{ + if (NSThread.isMainThread) { + [mainThreadCompletionExpectation fulfill]; + } + }]; [self waitForExpectationsWithTimeout:1 handler:nil]; } @@ -52,8 +52,7 @@ - (void)testSetStreamHandler_shouldDispatchToMainThreadIfCalledFromBackgroundThr XCTestExpectation *mainThreadCompletionExpectation = [self expectationWithDescription: @"setStreamHandler's completion block must be called on the main thread"]; - - + [_mockEventChannel setSetStreamHandlerStub:^(NSObject *handler) { if (NSThread.isMainThread) { [mainThreadExpectation fulfill]; @@ -63,11 +62,11 @@ - (void)testSetStreamHandler_shouldDispatchToMainThreadIfCalledFromBackgroundThr __weak typeof(self) weakSelf = self; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [weakSelf.threadSafeEventChannel setStreamHandler:nil - completion:^{ - if (NSThread.isMainThread) { - [mainThreadCompletionExpectation fulfill]; - } - }]; + completion:^{ + if (NSThread.isMainThread) { + [mainThreadCompletionExpectation fulfill]; + } + }]; }); [self waitForExpectationsWithTimeout:1 handler:nil]; } @@ -75,11 +74,11 @@ - (void)testSetStreamHandler_shouldDispatchToMainThreadIfCalledFromBackgroundThr - (void)testEventChannel_shouldBeKeptAliveWhenDispatchingBackToMainThread { XCTestExpectation *expectation = [self expectationWithDescription:@"Completion should be called."]; - + __weak typeof(self) weakSelf = self; dispatch_async(dispatch_queue_create("test", NULL), ^{ - FLTThreadSafeEventChannel *channel = [[FLTThreadSafeEventChannel alloc] - initWithEventChannel:weakSelf.mockEventChannel]; + FLTThreadSafeEventChannel *channel = + [[FLTThreadSafeEventChannel alloc] initWithEventChannel:weakSelf.mockEventChannel]; [channel setStreamHandler:nil completion:^{ diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m index 63a49025231..57b53b997b4 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m @@ -10,6 +10,7 @@ #import "./include/camera_avfoundation/CameraProperties.h" #import "./include/camera_avfoundation/FLTCam.h" +#import "./include/camera_avfoundation/FLTCameraDeviceDiscovering.h" #import "./include/camera_avfoundation/FLTCameraPermissionManager.h" #import "./include/camera_avfoundation/FLTThreadSafeEventChannel.h" #import "./include/camera_avfoundation/QueueUtils.h" @@ -26,6 +27,7 @@ @interface CameraPlugin () @property(readonly, nonatomic) NSObject *messenger; @property(nonatomic) FCPCameraGlobalEventApi *globalEventAPI; @property(readonly, nonatomic) FLTCameraPermissionManager *permissionManager; +@property(readonly, nonatomic) id deviceDiscoverer; @end @implementation CameraPlugin @@ -38,21 +40,23 @@ + (void)registerWithRegistrar:(NSObject *)registrar { - (instancetype)initWithRegistry:(NSObject *)registry messenger:(NSObject *)messenger { - return - [self initWithRegistry:registry - messenger:messenger - globalAPI:[[FCPCameraGlobalEventApi alloc] initWithBinaryMessenger:messenger]]; + return [self initWithRegistry:registry + messenger:messenger + globalAPI:[[FCPCameraGlobalEventApi alloc] initWithBinaryMessenger:messenger] + deviceDiscoverer:[[FLTDefaultCameraDeviceDiscoverer alloc] init]]; } - (instancetype)initWithRegistry:(NSObject *)registry messenger:(NSObject *)messenger - globalAPI:(FCPCameraGlobalEventApi *)globalAPI { + globalAPI:(FCPCameraGlobalEventApi *)globalAPI + deviceDiscoverer:(id)deviceDiscoverer { self = [super init]; NSAssert(self, @"super init cannot be nil"); _registry = registry; _messenger = messenger; _globalEventAPI = globalAPI; _captureSessionQueue = dispatch_queue_create("io.flutter.camera.captureSessionQueue", NULL); + _deviceDiscoverer = deviceDiscoverer; id permissionService = [[FLTDefaultPermissionService alloc] init]; _permissionManager = @@ -117,14 +121,13 @@ - (void)availableCamerasWithCompletion: if (@available(iOS 13.0, *)) { [discoveryDevices addObject:AVCaptureDeviceTypeBuiltInUltraWideCamera]; } - AVCaptureDeviceDiscoverySession *discoverySession = [AVCaptureDeviceDiscoverySession - discoverySessionWithDeviceTypes:discoveryDevices - mediaType:AVMediaTypeVideo - position:AVCaptureDevicePositionUnspecified]; - NSArray *devices = discoverySession.devices; + NSArray> *devices = + [self.deviceDiscoverer discoverySessionWithDeviceTypes:discoveryDevices + mediaType:AVMediaTypeVideo + position:AVCaptureDevicePositionUnspecified]; NSMutableArray *reply = [[NSMutableArray alloc] initWithCapacity:devices.count]; - for (AVCaptureDevice *device in devices) { + for (id device in devices) { FCPPlatformCameraLensDirection lensFacing; switch (device.position) { case AVCaptureDevicePositionBack: diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 9ca0884dacc..4f0729ae5d2 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -1215,7 +1215,8 @@ - (void)startImageStreamWithMessenger:(NSObject *)messen FlutterEventChannel *eventChannel = [FlutterEventChannel eventChannelWithName:@"plugins.flutter.io/camera_avfoundation/imageStream" binaryMessenger:messenger]; - id eventChannelProtocol = [[FLTDefaultEventChannel alloc] initWithEventChannel:eventChannel]; + id eventChannelProtocol = + [[FLTDefaultEventChannel alloc] initWithEventChannel:eventChannel]; FLTThreadSafeEventChannel *threadSafeEventChannel = [[FLTThreadSafeEventChannel alloc] initWithEventChannel:eventChannelProtocol]; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m new file mode 100644 index 00000000000..d257a4606a6 --- /dev/null +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m @@ -0,0 +1,32 @@ +// 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. + +@import Flutter; + +#import "FLTCameraDeviceDiscovering.h" + +@implementation FLTDefaultCameraDeviceDiscoverer + +- (NSArray> *) + discoverySessionWithDeviceTypes:(NSArray *)deviceTypes + mediaType:(AVMediaType)mediaType + position:(AVCaptureDevicePosition)position { + AVCaptureDeviceDiscoverySession *discoverySession = + [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:deviceTypes + mediaType:mediaType + position:position]; + + NSArray *devices = discoverySession.devices; + NSMutableArray> *deviceControllers = [NSMutableArray array]; + + for (AVCaptureDevice *device in devices) { + FLTDefaultCaptureDeviceController *controller = + [[FLTDefaultCaptureDeviceController alloc] initWithDevice:device]; + [deviceControllers addObject:controller]; + } + + return deviceControllers; +} + +@end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m index 658e0a0fedb..0b3e2e985ec 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m @@ -18,6 +18,10 @@ - (instancetype)initWithDevice:(AVCaptureDevice *)device { return self; } +- (nonnull NSString *)uniqueID { + return self.device.uniqueID; +} + // Position/Orientation - (AVCaptureDevicePosition)position { return self.device.position; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTEventChannel.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTEventChannel.m index cc9f86d2d21..ec9e21e3cc7 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTEventChannel.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTEventChannel.m @@ -1,27 +1,27 @@ // 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. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. - @import Flutter; +@import Flutter; #import "./include/camera_avfoundation/FLTEventChannel.h" - @interface FLTDefaultEventChannel () - @property(nonatomic, strong) FlutterEventChannel *channel; - @end +@interface FLTDefaultEventChannel () +@property(nonatomic, strong) FlutterEventChannel *channel; +@end - @implementation FLTDefaultEventChannel +@implementation FLTDefaultEventChannel - - (instancetype)initWithEventChannel:(FlutterEventChannel *)channel { - self = [super init]; - if (self) { - _channel = channel; - } - return self; - } +- (instancetype)initWithEventChannel:(FlutterEventChannel *)channel { + self = [super init]; + if (self) { + _channel = channel; + } + return self; +} - - (void)setStreamHandler:(NSObject *)handler { - [self.channel setStreamHandler:handler]; - } +- (void)setStreamHandler:(NSObject *)handler { + [self.channel setStreamHandler:handler]; +} - @end +@end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTThreadSafeEventChannel.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTThreadSafeEventChannel.m index 58f29038d0a..ceae1600e85 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTThreadSafeEventChannel.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTThreadSafeEventChannel.m @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "./include/camera_avfoundation/FLTEventChannel.h" #import "./include/camera_avfoundation/FLTThreadSafeEventChannel.h" +#import "./include/camera_avfoundation/FLTEventChannel.h" #import "./include/camera_avfoundation/QueueUtils.h" @interface FLTThreadSafeEventChannel () diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap index c4384df1a20..317d7497e04 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap @@ -5,6 +5,7 @@ framework module camera_avfoundation { module * { export * } explicit module Test { + header "FLTCameraDeviceDiscovering.h" header "FLTCaptureDeviceControlling.h" header "FLTDeviceOrientationProviding.h" header "FLTEventChannel.h" diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h index c29c2f306db..6439e737dbf 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h @@ -6,6 +6,7 @@ #import "CameraPlugin.h" #import "FLTCam.h" +#import "FLTCameraDeviceDiscovering.h" #import "messages.g.h" /// APIs exposed for unit testing. @@ -25,7 +26,9 @@ /// unit testing. - (instancetype)initWithRegistry:(NSObject *)registry messenger:(NSObject *)messenger - globalAPI:(FCPCameraGlobalEventApi *)globalAPI NS_DESIGNATED_INITIALIZER; + globalAPI:(FCPCameraGlobalEventApi *)globalAPI + deviceDiscoverer:(id)deviceDiscoverer + NS_DESIGNATED_INITIALIZER; /// Hide the default public constructor. - (instancetype)init NS_UNAVAILABLE; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCameraDeviceDiscovering.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCameraDeviceDiscovering.h new file mode 100644 index 00000000000..101ffc9aa54 --- /dev/null +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCameraDeviceDiscovering.h @@ -0,0 +1,21 @@ +// 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. + +@import AVFoundation; + +#import "FLTCaptureDeviceControlling.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol FLTCameraDeviceDiscovering +- (NSArray> *) + discoverySessionWithDeviceTypes:(NSArray *)deviceTypes + mediaType:(AVMediaType)mediaType + position:(AVCaptureDevicePosition)position; +@end + +@interface FLTDefaultCameraDeviceDiscoverer : NSObject +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h index 370f0e5df10..e9374e24db8 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h @@ -9,6 +9,8 @@ NS_ASSUME_NONNULL_BEGIN @protocol FLTCaptureDeviceControlling +- (NSString *)uniqueID; + // Position/Orientation - (AVCaptureDevicePosition)position; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h index a75e4265a6f..fa509c04dea 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h @@ -1,18 +1,18 @@ // 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. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. - @import Flutter; +@import Flutter; - NS_ASSUME_NONNULL_BEGIN +NS_ASSUME_NONNULL_BEGIN - @protocol FLTEventChannel - - (void)setStreamHandler:(nullable NSObject *)handler; - @end +@protocol FLTEventChannel +- (void)setStreamHandler:(nullable NSObject *)handler; +@end - /// The default method channel that wraps FlutterMethodChannel +/// The default method channel that wraps FlutterMethodChannel @interface FLTDefaultEventChannel : NSObject - - (instancetype)initWithEventChannel:(FlutterEventChannel *)channel; - @end +- (instancetype)initWithEventChannel:(FlutterEventChannel *)channel; +@end - NS_ASSUME_NONNULL_END +NS_ASSUME_NONNULL_END From abb1fdb3cb7f66f07532cf659b00d2659c44742c Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Thu, 2 Jan 2025 11:59:39 +0100 Subject: [PATCH 19/31] Update changelog --- packages/camera/camera_avfoundation/CHANGELOG.md | 4 ++++ packages/camera/camera_avfoundation/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index 4ed3637776f..8248ca70cbf 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.17+8 + +* Introduces new protocols `FLTEventChannel` and `FLTCameraDeviceDiscovering` + ## 0.9.17+7 * Introduces new protocols `FLTCaptureDeviceControlling` and `FLTDeviceOrientationProviding` diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index 5b335cac022..61b07b51d43 100644 --- a/packages/camera/camera_avfoundation/pubspec.yaml +++ b/packages/camera/camera_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_avfoundation description: iOS implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.17+7 +version: 0.9.17+8 environment: sdk: ^3.4.0 From 96e300a0c130e30ad411f9fa5e2f035b083adeb7 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Fri, 3 Jan 2025 15:53:48 +0100 Subject: [PATCH 20/31] Make default implementations for protocols and clean up the DI to make tests pass again --- .../ios/Runner.xcodeproj/project.pbxproj | 30 ++- .../ios/RunnerTests/AvailableCamerasTest.m | 9 +- ...eraCaptureSessionQueueRaceConditionTests.m | 19 +- .../ios/RunnerTests/CameraOrientationTests.m | 30 ++- .../RunnerTests/CameraSessionPresetsTests.m | 8 +- .../example/ios/RunnerTests/CameraTestUtils.m | 107 ++++++----- .../ios/RunnerTests/FLTCamPhotoCaptureTests.m | 4 +- .../{ => Mocks}/MockCameraDeviceDiscoverer.h | 0 .../{ => Mocks}/MockCameraDeviceDiscoverer.m | 0 .../{ => Mocks}/MockCaptureDeviceController.h | 6 +- .../{ => Mocks}/MockCaptureDeviceController.m | 4 + .../RunnerTests/Mocks/MockCaptureSession.h | 27 +++ .../RunnerTests/Mocks/MockCaptureSession.m | 85 +++++++++ .../MockDeviceOrientationProvider.h | 0 .../MockDeviceOrientationProvider.m | 0 .../{ => Mocks}/MockEventChannel.h | 0 .../{ => Mocks}/MockEventChannel.m | 0 .../camera_avfoundation/CameraPlugin.m | 33 +++- .../Sources/camera_avfoundation/FLTCam.m | 90 ++------- .../camera_avfoundation/FLTCamConfiguration.m | 32 ++++ .../FLTCameraDeviceDiscovering.m | 4 +- .../FLTCaptureDeviceControlling.m | 176 ------------------ .../camera_avfoundation/FLTEventChannel.m | 27 --- .../include/CameraPlugin.modulemap | 2 + .../camera_avfoundation/CameraPlugin_Test.h | 29 ++- .../include/camera_avfoundation/FLTCam.h | 18 +- .../camera_avfoundation/FLTCamConfiguration.h | 48 +++++ .../include/camera_avfoundation/FLTCam_Test.h | 33 ---- .../FLTCaptureDeviceControlling.h | 10 +- .../camera_avfoundation/FLTCaptureSession.h | 38 ++++ .../camera_avfoundation/FLTEventChannel.h | 4 +- 31 files changed, 456 insertions(+), 417 deletions(-) rename packages/camera/camera_avfoundation/example/ios/RunnerTests/{ => Mocks}/MockCameraDeviceDiscoverer.h (100%) rename packages/camera/camera_avfoundation/example/ios/RunnerTests/{ => Mocks}/MockCameraDeviceDiscoverer.m (100%) rename packages/camera/camera_avfoundation/example/ios/RunnerTests/{ => Mocks}/MockCaptureDeviceController.h (94%) rename packages/camera/camera_avfoundation/example/ios/RunnerTests/{ => Mocks}/MockCaptureDeviceController.m (98%) create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.m rename packages/camera/camera_avfoundation/example/ios/RunnerTests/{ => Mocks}/MockDeviceOrientationProvider.h (100%) rename packages/camera/camera_avfoundation/example/ios/RunnerTests/{ => Mocks}/MockDeviceOrientationProvider.m (100%) rename packages/camera/camera_avfoundation/example/ios/RunnerTests/{ => Mocks}/MockEventChannel.h (100%) rename packages/camera/camera_avfoundation/example/ios/RunnerTests/{ => Mocks}/MockEventChannel.m (100%) create mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m delete mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m delete mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTEventChannel.m create mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h create mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj index 35450c16d15..75ab129b619 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ 7D5FCCD42AEF9D0200FB7108 /* CameraSettingsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D5FCCD32AEF9D0200FB7108 /* CameraSettingsTests.m */; }; 7F29EB222D269ED500740257 /* MockEventChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F29EB212D269ED500740257 /* MockEventChannel.m */; }; 7F29EB292D26A59000740257 /* MockCameraDeviceDiscoverer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F29EB282D26A59000740257 /* MockCameraDeviceDiscoverer.m */; }; + 7F29EB412D281C7E00740257 /* MockCaptureSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F29EB402D281C7E00740257 /* MockCaptureSession.m */; }; 7F56D0382D1EDDCE005676A5 /* CameraPermissionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0B0D2BA27DFF2AF00E71E4B /* CameraPermissionTests.m */; }; 7F87E8022D01FD6F00A3549C /* MockCaptureDeviceController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */; }; 7F87E80C2D0325D900A3549C /* MockDeviceOrientationProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F87E80B2D0325D700A3549C /* MockDeviceOrientationProvider.m */; }; @@ -85,6 +86,8 @@ 7F29EB212D269ED500740257 /* MockEventChannel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockEventChannel.m; sourceTree = ""; }; 7F29EB272D26A55300740257 /* MockCameraDeviceDiscoverer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCameraDeviceDiscoverer.h; sourceTree = ""; }; 7F29EB282D26A59000740257 /* MockCameraDeviceDiscoverer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCameraDeviceDiscoverer.m; sourceTree = ""; }; + 7F29EB3E2D281C5800740257 /* MockCaptureSession.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCaptureSession.h; sourceTree = ""; }; + 7F29EB402D281C7E00740257 /* MockCaptureSession.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCaptureSession.m; sourceTree = ""; }; 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCaptureDeviceController.m; sourceTree = ""; }; 7F87E8032D02FF8C00A3549C /* MockCaptureDeviceController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCaptureDeviceController.h; sourceTree = ""; }; 7F87E80A2D0325B200A3549C /* MockDeviceOrientationProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockDeviceOrientationProvider.h; sourceTree = ""; }; @@ -142,14 +145,7 @@ 03BB76692665316900CE5A93 /* RunnerTests */ = { isa = PBXGroup; children = ( - 7F87E80B2D0325D700A3549C /* MockDeviceOrientationProvider.m */, - 7F87E80A2D0325B200A3549C /* MockDeviceOrientationProvider.h */, - 7F29EB282D26A59000740257 /* MockCameraDeviceDiscoverer.m */, - 7F29EB272D26A55300740257 /* MockCameraDeviceDiscoverer.h */, - 7F87E8032D02FF8C00A3549C /* MockCaptureDeviceController.h */, - 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */, - 7F29EB202D269E4300740257 /* MockEventChannel.h */, - 7F29EB212D269ED500740257 /* MockEventChannel.m */, + 7F29EB3F2D281C6D00740257 /* Mocks */, 7D5FCCD32AEF9D0200FB7108 /* CameraSettingsTests.m */, 03BB766A2665316900CE5A93 /* CameraFocusTests.m */, 7FA99E582D22C75300582559 /* CameraExposureTests.m */, @@ -183,6 +179,23 @@ name = Frameworks; sourceTree = ""; }; + 7F29EB3F2D281C6D00740257 /* Mocks */ = { + isa = PBXGroup; + children = ( + 7F87E80B2D0325D700A3549C /* MockDeviceOrientationProvider.m */, + 7F87E80A2D0325B200A3549C /* MockDeviceOrientationProvider.h */, + 7F29EB282D26A59000740257 /* MockCameraDeviceDiscoverer.m */, + 7F29EB272D26A55300740257 /* MockCameraDeviceDiscoverer.h */, + 7F87E8032D02FF8C00A3549C /* MockCaptureDeviceController.h */, + 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */, + 7F29EB202D269E4300740257 /* MockEventChannel.h */, + 7F29EB212D269ED500740257 /* MockEventChannel.m */, + 7F29EB3E2D281C5800740257 /* MockCaptureSession.h */, + 7F29EB402D281C7E00740257 /* MockCaptureSession.m */, + ); + path = Mocks; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -489,6 +502,7 @@ 7F29EB292D26A59000740257 /* MockCameraDeviceDiscoverer.m in Sources */, 788A065A27B0E02900533D74 /* StreamingTest.m in Sources */, E0C6E2022770F01A00EA6AA3 /* ThreadSafeEventChannelTests.m in Sources */, + 7F29EB412D281C7E00740257 /* MockCaptureSession.m in Sources */, E01EE4A82799F3A5008C1950 /* QueueUtilsTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m index a8628292c6d..be161cfd5ea 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m @@ -11,6 +11,7 @@ #import "MockCameraDeviceDiscoverer.h" #import "MockCaptureDeviceController.h" +#import "MockCaptureSession.h" @interface AvailableCamerasTest : XCTestCase @property(nonatomic, strong) MockCameraDeviceDiscoverer *mockDeviceDiscoverer; @@ -26,7 +27,13 @@ - (void)setUp { self.cameraPlugin = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil globalAPI:nil - deviceDiscoverer:_mockDeviceDiscoverer]; + deviceDiscoverer:_mockDeviceDiscoverer + deviceFactory:^id(NSString *name) { + return [[MockCaptureDeviceController alloc] init]; + } + captureSessionFactory:^id { + return [[MockCaptureSession alloc] init]; + }]; } - (void)testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m index 5892e1d4b79..7552d50fd36 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m @@ -8,13 +8,30 @@ #endif @import XCTest; +#import "MockCameraDeviceDiscoverer.h" +#import "MockCaptureDeviceController.h" +#import "MockCaptureSession.h" + @interface CameraCaptureSessionQueueRaceConditionTests : XCTestCase @end @implementation CameraCaptureSessionQueueRaceConditionTests - (void)testFixForCaptureSessionQueueNullPointerCrashDueToRaceCondition { - CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil]; + MockCaptureDeviceController *captureDevice = [[MockCaptureDeviceController alloc] init]; + captureDevice.inputToReturn = [[MockCaptureInput alloc] init]; + + CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil + messenger:nil + globalAPI:nil + deviceDiscoverer:[[MockCameraDeviceDiscoverer alloc] init] + deviceFactory:^id(NSString *name) { + return captureDevice; + } + captureSessionFactory:^id { + return [[MockCaptureSession alloc] init]; + } + ]; XCTestExpectation *disposeExpectation = [self expectationWithDescription:@"dispose's result block must be called"]; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m index 2f2cb56820d..cda38c1077a 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m @@ -11,6 +11,7 @@ #import "MockCameraDeviceDiscoverer.h" #import "MockCaptureDeviceController.h" +#import "MockCaptureSession.h" #import "MockDeviceOrientationProvider.h" @interface StubGlobalEventApi : FCPCameraGlobalEventApi @@ -85,7 +86,14 @@ - (void)setUp { _cameraPlugin = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil globalAPI:_eventAPI - deviceDiscoverer:_deviceDiscoverer]; + deviceDiscoverer:_deviceDiscoverer + deviceFactory:^id(NSString *name) { + return mockDevice; + } + captureSessionFactory:^id _Nonnull{ + return [[MockCaptureSession alloc] init]; + } + ]; _cameraPlugin.camera = _camera; } @@ -124,15 +132,9 @@ - (void)testOrientationNotificationsNotCalledForFaceUp { } - (void)testOrientationNotificationsNotCalledForFaceDown { - StubGlobalEventApi *eventAPI = [[StubGlobalEventApi alloc] init]; - CameraPlugin *cameraPlugin = [[CameraPlugin alloc] initWithRegistry:nil - messenger:nil - globalAPI:eventAPI - deviceDiscoverer:_deviceDiscoverer]; - - [self sendOrientation:UIDeviceOrientationFaceDown toCamera:cameraPlugin]; + [self sendOrientation:UIDeviceOrientationFaceDown toCamera:_cameraPlugin]; - XCTAssertFalse(eventAPI.called); + XCTAssertFalse(_eventAPI.called); } - (void)testOrientationUpdateMustBeOnCaptureSessionQueue { @@ -160,12 +162,20 @@ - (void)testOrientationChanged_noRetainCycle { dispatch_queue_t captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); __weak CameraPlugin *weakPlugin; + __weak MockCaptureDeviceController *weakDevice = _mockDevice; @autoreleasepool { CameraPlugin *plugin = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil globalAPI:_eventAPI - deviceDiscoverer:_deviceDiscoverer]; + deviceDiscoverer:_deviceDiscoverer + deviceFactory:^id(NSString *name) { + return weakDevice; + } + captureSessionFactory:^id _Nonnull{ + return [[MockCaptureSession alloc] init]; + } + ]; weakPlugin = plugin; plugin.captureSessionQueue = captureSessionQueue; plugin.camera = _camera; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m index 08cba70bf3a..5a5c9135d87 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m @@ -21,11 +21,11 @@ @implementation FLTCamSessionPresetsTest - (void)testResolutionPresetWithBestFormat_mustUpdateCaptureSessionPreset { NSString *expectedPreset = AVCaptureSessionPresetInputPriority; - id videoSessionMock = OCMClassMock([AVCaptureSession class]); + id videoSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]); id captureFormatMock = OCMClassMock([AVCaptureDeviceFormat class]); - id captureDeviceMock = OCMClassMock([AVCaptureDevice class]); + id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDeviceControlling)); OCMStub([captureDeviceMock formats]).andReturn(@[ captureFormatMock ]); OCMExpect([captureDeviceMock activeFormat]).andReturn(captureFormatMock); @@ -48,7 +48,7 @@ - (void)testResolutionPresetWithBestFormat_mustUpdateCaptureSessionPreset { - (void)testResolutionPresetWithCanSetSessionPresetMax_mustUpdateCaptureSessionPreset { NSString *expectedPreset = AVCaptureSessionPreset3840x2160; - id videoSessionMock = OCMClassMock([AVCaptureSession class]); + id videoSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]); // Make sure that setting resolution preset for session always succeeds. @@ -64,7 +64,7 @@ - (void)testResolutionPresetWithCanSetSessionPresetMax_mustUpdateCaptureSessionP - (void)testResolutionPresetWithCanSetSessionPresetUltraHigh_mustUpdateCaptureSessionPreset { NSString *expectedPreset = AVCaptureSessionPreset3840x2160; - id videoSessionMock = OCMClassMock([AVCaptureSession class]); + id videoSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]); // Make sure that setting resolution preset for session always succeeds. diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m index f10a3b122d7..796603d4787 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m @@ -8,6 +8,7 @@ @import AVFoundation; @import camera_avfoundation; +#import "MockCaptureSession.h" #import "MockDeviceOrientationProvider.h" static FCPPlatformMediaSettings *FCPGetDefaultMediaSettings( @@ -44,7 +45,7 @@ OCMStub([inputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg setTo:nil]]) .andReturn(inputMock); - id videoSessionMock = OCMClassMock([AVCaptureSession class]); + id videoSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); OCMStub([videoSessionMock beginConfiguration]) .andDo(^(NSInvocation *invocation){ }); @@ -55,7 +56,7 @@ OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]); OCMStub([videoSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - id audioSessionMock = OCMClassMock([AVCaptureSession class]); + id audioSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]); OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); @@ -75,7 +76,7 @@ frameRateRangeMock2 ]); - id captureDeviceMock = OCMClassMock([AVCaptureDevice class]); + id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDeviceControlling)); OCMStub([captureDeviceMock lockForConfiguration:[OCMArg setTo:nil]]).andReturn(YES); OCMStub([captureDeviceMock formats]).andReturn((@[ captureDeviceFormatMock1, captureDeviceFormatMock2 @@ -88,21 +89,27 @@ OCMStub([captureDeviceMock activeFormat]).andDo(^(NSInvocation *invocation) { [invocation setReturnValue:&format]; }); - - id fltCam = [[FLTCam alloc] initWithMediaSettings:mediaSettings - mediaSettingsAVWrapper:mediaSettingsAVWrapper - orientation:UIDeviceOrientationPortrait - videoCaptureSession:videoSessionMock - audioCaptureSession:audioSessionMock - captureSessionQueue:captureSessionQueue - captureDeviceFactory:captureDeviceFactory ?: ^id(void) { - return [[FLTDefaultCaptureDeviceController alloc] initWithDevice:captureDeviceMock]; - } - videoDimensionsForFormat:^CMVideoDimensions(AVCaptureDeviceFormat *format) { - return CMVideoFormatDescriptionGetDimensions(format.formatDescription); - } - deviceOrientationProvider:deviceOrientationProvider - error:nil]; + OCMStub([captureDeviceMock createInput:(NSError * __autoreleasing *)[OCMArg anyPointer]]).andReturn(inputMock); + + FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] initWithMediaSettings:mediaSettings + mediaSettingsWrapper:mediaSettingsAVWrapper + captureDeviceFactory:captureDeviceFactory ?: ^id(void) { + return captureDeviceMock; + } + captureSessionFactory:^id _Nonnull{ + return videoSessionMock; + } + captureSessionQueue:captureSessionQueue]; + + configuration.videoDimensionsForFormat = ^CMVideoDimensions(AVCaptureDeviceFormat *format) { + return CMVideoFormatDescriptionGetDimensions(format.formatDescription); + }; + configuration.deviceOrientationProvider = deviceOrientationProvider; + configuration.videoCaptureSession = videoSessionMock; + configuration.audioCaptureSession = audioSessionMock; + + id fltCam = [[FLTCam alloc] initWithConfiguration:configuration + error:nil]; id captureVideoDataOutputMock = [OCMockObject niceMockForClass:[AVCaptureVideoDataOutput class]]; @@ -132,24 +139,32 @@ return fltCam; } -FLTCam *FLTCreateCamWithVideoCaptureSession(AVCaptureSession *captureSession, +FLTCam *FLTCreateCamWithVideoCaptureSession(id captureSession, FCPPlatformResolutionPreset resolutionPreset) { id inputMock = OCMClassMock([AVCaptureDeviceInput class]); OCMStub([inputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg setTo:nil]]) .andReturn(inputMock); - id audioSessionMock = OCMClassMock([AVCaptureSession class]); + id audioSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]); OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - - return [[FLTCam alloc] initWithCameraName:@"camera" - mediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) - mediaSettingsAVWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] - orientation:UIDeviceOrientationPortrait - videoCaptureSession:captureSession - audioCaptureSession:audioSessionMock - captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL) - error:nil]; + + id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDeviceControlling)); + + FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) + mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] + captureDeviceFactory: ^id(void) { + return captureDeviceMock; + } + captureSessionFactory:^id _Nonnull{ + return captureSession; + } + captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL)]; + configuration.orientation = UIDeviceOrientationPortrait; + configuration.videoCaptureSession = captureSession; + configuration.audioCaptureSession = audioSessionMock; + + return [[FLTCam alloc] initWithConfiguration:configuration error:nil]; } FLTCam *FLTCreateCamWithVideoDimensionsForFormat( @@ -159,23 +174,27 @@ OCMStub([inputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg setTo:nil]]) .andReturn(inputMock); - id audioSessionMock = OCMClassMock([AVCaptureSession class]); + id audioSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]); OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - - return [[FLTCam alloc] - initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) - mediaSettingsAVWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] - orientation:UIDeviceOrientationPortrait - videoCaptureSession:captureSession - audioCaptureSession:audioSessionMock - captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL) - captureDeviceFactory:^id(void) { - return [[FLTDefaultCaptureDeviceController alloc] initWithDevice:captureDevice]; - } - videoDimensionsForFormat:videoDimensionsForFormat - deviceOrientationProvider:[[MockDeviceOrientationProvider alloc] init] - error:nil]; + + FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) + mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] + captureDeviceFactory:^id(void){ + return captureDevice; + } + captureSessionFactory:^id _Nonnull{ + return [[AVCaptureSession alloc] init]; + } + captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL)]; + + configuration.videoDimensionsForFormat = videoDimensionsForFormat; + configuration.deviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; + configuration.videoCaptureSession = captureSession; + configuration.audioCaptureSession = audioSessionMock; + configuration.orientation = UIDeviceOrientationPortrait; + + return [[FLTCam alloc] initWithConfiguration:configuration error:nil]; } CMSampleBufferRef FLTCreateTestSampleBuffer(void) { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m index c1bfb6ad376..90c115936e0 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m @@ -177,7 +177,7 @@ - (void)testCaptureToFile_handlesTorchMode { [self expectationWithDescription: @"Must send file path to result if save photo delegate completes with file path."]; - id captureDeviceMock = OCMClassMock([AVCaptureDevice class]); + id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDeviceControlling)); OCMStub([captureDeviceMock hasTorch]).andReturn(YES); OCMStub([captureDeviceMock isTorchAvailable]).andReturn(YES); OCMStub([captureDeviceMock torchMode]).andReturn(AVCaptureTorchModeAuto); @@ -190,7 +190,7 @@ - (void)testCaptureToFile_handlesTorchMode { FLTCam *cam = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( captureSessionQueue, nil, nil, ^id(void) { - return [[FLTDefaultCaptureDeviceController alloc] initWithDevice:captureDeviceMock]; + return captureDeviceMock; }, nil); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCameraDeviceDiscoverer.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h similarity index 100% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCameraDeviceDiscoverer.h rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCameraDeviceDiscoverer.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.m similarity index 100% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCameraDeviceDiscoverer.m rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.m diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.h similarity index 94% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.h index 571bf811144..cf0a046ca3a 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.h @@ -73,9 +73,13 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, copy) void (^setActiveVideoMaxFrameDurationStub)(CMTime duration); // Input Creation -@property(nonatomic, strong) AVCaptureInput *inputToReturn; +@property(nonatomic, strong) id inputToReturn; @property(nonatomic, copy) void (^createInputStub)(NSError **error); @end +@interface MockCaptureInput : NSObject +@property(nonatomic, strong) NSArray *ports; +@end + NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.m similarity index 98% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.m index cc89bb85abf..82e0023a89e 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.m @@ -126,3 +126,7 @@ - (AVCaptureInput *)createInput:(NSError *_Nullable *_Nullable)error { } @end + +@implementation MockCaptureInput +@synthesize ports; +@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h new file mode 100644 index 00000000000..5d14a14115b --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h @@ -0,0 +1,27 @@ +// 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. + +@import camera_avfoundation; +#if __has_include() +@import camera_avfoundation.Test; +#endif +@import AVFoundation; + +NS_ASSUME_NONNULL_BEGIN + +@interface MockCaptureSession : NSObject +@property(nonatomic, copy) void (^beginConfigurationStub)(void); +@property(nonatomic, copy) void (^commitConfigurationStub)(void); +@property(nonatomic, copy) void (^startRunningStub)(void); +@property(nonatomic, copy) void (^stopRunningStub)(void); +@property(nonatomic, copy) void (^setSessionPresetStub)(AVCaptureSessionPreset preset); + +@property(nonatomic, strong) NSMutableArray *inputs; +@property(nonatomic, strong) NSMutableArray *outputs; +@property(nonatomic, assign) BOOL mockCanSetSessionPreset; +@property(nonatomic, copy) AVCaptureSessionPreset sessionPreset; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.m new file mode 100644 index 00000000000..9adb54e90d6 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.m @@ -0,0 +1,85 @@ +// 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. + +#import "MockCaptureSession.h" + +@implementation MockCaptureSession + +- (instancetype)init { + self = [super init]; + if (self) { + _inputs = [NSMutableArray array]; + _outputs = [NSMutableArray array]; + } + return self; +} + +- (void)beginConfiguration { + if (self.beginConfigurationStub) { + self.beginConfigurationStub(); + } +} + +- (void)commitConfiguration { + if (self.commitConfigurationStub) { + self.commitConfigurationStub(); + } +} + +- (void)startRunning { + if (self.startRunningStub) { + self.startRunningStub(); + } +} + +- (void)stopRunning { + if (self.stopRunningStub) { + self.stopRunningStub(); + } +} + +- (BOOL)canSetSessionPreset:(AVCaptureSessionPreset)preset { + return self.mockCanSetSessionPreset; +} + +- (void)addConnection:(nonnull AVCaptureConnection *)connection { +} + +- (void)addInput:(nonnull AVCaptureInput *)input { +} + +- (void)addInputWithNoConnections:(nonnull AVCaptureInput *)input { +} + +- (void)addOutput:(nonnull AVCaptureOutput *)output { +} + +- (void)addOutputWithNoConnections:(nonnull AVCaptureOutput *)output { +} + +- (BOOL)canAddConnection:(nonnull AVCaptureConnection *)connection { + return YES; +} + +- (BOOL)canAddInput:(nonnull AVCaptureInput *)input { + return YES; +} + +- (BOOL)canAddOutput:(nonnull AVCaptureOutput *)output { + return YES; +} + +- (void)removeInput:(nonnull AVCaptureInput *)input { +} + +- (void)removeOutput:(nonnull AVCaptureOutput *)output { +} + +- (void)setSessionPreset:(AVCaptureSessionPreset)sessionPreset { + if (_setSessionPresetStub) { + _setSessionPresetStub(sessionPreset); + } +} + +@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceOrientationProvider.h similarity index 100% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.h rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceOrientationProvider.h diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceOrientationProvider.m similarity index 100% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.m rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceOrientationProvider.m diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockEventChannel.h similarity index 100% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.h rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockEventChannel.h diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockEventChannel.m similarity index 100% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/MockEventChannel.m rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockEventChannel.m diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m index 57b53b997b4..a057f98dc10 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m @@ -28,6 +28,8 @@ @interface CameraPlugin () @property(nonatomic) FCPCameraGlobalEventApi *globalEventAPI; @property(readonly, nonatomic) FLTCameraPermissionManager *permissionManager; @property(readonly, nonatomic) id deviceDiscoverer; +@property(readonly, nonatomic) CaptureNamedDeviceFactory captureDeviceFactory; +@property(readonly, nonatomic) CaptureSessionFactory captureSessionFactory; @end @implementation CameraPlugin @@ -43,13 +45,21 @@ - (instancetype)initWithRegistry:(NSObject *)registry return [self initWithRegistry:registry messenger:messenger globalAPI:[[FCPCameraGlobalEventApi alloc] initWithBinaryMessenger:messenger] - deviceDiscoverer:[[FLTDefaultCameraDeviceDiscoverer alloc] init]]; + deviceDiscoverer:[[FLTDefaultCameraDeviceDiscoverer alloc] init] + deviceFactory:^id(NSString *name) { + return [AVCaptureDevice deviceWithUniqueID:name]; + } + captureSessionFactory:^id (void){ + return [[AVCaptureSession alloc] init]; + }]; } - (instancetype)initWithRegistry:(NSObject *)registry messenger:(NSObject *)messenger globalAPI:(FCPCameraGlobalEventApi *)globalAPI - deviceDiscoverer:(id)deviceDiscoverer { + deviceDiscoverer:(id)deviceDiscoverer + deviceFactory:(CaptureNamedDeviceFactory)deviceFactory + captureSessionFactory:(CaptureSessionFactory)captureSessionFactory { self = [super init]; NSAssert(self, @"super init cannot be nil"); _registry = registry; @@ -57,6 +67,8 @@ - (instancetype)initWithRegistry:(NSObject *)registry _globalEventAPI = globalAPI; _captureSessionQueue = dispatch_queue_create("io.flutter.camera.captureSessionQueue", NULL); _deviceDiscoverer = deviceDiscoverer; + _captureDeviceFactory = deviceFactory; + _captureSessionFactory = captureSessionFactory; id permissionService = [[FLTDefaultPermissionService alloc] init]; _permissionManager = @@ -479,14 +491,19 @@ - (void)sessionQueueCreateCameraWithName:(NSString *)name FlutterError *_Nullable))completion { FLTCamMediaSettingsAVWrapper *mediaSettingsAVWrapper = [[FLTCamMediaSettingsAVWrapper alloc] init]; + + FLTCamConfiguration *camConfiguration = [[FLTCamConfiguration alloc] initWithMediaSettings:settings + mediaSettingsWrapper:mediaSettingsAVWrapper + captureDeviceFactory:^id _Nonnull{ + return self.captureDeviceFactory(name); + } + captureSessionFactory:_captureSessionFactory + captureSessionQueue:_captureSessionQueue + ]; NSError *error; - FLTCam *cam = [[FLTCam alloc] initWithCameraName:name - mediaSettings:settings - mediaSettingsAVWrapper:mediaSettingsAVWrapper - orientation:[[UIDevice currentDevice] orientation] - captureSessionQueue:self.captureSessionQueue - error:&error]; + FLTCam *cam = [[FLTCam alloc] initWithConfiguration:camConfiguration + error:&error]; if (error) { completion(nil, FlutterErrorFromNSError(error)); diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 4f0729ae5d2..d7ca4a32348 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -57,8 +57,8 @@ @interface FLTCam () videoCaptureSession; +@property(readonly, nonatomic) id audioCaptureSession; @property(readonly, nonatomic) AVCaptureInput *captureVideoInput; /// Tracks the latest pixel buffer sent from AVFoundation's sample buffer delegate callback. @@ -117,47 +117,6 @@ @implementation FLTCam NSString *const errorMethod = @"error"; -- (instancetype)initWithCameraName:(NSString *)cameraName - mediaSettings:(FCPPlatformMediaSettings *)mediaSettings - mediaSettingsAVWrapper:(FLTCamMediaSettingsAVWrapper *)mediaSettingsAVWrapper - orientation:(UIDeviceOrientation)orientation - captureSessionQueue:(dispatch_queue_t)captureSessionQueue - error:(NSError **)error { - return [self initWithCameraName:cameraName - mediaSettings:mediaSettings - mediaSettingsAVWrapper:mediaSettingsAVWrapper - orientation:orientation - videoCaptureSession:[[AVCaptureSession alloc] init] - audioCaptureSession:[[AVCaptureSession alloc] init] - captureSessionQueue:captureSessionQueue - error:error]; -} - -- (instancetype)initWithCameraName:(NSString *)cameraName - mediaSettings:(FCPPlatformMediaSettings *)mediaSettings - mediaSettingsAVWrapper:(FLTCamMediaSettingsAVWrapper *)mediaSettingsAVWrapper - orientation:(UIDeviceOrientation)orientation - videoCaptureSession:(AVCaptureSession *)videoCaptureSession - audioCaptureSession:(AVCaptureSession *)audioCaptureSession - captureSessionQueue:(dispatch_queue_t)captureSessionQueue - error:(NSError **)error { - return [self initWithMediaSettings:mediaSettings - mediaSettingsAVWrapper:mediaSettingsAVWrapper - orientation:orientation - videoCaptureSession:videoCaptureSession - audioCaptureSession:videoCaptureSession - captureSessionQueue:captureSessionQueue - captureDeviceFactory:^id(void) { - AVCaptureDevice *device = [AVCaptureDevice deviceWithUniqueID:cameraName]; - return [[FLTDefaultCaptureDeviceController alloc] initWithDevice:device]; - } - videoDimensionsForFormat:^CMVideoDimensions(AVCaptureDeviceFormat *format) { - return CMVideoFormatDescriptionGetDimensions(format.formatDescription); - } - deviceOrientationProvider:[[FLTDefaultDeviceOrientationProvider alloc] init] - error:error]; -} - // Returns frame rate supported by format closest to targetFrameRate. static double bestFrameRateForFormat(AVCaptureDeviceFormat *format, double targetFrameRate) { double bestFrameRate = 0; @@ -211,35 +170,27 @@ static void selectBestFormatForRequestedFrameRate( mediaSettings.framesPerSecond = @(bestFrameRate); } -- (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings - mediaSettingsAVWrapper:(FLTCamMediaSettingsAVWrapper *)mediaSettingsAVWrapper - orientation:(UIDeviceOrientation)orientation - videoCaptureSession:(AVCaptureSession *)videoCaptureSession - audioCaptureSession:(AVCaptureSession *)audioCaptureSession - captureSessionQueue:(dispatch_queue_t)captureSessionQueue - captureDeviceFactory:(CaptureDeviceFactory)captureDeviceFactory - videoDimensionsForFormat:(VideoDimensionsForFormat)videoDimensionsForFormat - deviceOrientationProvider:(id)deviceOrientationProvider - error:(NSError **)error { +- (instancetype)initWithConfiguration:(nonnull FLTCamConfiguration *)configuration + error:(NSError **)error { self = [super init]; NSAssert(self, @"super init cannot be nil"); - _mediaSettings = mediaSettings; - _mediaSettingsAVWrapper = mediaSettingsAVWrapper; + _mediaSettings = configuration.mediaSettings; + _mediaSettingsAVWrapper = configuration.mediaSettingsWrapper; - _captureSessionQueue = captureSessionQueue; + _captureSessionQueue = configuration.captureSessionQueue; _pixelBufferSynchronizationQueue = dispatch_queue_create("io.flutter.camera.pixelBufferSynchronizationQueue", NULL); _photoIOQueue = dispatch_queue_create("io.flutter.camera.photoIOQueue", NULL); - _videoCaptureSession = videoCaptureSession; - _audioCaptureSession = audioCaptureSession; - _captureDeviceFactory = captureDeviceFactory; - _captureDevice = captureDeviceFactory(); - _videoDimensionsForFormat = videoDimensionsForFormat; + _videoCaptureSession = configuration.videoCaptureSession; + _audioCaptureSession = configuration.audioCaptureSession; + _captureDeviceFactory = configuration.captureDeviceFactory; + _captureDevice = _captureDeviceFactory(); + _videoDimensionsForFormat = configuration.videoDimensionsForFormat; _flashMode = _captureDevice.hasFlash ? FCPPlatformFlashModeAuto : FCPPlatformFlashModeOff; _exposureMode = FCPPlatformExposureModeAuto; _focusMode = FCPPlatformFocusModeAuto; _lockedCaptureOrientation = UIDeviceOrientationUnknown; - _deviceOrientation = orientation; + _deviceOrientation = configuration.orientation; _videoFormat = kCVPixelFormatType_32BGRA; _inProgressSavePhotoDelegates = [NSMutableDictionary dictionary]; _fileFormat = FCPPlatformImageFileFormatJpeg; @@ -269,11 +220,11 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings _motionManager = [[CMMotionManager alloc] init]; [_motionManager startAccelerometerUpdates]; - _deviceOrientationProvider = deviceOrientationProvider; + _deviceOrientationProvider = configuration.deviceOrientationProvider; if (_mediaSettings.framesPerSecond) { // The frame rate can be changed only on a locked for configuration device. - if ([mediaSettingsAVWrapper lockDevice:_captureDevice error:error]) { + if ([_mediaSettingsAVWrapper lockDevice:_captureDevice error:error]) { [_mediaSettingsAVWrapper beginConfigurationForSession:_videoCaptureSession]; // Possible values for presets are hard-coded in FLT interface having @@ -294,8 +245,8 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings int fpsNominator = floor([_mediaSettings.framesPerSecond doubleValue] * 10.0); CMTime duration = CMTimeMake(10, fpsNominator); - [mediaSettingsAVWrapper setMinFrameDuration:duration onDevice:_captureDevice]; - [mediaSettingsAVWrapper setMaxFrameDuration:duration onDevice:_captureDevice]; + [_mediaSettingsAVWrapper setMinFrameDuration:duration onDevice:_captureDevice]; + [_mediaSettingsAVWrapper setMaxFrameDuration:duration onDevice:_captureDevice]; [_mediaSettingsAVWrapper commitConfigurationForSession:_videoCaptureSession]; [_mediaSettingsAVWrapper unlockDevice:_captureDevice]; @@ -1212,13 +1163,10 @@ - (void)startImageStreamWithMessenger:(NSObject *)messen - (void)startImageStreamWithMessenger:(NSObject *)messenger imageStreamHandler:(FLTImageStreamHandler *)imageStreamHandler { if (!_isStreamingImages) { - FlutterEventChannel *eventChannel = [FlutterEventChannel + id eventChannel = [FlutterEventChannel eventChannelWithName:@"plugins.flutter.io/camera_avfoundation/imageStream" binaryMessenger:messenger]; - id eventChannelProtocol = - [[FLTDefaultEventChannel alloc] initWithEventChannel:eventChannel]; - FLTThreadSafeEventChannel *threadSafeEventChannel = - [[FLTThreadSafeEventChannel alloc] initWithEventChannel:eventChannelProtocol]; + FLTThreadSafeEventChannel *threadSafeEventChannel = [[FLTThreadSafeEventChannel alloc] initWithEventChannel:eventChannel]; _imageStreamHandler = imageStreamHandler; __weak typeof(self) weakSelf = self; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m new file mode 100644 index 00000000000..ea02e9d8ee7 --- /dev/null +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m @@ -0,0 +1,32 @@ +// 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. + +#import "./include/camera_avfoundation/FLTCamConfiguration.h" + +@implementation FLTCamConfiguration + +- (instancetype) + initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings + mediaSettingsWrapper:(FLTCamMediaSettingsAVWrapper *)mediaSettingsWrapper + captureDeviceFactory:(CaptureDeviceFactory)captureDeviceFactory + captureSessionFactory:(CaptureSessionFactory)captureSessionFactory + captureSessionQueue:(dispatch_queue_t)captureSessionQueue { + self = [super init]; + if (self) { + _mediaSettings = mediaSettings; + _mediaSettingsWrapper = mediaSettingsWrapper; + _captureSessionQueue = captureSessionQueue; + _videoCaptureSession = captureSessionFactory(); + _audioCaptureSession = captureSessionFactory(); + _captureDeviceFactory = captureDeviceFactory; + _orientation = [[UIDevice currentDevice] orientation]; + _deviceOrientationProvider = [[FLTDefaultDeviceOrientationProvider alloc] init]; + _videoDimensionsForFormat = ^CMVideoDimensions(AVCaptureDeviceFormat *format) { + return CMVideoFormatDescriptionGetDimensions(format.formatDescription); + }; + } + return self; +} + +@end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m index d257a4606a6..39322f808de 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m @@ -21,9 +21,7 @@ @implementation FLTDefaultCameraDeviceDiscoverer NSMutableArray> *deviceControllers = [NSMutableArray array]; for (AVCaptureDevice *device in devices) { - FLTDefaultCaptureDeviceController *controller = - [[FLTDefaultCaptureDeviceController alloc] initWithDevice:device]; - [deviceControllers addObject:controller]; + [deviceControllers addObject:(id)device]; } return deviceControllers; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m deleted file mode 100644 index 0b3e2e985ec..00000000000 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m +++ /dev/null @@ -1,176 +0,0 @@ -// 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. - -#import "./include/camera_avfoundation/FLTCaptureDeviceControlling.h" - -@interface FLTDefaultCaptureDeviceController () -@property(nonatomic, strong) AVCaptureDevice *device; -@end - -@implementation FLTDefaultCaptureDeviceController - -- (instancetype)initWithDevice:(AVCaptureDevice *)device { - self = [super init]; - if (self) { - _device = device; - } - return self; -} - -- (nonnull NSString *)uniqueID { - return self.device.uniqueID; -} - -// Position/Orientation -- (AVCaptureDevicePosition)position { - return self.device.position; -} - -// Format/Configuration -- (AVCaptureDeviceFormat *)activeFormat { - return self.device.activeFormat; -} - -- (NSArray *)formats { - return self.device.formats; -} - -- (void)setActiveFormat:(AVCaptureDeviceFormat *)format { - self.device.activeFormat = format; -} - -// Flash/Torch -- (BOOL)hasFlash { - return self.device.hasFlash; -} - -- (BOOL)hasTorch { - return self.device.hasTorch; -} - -- (BOOL)isTorchAvailable { - return self.device.isTorchAvailable; -} - -- (AVCaptureTorchMode)torchMode { - return self.device.torchMode; -} - -- (void)setTorchMode:(AVCaptureTorchMode)torchMode { - self.device.torchMode = torchMode; -} - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -- (BOOL)isFlashModeSupported:(AVCaptureFlashMode)mode { - return [self.device isFlashModeSupported:mode]; -} -#pragma clang diagnostic pop - -// Focus -- (BOOL)isFocusPointOfInterestSupported { - return self.device.isFocusPointOfInterestSupported; -} - -- (BOOL)isFocusModeSupported:(AVCaptureFocusMode)mode { - return [self.device isFocusModeSupported:mode]; -} - -- (void)setFocusMode:(AVCaptureFocusMode)focusMode { - self.device.focusMode = focusMode; -} - -- (void)setFocusPointOfInterest:(CGPoint)point { - self.device.focusPointOfInterest = point; -} - -// Exposure -- (BOOL)isExposurePointOfInterestSupported { - return self.device.isExposurePointOfInterestSupported; -} - -- (void)setExposureMode:(AVCaptureExposureMode)exposureMode { - self.device.exposureMode = exposureMode; -} - -- (void)setExposurePointOfInterest:(CGPoint)point { - self.device.exposurePointOfInterest = point; -} - -- (float)minExposureTargetBias { - return self.device.minExposureTargetBias; -} - -- (float)maxExposureTargetBias { - return self.device.maxExposureTargetBias; -} - -- (void)setExposureTargetBias:(float)bias completionHandler:(void (^)(CMTime))handler { - [self.device setExposureTargetBias:bias completionHandler:handler]; -} - -- (BOOL)isExposureModeSupported:(AVCaptureExposureMode)mode { - return [self.device isExposureModeSupported:mode]; -} - -// Zoom -- (float)maxAvailableVideoZoomFactor { - return self.device.maxAvailableVideoZoomFactor; -} - -- (float)minAvailableVideoZoomFactor { - return self.device.minAvailableVideoZoomFactor; -} - -- (float)videoZoomFactor { - return self.device.videoZoomFactor; -} - -- (void)setVideoZoomFactor:(float)factor { - self.device.videoZoomFactor = factor; -} - -// Camera Properties -- (float)lensAperture { - return self.device.lensAperture; -} - -- (CMTime)exposureDuration { - return self.device.exposureDuration; -} - -- (float)ISO { - return self.device.ISO; -} - -// Configuration Lock -- (BOOL)lockForConfiguration:(NSError **)error { - return [self.device lockForConfiguration:error]; -} - -- (void)unlockForConfiguration { - [self.device unlockForConfiguration]; -} - -- (CMTime)activeVideoMinFrameDuration { - return self.device.activeVideoMinFrameDuration; -} - -- (void)setActiveVideoMinFrameDuration:(CMTime)duration { - self.device.activeVideoMinFrameDuration = duration; -} - -- (CMTime)activeVideoMaxFrameDuration { - return self.device.activeVideoMaxFrameDuration; -} - -- (void)setActiveVideoMaxFrameDuration:(CMTime)duration { - self.device.activeVideoMaxFrameDuration = duration; -} - -- (AVCaptureInput *)createInput:(NSError *_Nullable *_Nullable)error { - return [AVCaptureDeviceInput deviceInputWithDevice:_device error:error]; -} - -@end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTEventChannel.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTEventChannel.m deleted file mode 100644 index ec9e21e3cc7..00000000000 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTEventChannel.m +++ /dev/null @@ -1,27 +0,0 @@ -// 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. - -@import Flutter; - -#import "./include/camera_avfoundation/FLTEventChannel.h" - -@interface FLTDefaultEventChannel () -@property(nonatomic, strong) FlutterEventChannel *channel; -@end - -@implementation FLTDefaultEventChannel - -- (instancetype)initWithEventChannel:(FlutterEventChannel *)channel { - self = [super init]; - if (self) { - _channel = channel; - } - return self; -} - -- (void)setStreamHandler:(NSObject *)handler { - [self.channel setStreamHandler:handler]; -} - -@end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap index 317d7497e04..9572ba9d8d2 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap @@ -7,6 +7,7 @@ framework module camera_avfoundation { explicit module Test { header "FLTCameraDeviceDiscovering.h" header "FLTCaptureDeviceControlling.h" + header "FLTCaptureSession.h" header "FLTDeviceOrientationProviding.h" header "FLTEventChannel.h" header "FLTPermissionServicing.h" @@ -14,6 +15,7 @@ framework module camera_avfoundation { header "CameraProperties.h" header "FLTCam.h" header "FLTCam_Test.h" + header "FLTCamConfiguration.h" header "FLTSavePhotoDelegate_Test.h" header "FLTThreadSafeEventChannel.h" header "FLTCameraPermissionManager.h" diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h index 6439e737dbf..d61f8f1b294 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h @@ -6,9 +6,15 @@ #import "CameraPlugin.h" #import "FLTCam.h" +#import "FLTCamConfiguration.h" #import "FLTCameraDeviceDiscovering.h" +#import "FLTCaptureDeviceControlling.h" #import "messages.g.h" +NS_ASSUME_NONNULL_BEGIN + +typedef id _Nonnull (^CaptureNamedDeviceFactory)(NSString *name); + /// APIs exposed for unit testing. @interface CameraPlugin () @@ -16,22 +22,23 @@ @property(nonatomic, strong) dispatch_queue_t captureSessionQueue; /// An internal camera object that manages camera's state and performs camera operations. -@property(nonatomic, strong) FLTCam *camera; +@property(nonatomic, strong) FLTCam * _Nullable camera; /// Inject @p FlutterTextureRegistry and @p FlutterBinaryMessenger for unit testing. -- (instancetype)initWithRegistry:(NSObject *)registry - messenger:(NSObject *)messenger; +- (nonnull instancetype)initWithRegistry:(NSObject * _Nullable)registry + messenger:(NSObject * _Nullable)messenger; /// Inject @p FlutterTextureRegistry, @p FlutterBinaryMessenger, and Pigeon callback handler for /// unit testing. -- (instancetype)initWithRegistry:(NSObject *)registry - messenger:(NSObject *)messenger - globalAPI:(FCPCameraGlobalEventApi *)globalAPI +- (nonnull instancetype)initWithRegistry:(NSObject * _Nullable)registry + messenger:(NSObject * _Nullable)messenger + globalAPI:(FCPCameraGlobalEventApi * _Nullable)globalAPI deviceDiscoverer:(id)deviceDiscoverer - NS_DESIGNATED_INITIALIZER; + deviceFactory:(CaptureNamedDeviceFactory)deviceFactory + captureSessionFactory:(CaptureSessionFactory)captureSessionFactory NS_DESIGNATED_INITIALIZER; /// Hide the default public constructor. -- (instancetype)init NS_UNAVAILABLE; +- (nonnull instancetype)init NS_UNAVAILABLE; /// Called by the @c NSNotificationManager each time the device's orientation is changed. /// @@ -43,7 +50,9 @@ /// @param name the name of the camera. /// @param settings the creation settings. /// @param completion the callback to inform the Dart side of the plugin of creation. -- (void)createCameraOnSessionQueueWithName:(NSString *)name +- (void)createCameraOnSessionQueueWithName:(NSString *_Nullable)name settings:(FCPPlatformMediaSettings *)settings - completion:(void (^)(NSNumber *, FlutterError *))completion; + completion:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion; @end + +NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h index b5418124bf5..eccc484df48 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h @@ -7,8 +7,10 @@ @import Flutter; #import "CameraProperties.h" +#import "FLTCamConfiguration.h" #import "FLTCamMediaSettingsAVWrapper.h" #import "FLTCaptureDeviceControlling.h" +#import "FLTDeviceOrientationProviding.h" #import "messages.g.h" NS_ASSUME_NONNULL_BEGIN @@ -32,20 +34,10 @@ NS_ASSUME_NONNULL_BEGIN @property(assign, nonatomic) CGFloat minimumAvailableZoomFactor; @property(assign, nonatomic) CGFloat maximumAvailableZoomFactor; -/// Initializes an `FLTCam` instance. -/// @param cameraName a name used to uniquely identify the camera. -/// @param mediaSettings the media settings configuration parameters -/// @param mediaSettingsAVWrapper AVFoundation wrapper to perform media settings related operations -/// (for dependency injection in unit tests). -/// @param orientation the orientation of camera -/// @param captureSessionQueue the queue on which camera's capture session operations happen. +/// Initializes an `FLTCam` instance with the given configuration. /// @param error report to the caller if any error happened creating the camera. -- (instancetype)initWithCameraName:(NSString *)cameraName - mediaSettings:(FCPPlatformMediaSettings *)mediaSettings - mediaSettingsAVWrapper:(FLTCamMediaSettingsAVWrapper *)mediaSettingsAVWrapper - orientation:(UIDeviceOrientation)orientation - captureSessionQueue:(dispatch_queue_t)captureSessionQueue - error:(NSError **)error; +- (instancetype)initWithConfiguration:(FLTCamConfiguration *)configuration + error:(NSError **)error; /// Informs the Dart side of the plugin of the current camera state and capabilities. - (void)reportInitializationState; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h new file mode 100644 index 00000000000..d5ead448c2f --- /dev/null +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h @@ -0,0 +1,48 @@ +// 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. + +@import AVFoundation; +@import Foundation; +@import Flutter; + +#import "CameraProperties.h" +#import "FLTCamMediaSettingsAVWrapper.h" +#import "FLTCaptureDeviceControlling.h" +#import "FLTCaptureSession.h" +#import "FLTDeviceOrientationProviding.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Factory block returning an AVCaptureDevice. +/// Used in tests to inject a device into FLTCam. +typedef id _Nonnull (^CaptureDeviceFactory)(void); + +typedef id _Nonnull (^CaptureSessionFactory)(void); + +/// Determines the video dimensions (width and height) for a given capture device format. +/// Used in tests to mock CMVideoFormatDescriptionGetDimensions. +typedef CMVideoDimensions (^VideoDimensionsForFormat)(AVCaptureDeviceFormat *); + +@interface FLTCamConfiguration : NSObject + +- (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings + mediaSettingsWrapper:(FLTCamMediaSettingsAVWrapper *)mediaSettingsWrapper + captureDeviceFactory:(CaptureDeviceFactory)captureDeviceFactory + captureSessionFactory:(CaptureSessionFactory)captureSessionFactory + captureSessionQueue:(dispatch_queue_t)captureSessionQueue; + +@property(nonatomic, strong) id deviceOrientationProvider; +@property(nonatomic, strong) dispatch_queue_t captureSessionQueue; +@property(nonatomic, strong) FCPPlatformMediaSettings *mediaSettings; +@property(nonatomic, strong) FLTCamMediaSettingsAVWrapper *mediaSettingsWrapper; +@property(nonatomic, copy) CaptureDeviceFactory captureDeviceFactory; +@property(nonatomic, copy) CaptureDeviceFactory audioCaptureDeviceFactory; +@property(nonatomic, copy) VideoDimensionsForFormat videoDimensionsForFormat; +@property(nonatomic, assign) UIDeviceOrientation orientation; +@property(nonatomic, strong) id videoCaptureSession; +@property(nonatomic, strong) id audioCaptureSession; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h index 7e27e31a888..96ae24931e5 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h @@ -7,14 +7,6 @@ #import "FLTDeviceOrientationProviding.h" #import "FLTSavePhotoDelegate.h" -/// Determines the video dimensions (width and height) for a given capture device format. -/// Used in tests to mock CMVideoFormatDescriptionGetDimensions. -typedef CMVideoDimensions (^VideoDimensionsForFormat)(AVCaptureDeviceFormat *); - -/// Factory block returning an AVCaptureDevice. -/// Used in tests to inject a device into FLTCam. -typedef id (^CaptureDeviceFactory)(void); - @interface FLTImageStreamHandler : NSObject /// The queue on which `eventSink` property should be accessed. @@ -54,31 +46,6 @@ typedef id (^CaptureDeviceFactory)(void); didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection; -/// Initializes a camera instance. -/// Allows for injecting dependencies that are usually internal. -- (instancetype)initWithCameraName:(NSString *)cameraName - mediaSettings:(FCPPlatformMediaSettings *)mediaSettings - mediaSettingsAVWrapper:(FLTCamMediaSettingsAVWrapper *)mediaSettingsAVWrapper - orientation:(UIDeviceOrientation)orientation - videoCaptureSession:(AVCaptureSession *)videoCaptureSession - audioCaptureSession:(AVCaptureSession *)audioCaptureSession - captureSessionQueue:(dispatch_queue_t)captureSessionQueue - error:(NSError **)error; - -/// Initializes a camera instance. -/// Allows for testing with specified resolution, audio preference, orientation, -/// and direct access to capture sessions and blocks. -- (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings - mediaSettingsAVWrapper:(FLTCamMediaSettingsAVWrapper *)mediaSettingsAVWrapper - orientation:(UIDeviceOrientation)orientation - videoCaptureSession:(AVCaptureSession *)videoCaptureSession - audioCaptureSession:(AVCaptureSession *)audioCaptureSession - captureSessionQueue:(dispatch_queue_t)captureSessionQueue - captureDeviceFactory:(CaptureDeviceFactory)captureDeviceFactory - videoDimensionsForFormat:(VideoDimensionsForFormat)videoDimensionsForFormat - deviceOrientationProvider:(id)deviceOrientationProvider - error:(NSError **)error; - /// Start streaming images. - (void)startImageStreamWithMessenger:(NSObject *)messenger imageStreamHandler:(FLTImageStreamHandler *)imageStreamHandler; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h index e9374e24db8..3a86e16e564 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h @@ -7,6 +7,10 @@ NS_ASSUME_NONNULL_BEGIN +@protocol FLTCaptureInput +@property(nonatomic, readonly) NSArray *ports; +@end + @protocol FLTCaptureDeviceControlling - (NSString *)uniqueID; @@ -67,8 +71,10 @@ NS_ASSUME_NONNULL_BEGIN @end -@interface FLTDefaultCaptureDeviceController : NSObject -- (instancetype)initWithDevice:(AVCaptureDevice *)device; +@interface AVCaptureDevice (FLTCaptureDeviceControlling) +@end + +@interface AVCaptureInput (FLTCaptureInput) @end NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h new file mode 100644 index 00000000000..3758695b707 --- /dev/null +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h @@ -0,0 +1,38 @@ +// 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. + +@import AVFoundation; + +#import "FLTCaptureDeviceControlling.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol FLTCaptureSession + +@property(nonatomic, copy) AVCaptureSessionPreset sessionPreset; +@property(nonatomic, readonly) NSArray *inputs; +@property(nonatomic, readonly) NSArray *outputs; + +- (void)beginConfiguration; +- (void)commitConfiguration; +- (void)startRunning; +- (void)stopRunning; +- (BOOL)canSetSessionPreset:(AVCaptureSessionPreset)preset; +- (void)addInputWithNoConnections:(AVCaptureInput *)input; +- (void)addOutputWithNoConnections:(AVCaptureOutput *)output; +- (void)addConnection:(AVCaptureConnection *)connection; +- (void)addOutput:(AVCaptureOutput *)output; +- (void)removeInput:(AVCaptureInput *)input; +- (void)removeOutput:(AVCaptureOutput *)output; +- (BOOL)canAddInput:(AVCaptureInput *)input; +- (BOOL)canAddOutput:(AVCaptureOutput *)output; +- (BOOL)canAddConnection:(AVCaptureConnection *)connection; +- (void)addInput:(AVCaptureInput *)input; + +@end + +@interface AVCaptureSession (FLTCaptureSession) +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h index fa509c04dea..f914ded9979 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h @@ -10,9 +10,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)setStreamHandler:(nullable NSObject *)handler; @end -/// The default method channel that wraps FlutterMethodChannel -@interface FLTDefaultEventChannel : NSObject -- (instancetype)initWithEventChannel:(FlutterEventChannel *)channel; +@interface FlutterEventChannel (FLTEventChannel) @end NS_ASSUME_NONNULL_END From 88f9fe6b613bfe5a6b4a6caeef1741efe0422326 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Mon, 6 Jan 2025 21:52:48 +0100 Subject: [PATCH 21/31] Introduce new protocol for creating capture inputs --- .../CameraCaptureSessionQueueRaceConditionTests.m | 1 - .../example/ios/RunnerTests/CameraTestUtils.m | 1 - .../RunnerTests/Mocks/MockCaptureDeviceController.h | 8 -------- .../RunnerTests/Mocks/MockCaptureDeviceController.m | 11 ----------- .../Sources/camera_avfoundation/FLTCam.m | 2 +- .../camera_avfoundation/FLTCamConfiguration.m | 3 ++- .../FLTCaptureDeviceControlling.h | 12 ++++++------ 7 files changed, 9 insertions(+), 29 deletions(-) diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m index 7552d50fd36..007c67c3762 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m @@ -19,7 +19,6 @@ @implementation CameraCaptureSessionQueueRaceConditionTests - (void)testFixForCaptureSessionQueueNullPointerCrashDueToRaceCondition { MockCaptureDeviceController *captureDevice = [[MockCaptureDeviceController alloc] init]; - captureDevice.inputToReturn = [[MockCaptureInput alloc] init]; CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m index 796603d4787..0c498c218f4 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m @@ -89,7 +89,6 @@ OCMStub([captureDeviceMock activeFormat]).andDo(^(NSInvocation *invocation) { [invocation setReturnValue:&format]; }); - OCMStub([captureDeviceMock createInput:(NSError * __autoreleasing *)[OCMArg anyPointer]]).andReturn(inputMock); FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] initWithMediaSettings:mediaSettings mediaSettingsWrapper:mediaSettingsAVWrapper diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.h index cf0a046ca3a..3d5cab3bf2a 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.h @@ -72,14 +72,6 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, copy) void (^setActiveVideoMinFrameDurationStub)(CMTime duration); @property(nonatomic, copy) void (^setActiveVideoMaxFrameDurationStub)(CMTime duration); -// Input Creation -@property(nonatomic, strong) id inputToReturn; -@property(nonatomic, copy) void (^createInputStub)(NSError **error); - -@end - -@interface MockCaptureInput : NSObject -@property(nonatomic, strong) NSArray *ports; @end NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.m index 82e0023a89e..129fcb9df91 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.m @@ -118,15 +118,4 @@ - (BOOL)isExposureModeSupported:(AVCaptureExposureMode)mode { return self.exposureModeSupported; } -- (AVCaptureInput *)createInput:(NSError *_Nullable *_Nullable)error { - if (self.createInputStub) { - self.createInputStub(error); - } - return self.inputToReturn; -} - -@end - -@implementation MockCaptureInput -@synthesize ports; @end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index d7ca4a32348..3d4f590608e 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -268,7 +268,7 @@ - (instancetype)initWithConfiguration:(nonnull FLTCamConfiguration *)configurati - (AVCaptureConnection *)createConnection:(NSError **)error { // Setup video capture input. - _captureVideoInput = [_captureDevice createInput:error]; + _captureVideoInput = [AVCaptureDeviceInput deviceInputWithDevice:_captureDevice error:error]; // Test the return value of the `deviceInputWithDevice` method to see whether an error occurred. // Don’t just test to see whether the error pointer was set to point to an error. diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m index ea02e9d8ee7..63beb1adbff 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m @@ -11,7 +11,8 @@ @implementation FLTCamConfiguration mediaSettingsWrapper:(FLTCamMediaSettingsAVWrapper *)mediaSettingsWrapper captureDeviceFactory:(CaptureDeviceFactory)captureDeviceFactory captureSessionFactory:(CaptureSessionFactory)captureSessionFactory - captureSessionQueue:(dispatch_queue_t)captureSessionQueue { + captureSessionQueue:(dispatch_queue_t)captureSessionQueue + captureDeviceInputFactory:(id)captureDeviceInputFactory { self = [super init]; if (self) { _mediaSettings = mediaSettings; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h index 3a86e16e564..68e789f6694 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h @@ -7,12 +7,9 @@ NS_ASSUME_NONNULL_BEGIN -@protocol FLTCaptureInput -@property(nonatomic, readonly) NSArray *ports; -@end - @protocol FLTCaptureDeviceControlling +// Device - (NSString *)uniqueID; // Position/Orientation @@ -67,14 +64,17 @@ NS_ASSUME_NONNULL_BEGIN - (CMTime)activeVideoMaxFrameDuration; - (void)setActiveVideoMaxFrameDuration:(CMTime)duration; -- (AVCaptureInput *)createInput:(NSError *_Nullable *_Nullable)error; +@end +@protocol FLTCaptureDeviceInputFactory ++ (nullable AVCaptureInput*)deviceInputWithDevice:(id)device + error:(NSError **)error; @end @interface AVCaptureDevice (FLTCaptureDeviceControlling) @end -@interface AVCaptureInput (FLTCaptureInput) +@interface AVCaptureDeviceInput (FLTCaptureDeviceInputFactory) @end NS_ASSUME_NONNULL_END From 0063b6f2dd77e416812e482e5e0d0523ee64d3fa Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Tue, 7 Jan 2025 12:47:52 +0100 Subject: [PATCH 22/31] Fix DI and tests --- .../ios/RunnerTests/AvailableCamerasTest.m | 19 +++--- ...eraCaptureSessionQueueRaceConditionTests.m | 20 +++--- .../ios/RunnerTests/CameraOrientationTests.m | 40 ++++++------ .../example/ios/RunnerTests/CameraTestUtils.m | 64 ++++++++++--------- .../Mocks/MockCaptureDeviceController.h | 9 +++ .../Mocks/MockCaptureDeviceController.m | 29 +++++++++ .../camera_avfoundation/CameraPlugin.m | 46 +++++++------ .../Sources/camera_avfoundation/FLTCam.m | 16 +++-- .../camera_avfoundation/FLTCamConfiguration.m | 14 ++-- .../FLTCaptureDeviceControlling.m | 16 +++++ .../camera_avfoundation/CameraPlugin_Test.h | 23 ++++--- .../include/camera_avfoundation/FLTCam.h | 3 +- .../camera_avfoundation/FLTCamConfiguration.h | 4 +- .../FLTCaptureDeviceControlling.h | 13 +++- 14 files changed, 198 insertions(+), 118 deletions(-) create mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m index be161cfd5ea..6029af67bcc 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m @@ -25,15 +25,16 @@ - (void)setUp { self.mockDeviceDiscoverer = [[MockCameraDeviceDiscoverer alloc] init]; self.cameraPlugin = [[CameraPlugin alloc] initWithRegistry:nil - messenger:nil - globalAPI:nil - deviceDiscoverer:_mockDeviceDiscoverer - deviceFactory:^id(NSString *name) { - return [[MockCaptureDeviceController alloc] init]; - } - captureSessionFactory:^id { - return [[MockCaptureSession alloc] init]; - }]; + messenger:nil + globalAPI:nil + deviceDiscoverer:_mockDeviceDiscoverer + deviceFactory:^id(NSString *name) { + return [[MockCaptureDeviceController alloc] init]; + } + captureSessionFactory:^id { + return [[MockCaptureSession alloc] init]; + } + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; } - (void)testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m index 007c67c3762..2095610dece 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m @@ -21,16 +21,16 @@ - (void)testFixForCaptureSessionQueueNullPointerCrashDueToRaceCondition { MockCaptureDeviceController *captureDevice = [[MockCaptureDeviceController alloc] init]; CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil - messenger:nil - globalAPI:nil - deviceDiscoverer:[[MockCameraDeviceDiscoverer alloc] init] - deviceFactory:^id(NSString *name) { - return captureDevice; - } - captureSessionFactory:^id { - return [[MockCaptureSession alloc] init]; - } - ]; + messenger:nil + globalAPI:nil + deviceDiscoverer:[[MockCameraDeviceDiscoverer alloc] init] + deviceFactory:^id(NSString *name) { + return captureDevice; + } + captureSessionFactory:^id { + return [[MockCaptureSession alloc] init]; + } + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; XCTestExpectation *disposeExpectation = [self expectationWithDescription:@"dispose's result block must be called"]; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m index cda38c1077a..850ebd7aa0e 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m @@ -84,16 +84,16 @@ - (void)setUp { _deviceDiscoverer = [[MockCameraDeviceDiscoverer alloc] init]; _cameraPlugin = [[CameraPlugin alloc] initWithRegistry:nil - messenger:nil - globalAPI:_eventAPI - deviceDiscoverer:_deviceDiscoverer - deviceFactory:^id(NSString *name) { - return mockDevice; - } - captureSessionFactory:^id _Nonnull{ - return [[MockCaptureSession alloc] init]; - } - ]; + messenger:nil + globalAPI:_eventAPI + deviceDiscoverer:_deviceDiscoverer + deviceFactory:^id(NSString *name) { + return mockDevice; + } + captureSessionFactory:^id _Nonnull { + return [[MockCaptureSession alloc] init]; + } + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; _cameraPlugin.camera = _camera; } @@ -166,16 +166,16 @@ - (void)testOrientationChanged_noRetainCycle { @autoreleasepool { CameraPlugin *plugin = [[CameraPlugin alloc] initWithRegistry:nil - messenger:nil - globalAPI:_eventAPI - deviceDiscoverer:_deviceDiscoverer - deviceFactory:^id(NSString *name) { - return weakDevice; - } - captureSessionFactory:^id _Nonnull{ - return [[MockCaptureSession alloc] init]; - } - ]; + messenger:nil + globalAPI:_eventAPI + deviceDiscoverer:_deviceDiscoverer + deviceFactory:^id(NSString *name) { + return weakDevice; + } + captureSessionFactory:^id _Nonnull { + return [[MockCaptureSession alloc] init]; + } + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; weakPlugin = plugin; plugin.captureSessionQueue = captureSessionQueue; plugin.camera = _camera; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m index 0c498c218f4..c1b00aba6f6 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m @@ -8,6 +8,7 @@ @import AVFoundation; @import camera_avfoundation; +#import "MockCaptureDeviceController.h" #import "MockCaptureSession.h" #import "MockDeviceOrientationProvider.h" @@ -41,9 +42,9 @@ deviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; } - id inputMock = OCMClassMock([AVCaptureDeviceInput class]); - OCMStub([inputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg setTo:nil]]) - .andReturn(inputMock); + if (!captureSessionQueue) { + captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); + } id videoSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); OCMStub([videoSessionMock beginConfiguration]) @@ -89,7 +90,7 @@ OCMStub([captureDeviceMock activeFormat]).andDo(^(NSInvocation *invocation) { [invocation setReturnValue:&format]; }); - + FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] initWithMediaSettings:mediaSettings mediaSettingsWrapper:mediaSettingsAVWrapper captureDeviceFactory:captureDeviceFactory ?: ^id(void) { @@ -98,8 +99,9 @@ captureSessionFactory:^id _Nonnull{ return videoSessionMock; } - captureSessionQueue:captureSessionQueue]; - + captureSessionQueue:captureSessionQueue + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; + configuration.videoDimensionsForFormat = ^CMVideoDimensions(AVCaptureDeviceFormat *format) { return CMVideoFormatDescriptionGetDimensions(format.formatDescription); }; @@ -107,8 +109,7 @@ configuration.videoCaptureSession = videoSessionMock; configuration.audioCaptureSession = audioSessionMock; - id fltCam = [[FLTCam alloc] initWithConfiguration:configuration - error:nil]; + id fltCam = [[FLTCam alloc] initWithConfiguration:configuration error:nil]; id captureVideoDataOutputMock = [OCMockObject niceMockForClass:[AVCaptureVideoDataOutput class]]; @@ -147,18 +148,21 @@ id audioSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]); OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - + id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDeviceControlling)); - FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) - mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] - captureDeviceFactory: ^id(void) { - return captureDeviceMock; - } - captureSessionFactory:^id _Nonnull{ - return captureSession; - } - captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL)]; + FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] + initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) + mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] + captureDeviceFactory:^id(void) { + return captureDeviceMock; + } + captureSessionFactory:^id _Nonnull { + return captureSession; + } + captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL) + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; + configuration.orientation = UIDeviceOrientationPortrait; configuration.videoCaptureSession = captureSession; configuration.audioCaptureSession = audioSessionMock; @@ -176,17 +180,19 @@ id audioSessionMock = OCMProtocolMock(@protocol(FLTCaptureSession)); OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]); OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - - FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) - mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] - captureDeviceFactory:^id(void){ - return captureDevice; - } - captureSessionFactory:^id _Nonnull{ - return [[AVCaptureSession alloc] init]; - } - captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL)]; - + + FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] + initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) + mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] + captureDeviceFactory:^id(void) { + return captureDevice; + } + captureSessionFactory:^id _Nonnull { + return [[AVCaptureSession alloc] init]; + } + captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL) + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; + configuration.videoDimensionsForFormat = videoDimensionsForFormat; configuration.deviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; configuration.videoCaptureSession = captureSession; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.h index 3d5cab3bf2a..637b3eb1473 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.h @@ -74,4 +74,13 @@ NS_ASSUME_NONNULL_BEGIN @end +@interface MockCaptureInput : NSObject +@property(nonatomic, strong) NSArray *ports; +@end + +@interface MockCaptureDeviceInputFactory : NSObject +- (nonnull instancetype)initWithMockDeviceInput:(id)mockDeviceInput; +@property(nonatomic, strong) id mockDeviceInput; +@end + NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.m index 129fcb9df91..c6fa40c7bab 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.m @@ -119,3 +119,32 @@ - (BOOL)isExposureModeSupported:(AVCaptureExposureMode)mode { } @end + +@implementation MockCaptureInput +@synthesize ports; +@end + +@implementation MockCaptureDeviceInputFactory + +- (nonnull instancetype)init { + self = [super init]; + if (self) { + _mockDeviceInput = [[MockCaptureInput alloc] init]; + } + return self; +} + +- (nonnull instancetype)initWithMockDeviceInput:(nonnull id)mockDeviceInput { + self = [super init]; + if (self) { + _mockDeviceInput = mockDeviceInput; + } + return self; +} + +- (id)deviceInputWithDevice:(id)device + error:(NSError **)error { + return _mockDeviceInput; +} + +@end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m index a057f98dc10..daa207c9138 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m @@ -30,6 +30,7 @@ @interface CameraPlugin () @property(readonly, nonatomic) id deviceDiscoverer; @property(readonly, nonatomic) CaptureNamedDeviceFactory captureDeviceFactory; @property(readonly, nonatomic) CaptureSessionFactory captureSessionFactory; +@property(readonly, nonatomic) id captureDeviceInputFactory; @end @implementation CameraPlugin @@ -43,15 +44,16 @@ + (void)registerWithRegistrar:(NSObject *)registrar { - (instancetype)initWithRegistry:(NSObject *)registry messenger:(NSObject *)messenger { return [self initWithRegistry:registry - messenger:messenger - globalAPI:[[FCPCameraGlobalEventApi alloc] initWithBinaryMessenger:messenger] - deviceDiscoverer:[[FLTDefaultCameraDeviceDiscoverer alloc] init] - deviceFactory:^id(NSString *name) { - return [AVCaptureDevice deviceWithUniqueID:name]; - } - captureSessionFactory:^id (void){ - return [[AVCaptureSession alloc] init]; - }]; + messenger:messenger + globalAPI:[[FCPCameraGlobalEventApi alloc] initWithBinaryMessenger:messenger] + deviceDiscoverer:[[FLTDefaultCameraDeviceDiscoverer alloc] init] + deviceFactory:^id(NSString *name) { + return [AVCaptureDevice deviceWithUniqueID:name]; + } + captureSessionFactory:^id(void) { + return [[AVCaptureSession alloc] init]; + } + captureDeviceInputFactory:[[FLTDefaultCaptureDeviceInputFactory alloc] init]]; } - (instancetype)initWithRegistry:(NSObject *)registry @@ -59,7 +61,8 @@ - (instancetype)initWithRegistry:(NSObject *)registry globalAPI:(FCPCameraGlobalEventApi *)globalAPI deviceDiscoverer:(id)deviceDiscoverer deviceFactory:(CaptureNamedDeviceFactory)deviceFactory - captureSessionFactory:(CaptureSessionFactory)captureSessionFactory { + captureSessionFactory:(CaptureSessionFactory)captureSessionFactory + captureDeviceInputFactory:(id)captureDeviceInputFactory { self = [super init]; NSAssert(self, @"super init cannot be nil"); _registry = registry; @@ -69,6 +72,7 @@ - (instancetype)initWithRegistry:(NSObject *)registry _deviceDiscoverer = deviceDiscoverer; _captureDeviceFactory = deviceFactory; _captureSessionFactory = captureSessionFactory; + _captureDeviceInputFactory = captureDeviceInputFactory; id permissionService = [[FLTDefaultPermissionService alloc] init]; _permissionManager = @@ -491,19 +495,19 @@ - (void)sessionQueueCreateCameraWithName:(NSString *)name FlutterError *_Nullable))completion { FLTCamMediaSettingsAVWrapper *mediaSettingsAVWrapper = [[FLTCamMediaSettingsAVWrapper alloc] init]; - - FLTCamConfiguration *camConfiguration = [[FLTCamConfiguration alloc] initWithMediaSettings:settings - mediaSettingsWrapper:mediaSettingsAVWrapper - captureDeviceFactory:^id _Nonnull{ - return self.captureDeviceFactory(name); - } - captureSessionFactory:_captureSessionFactory - captureSessionQueue:_captureSessionQueue - ]; + + FLTCamConfiguration *camConfiguration = + [[FLTCamConfiguration alloc] initWithMediaSettings:settings + mediaSettingsWrapper:mediaSettingsAVWrapper + captureDeviceFactory:^id _Nonnull { + return self.captureDeviceFactory(name); + } + captureSessionFactory:_captureSessionFactory + captureSessionQueue:_captureSessionQueue + captureDeviceInputFactory:_captureDeviceInputFactory]; NSError *error; - FLTCam *cam = [[FLTCam alloc] initWithConfiguration:camConfiguration - error:&error]; + FLTCam *cam = [[FLTCam alloc] initWithConfiguration:camConfiguration error:&error]; if (error) { completion(nil, FlutterErrorFromNSError(error)); diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 3d4f590608e..4449dc26b19 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -60,7 +60,7 @@ @interface FLTCam () videoCaptureSession; @property(readonly, nonatomic) id audioCaptureSession; -@property(readonly, nonatomic) AVCaptureInput *captureVideoInput; +@property(readonly, nonatomic) id captureVideoInput; /// Tracks the latest pixel buffer sent from AVFoundation's sample buffer delegate callback. /// Used to deliver the latest pixel buffer to the flutter engine via the `copyPixelBuffer` API. @property(readwrite, nonatomic) CVPixelBufferRef latestPixelBuffer; @@ -106,6 +106,7 @@ @interface FLTCam () captureDeviceInputFactory; @property(readonly, nonatomic) id deviceOrientationProvider; /// Reports the given error message to the Dart side of the plugin. /// @@ -171,7 +172,7 @@ static void selectBestFormatForRequestedFrameRate( } - (instancetype)initWithConfiguration:(nonnull FLTCamConfiguration *)configuration - error:(NSError **)error { + error:(NSError **)error { self = [super init]; NSAssert(self, @"super init cannot be nil"); _mediaSettings = configuration.mediaSettings; @@ -185,6 +186,7 @@ - (instancetype)initWithConfiguration:(nonnull FLTCamConfiguration *)configurati _audioCaptureSession = configuration.audioCaptureSession; _captureDeviceFactory = configuration.captureDeviceFactory; _captureDevice = _captureDeviceFactory(); + _captureDeviceInputFactory = configuration.captureDeviceInputFactory; _videoDimensionsForFormat = configuration.videoDimensionsForFormat; _flashMode = _captureDevice.hasFlash ? FCPPlatformFlashModeAuto : FCPPlatformFlashModeOff; _exposureMode = FCPPlatformExposureModeAuto; @@ -268,7 +270,8 @@ - (instancetype)initWithConfiguration:(nonnull FLTCamConfiguration *)configurati - (AVCaptureConnection *)createConnection:(NSError **)error { // Setup video capture input. - _captureVideoInput = [AVCaptureDeviceInput deviceInputWithDevice:_captureDevice error:error]; + _captureVideoInput = [_captureDeviceInputFactory deviceInputWithDevice:_captureDevice + error:error]; // Test the return value of the `deviceInputWithDevice` method to see whether an error occurred. // Don’t just test to see whether the error pointer was set to point to an error. @@ -1166,7 +1169,8 @@ - (void)startImageStreamWithMessenger:(NSObject *)messen id eventChannel = [FlutterEventChannel eventChannelWithName:@"plugins.flutter.io/camera_avfoundation/imageStream" binaryMessenger:messenger]; - FLTThreadSafeEventChannel *threadSafeEventChannel = [[FLTThreadSafeEventChannel alloc] initWithEventChannel:eventChannel]; + FLTThreadSafeEventChannel *threadSafeEventChannel = + [[FLTThreadSafeEventChannel alloc] initWithEventChannel:eventChannel]; _imageStreamHandler = imageStreamHandler; __weak typeof(self) weakSelf = self; @@ -1334,8 +1338,8 @@ - (void)setUpCaptureSessionForAudio { // Create a device input with the device and add it to the session. // Setup the audio input. AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; - AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice - error:&error]; + id audioInput = [_captureDeviceInputFactory deviceInputWithDevice:audioDevice + error:&error]; if (error) { [self reportErrorMessage:error.description]; } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m index 63beb1adbff..cef02879c0d 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m @@ -6,13 +6,12 @@ @implementation FLTCamConfiguration -- (instancetype) - initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings - mediaSettingsWrapper:(FLTCamMediaSettingsAVWrapper *)mediaSettingsWrapper - captureDeviceFactory:(CaptureDeviceFactory)captureDeviceFactory - captureSessionFactory:(CaptureSessionFactory)captureSessionFactory - captureSessionQueue:(dispatch_queue_t)captureSessionQueue - captureDeviceInputFactory:(id)captureDeviceInputFactory { +- (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings + mediaSettingsWrapper:(FLTCamMediaSettingsAVWrapper *)mediaSettingsWrapper + captureDeviceFactory:(CaptureDeviceFactory)captureDeviceFactory + captureSessionFactory:(CaptureSessionFactory)captureSessionFactory + captureSessionQueue:(dispatch_queue_t)captureSessionQueue + captureDeviceInputFactory:(id)captureDeviceInputFactory { self = [super init]; if (self) { _mediaSettings = mediaSettings; @@ -26,6 +25,7 @@ @implementation FLTCamConfiguration _videoDimensionsForFormat = ^CMVideoDimensions(AVCaptureDeviceFormat *format) { return CMVideoFormatDescriptionGetDimensions(format.formatDescription); }; + _captureDeviceInputFactory = captureDeviceInputFactory; } return self; } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m new file mode 100644 index 00000000000..367d7747086 --- /dev/null +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m @@ -0,0 +1,16 @@ +// 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. + +@import Flutter; + +#import "FLTCaptureDeviceControlling.h" + +@implementation FLTDefaultCaptureDeviceInputFactory + +- (AVCaptureInput *)deviceInputWithDevice:(id)device + error:(NSError **)error { + return [AVCaptureDeviceInput deviceInputWithDevice:device error:error]; +} + +@end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h index d61f8f1b294..4f3b31466ef 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h @@ -22,20 +22,22 @@ typedef id _Nonnull (^CaptureNamedDeviceFactory)(NS @property(nonatomic, strong) dispatch_queue_t captureSessionQueue; /// An internal camera object that manages camera's state and performs camera operations. -@property(nonatomic, strong) FLTCam * _Nullable camera; +@property(nonatomic, strong) FLTCam *_Nullable camera; /// Inject @p FlutterTextureRegistry and @p FlutterBinaryMessenger for unit testing. -- (nonnull instancetype)initWithRegistry:(NSObject * _Nullable)registry - messenger:(NSObject * _Nullable)messenger; +- (nonnull instancetype)initWithRegistry:(NSObject *_Nullable)registry + messenger:(NSObject *_Nullable)messenger; /// Inject @p FlutterTextureRegistry, @p FlutterBinaryMessenger, and Pigeon callback handler for /// unit testing. -- (nonnull instancetype)initWithRegistry:(NSObject * _Nullable)registry - messenger:(NSObject * _Nullable)messenger - globalAPI:(FCPCameraGlobalEventApi * _Nullable)globalAPI - deviceDiscoverer:(id)deviceDiscoverer - deviceFactory:(CaptureNamedDeviceFactory)deviceFactory - captureSessionFactory:(CaptureSessionFactory)captureSessionFactory NS_DESIGNATED_INITIALIZER; +- (nonnull instancetype)initWithRegistry:(NSObject *_Nullable)registry + messenger:(NSObject *_Nullable)messenger + globalAPI:(FCPCameraGlobalEventApi *_Nullable)globalAPI + deviceDiscoverer:(id)deviceDiscoverer + deviceFactory:(CaptureNamedDeviceFactory)deviceFactory + captureSessionFactory:(CaptureSessionFactory)captureSessionFactory + captureDeviceInputFactory:(id)captureDeviceInputFactory + NS_DESIGNATED_INITIALIZER; /// Hide the default public constructor. - (nonnull instancetype)init NS_UNAVAILABLE; @@ -52,7 +54,8 @@ typedef id _Nonnull (^CaptureNamedDeviceFactory)(NS /// @param completion the callback to inform the Dart side of the plugin of creation. - (void)createCameraOnSessionQueueWithName:(NSString *_Nullable)name settings:(FCPPlatformMediaSettings *)settings - completion:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion; + completion:(void (^)(NSNumber *_Nullable, + FlutterError *_Nullable))completion; @end NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h index eccc484df48..034e6e1ab99 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h @@ -36,8 +36,7 @@ NS_ASSUME_NONNULL_BEGIN /// Initializes an `FLTCam` instance with the given configuration. /// @param error report to the caller if any error happened creating the camera. -- (instancetype)initWithConfiguration:(FLTCamConfiguration *)configuration - error:(NSError **)error; +- (instancetype)initWithConfiguration:(FLTCamConfiguration *)configuration error:(NSError **)error; /// Informs the Dart side of the plugin of the current camera state and capabilities. - (void)reportInitializationState; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h index d5ead448c2f..7ef84d93052 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h @@ -30,7 +30,8 @@ typedef CMVideoDimensions (^VideoDimensionsForFormat)(AVCaptureDeviceFormat *); mediaSettingsWrapper:(FLTCamMediaSettingsAVWrapper *)mediaSettingsWrapper captureDeviceFactory:(CaptureDeviceFactory)captureDeviceFactory captureSessionFactory:(CaptureSessionFactory)captureSessionFactory - captureSessionQueue:(dispatch_queue_t)captureSessionQueue; + captureSessionQueue:(dispatch_queue_t)captureSessionQueue + captureDeviceInputFactory:(id)captureDeviceInputFactory; @property(nonatomic, strong) id deviceOrientationProvider; @property(nonatomic, strong) dispatch_queue_t captureSessionQueue; @@ -42,6 +43,7 @@ typedef CMVideoDimensions (^VideoDimensionsForFormat)(AVCaptureDeviceFormat *); @property(nonatomic, assign) UIDeviceOrientation orientation; @property(nonatomic, strong) id videoCaptureSession; @property(nonatomic, strong) id audioCaptureSession; +@property(nonatomic, strong) id captureDeviceInputFactory; @end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h index 68e789f6694..f672df9e760 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h @@ -66,15 +66,22 @@ NS_ASSUME_NONNULL_BEGIN @end +@protocol FLTCaptureInput +@property(nonatomic, readonly) NSArray *ports; +@end + @protocol FLTCaptureDeviceInputFactory -+ (nullable AVCaptureInput*)deviceInputWithDevice:(id)device - error:(NSError **)error; +- (nullable id)deviceInputWithDevice:(id)device + error:(NSError **)error; @end @interface AVCaptureDevice (FLTCaptureDeviceControlling) @end -@interface AVCaptureDeviceInput (FLTCaptureDeviceInputFactory) +@interface AVCaptureInput (FLTCaptureInput) +@end + +@interface FLTDefaultCaptureDeviceInputFactory : NSObject @end NS_ASSUME_NONNULL_END From 327233de87b5a4ee4df020da294ce43c0d49d91f Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Thu, 9 Jan 2025 10:59:32 +0100 Subject: [PATCH 23/31] Rename FLTCaptureDeviceControlling to FLTCaptureDevice --- .../ios/Runner.xcodeproj/project.pbxproj | 12 +++++----- .../ios/RunnerTests/AvailableCamerasTest.m | 22 +++++++++---------- ...eraCaptureSessionQueueRaceConditionTests.m | 6 ++--- .../ios/RunnerTests/CameraExposureTests.m | 8 +++---- .../ios/RunnerTests/CameraFocusTests.m | 8 +++---- .../ios/RunnerTests/CameraOrientationTests.m | 14 ++++++------ .../RunnerTests/CameraSessionPresetsTests.m | 2 +- .../example/ios/RunnerTests/CameraTestUtils.m | 12 +++++----- .../ios/RunnerTests/FLTCamPhotoCaptureTests.m | 4 ++-- .../Mocks/MockCameraDeviceDiscoverer.h | 2 +- .../Mocks/MockCameraDeviceDiscoverer.m | 2 +- ...DeviceController.h => MockCaptureDevice.h} | 2 +- ...DeviceController.m => MockCaptureDevice.m} | 6 ++--- .../camera_avfoundation/CameraPlugin.m | 8 +++---- .../Sources/camera_avfoundation/FLTCam.m | 4 ++-- .../FLTCamMediaSettingsAVWrapper.m | 10 ++++----- .../FLTCameraDeviceDiscovering.m | 6 ++--- ...DeviceControlling.m => FLTCaptureDevice.m} | 4 ++-- .../include/CameraPlugin.modulemap | 2 +- .../camera_avfoundation/CameraPlugin_Test.h | 4 ++-- .../include/camera_avfoundation/FLTCam.h | 6 ++--- .../camera_avfoundation/FLTCamConfiguration.h | 4 ++-- .../FLTCamMediaSettingsAVWrapper.h | 10 ++++----- .../include/camera_avfoundation/FLTCam_Test.h | 2 +- .../FLTCameraDeviceDiscovering.h | 4 ++-- ...DeviceControlling.h => FLTCaptureDevice.h} | 6 ++--- .../camera_avfoundation/FLTCaptureSession.h | 2 +- 27 files changed, 86 insertions(+), 86 deletions(-) rename packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/{MockCaptureDeviceController.h => MockCaptureDevice.h} (97%) rename packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/{MockCaptureDeviceController.m => MockCaptureDevice.m} (97%) rename packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/{FLTCaptureDeviceControlling.m => FLTCaptureDevice.m} (75%) rename packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/{FLTCaptureDeviceControlling.h => FLTCaptureDevice.h} (93%) diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj index 75ab129b619..130ea2e41ea 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj @@ -23,7 +23,7 @@ 7F29EB292D26A59000740257 /* MockCameraDeviceDiscoverer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F29EB282D26A59000740257 /* MockCameraDeviceDiscoverer.m */; }; 7F29EB412D281C7E00740257 /* MockCaptureSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F29EB402D281C7E00740257 /* MockCaptureSession.m */; }; 7F56D0382D1EDDCE005676A5 /* CameraPermissionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0B0D2BA27DFF2AF00E71E4B /* CameraPermissionTests.m */; }; - 7F87E8022D01FD6F00A3549C /* MockCaptureDeviceController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */; }; + 7F87E8022D01FD6F00A3549C /* MockCaptureDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F87E8012D01FD5600A3549C /* MockCaptureDevice.m */; }; 7F87E80C2D0325D900A3549C /* MockDeviceOrientationProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F87E80B2D0325D700A3549C /* MockDeviceOrientationProvider.m */; }; 7FA99E592D22C75300582559 /* CameraExposureTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FA99E582D22C75300582559 /* CameraExposureTests.m */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; @@ -88,8 +88,8 @@ 7F29EB282D26A59000740257 /* MockCameraDeviceDiscoverer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCameraDeviceDiscoverer.m; sourceTree = ""; }; 7F29EB3E2D281C5800740257 /* MockCaptureSession.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCaptureSession.h; sourceTree = ""; }; 7F29EB402D281C7E00740257 /* MockCaptureSession.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCaptureSession.m; sourceTree = ""; }; - 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCaptureDeviceController.m; sourceTree = ""; }; - 7F87E8032D02FF8C00A3549C /* MockCaptureDeviceController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCaptureDeviceController.h; sourceTree = ""; }; + 7F87E8012D01FD5600A3549C /* MockCaptureDevice.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCaptureDevice.m; sourceTree = ""; }; + 7F87E8032D02FF8C00A3549C /* MockCaptureDevice.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCaptureDevice.h; sourceTree = ""; }; 7F87E80A2D0325B200A3549C /* MockDeviceOrientationProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockDeviceOrientationProvider.h; sourceTree = ""; }; 7F87E80B2D0325D700A3549C /* MockDeviceOrientationProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockDeviceOrientationProvider.m; sourceTree = ""; }; 7FA99E582D22C75300582559 /* CameraExposureTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CameraExposureTests.m; sourceTree = ""; }; @@ -186,8 +186,8 @@ 7F87E80A2D0325B200A3549C /* MockDeviceOrientationProvider.h */, 7F29EB282D26A59000740257 /* MockCameraDeviceDiscoverer.m */, 7F29EB272D26A55300740257 /* MockCameraDeviceDiscoverer.h */, - 7F87E8032D02FF8C00A3549C /* MockCaptureDeviceController.h */, - 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */, + 7F87E8032D02FF8C00A3549C /* MockCaptureDevice.h */, + 7F87E8012D01FD5600A3549C /* MockCaptureDevice.m */, 7F29EB202D269E4300740257 /* MockEventChannel.h */, 7F29EB212D269ED500740257 /* MockEventChannel.m */, 7F29EB3E2D281C5800740257 /* MockCaptureSession.h */, @@ -486,7 +486,7 @@ 7F56D0382D1EDDCE005676A5 /* CameraPermissionTests.m in Sources */, E0F95E3D27A32AB900699390 /* CameraPropertiesTests.m in Sources */, 03BB766B2665316900CE5A93 /* CameraFocusTests.m in Sources */, - 7F87E8022D01FD6F00A3549C /* MockCaptureDeviceController.m in Sources */, + 7F87E8022D01FD6F00A3549C /* MockCaptureDevice.m in Sources */, 7D5FCCD42AEF9D0200FB7108 /* CameraSettingsTests.m in Sources */, 7FA99E592D22C75300582559 /* CameraExposureTests.m in Sources */, E487C86026D686A10034AC92 /* CameraPreviewPauseTests.m in Sources */, diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m index 6029af67bcc..b94f24e8395 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m @@ -10,7 +10,7 @@ @import AVFoundation; #import "MockCameraDeviceDiscoverer.h" -#import "MockCaptureDeviceController.h" +#import "MockCaptureDevice.h" #import "MockCaptureSession.h" @interface AvailableCamerasTest : XCTestCase @@ -28,8 +28,8 @@ - (void)setUp { messenger:nil globalAPI:nil deviceDiscoverer:_mockDeviceDiscoverer - deviceFactory:^id(NSString *name) { - return [[MockCaptureDeviceController alloc] init]; + deviceFactory:^id(NSString *name) { + return [[MockCaptureDevice alloc] init]; } captureSessionFactory:^id { return [[MockCaptureSession alloc] init]; @@ -41,19 +41,19 @@ - (void)testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone { XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; // iPhone 13 Cameras: - MockCaptureDeviceController *wideAngleCamera = [[MockCaptureDeviceController alloc] init]; + MockCaptureDevice *wideAngleCamera = [[MockCaptureDevice alloc] init]; wideAngleCamera.uniqueID = @"0"; wideAngleCamera.position = AVCaptureDevicePositionBack; - MockCaptureDeviceController *frontFacingCamera = [[MockCaptureDeviceController alloc] init]; + MockCaptureDevice *frontFacingCamera = [[MockCaptureDevice alloc] init]; frontFacingCamera.uniqueID = @"1"; frontFacingCamera.position = AVCaptureDevicePositionFront; - MockCaptureDeviceController *ultraWideCamera = [[MockCaptureDeviceController alloc] init]; + MockCaptureDevice *ultraWideCamera = [[MockCaptureDevice alloc] init]; ultraWideCamera.uniqueID = @"2"; ultraWideCamera.position = AVCaptureDevicePositionBack; - MockCaptureDeviceController *telephotoCamera = [[MockCaptureDeviceController alloc] init]; + MockCaptureDevice *telephotoCamera = [[MockCaptureDevice alloc] init]; telephotoCamera.uniqueID = @"3"; telephotoCamera.position = AVCaptureDevicePositionBack; @@ -70,7 +70,7 @@ - (void)testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone { [cameras addObject:ultraWideCamera]; } - _mockDeviceDiscoverer.discoverySessionStub = ^NSArray> *_Nullable( + _mockDeviceDiscoverer.discoverySessionStub = ^NSArray> *_Nullable( NSArray *_Nonnull deviceTypes, AVMediaType _Nonnull mediaType, AVCaptureDevicePosition position) { XCTAssertEqualObjects(deviceTypes, requiredTypes); @@ -100,11 +100,11 @@ - (void)testAvailableCamerasShouldReturnOneCameraOnSingleCameraIPhone { XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; // iPhone 8 Cameras: - MockCaptureDeviceController *wideAngleCamera = [[MockCaptureDeviceController alloc] init]; + MockCaptureDevice *wideAngleCamera = [[MockCaptureDevice alloc] init]; wideAngleCamera.uniqueID = @"0"; wideAngleCamera.position = AVCaptureDevicePositionBack; - MockCaptureDeviceController *frontFacingCamera = [[MockCaptureDeviceController alloc] init]; + MockCaptureDevice *frontFacingCamera = [[MockCaptureDevice alloc] init]; frontFacingCamera.uniqueID = @"1"; frontFacingCamera.position = AVCaptureDevicePositionFront; @@ -118,7 +118,7 @@ - (void)testAvailableCamerasShouldReturnOneCameraOnSingleCameraIPhone { NSMutableArray *cameras = [NSMutableArray array]; [cameras addObjectsFromArray:@[ wideAngleCamera, frontFacingCamera ]]; - _mockDeviceDiscoverer.discoverySessionStub = ^NSArray> *_Nullable( + _mockDeviceDiscoverer.discoverySessionStub = ^NSArray> *_Nullable( NSArray *_Nonnull deviceTypes, AVMediaType _Nonnull mediaType, AVCaptureDevicePosition position) { XCTAssertEqualObjects(deviceTypes, requiredTypes); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m index 2095610dece..fe6db5ca9dc 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m @@ -9,7 +9,7 @@ @import XCTest; #import "MockCameraDeviceDiscoverer.h" -#import "MockCaptureDeviceController.h" +#import "MockCaptureDevice.h" #import "MockCaptureSession.h" @interface CameraCaptureSessionQueueRaceConditionTests : XCTestCase @@ -18,13 +18,13 @@ @interface CameraCaptureSessionQueueRaceConditionTests : XCTestCase @implementation CameraCaptureSessionQueueRaceConditionTests - (void)testFixForCaptureSessionQueueNullPointerCrashDueToRaceCondition { - MockCaptureDeviceController *captureDevice = [[MockCaptureDeviceController alloc] init]; + MockCaptureDevice *captureDevice = [[MockCaptureDevice alloc] init]; CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil globalAPI:nil deviceDiscoverer:[[MockCameraDeviceDiscoverer alloc] init] - deviceFactory:^id(NSString *name) { + deviceFactory:^id(NSString *name) { return captureDevice; } captureSessionFactory:^id { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m index 23f57358190..7e4c5a86eb8 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m @@ -7,25 +7,25 @@ @import AVFoundation; #import "CameraTestUtils.h" -#import "MockCaptureDeviceController.h" +#import "MockCaptureDevice.h" #import "MockDeviceOrientationProvider.h" @interface CameraExposureTests : XCTestCase @property(readonly, nonatomic) FLTCam *camera; -@property(readonly, nonatomic) MockCaptureDeviceController *mockDevice; +@property(readonly, nonatomic) MockCaptureDevice *mockDevice; @property(readonly, nonatomic) MockDeviceOrientationProvider *mockDeviceOrientationProvider; @end @implementation CameraExposureTests - (void)setUp { - MockCaptureDeviceController *mockDevice = [[MockCaptureDeviceController alloc] init]; + MockCaptureDevice *mockDevice = [[MockCaptureDevice alloc] init]; _mockDeviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; _mockDevice = mockDevice; _camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( nil, nil, nil, - ^id(void) { + ^id(void) { return mockDevice; }, _mockDeviceOrientationProvider); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m index 18fd29d89f3..7c2355c33da 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m @@ -10,25 +10,25 @@ @import AVFoundation; #import "CameraTestUtils.h" -#import "MockCaptureDeviceController.h" +#import "MockCaptureDevice.h" #import "MockDeviceOrientationProvider.h" @interface CameraFocusTests : XCTestCase @property(readonly, nonatomic) FLTCam *camera; -@property(readonly, nonatomic) MockCaptureDeviceController *mockDevice; +@property(readonly, nonatomic) MockCaptureDevice *mockDevice; @property(readonly, nonatomic) MockDeviceOrientationProvider *mockDeviceOrientationProvider; @end @implementation CameraFocusTests - (void)setUp { - MockCaptureDeviceController *mockDevice = [[MockCaptureDeviceController alloc] init]; + MockCaptureDevice *mockDevice = [[MockCaptureDevice alloc] init]; _mockDevice = mockDevice; _mockDeviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; _camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( nil, nil, nil, - ^id(void) { + ^id(void) { return mockDevice; }, _mockDeviceOrientationProvider); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m index 850ebd7aa0e..fe2c0e1e04d 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m @@ -10,7 +10,7 @@ @import Flutter; #import "MockCameraDeviceDiscoverer.h" -#import "MockCaptureDeviceController.h" +#import "MockCaptureDevice.h" #import "MockCaptureSession.h" #import "MockDeviceOrientationProvider.h" @@ -46,7 +46,7 @@ - (void)setDeviceOrientation:(UIDeviceOrientation)orientation { } } -- (void)setCaptureDevice:(id)device { +- (void)setCaptureDevice:(id)device { self.captureDevice = device; } @@ -67,7 +67,7 @@ - (UIDeviceOrientation)orientation { @interface CameraOrientationTests : XCTestCase @property(readonly, nonatomic) MockCamera *camera; -@property(readonly, nonatomic) MockCaptureDeviceController *mockDevice; +@property(readonly, nonatomic) MockCaptureDevice *mockDevice; @property(readonly, nonatomic) StubGlobalEventApi *eventAPI; @property(readonly, nonatomic) CameraPlugin *cameraPlugin; @property(readonly, nonatomic) MockCameraDeviceDiscoverer *deviceDiscoverer; @@ -77,7 +77,7 @@ @implementation CameraOrientationTests - (void)setUp { [super setUp]; - MockCaptureDeviceController *mockDevice = [[MockCaptureDeviceController alloc] init]; + MockCaptureDevice *mockDevice = [[MockCaptureDevice alloc] init]; _camera = [[MockCamera alloc] init]; _eventAPI = [[StubGlobalEventApi alloc] init]; _mockDevice = mockDevice; @@ -87,7 +87,7 @@ - (void)setUp { messenger:nil globalAPI:_eventAPI deviceDiscoverer:_deviceDiscoverer - deviceFactory:^id(NSString *name) { + deviceFactory:^id(NSString *name) { return mockDevice; } captureSessionFactory:^id _Nonnull { @@ -162,14 +162,14 @@ - (void)testOrientationChanged_noRetainCycle { dispatch_queue_t captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL); __weak CameraPlugin *weakPlugin; - __weak MockCaptureDeviceController *weakDevice = _mockDevice; + __weak MockCaptureDevice *weakDevice = _mockDevice; @autoreleasepool { CameraPlugin *plugin = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil globalAPI:_eventAPI deviceDiscoverer:_deviceDiscoverer - deviceFactory:^id(NSString *name) { + deviceFactory:^id(NSString *name) { return weakDevice; } captureSessionFactory:^id _Nonnull { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m index 5a5c9135d87..9f7092f6e52 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSessionPresetsTests.m @@ -25,7 +25,7 @@ - (void)testResolutionPresetWithBestFormat_mustUpdateCaptureSessionPreset { OCMStub([videoSessionMock addInputWithNoConnections:[OCMArg any]]); id captureFormatMock = OCMClassMock([AVCaptureDeviceFormat class]); - id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDeviceControlling)); + id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDevice)); OCMStub([captureDeviceMock formats]).andReturn(@[ captureFormatMock ]); OCMExpect([captureDeviceMock activeFormat]).andReturn(captureFormatMock); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m index c1b00aba6f6..7dbcbd79b26 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m @@ -8,7 +8,7 @@ @import AVFoundation; @import camera_avfoundation; -#import "MockCaptureDeviceController.h" +#import "MockCaptureDevice.h" #import "MockCaptureSession.h" #import "MockDeviceOrientationProvider.h" @@ -77,7 +77,7 @@ frameRateRangeMock2 ]); - id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDeviceControlling)); + id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDevice)); OCMStub([captureDeviceMock lockForConfiguration:[OCMArg setTo:nil]]).andReturn(YES); OCMStub([captureDeviceMock formats]).andReturn((@[ captureDeviceFormatMock1, captureDeviceFormatMock2 @@ -93,7 +93,7 @@ FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] initWithMediaSettings:mediaSettings mediaSettingsWrapper:mediaSettingsAVWrapper - captureDeviceFactory:captureDeviceFactory ?: ^id(void) { + captureDeviceFactory:captureDeviceFactory ?: ^id(void) { return captureDeviceMock; } captureSessionFactory:^id _Nonnull{ @@ -149,12 +149,12 @@ OCMStub([audioSessionMock addInputWithNoConnections:[OCMArg any]]); OCMStub([audioSessionMock canSetSessionPreset:[OCMArg any]]).andReturn(YES); - id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDeviceControlling)); + id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDevice)); FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] - captureDeviceFactory:^id(void) { + captureDeviceFactory:^id(void) { return captureDeviceMock; } captureSessionFactory:^id _Nonnull { @@ -184,7 +184,7 @@ FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] - captureDeviceFactory:^id(void) { + captureDeviceFactory:^id(void) { return captureDevice; } captureSessionFactory:^id _Nonnull { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m index 90c115936e0..f68301d86f2 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m @@ -177,7 +177,7 @@ - (void)testCaptureToFile_handlesTorchMode { [self expectationWithDescription: @"Must send file path to result if save photo delegate completes with file path."]; - id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDeviceControlling)); + id captureDeviceMock = OCMProtocolMock(@protocol(FLTCaptureDevice)); OCMStub([captureDeviceMock hasTorch]).andReturn(YES); OCMStub([captureDeviceMock isTorchAvailable]).andReturn(YES); OCMStub([captureDeviceMock torchMode]).andReturn(AVCaptureTorchModeAuto); @@ -189,7 +189,7 @@ - (void)testCaptureToFile_handlesTorchMode { FLTCam *cam = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( captureSessionQueue, nil, nil, - ^id(void) { + ^id(void) { return captureDeviceMock; }, nil); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h index 87feaf3314d..b6038f292ab 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h @@ -9,7 +9,7 @@ NS_ASSUME_NONNULL_BEGIN @interface MockCameraDeviceDiscoverer : NSObject @property(nonatomic, copy) - NSArray> *_Nullable (^discoverySessionStub) + NSArray> *_Nullable (^discoverySessionStub) (NSArray *deviceTypes, AVMediaType mediaType, AVCaptureDevicePosition position); @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.m index bbc31702e59..3a8c2cc63dc 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.m @@ -6,7 +6,7 @@ @implementation MockCameraDeviceDiscoverer -- (NSArray> *) +- (NSArray> *) discoverySessionWithDeviceTypes:(NSArray *)deviceTypes mediaType:(AVMediaType)mediaType position:(AVCaptureDevicePosition)position { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h similarity index 97% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.h rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h index 637b3eb1473..e705d7fa0f0 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h @@ -10,7 +10,7 @@ NS_ASSUME_NONNULL_BEGIN -@interface MockCaptureDeviceController : NSObject +@interface MockCaptureDevice : NSObject @property(nonatomic, assign) NSString *uniqueID; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m similarity index 97% rename from packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.m rename to packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m index c6fa40c7bab..e1f11a17567 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDeviceController.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m @@ -8,9 +8,9 @@ #endif @import AVFoundation; -#import "MockCaptureDeviceController.h" +#import "MockCaptureDevice.h" -@implementation MockCaptureDeviceController +@implementation MockCaptureDevice - (void)setActiveFormat:(AVCaptureDeviceFormat *)format { _activeFormat = format; @@ -142,7 +142,7 @@ - (nonnull instancetype)initWithMockDeviceInput:(nonnull id)moc return self; } -- (id)deviceInputWithDevice:(id)device +- (id)deviceInputWithDevice:(id)device error:(NSError **)error { return _mockDeviceInput; } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m index daa207c9138..0dcefc69fbf 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m @@ -47,7 +47,7 @@ - (instancetype)initWithRegistry:(NSObject *)registry messenger:messenger globalAPI:[[FCPCameraGlobalEventApi alloc] initWithBinaryMessenger:messenger] deviceDiscoverer:[[FLTDefaultCameraDeviceDiscoverer alloc] init] - deviceFactory:^id(NSString *name) { + deviceFactory:^id(NSString *name) { return [AVCaptureDevice deviceWithUniqueID:name]; } captureSessionFactory:^id(void) { @@ -137,13 +137,13 @@ - (void)availableCamerasWithCompletion: if (@available(iOS 13.0, *)) { [discoveryDevices addObject:AVCaptureDeviceTypeBuiltInUltraWideCamera]; } - NSArray> *devices = + NSArray> *devices = [self.deviceDiscoverer discoverySessionWithDeviceTypes:discoveryDevices mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified]; NSMutableArray *reply = [[NSMutableArray alloc] initWithCapacity:devices.count]; - for (id device in devices) { + for (id device in devices) { FCPPlatformCameraLensDirection lensFacing; switch (device.position) { case AVCaptureDevicePositionBack: @@ -499,7 +499,7 @@ - (void)sessionQueueCreateCameraWithName:(NSString *)name FLTCamConfiguration *camConfiguration = [[FLTCamConfiguration alloc] initWithMediaSettings:settings mediaSettingsWrapper:mediaSettingsAVWrapper - captureDeviceFactory:^id _Nonnull { + captureDeviceFactory:^id _Nonnull { return self.captureDeviceFactory(name); } captureSessionFactory:_captureSessionFactory diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 4449dc26b19..cb2bc7cf992 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -9,7 +9,7 @@ @import Flutter; #import -#import "./include/camera_avfoundation/FLTCaptureDeviceControlling.h" +#import "./include/camera_avfoundation/FLTCaptureDevice.h" #import "./include/camera_avfoundation/FLTDeviceOrientationProviding.h" #import "./include/camera_avfoundation/FLTEventChannel.h" #import "./include/camera_avfoundation/FLTSavePhotoDelegate.h" @@ -1001,7 +1001,7 @@ - (void)applyFocusMode { } - (void)applyFocusMode:(FCPPlatformFocusMode)focusMode - onDevice:(id)captureDevice { + onDevice:(id)captureDevice { [captureDevice lockForConfiguration:nil]; switch (focusMode) { case FCPPlatformFocusModeLocked: diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m index 21a0d9a68ee..c8420f751b5 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m @@ -3,16 +3,16 @@ // found in the LICENSE file. #import "./include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h" -#import "./include/camera_avfoundation/FLTCaptureDeviceControlling.h" +#import "./include/camera_avfoundation/FLTCaptureDevice.h" @implementation FLTCamMediaSettingsAVWrapper -- (BOOL)lockDevice:(id)captureDevice +- (BOOL)lockDevice:(id)captureDevice error:(NSError *_Nullable *_Nullable)outError { return [captureDevice lockForConfiguration:outError]; } -- (void)unlockDevice:(id)captureDevice { +- (void)unlockDevice:(id)captureDevice { return [captureDevice unlockForConfiguration]; } @@ -25,12 +25,12 @@ - (void)commitConfigurationForSession:(AVCaptureSession *)videoCaptureSession { } - (void)setMinFrameDuration:(CMTime)duration - onDevice:(id)captureDevice { + onDevice:(id)captureDevice { captureDevice.activeVideoMinFrameDuration = duration; } - (void)setMaxFrameDuration:(CMTime)duration - onDevice:(id)captureDevice { + onDevice:(id)captureDevice { captureDevice.activeVideoMaxFrameDuration = duration; } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m index 39322f808de..25189ff6c3b 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m @@ -8,7 +8,7 @@ @implementation FLTDefaultCameraDeviceDiscoverer -- (NSArray> *) +- (NSArray> *) discoverySessionWithDeviceTypes:(NSArray *)deviceTypes mediaType:(AVMediaType)mediaType position:(AVCaptureDevicePosition)position { @@ -18,10 +18,10 @@ @implementation FLTDefaultCameraDeviceDiscoverer position:position]; NSArray *devices = discoverySession.devices; - NSMutableArray> *deviceControllers = [NSMutableArray array]; + NSMutableArray> *deviceControllers = [NSMutableArray array]; for (AVCaptureDevice *device in devices) { - [deviceControllers addObject:(id)device]; + [deviceControllers addObject:(id)device]; } return deviceControllers; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m similarity index 75% rename from packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m rename to packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m index 367d7747086..01fe1147065 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m @@ -4,11 +4,11 @@ @import Flutter; -#import "FLTCaptureDeviceControlling.h" +#import "FLTCaptureDevice.h" @implementation FLTDefaultCaptureDeviceInputFactory -- (AVCaptureInput *)deviceInputWithDevice:(id)device +- (AVCaptureInput *)deviceInputWithDevice:(id)device error:(NSError **)error { return [AVCaptureDeviceInput deviceInputWithDevice:device error:error]; } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap index 9572ba9d8d2..394fba5d570 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/CameraPlugin.modulemap @@ -6,7 +6,7 @@ framework module camera_avfoundation { explicit module Test { header "FLTCameraDeviceDiscovering.h" - header "FLTCaptureDeviceControlling.h" + header "FLTCaptureDevice.h" header "FLTCaptureSession.h" header "FLTDeviceOrientationProviding.h" header "FLTEventChannel.h" diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h index 4f3b31466ef..dbc55e11c97 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h @@ -8,12 +8,12 @@ #import "FLTCam.h" #import "FLTCamConfiguration.h" #import "FLTCameraDeviceDiscovering.h" -#import "FLTCaptureDeviceControlling.h" +#import "FLTCaptureDevice.h" #import "messages.g.h" NS_ASSUME_NONNULL_BEGIN -typedef id _Nonnull (^CaptureNamedDeviceFactory)(NSString *name); +typedef id _Nonnull (^CaptureNamedDeviceFactory)(NSString *name); /// APIs exposed for unit testing. @interface CameraPlugin () diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h index 034e6e1ab99..b90c9b63a40 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h @@ -9,7 +9,7 @@ #import "CameraProperties.h" #import "FLTCamConfiguration.h" #import "FLTCamMediaSettingsAVWrapper.h" -#import "FLTCaptureDeviceControlling.h" +#import "FLTCaptureDevice.h" #import "FLTDeviceOrientationProviding.h" #import "messages.g.h" @@ -18,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN /// A class that manages camera's state and performs camera operations. @interface FLTCam : NSObject -@property(readonly, nonatomic) id captureDevice; +@property(readonly, nonatomic) id captureDevice; @property(readonly, nonatomic) CGSize previewSize; @property(assign, nonatomic) BOOL isPreviewPaused; @property(nonatomic, copy) void (^onFrameAvailable)(void); @@ -85,7 +85,7 @@ NS_ASSUME_NONNULL_BEGIN /// @param focusMode The focus mode that should be applied to the @captureDevice instance. /// @param captureDevice The AVCaptureDevice to which the @focusMode will be applied. - (void)applyFocusMode:(FCPPlatformFocusMode)focusMode - onDevice:(id)captureDevice; + onDevice:(id)captureDevice; - (void)pausePreview; - (void)resumePreview; - (void)setDescriptionWhileRecording:(NSString *)cameraName diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h index 7ef84d93052..b0034d0fd6c 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h @@ -8,7 +8,7 @@ #import "CameraProperties.h" #import "FLTCamMediaSettingsAVWrapper.h" -#import "FLTCaptureDeviceControlling.h" +#import "FLTCaptureDevice.h" #import "FLTCaptureSession.h" #import "FLTDeviceOrientationProviding.h" @@ -16,7 +16,7 @@ NS_ASSUME_NONNULL_BEGIN /// Factory block returning an AVCaptureDevice. /// Used in tests to inject a device into FLTCam. -typedef id _Nonnull (^CaptureDeviceFactory)(void); +typedef id _Nonnull (^CaptureDeviceFactory)(void); typedef id _Nonnull (^CaptureSessionFactory)(void); diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h index 8d95cf02afe..b00ccbfc329 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h @@ -5,7 +5,7 @@ @import AVFoundation; @import Foundation; -#import "FLTCaptureDeviceControlling.h" +#import "FLTCaptureDevice.h" NS_ASSUME_NONNULL_BEGIN @@ -27,7 +27,7 @@ NS_ASSUME_NONNULL_BEGIN * @param outError The optional error. * @result A BOOL indicating whether the device was successfully locked for configuration. */ -- (BOOL)lockDevice:(id)captureDevice +- (BOOL)lockDevice:(id)captureDevice error:(NSError *_Nullable *_Nullable)outError; /** @@ -35,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN * @abstract Release exclusive control over device hardware properties. * @param captureDevice The capture device. */ -- (void)unlockDevice:(id)captureDevice; +- (void)unlockDevice:(id)captureDevice; /** * @method beginConfigurationForSession: @@ -61,7 +61,7 @@ NS_ASSUME_NONNULL_BEGIN * @param captureDevice The capture device */ - (void)setMinFrameDuration:(CMTime)duration - onDevice:(id)captureDevice; + onDevice:(id)captureDevice; /** * @method setMaxFrameDuration:onDevice: @@ -71,7 +71,7 @@ NS_ASSUME_NONNULL_BEGIN * @param captureDevice The capture device */ - (void)setMaxFrameDuration:(CMTime)duration - onDevice:(id)captureDevice; + onDevice:(id)captureDevice; /** * @method assetWriterAudioInputWithOutputSettings: diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h index 96ae24931e5..5651755d895 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam_Test.h @@ -3,7 +3,7 @@ // found in the LICENSE file. #import "FLTCam.h" -#import "FLTCaptureDeviceControlling.h" +#import "FLTCaptureDevice.h" #import "FLTDeviceOrientationProviding.h" #import "FLTSavePhotoDelegate.h" diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCameraDeviceDiscovering.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCameraDeviceDiscovering.h index 101ffc9aa54..f869a3f4f3b 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCameraDeviceDiscovering.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCameraDeviceDiscovering.h @@ -4,12 +4,12 @@ @import AVFoundation; -#import "FLTCaptureDeviceControlling.h" +#import "FLTCaptureDevice.h" NS_ASSUME_NONNULL_BEGIN @protocol FLTCameraDeviceDiscovering -- (NSArray> *) +- (NSArray> *) discoverySessionWithDeviceTypes:(NSArray *)deviceTypes mediaType:(AVMediaType)mediaType position:(AVCaptureDevicePosition)position; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h similarity index 93% rename from packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h rename to packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h index f672df9e760..18ef724dcab 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h @@ -7,7 +7,7 @@ NS_ASSUME_NONNULL_BEGIN -@protocol FLTCaptureDeviceControlling +@protocol FLTCaptureDevice // Device - (NSString *)uniqueID; @@ -71,11 +71,11 @@ NS_ASSUME_NONNULL_BEGIN @end @protocol FLTCaptureDeviceInputFactory -- (nullable id)deviceInputWithDevice:(id)device +- (nullable id)deviceInputWithDevice:(id)device error:(NSError **)error; @end -@interface AVCaptureDevice (FLTCaptureDeviceControlling) +@interface AVCaptureDevice (FLTCaptureDevice) @end @interface AVCaptureInput (FLTCaptureInput) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h index 3758695b707..4cf0537f0af 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h @@ -4,7 +4,7 @@ @import AVFoundation; -#import "FLTCaptureDeviceControlling.h" +#import "FLTCaptureDevice.h" NS_ASSUME_NONNULL_BEGIN From 6cdf473fc0b993c8e4639a41b4f5e5523aa294d8 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Fri, 24 Jan 2025 14:42:29 +0100 Subject: [PATCH 24/31] Fix conflicts --- .../ios/Runner.xcodeproj/project.pbxproj | 33 ++-- .../ios/RunnerTests/CameraExposureTests.m | 1 - .../ios/RunnerTests/CameraOrientationTests.m | 2 - .../RunnerTests/MockCaptureDeviceController.h | 105 ----------- .../RunnerTests/MockCaptureDeviceController.m | 111 ----------- .../MockDeviceOrientationProvider.h | 17 -- .../MockDeviceOrientationProvider.m | 14 -- .../ios/RunnerTests/Mocks/MockCaptureDevice.h | 51 +++++- .../ios/RunnerTests/Mocks/MockCaptureDevice.m | 41 ++--- .../RunnerTests/Mocks/MockCaptureSession.h | 1 + .../RunnerTests/Mocks/MockCaptureSession.m | 9 +- .../Mocks/MockDeviceOrientationProvider.m | 4 +- .../Sources/camera_avfoundation/FLTCam.m | 4 +- .../FLTCaptureDeviceControlling.m | 172 ------------------ .../FLTCaptureDeviceControlling.h | 79 -------- .../camera_avfoundation/FLTCaptureSession.h | 1 + 16 files changed, 85 insertions(+), 560 deletions(-) delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.h delete mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.m delete mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m delete mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj index 785d782f6c0..4350a7a91e1 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj @@ -23,11 +23,9 @@ 7F29EB292D26A59000740257 /* MockCameraDeviceDiscoverer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F29EB282D26A59000740257 /* MockCameraDeviceDiscoverer.m */; }; 7F29EB412D281C7E00740257 /* MockCaptureSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F29EB402D281C7E00740257 /* MockCaptureSession.m */; }; 7F56D0382D1EDDCE005676A5 /* CameraPermissionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0B0D2BA27DFF2AF00E71E4B /* CameraPermissionTests.m */; }; - 7F87E8022D01FD6F00A3549C /* MockCaptureDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F87E8012D01FD5600A3549C /* MockCaptureDevice.m */; }; - 7F56D0382D1EDDCE005676A5 /* CameraPermissionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0B0D2BA27DFF2AF00E71E4B /* CameraPermissionTests.m */; }; - 7F87E8022D01FD6F00A3549C /* MockCaptureDeviceController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */; }; - 7F87E80C2D0325D900A3549C /* MockDeviceOrientationProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F87E80B2D0325D700A3549C /* MockDeviceOrientationProvider.m */; }; 7FA99E592D22C75300582559 /* CameraExposureTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FA99E582D22C75300582559 /* CameraExposureTests.m */; }; + 7FCEDD352D43C2B900EA1CA8 /* MockDeviceOrientationProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FCEDD342D43C2B900EA1CA8 /* MockDeviceOrientationProvider.m */; }; + 7FCEDD362D43C2B900EA1CA8 /* MockCaptureDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FCEDD322D43C2B900EA1CA8 /* MockCaptureDevice.m */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; @@ -90,13 +88,11 @@ 7F29EB282D26A59000740257 /* MockCameraDeviceDiscoverer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCameraDeviceDiscoverer.m; sourceTree = ""; }; 7F29EB3E2D281C5800740257 /* MockCaptureSession.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCaptureSession.h; sourceTree = ""; }; 7F29EB402D281C7E00740257 /* MockCaptureSession.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCaptureSession.m; sourceTree = ""; }; - 7F87E8012D01FD5600A3549C /* MockCaptureDevice.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCaptureDevice.m; sourceTree = ""; }; - 7F87E8032D02FF8C00A3549C /* MockCaptureDevice.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCaptureDevice.h; sourceTree = ""; }; - 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCaptureDeviceController.m; sourceTree = ""; }; - 7F87E8032D02FF8C00A3549C /* MockCaptureDeviceController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCaptureDeviceController.h; sourceTree = ""; }; - 7F87E80A2D0325B200A3549C /* MockDeviceOrientationProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockDeviceOrientationProvider.h; sourceTree = ""; }; - 7F87E80B2D0325D700A3549C /* MockDeviceOrientationProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockDeviceOrientationProvider.m; sourceTree = ""; }; 7FA99E582D22C75300582559 /* CameraExposureTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CameraExposureTests.m; sourceTree = ""; }; + 7FCEDD312D43C2B900EA1CA8 /* MockCaptureDevice.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCaptureDevice.h; sourceTree = ""; }; + 7FCEDD322D43C2B900EA1CA8 /* MockCaptureDevice.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCaptureDevice.m; sourceTree = ""; }; + 7FCEDD332D43C2B900EA1CA8 /* MockDeviceOrientationProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockDeviceOrientationProvider.h; sourceTree = ""; }; + 7FCEDD342D43C2B900EA1CA8 /* MockDeviceOrientationProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockDeviceOrientationProvider.m; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -150,10 +146,6 @@ isa = PBXGroup; children = ( 7F29EB3F2D281C6D00740257 /* Mocks */, - 7F87E80B2D0325D700A3549C /* MockDeviceOrientationProvider.m */, - 7F87E80A2D0325B200A3549C /* MockDeviceOrientationProvider.h */, - 7F87E8032D02FF8C00A3549C /* MockCaptureDeviceController.h */, - 7F87E8012D01FD5600A3549C /* MockCaptureDeviceController.m */, 7D5FCCD32AEF9D0200FB7108 /* CameraSettingsTests.m */, 03BB766A2665316900CE5A93 /* CameraFocusTests.m */, 7FA99E582D22C75300582559 /* CameraExposureTests.m */, @@ -190,12 +182,12 @@ 7F29EB3F2D281C6D00740257 /* Mocks */ = { isa = PBXGroup; children = ( - 7F87E80B2D0325D700A3549C /* MockDeviceOrientationProvider.m */, - 7F87E80A2D0325B200A3549C /* MockDeviceOrientationProvider.h */, + 7FCEDD312D43C2B900EA1CA8 /* MockCaptureDevice.h */, + 7FCEDD322D43C2B900EA1CA8 /* MockCaptureDevice.m */, + 7FCEDD332D43C2B900EA1CA8 /* MockDeviceOrientationProvider.h */, + 7FCEDD342D43C2B900EA1CA8 /* MockDeviceOrientationProvider.m */, 7F29EB282D26A59000740257 /* MockCameraDeviceDiscoverer.m */, 7F29EB272D26A55300740257 /* MockCameraDeviceDiscoverer.h */, - 7F87E8032D02FF8C00A3549C /* MockCaptureDevice.h */, - 7F87E8012D01FD5600A3549C /* MockCaptureDevice.m */, 7F29EB202D269E4300740257 /* MockEventChannel.h */, 7F29EB212D269ED500740257 /* MockEventChannel.m */, 7F29EB3E2D281C5800740257 /* MockCaptureSession.h */, @@ -494,12 +486,9 @@ 7F56D0382D1EDDCE005676A5 /* CameraPermissionTests.m in Sources */, E0F95E3D27A32AB900699390 /* CameraPropertiesTests.m in Sources */, 03BB766B2665316900CE5A93 /* CameraFocusTests.m in Sources */, - 7F87E8022D01FD6F00A3549C /* MockCaptureDevice.m in Sources */, - 7F87E8022D01FD6F00A3549C /* MockCaptureDeviceController.m in Sources */, 7D5FCCD42AEF9D0200FB7108 /* CameraSettingsTests.m in Sources */, 7FA99E592D22C75300582559 /* CameraExposureTests.m in Sources */, E487C86026D686A10034AC92 /* CameraPreviewPauseTests.m in Sources */, - 7F87E80C2D0325D900A3549C /* MockDeviceOrientationProvider.m in Sources */, E071CF7427B31DE4006EF3BA /* FLTCamSampleBufferTests.m in Sources */, 7F29EB222D269ED500740257 /* MockEventChannel.m in Sources */, E04F108627A87CA600573D0C /* FLTSavePhotoDelegateTests.m in Sources */, @@ -513,6 +502,8 @@ E0C6E2022770F01A00EA6AA3 /* ThreadSafeEventChannelTests.m in Sources */, 7F29EB412D281C7E00740257 /* MockCaptureSession.m in Sources */, E01EE4A82799F3A5008C1950 /* QueueUtilsTests.m in Sources */, + 7FCEDD352D43C2B900EA1CA8 /* MockDeviceOrientationProvider.m in Sources */, + 7FCEDD362D43C2B900EA1CA8 /* MockCaptureDevice.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m index 1f595cdabe1..11a7ff3ba54 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m @@ -8,7 +8,6 @@ #import "CameraTestUtils.h" #import "MockCaptureDevice.h" -#import "MockCaptureDeviceController.h" #import "MockDeviceOrientationProvider.h" @interface CameraExposureTests : XCTestCase diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m index 6a6c9c797a6..fe2c0e1e04d 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m @@ -14,8 +14,6 @@ #import "MockCaptureSession.h" #import "MockDeviceOrientationProvider.h" -#import "MockCaptureDeviceController.h" - @interface StubGlobalEventApi : FCPCameraGlobalEventApi @property(nonatomic) BOOL called; @property(nonatomic) FCPPlatformDeviceOrientation lastOrientation; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h deleted file mode 100644 index bd7b2ee9a58..00000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.h +++ /dev/null @@ -1,105 +0,0 @@ -// 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. - -@import camera_avfoundation; -#if __has_include() -@import camera_avfoundation.Test; -#endif -@import AVFoundation; - -NS_ASSUME_NONNULL_BEGIN - -@interface MockCaptureDeviceController : NSObject -// Position/Orientation -@property(nonatomic, assign) AVCaptureDevicePosition position; - -// Format/Configuration -@property(nonatomic, strong) AVCaptureDeviceFormat *activeFormat; -@property(nonatomic, strong) NSArray *formats; -/// Overrides the default implementation of setting active format. -/// @param format The format being set -@property(nonatomic, copy) void (^setActiveFormatStub)(AVCaptureDeviceFormat *format); - -// Flash/Torch -@property(nonatomic, assign) BOOL hasFlash; -@property(nonatomic, assign) BOOL hasTorch; -@property(nonatomic, assign) BOOL isTorchAvailable; -@property(nonatomic, assign) AVCaptureTorchMode torchMode; -/// Overrides the default implementation of setting torch mode. -/// @param mode The torch mode being set -@property(nonatomic, copy) void (^setTorchModeStub)(AVCaptureTorchMode mode); -@property(nonatomic, assign) BOOL flashModeSupported; - -// Focus -@property(nonatomic, assign) BOOL focusPointOfInterestSupported; -/// Overrides the default implementation of checking if focus mode is supported. -/// @param mode The focus mode to check -/// @return Whether the focus mode is supported -@property(nonatomic, copy) BOOL (^isFocusModeSupportedStub)(AVCaptureFocusMode mode); -@property(nonatomic, assign) AVCaptureFocusMode focusMode; -/// Overrides the default implementation of setting focus mode. -/// @param mode The focus mode being set -@property(nonatomic, copy) void (^setFocusModeStub)(AVCaptureFocusMode mode); -@property(nonatomic, assign) CGPoint focusPointOfInterest; -/// Overrides the default implementation of setting focus point of interest. -/// @param point The focus point being set -@property(nonatomic, copy) void (^setFocusPointOfInterestStub)(CGPoint point); - -// Exposure -@property(nonatomic, assign) BOOL exposurePointOfInterestSupported; -@property(nonatomic, assign) AVCaptureExposureMode exposureMode; -@property(nonatomic, assign) BOOL exposureModeSupported; -/// Overrides the default implementation of setting exposure mode. -/// @param mode The exposure mode being set -@property(nonatomic, copy) void (^setExposureModeStub)(AVCaptureExposureMode mode); -@property(nonatomic, assign) CGPoint exposurePointOfInterest; -/// Override the default implementation of setting exposure point of interest. -/// @param point The exposure point being set -@property(nonatomic, copy) void (^setExposurePointOfInterestStub)(CGPoint point); -@property(nonatomic, assign) float minExposureTargetBias; -@property(nonatomic, assign) float maxExposureTargetBias; -/// Overrides the default implementation of setting exposure target bias. -/// @param bias The exposure bias being set -/// @param handler The completion handler to be called -@property(nonatomic, copy) void (^setExposureTargetBiasStub) - (float bias, void (^_Nullable handler)(CMTime)); - -// Zoom -@property(nonatomic, assign) float maxAvailableVideoZoomFactor; -@property(nonatomic, assign) float minAvailableVideoZoomFactor; -@property(nonatomic, assign) float videoZoomFactor; -/// Overrides the default implementation of setting video zoom factor. -/// @param factor The zoom factor being set -@property(nonatomic, copy) void (^setVideoZoomFactorStub)(float factor); - -// Camera Properties -@property(nonatomic, assign) float lensAperture; -@property(nonatomic, assign) CMTime exposureDuration; -@property(nonatomic, assign) float ISO; - -// Configuration Lock -/// Overrides the default implementation of locking device for configuration. -/// @param error Error pointer to be set if lock fails -@property(nonatomic, copy) BOOL (^lockForConfigurationStub)(NSError **error); -/// Overrides the default implementation of unlocking device configuration. -@property(nonatomic, copy) void (^unlockForConfigurationStub)(void); - -// Frame Duration -@property(nonatomic, assign) CMTime activeVideoMinFrameDuration; -@property(nonatomic, assign) CMTime activeVideoMaxFrameDuration; -/// Overrides the default implementation of setting minimum frame duration. -/// @param duration The minimum frame duration being set -@property(nonatomic, copy) void (^setActiveVideoMinFrameDurationStub)(CMTime duration); -/// Overrides the default implementation of setting maximum frame duration. -/// @param duration The maximum frame duration being set -@property(nonatomic, copy) void (^setActiveVideoMaxFrameDurationStub)(CMTime duration); - -// Input Creation -/// Overrides the default implementation of creating capture input. -/// @param error Error pointer to be set if creation fails -@property(nonatomic, copy) AVCaptureInput * (^createInputStub)(NSError **error); - -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m deleted file mode 100644 index 38403656fff..00000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockCaptureDeviceController.m +++ /dev/null @@ -1,111 +0,0 @@ - -// 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. - -#import "MockCaptureDeviceController.h" - -@import camera_avfoundation; -#if __has_include() -@import camera_avfoundation.Test; -#endif -@import AVFoundation; - -@implementation MockCaptureDeviceController - -- (void)setActiveFormat:(AVCaptureDeviceFormat *)format { - if (self.setActiveFormatStub) { - self.setActiveFormatStub(format); - } -} - -- (BOOL)isFlashModeSupported:(AVCaptureFlashMode)mode { - return self.flashModeSupported; -} - -- (void)setTorchMode:(AVCaptureTorchMode)mode { - if (self.setTorchModeStub) { - self.setTorchModeStub(mode); - } -} - -- (BOOL)isFocusModeSupported:(AVCaptureFocusMode)mode { - if (self.isFocusModeSupportedStub) { - return self.isFocusModeSupportedStub(mode); - } - return NO; -} - -- (void)setFocusMode:(AVCaptureFocusMode)mode { - if (self.setFocusModeStub) { - self.setFocusModeStub(mode); - } -} - -- (void)setFocusPointOfInterest:(CGPoint)point { - if (self.setFocusPointOfInterestStub) { - self.setFocusPointOfInterestStub(point); - } -} - -- (void)setExposureMode:(AVCaptureExposureMode)mode { - if (self.setExposureModeStub) { - self.setExposureModeStub(mode); - } -} - -- (void)setExposurePointOfInterest:(CGPoint)point { - if (self.setExposurePointOfInterestStub) { - self.setExposurePointOfInterestStub(point); - } -} - -- (void)setExposureTargetBias:(float)bias completionHandler:(void (^)(CMTime))handler { - if (self.setExposureTargetBiasStub) { - self.setExposureTargetBiasStub(bias, handler); - } -} - -- (void)setVideoZoomFactor:(float)factor { - if (self.setVideoZoomFactorStub) { - self.setVideoZoomFactorStub(factor); - } -} - -- (BOOL)lockForConfiguration:(NSError **)error { - if (self.lockForConfigurationStub) { - return self.lockForConfigurationStub(error); - } - return YES; -} - -- (void)unlockForConfiguration { - if (self.unlockForConfigurationStub) { - self.unlockForConfigurationStub(); - } -} - -- (void)setActiveVideoMinFrameDuration:(CMTime)duration { - if (self.setActiveVideoMinFrameDurationStub) { - self.setActiveVideoMinFrameDurationStub(duration); - } -} - -- (void)setActiveVideoMaxFrameDuration:(CMTime)duration { - if (self.setActiveVideoMaxFrameDurationStub) { - self.setActiveVideoMaxFrameDurationStub(duration); - } -} - -- (BOOL)isExposureModeSupported:(AVCaptureExposureMode)mode { - return self.exposureModeSupported; -} - -- (AVCaptureInput *)createInput:(NSError *_Nullable *_Nullable)error { - if (self.createInputStub) { - return self.createInputStub(error); - } - return NULL; -} - -@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.h deleted file mode 100644 index 0421ec66529..00000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.h +++ /dev/null @@ -1,17 +0,0 @@ -// 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. - -@import camera_avfoundation; -#if __has_include() -@import camera_avfoundation.Test; -#endif -@import AVFoundation; - -NS_ASSUME_NONNULL_BEGIN - -@interface MockDeviceOrientationProvider : NSObject -@property(nonatomic, assign) UIDeviceOrientation orientation; -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.m deleted file mode 100644 index 730572b315a..00000000000 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/MockDeviceOrientationProvider.m +++ /dev/null @@ -1,14 +0,0 @@ -// 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. - -#import "MockDeviceOrientationProvider.h" - -@import camera_avfoundation; -#if __has_include() -@import camera_avfoundation.Test; -#endif -@import AVFoundation; - -@implementation MockDeviceOrientationProvider -@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h index e705d7fa0f0..42e8e016c41 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h @@ -20,6 +20,8 @@ NS_ASSUME_NONNULL_BEGIN // Format/Configuration @property(nonatomic, strong) AVCaptureDeviceFormat *activeFormat; @property(nonatomic, strong) NSArray *formats; +/// Overrides the default implementation of setting active format. +/// @param format The format being set @property(nonatomic, copy) void (^setActiveFormatStub)(AVCaptureDeviceFormat *format); // Flash/Torch @@ -27,26 +29,42 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, assign) BOOL hasTorch; @property(nonatomic, assign) BOOL isTorchAvailable; @property(nonatomic, assign) AVCaptureTorchMode torchMode; +/// Overrides the default implementation of setting torch mode. +/// @param mode The torch mode being set @property(nonatomic, copy) void (^setTorchModeStub)(AVCaptureTorchMode mode); @property(nonatomic, assign) BOOL flashModeSupported; // Focus -@property(nonatomic, assign) BOOL isFocusPointOfInterestSupported; +@property(nonatomic, assign) BOOL focusPointOfInterestSupported; +/// Overrides the default implementation of checking if focus mode is supported. +/// @param mode The focus mode to check +/// @return Whether the focus mode is supported @property(nonatomic, copy) BOOL (^isFocusModeSupportedStub)(AVCaptureFocusMode mode); @property(nonatomic, assign) AVCaptureFocusMode focusMode; +/// Overrides the default implementation of setting focus mode. +/// @param mode The focus mode being set @property(nonatomic, copy) void (^setFocusModeStub)(AVCaptureFocusMode mode); @property(nonatomic, assign) CGPoint focusPointOfInterest; +/// Overrides the default implementation of setting focus point of interest. +/// @param point The focus point being set @property(nonatomic, copy) void (^setFocusPointOfInterestStub)(CGPoint point); // Exposure -@property(nonatomic, assign) BOOL isExposurePointOfInterestSupported; +@property(nonatomic, assign) BOOL exposurePointOfInterestSupported; @property(nonatomic, assign) AVCaptureExposureMode exposureMode; @property(nonatomic, assign) BOOL exposureModeSupported; +/// Overrides the default implementation of setting exposure mode. +/// @param mode The exposure mode being set @property(nonatomic, copy) void (^setExposureModeStub)(AVCaptureExposureMode mode); @property(nonatomic, assign) CGPoint exposurePointOfInterest; +/// Override the default implementation of setting exposure point of interest. +/// @param point The exposure point being set @property(nonatomic, copy) void (^setExposurePointOfInterestStub)(CGPoint point); @property(nonatomic, assign) float minExposureTargetBias; @property(nonatomic, assign) float maxExposureTargetBias; +/// Overrides the default implementation of setting exposure target bias. +/// @param bias The exposure bias being set +/// @param handler The completion handler to be called @property(nonatomic, copy) void (^setExposureTargetBiasStub) (float bias, void (^_Nullable handler)(CMTime)); @@ -54,6 +72,8 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, assign) float maxAvailableVideoZoomFactor; @property(nonatomic, assign) float minAvailableVideoZoomFactor; @property(nonatomic, assign) float videoZoomFactor; +/// Overrides the default implementation of setting video zoom factor. +/// @param factor The zoom factor being set @property(nonatomic, copy) void (^setVideoZoomFactorStub)(float factor); // Camera Properties @@ -62,25 +82,36 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, assign) float ISO; // Configuration Lock -@property(nonatomic, assign) BOOL shouldFailConfiguration; -@property(nonatomic, copy) void (^lockForConfigurationStub)(NSError **error); +/// Overrides the default implementation of locking device for configuration. +/// @param error Error pointer to be set if lock fails +@property(nonatomic, copy) BOOL (^lockForConfigurationStub)(NSError **error); +/// Overrides the default implementation of unlocking device configuration. @property(nonatomic, copy) void (^unlockForConfigurationStub)(void); // Frame Duration @property(nonatomic, assign) CMTime activeVideoMinFrameDuration; @property(nonatomic, assign) CMTime activeVideoMaxFrameDuration; +/// Overrides the default implementation of setting minimum frame duration. +/// @param duration The minimum frame duration being set @property(nonatomic, copy) void (^setActiveVideoMinFrameDurationStub)(CMTime duration); +/// Overrides the default implementation of setting maximum frame duration. +/// @param duration The maximum frame duration being set @property(nonatomic, copy) void (^setActiveVideoMaxFrameDurationStub)(CMTime duration); +// Input Creation +/// Overrides the default implementation of creating capture input. +/// @param error Error pointer to be set if creation fails +@property(nonatomic, copy) AVCaptureInput * (^createInputStub)(NSError **error); + @end @interface MockCaptureInput : NSObject -@property(nonatomic, strong) NSArray *ports; -@end + @property(nonatomic, strong) NSArray *ports; + @end -@interface MockCaptureDeviceInputFactory : NSObject -- (nonnull instancetype)initWithMockDeviceInput:(id)mockDeviceInput; -@property(nonatomic, strong) id mockDeviceInput; -@end + @interface MockCaptureDeviceInputFactory : NSObject + - (nonnull instancetype)initWithMockDeviceInput:(id)mockDeviceInput; + @property(nonatomic, strong) id mockDeviceInput; + @end NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m index e1f11a17567..63de5230f0f 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m @@ -2,18 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#import "MockCaptureDevice.h" + @import camera_avfoundation; #if __has_include() @import camera_avfoundation.Test; #endif @import AVFoundation; -#import "MockCaptureDevice.h" - @implementation MockCaptureDevice - (void)setActiveFormat:(AVCaptureDeviceFormat *)format { - _activeFormat = format; if (self.setActiveFormatStub) { self.setActiveFormatStub(format); } @@ -24,7 +23,6 @@ - (BOOL)isFlashModeSupported:(AVCaptureFlashMode)mode { } - (void)setTorchMode:(AVCaptureTorchMode)mode { - _torchMode = mode; if (self.setTorchModeStub) { self.setTorchModeStub(mode); } @@ -38,28 +36,24 @@ - (BOOL)isFocusModeSupported:(AVCaptureFocusMode)mode { } - (void)setFocusMode:(AVCaptureFocusMode)mode { - _focusMode = mode; if (self.setFocusModeStub) { self.setFocusModeStub(mode); } } - (void)setFocusPointOfInterest:(CGPoint)point { - _focusPointOfInterest = point; if (self.setFocusPointOfInterestStub) { self.setFocusPointOfInterestStub(point); } } - (void)setExposureMode:(AVCaptureExposureMode)mode { - _exposureMode = mode; if (self.setExposureModeStub) { self.setExposureModeStub(mode); } } - (void)setExposurePointOfInterest:(CGPoint)point { - _exposurePointOfInterest = point; if (self.setExposurePointOfInterestStub) { self.setExposurePointOfInterestStub(point); } @@ -68,13 +62,10 @@ - (void)setExposurePointOfInterest:(CGPoint)point { - (void)setExposureTargetBias:(float)bias completionHandler:(void (^)(CMTime))handler { if (self.setExposureTargetBiasStub) { self.setExposureTargetBiasStub(bias, handler); - } else if (handler) { - handler(kCMTimeZero); } } - (void)setVideoZoomFactor:(float)factor { - _videoZoomFactor = factor; if (self.setVideoZoomFactorStub) { self.setVideoZoomFactorStub(factor); } @@ -82,14 +73,7 @@ - (void)setVideoZoomFactor:(float)factor { - (BOOL)lockForConfiguration:(NSError **)error { if (self.lockForConfigurationStub) { - self.lockForConfigurationStub(error); - return !self.shouldFailConfiguration; - } - if (self.shouldFailConfiguration) { - if (error) { - *error = [NSError errorWithDomain:@"test" code:0 userInfo:nil]; - } - return NO; + return self.lockForConfigurationStub(error); } return YES; } @@ -101,14 +85,12 @@ - (void)unlockForConfiguration { } - (void)setActiveVideoMinFrameDuration:(CMTime)duration { - _activeVideoMinFrameDuration = duration; if (self.setActiveVideoMinFrameDurationStub) { self.setActiveVideoMinFrameDurationStub(duration); } } - (void)setActiveVideoMaxFrameDuration:(CMTime)duration { - _activeVideoMaxFrameDuration = duration; if (self.setActiveVideoMaxFrameDurationStub) { self.setActiveVideoMaxFrameDurationStub(duration); } @@ -118,6 +100,23 @@ - (BOOL)isExposureModeSupported:(AVCaptureExposureMode)mode { return self.exposureModeSupported; } +- (BOOL)isExposurePointOfInterestSupported { + return self.exposurePointOfInterestSupported; +} + + +- (BOOL)isFocusPointOfInterestSupported { + return self.focusPointOfInterestSupported; +} + + +- (AVCaptureInput *)createInput:(NSError *_Nullable *_Nullable)error { + if (self.createInputStub) { + return self.createInputStub(error); + } + return NULL; +} + @end @implementation MockCaptureInput diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h index 5d14a14115b..c00fa29ad5a 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h @@ -21,6 +21,7 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, strong) NSMutableArray *outputs; @property(nonatomic, assign) BOOL mockCanSetSessionPreset; @property(nonatomic, copy) AVCaptureSessionPreset sessionPreset; +@property(nonatomic, assign) BOOL automaticallyConfiguresApplicationAudioSession; @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.m index 9adb54e90d6..4570386c37d 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.m @@ -40,7 +40,10 @@ - (void)stopRunning { } - (BOOL)canSetSessionPreset:(AVCaptureSessionPreset)preset { - return self.mockCanSetSessionPreset; + if (self.mockCanSetSessionPreset) { + return self.mockCanSetSessionPreset; + } + return YES; } - (void)addConnection:(nonnull AVCaptureConnection *)connection { @@ -77,8 +80,8 @@ - (void)removeOutput:(nonnull AVCaptureOutput *)output { } - (void)setSessionPreset:(AVCaptureSessionPreset)sessionPreset { - if (_setSessionPresetStub) { - _setSessionPresetStub(sessionPreset); + if (self.setSessionPresetStub) { + self.setSessionPresetStub(sessionPreset); } } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceOrientationProvider.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceOrientationProvider.m index 963cb7e96ff..730572b315a 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceOrientationProvider.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockDeviceOrientationProvider.m @@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#import "MockDeviceOrientationProvider.h" + @import camera_avfoundation; #if __has_include() @import camera_avfoundation.Test; #endif @import AVFoundation; -#import "MockDeviceOrientationProvider.h" - @implementation MockDeviceOrientationProvider @end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 7971decb0b9..079114127f6 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -1113,7 +1113,7 @@ - (CGPoint)CGPointForPoint:(nonnull FCPPlatformPoint *)point - (void)setExposurePoint:(FCPPlatformPoint *)point withCompletion:(void (^)(FlutterError *_Nullable))completion { - if (!_captureDevice.exposurePointOfInterestSupported) { + if (!_captureDevice.isExposurePointOfInterestSupported) { completion([FlutterError errorWithCode:@"setExposurePointFailed" message:@"Device does not have exposure point capabilities" details:nil]); @@ -1135,7 +1135,7 @@ - (void)setExposurePoint:(FCPPlatformPoint *)point - (void)setFocusPoint:(FCPPlatformPoint *)point withCompletion:(void (^)(FlutterError *_Nullable))completion { - if (!_captureDevice.focusPointOfInterestSupported) { + if (!_captureDevice.isFocusPointOfInterestSupported) { completion([FlutterError errorWithCode:@"setFocusPointFailed" message:@"Device does not have focus point capabilities" details:nil]); diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m deleted file mode 100644 index 95d3f80519f..00000000000 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDeviceControlling.m +++ /dev/null @@ -1,172 +0,0 @@ -// 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. - -#import "./include/camera_avfoundation/FLTCaptureDeviceControlling.h" - -@interface FLTDefaultCaptureDeviceController () -@property(nonatomic, strong) AVCaptureDevice *device; -@end - -@implementation FLTDefaultCaptureDeviceController - -- (instancetype)initWithDevice:(AVCaptureDevice *)device { - self = [super init]; - if (self) { - _device = device; - } - return self; -} - -// Position/Orientation -- (AVCaptureDevicePosition)position { - return self.device.position; -} - -// Format/Configuration -- (AVCaptureDeviceFormat *)activeFormat { - return self.device.activeFormat; -} - -- (NSArray *)formats { - return self.device.formats; -} - -- (void)setActiveFormat:(AVCaptureDeviceFormat *)format { - self.device.activeFormat = format; -} - -// Flash/Torch -- (BOOL)hasFlash { - return self.device.hasFlash; -} - -- (BOOL)hasTorch { - return self.device.hasTorch; -} - -- (BOOL)isTorchAvailable { - return self.device.isTorchAvailable; -} - -- (AVCaptureTorchMode)torchMode { - return self.device.torchMode; -} - -- (void)setTorchMode:(AVCaptureTorchMode)torchMode { - self.device.torchMode = torchMode; -} - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -- (BOOL)isFlashModeSupported:(AVCaptureFlashMode)mode { - return [self.device isFlashModeSupported:mode]; -} -#pragma clang diagnostic pop - -// Focus -- (BOOL)focusPointOfInterestSupported { - return self.device.focusPointOfInterestSupported; -} - -- (BOOL)isFocusModeSupported:(AVCaptureFocusMode)mode { - return [self.device isFocusModeSupported:mode]; -} - -- (void)setFocusMode:(AVCaptureFocusMode)focusMode { - self.device.focusMode = focusMode; -} - -- (void)setFocusPointOfInterest:(CGPoint)point { - self.device.focusPointOfInterest = point; -} - -// Exposure -- (BOOL)exposurePointOfInterestSupported { - return self.device.exposurePointOfInterestSupported; -} - -- (void)setExposureMode:(AVCaptureExposureMode)exposureMode { - self.device.exposureMode = exposureMode; -} - -- (void)setExposurePointOfInterest:(CGPoint)point { - self.device.exposurePointOfInterest = point; -} - -- (float)minExposureTargetBias { - return self.device.minExposureTargetBias; -} - -- (float)maxExposureTargetBias { - return self.device.maxExposureTargetBias; -} - -- (void)setExposureTargetBias:(float)bias completionHandler:(void (^)(CMTime))handler { - [self.device setExposureTargetBias:bias completionHandler:handler]; -} - -- (BOOL)isExposureModeSupported:(AVCaptureExposureMode)mode { - return [self.device isExposureModeSupported:mode]; -} - -// Zoom -- (float)maxAvailableVideoZoomFactor { - return self.device.maxAvailableVideoZoomFactor; -} - -- (float)minAvailableVideoZoomFactor { - return self.device.minAvailableVideoZoomFactor; -} - -- (float)videoZoomFactor { - return self.device.videoZoomFactor; -} - -- (void)setVideoZoomFactor:(float)factor { - self.device.videoZoomFactor = factor; -} - -// Camera Properties -- (float)lensAperture { - return self.device.lensAperture; -} - -- (CMTime)exposureDuration { - return self.device.exposureDuration; -} - -- (float)ISO { - return self.device.ISO; -} - -// Configuration Lock -- (BOOL)lockForConfiguration:(NSError **)error { - return [self.device lockForConfiguration:error]; -} - -- (void)unlockForConfiguration { - [self.device unlockForConfiguration]; -} - -- (CMTime)activeVideoMinFrameDuration { - return self.device.activeVideoMinFrameDuration; -} - -- (void)setActiveVideoMinFrameDuration:(CMTime)duration { - self.device.activeVideoMinFrameDuration = duration; -} - -- (CMTime)activeVideoMaxFrameDuration { - return self.device.activeVideoMaxFrameDuration; -} - -- (void)setActiveVideoMaxFrameDuration:(CMTime)duration { - self.device.activeVideoMaxFrameDuration = duration; -} - -- (AVCaptureInput *)createInput:(NSError *_Nullable *_Nullable)error { - return [AVCaptureDeviceInput deviceInputWithDevice:_device error:error]; -} - -@end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h deleted file mode 100644 index 38f79408959..00000000000 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDeviceControlling.h +++ /dev/null @@ -1,79 +0,0 @@ -// 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. - -@import AVFoundation; -@import Foundation; - -NS_ASSUME_NONNULL_BEGIN - -/// A protocol which is a direct passthrough to AVCaptureDevice. -/// It exists to allow replacing AVCaptureDevice in tests. -@protocol FLTCaptureDeviceControlling - -// Position/Orientation -- (AVCaptureDevicePosition)position; - -// Format/Configuration -- (AVCaptureDeviceFormat *)activeFormat; -- (NSArray *)formats; -- (void)setActiveFormat:(AVCaptureDeviceFormat *)format; - -// Flash/Torch -- (BOOL)hasFlash; -- (BOOL)hasTorch; -- (BOOL)isTorchAvailable; -- (AVCaptureTorchMode)torchMode; -- (void)setTorchMode:(AVCaptureTorchMode)torchMode; -- (BOOL)isFlashModeSupported:(AVCaptureFlashMode)mode; - -// Focus -- (BOOL)focusPointOfInterestSupported; -- (BOOL)isFocusModeSupported:(AVCaptureFocusMode)mode; -- (void)setFocusMode:(AVCaptureFocusMode)focusMode; -- (void)setFocusPointOfInterest:(CGPoint)point; - -// Exposure -- (BOOL)exposurePointOfInterestSupported; -- (void)setExposureMode:(AVCaptureExposureMode)exposureMode; -- (void)setExposurePointOfInterest:(CGPoint)point; -- (float)minExposureTargetBias; -- (float)maxExposureTargetBias; -- (void)setExposureTargetBias:(float)bias completionHandler:(void (^_Nullable)(CMTime))handler; -- (BOOL)isExposureModeSupported:(AVCaptureExposureMode)mode; - -// Zoom -- (float)maxAvailableVideoZoomFactor; -- (float)minAvailableVideoZoomFactor; -- (float)videoZoomFactor; -- (void)setVideoZoomFactor:(float)factor; - -// Camera Properties -- (float)lensAperture; -- (CMTime)exposureDuration; -- (float)ISO; - -// Configuration Lock -- (BOOL)lockForConfiguration:(NSError **)error; -- (void)unlockForConfiguration; - -// Frame Duration -- (CMTime)activeVideoMinFrameDuration; -- (void)setActiveVideoMinFrameDuration:(CMTime)duration; -- (CMTime)activeVideoMaxFrameDuration; -- (void)setActiveVideoMaxFrameDuration:(CMTime)duration; - -- (AVCaptureInput *)createInput:(NSError *_Nullable *_Nullable)error; - -@end - -/// A default implementation of FLTCaptureDeviceControlling protocol which -/// wraps an instance of AVCaptureDevice. -@interface FLTDefaultCaptureDeviceController : NSObject - -/// Initializes the controller with the given device. -- (instancetype)initWithDevice:(AVCaptureDevice *)device; - -@end - -NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h index 4cf0537f0af..2a1a86f5502 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h @@ -13,6 +13,7 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, copy) AVCaptureSessionPreset sessionPreset; @property(nonatomic, readonly) NSArray *inputs; @property(nonatomic, readonly) NSArray *outputs; +@property(nonatomic, assign) BOOL automaticallyConfiguresApplicationAudioSession; - (void)beginConfiguration; - (void)commitConfiguration; From 469bc8e3bf23029623c2f3fbce040007f1a046e2 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Fri, 24 Jan 2025 15:28:20 +0100 Subject: [PATCH 25/31] Add doc comments --- .../ios/RunnerTests/Mocks/MockCaptureDevice.m | 10 ---------- .../Sources/camera_avfoundation/FLTCam.m | 8 ++++---- .../camera_avfoundation/FLTCamConfiguration.h | 2 ++ .../camera_avfoundation/FLTCameraDeviceDiscovering.h | 4 ++++ .../include/camera_avfoundation/FLTCaptureDevice.h | 12 ++++++++++-- .../include/camera_avfoundation/FLTCaptureSession.h | 2 ++ .../include/camera_avfoundation/FLTEventChannel.h | 2 ++ 7 files changed, 24 insertions(+), 16 deletions(-) diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m index 63de5230f0f..cdfee2a75a6 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m @@ -100,16 +100,6 @@ - (BOOL)isExposureModeSupported:(AVCaptureExposureMode)mode { return self.exposureModeSupported; } -- (BOOL)isExposurePointOfInterestSupported { - return self.exposurePointOfInterestSupported; -} - - -- (BOOL)isFocusPointOfInterestSupported { - return self.focusPointOfInterestSupported; -} - - - (AVCaptureInput *)createInput:(NSError *_Nullable *_Nullable)error { if (self.createInputStub) { return self.createInputStub(error); diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 079114127f6..5834d3bc0bb 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -308,8 +308,8 @@ - (void)reportInitializationState { height:self.previewSize.height] exposureMode:self.exposureMode focusMode:self.focusMode - exposurePointSupported:self.captureDevice.isExposurePointOfInterestSupported - focusPointSupported:self.captureDevice.isFocusPointOfInterestSupported]; + exposurePointSupported:self.captureDevice.exposurePointOfInterestSupported + focusPointSupported:self.captureDevice.focusPointOfInterestSupported]; __weak typeof(self) weakSelf = self; FLTEnsureToRunOnMainQueue(^{ @@ -1113,7 +1113,7 @@ - (CGPoint)CGPointForPoint:(nonnull FCPPlatformPoint *)point - (void)setExposurePoint:(FCPPlatformPoint *)point withCompletion:(void (^)(FlutterError *_Nullable))completion { - if (!_captureDevice.isExposurePointOfInterestSupported) { + if (!_captureDevice.exposurePointOfInterestSupported) { completion([FlutterError errorWithCode:@"setExposurePointFailed" message:@"Device does not have exposure point capabilities" details:nil]); @@ -1135,7 +1135,7 @@ - (void)setExposurePoint:(FCPPlatformPoint *)point - (void)setFocusPoint:(FCPPlatformPoint *)point withCompletion:(void (^)(FlutterError *_Nullable))completion { - if (!_captureDevice.isFocusPointOfInterestSupported) { + if (!_captureDevice.focusPointOfInterestSupported) { completion([FlutterError errorWithCode:@"setFocusPointFailed" message:@"Device does not have focus point capabilities" details:nil]); diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h index b0034d0fd6c..fc41ee46a3e 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h @@ -24,8 +24,10 @@ typedef id _Nonnull (^CaptureSessionFactory)(void); /// Used in tests to mock CMVideoFormatDescriptionGetDimensions. typedef CMVideoDimensions (^VideoDimensionsForFormat)(AVCaptureDeviceFormat *); +/// A configuration object that centralizes dependencies for `FLTCam`. @interface FLTCamConfiguration : NSObject +/// Initializes a new camera configuration with specified media settings and factories. - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings mediaSettingsWrapper:(FLTCamMediaSettingsAVWrapper *)mediaSettingsWrapper captureDeviceFactory:(CaptureDeviceFactory)captureDeviceFactory diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCameraDeviceDiscovering.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCameraDeviceDiscovering.h index f869a3f4f3b..73f8286bd50 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCameraDeviceDiscovering.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCameraDeviceDiscovering.h @@ -8,6 +8,8 @@ NS_ASSUME_NONNULL_BEGIN +/// A protocol which abstracts the discovery of camera devices. +/// It is a thin wrapper around `AVCaptureDiscoverySession` and it exists to allow mocking in tests. @protocol FLTCameraDeviceDiscovering - (NSArray> *) discoverySessionWithDeviceTypes:(NSArray *)deviceTypes @@ -15,6 +17,8 @@ NS_ASSUME_NONNULL_BEGIN position:(AVCaptureDevicePosition)position; @end +/// The default implementation of the `FLTCameraDeviceDiscovering` protocol. +/// It wraps a call to `AVCaptureDeviceDiscoverySession`. @interface FLTDefaultCameraDeviceDiscoverer : NSObject @end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h index 18ef724dcab..09ccc2f3774 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h @@ -7,6 +7,8 @@ NS_ASSUME_NONNULL_BEGIN +/// A protocol which is a direct passthrough to AVCaptureDevice. +/// It exists to allow replacing AVCaptureDevice in tests. @protocol FLTCaptureDevice // Device @@ -29,13 +31,13 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)isFlashModeSupported:(AVCaptureFlashMode)mode; // Focus -- (BOOL)isFocusPointOfInterestSupported; +- (BOOL)focusPointOfInterestSupported; - (BOOL)isFocusModeSupported:(AVCaptureFocusMode)mode; - (void)setFocusMode:(AVCaptureFocusMode)focusMode; - (void)setFocusPointOfInterest:(CGPoint)point; // Exposure -- (BOOL)isExposurePointOfInterestSupported; +- (BOOL)exposurePointOfInterestSupported; - (void)setExposureMode:(AVCaptureExposureMode)exposureMode; - (void)setExposurePointOfInterest:(CGPoint)point; - (float)minExposureTargetBias; @@ -66,10 +68,14 @@ NS_ASSUME_NONNULL_BEGIN @end +/// A protocol which is a direct passthrough to AVCaptureInput. +/// It exists to allow replacing AVCaptureInput in tests. @protocol FLTCaptureInput @property(nonatomic, readonly) NSArray *ports; @end +/// A protocol which wraps the creation of AVCaptureDeviceInput. +/// It exists to allow mocking instances of AVCaptureDeviceInput in tests. @protocol FLTCaptureDeviceInputFactory - (nullable id)deviceInputWithDevice:(id)device error:(NSError **)error; @@ -81,6 +87,8 @@ NS_ASSUME_NONNULL_BEGIN @interface AVCaptureInput (FLTCaptureInput) @end +/// A default implementation of FLTCaptureDeviceInputFactory protocol which +/// wraps a call to AVCaptureInput static method `deviceInputWithDevice`. @interface FLTDefaultCaptureDeviceInputFactory : NSObject @end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h index 2a1a86f5502..fefa2338992 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h @@ -8,6 +8,8 @@ NS_ASSUME_NONNULL_BEGIN +/// A protocol which is a direct passthrough to AVCaptureSession. +/// It exists to allow replacing AVCaptureSession in tests. @protocol FLTCaptureSession @property(nonatomic, copy) AVCaptureSessionPreset sessionPreset; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h index f914ded9979..6dc6b4e4e39 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTEventChannel.h @@ -6,6 +6,8 @@ NS_ASSUME_NONNULL_BEGIN +/// A protocol which is a direct passthrough to FlutterStreamHandler. +/// It exists to allow replacing FlutterStreamHandler in tests. @protocol FLTEventChannel - (void)setStreamHandler:(nullable NSObject *)handler; @end From 5ea3480f7b64c9dbd290ac07bdb88658abc4dea5 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Fri, 24 Jan 2025 15:38:29 +0100 Subject: [PATCH 26/31] Rename property --- .../example/ios/RunnerTests/Mocks/MockCaptureSession.h | 2 +- .../example/ios/RunnerTests/Mocks/MockCaptureSession.m | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h index c00fa29ad5a..c98b212fd7f 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h @@ -19,7 +19,7 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, strong) NSMutableArray *inputs; @property(nonatomic, strong) NSMutableArray *outputs; -@property(nonatomic, assign) BOOL mockCanSetSessionPreset; +@property(nonatomic, assign) BOOL canSetSessionPreset; @property(nonatomic, copy) AVCaptureSessionPreset sessionPreset; @property(nonatomic, assign) BOOL automaticallyConfiguresApplicationAudioSession; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.m index 4570386c37d..3e13e6a7f02 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.m @@ -40,10 +40,7 @@ - (void)stopRunning { } - (BOOL)canSetSessionPreset:(AVCaptureSessionPreset)preset { - if (self.mockCanSetSessionPreset) { - return self.mockCanSetSessionPreset; - } - return YES; + return self.canSetSessionPreset; } - (void)addConnection:(nonnull AVCaptureConnection *)connection { From 7f20088af9fb9b3e5b77e4848b2243f04659f550 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Fri, 24 Jan 2025 15:47:25 +0100 Subject: [PATCH 27/31] Fix formatting --- .../RunnerTests/Mocks/MockCameraDeviceDiscoverer.h | 7 +++---- .../ios/RunnerTests/Mocks/MockCaptureDevice.h | 12 ++++++------ .../ios/RunnerTests/Mocks/MockCaptureDevice.m | 3 +-- .../FLTCamMediaSettingsAVWrapper.m | 6 ++---- .../Sources/camera_avfoundation/FLTCaptureDevice.m | 3 +-- .../include/camera_avfoundation/FLTCam.h | 3 +-- .../FLTCamMediaSettingsAVWrapper.h | 6 ++---- 7 files changed, 16 insertions(+), 24 deletions(-) diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h index b6038f292ab..6fec3cb4eb5 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h @@ -8,10 +8,9 @@ NS_ASSUME_NONNULL_BEGIN @interface MockCameraDeviceDiscoverer : NSObject -@property(nonatomic, copy) - NSArray> *_Nullable (^discoverySessionStub) - (NSArray *deviceTypes, AVMediaType mediaType, - AVCaptureDevicePosition position); +@property(nonatomic, copy) NSArray> *_Nullable (^discoverySessionStub) + (NSArray *deviceTypes, AVMediaType mediaType, + AVCaptureDevicePosition position); @end NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h index 42e8e016c41..bfd8a11e9d1 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h @@ -106,12 +106,12 @@ NS_ASSUME_NONNULL_BEGIN @end @interface MockCaptureInput : NSObject - @property(nonatomic, strong) NSArray *ports; - @end +@property(nonatomic, strong) NSArray *ports; +@end - @interface MockCaptureDeviceInputFactory : NSObject - - (nonnull instancetype)initWithMockDeviceInput:(id)mockDeviceInput; - @property(nonatomic, strong) id mockDeviceInput; - @end +@interface MockCaptureDeviceInputFactory : NSObject +- (nonnull instancetype)initWithMockDeviceInput:(id)mockDeviceInput; +@property(nonatomic, strong) id mockDeviceInput; +@end NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m index cdfee2a75a6..49b2da33780 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m @@ -131,8 +131,7 @@ - (nonnull instancetype)initWithMockDeviceInput:(nonnull id)moc return self; } -- (id)deviceInputWithDevice:(id)device - error:(NSError **)error { +- (id)deviceInputWithDevice:(id)device error:(NSError **)error { return _mockDeviceInput; } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m index c8420f751b5..5f4aab44a4b 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m @@ -24,13 +24,11 @@ - (void)commitConfigurationForSession:(AVCaptureSession *)videoCaptureSession { [videoCaptureSession commitConfiguration]; } -- (void)setMinFrameDuration:(CMTime)duration - onDevice:(id)captureDevice { +- (void)setMinFrameDuration:(CMTime)duration onDevice:(id)captureDevice { captureDevice.activeVideoMinFrameDuration = duration; } -- (void)setMaxFrameDuration:(CMTime)duration - onDevice:(id)captureDevice { +- (void)setMaxFrameDuration:(CMTime)duration onDevice:(id)captureDevice { captureDevice.activeVideoMaxFrameDuration = duration; } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m index 01fe1147065..4981e580f71 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m @@ -8,8 +8,7 @@ @implementation FLTDefaultCaptureDeviceInputFactory -- (AVCaptureInput *)deviceInputWithDevice:(id)device - error:(NSError **)error { +- (AVCaptureInput *)deviceInputWithDevice:(id)device error:(NSError **)error { return [AVCaptureDeviceInput deviceInputWithDevice:device error:error]; } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h index c2dac6e53f0..4262bae0c05 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h @@ -84,8 +84,7 @@ NS_ASSUME_NONNULL_BEGIN /// /// @param focusMode The focus mode that should be applied to the @captureDevice instance. /// @param captureDevice The AVCaptureDevice to which the @focusMode will be applied. -- (void)applyFocusMode:(FCPPlatformFocusMode)focusMode - onDevice:(id)captureDevice; +- (void)applyFocusMode:(FCPPlatformFocusMode)focusMode onDevice:(id)captureDevice; - (void)pausePreview; - (void)resumePreview; - (void)setDescriptionWhileRecording:(NSString *)cameraName diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h index b00ccbfc329..2baf2c406b3 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h @@ -60,8 +60,7 @@ NS_ASSUME_NONNULL_BEGIN * @param duration The frame duration. * @param captureDevice The capture device */ -- (void)setMinFrameDuration:(CMTime)duration - onDevice:(id)captureDevice; +- (void)setMinFrameDuration:(CMTime)duration onDevice:(id)captureDevice; /** * @method setMaxFrameDuration:onDevice: @@ -70,8 +69,7 @@ NS_ASSUME_NONNULL_BEGIN * @param duration The frame duration. * @param captureDevice The capture device */ -- (void)setMaxFrameDuration:(CMTime)duration - onDevice:(id)captureDevice; +- (void)setMaxFrameDuration:(CMTime)duration onDevice:(id)captureDevice; /** * @method assetWriterAudioInputWithOutputSettings: From 64c3d1fc2123124c1822d740712f03d69adc616a Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Thu, 30 Jan 2025 18:55:59 +0100 Subject: [PATCH 28/31] Code cleanup --- .../ios/RunnerTests/AvailableCamerasTest.m | 44 ++++++++++--------- .../Mocks/MockCameraDeviceDiscoverer.h | 5 +++ .../ios/RunnerTests/Mocks/MockCaptureDevice.h | 11 +++++ .../RunnerTests/Mocks/MockCaptureSession.h | 4 ++ .../ios/RunnerTests/Mocks/MockEventChannel.h | 4 ++ .../RunnerTests/ThreadSafeEventChannelTests.m | 33 +++++++------- .../FLTCameraDeviceDiscovering.m | 4 +- .../camera_avfoundation/CameraPlugin_Test.h | 14 +++--- .../camera_avfoundation/FLTCaptureDevice.h | 4 +- 9 files changed, 76 insertions(+), 47 deletions(-) diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m index b94f24e8395..6637a562f45 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m @@ -14,30 +14,29 @@ #import "MockCaptureSession.h" @interface AvailableCamerasTest : XCTestCase -@property(nonatomic, strong) MockCameraDeviceDiscoverer *mockDeviceDiscoverer; -@property(nonatomic, strong) CameraPlugin *cameraPlugin; + @end @implementation AvailableCamerasTest -- (void)setUp { - [super setUp]; - - self.mockDeviceDiscoverer = [[MockCameraDeviceDiscoverer alloc] init]; - self.cameraPlugin = [[CameraPlugin alloc] initWithRegistry:nil - messenger:nil - globalAPI:nil - deviceDiscoverer:_mockDeviceDiscoverer - deviceFactory:^id(NSString *name) { - return [[MockCaptureDevice alloc] init]; - } - captureSessionFactory:^id { - return [[MockCaptureSession alloc] init]; - } - captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; +- (CameraPlugin*)createCameraPluginWithDeviceDiscoverer:(MockCameraDeviceDiscoverer*)deviceDiscoverer { + return [[CameraPlugin alloc] initWithRegistry:nil + messenger:nil + globalAPI:nil + deviceDiscoverer:deviceDiscoverer + deviceFactory:^id(NSString *name) { + return [[MockCaptureDevice alloc] init]; + } + captureSessionFactory:^id { + return [[MockCaptureSession alloc] init]; + } + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; } - (void)testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone { + MockCameraDeviceDiscoverer *mockDeviceDiscoverer = [[MockCameraDeviceDiscoverer alloc] init]; + CameraPlugin *cameraPlugin = [self createCameraPluginWithDeviceDiscoverer:mockDeviceDiscoverer]; + XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; // iPhone 13 Cameras: @@ -70,7 +69,7 @@ - (void)testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone { [cameras addObject:ultraWideCamera]; } - _mockDeviceDiscoverer.discoverySessionStub = ^NSArray> *_Nullable( + mockDeviceDiscoverer.discoverySessionStub = ^NSArray> *_Nullable( NSArray *_Nonnull deviceTypes, AVMediaType _Nonnull mediaType, AVCaptureDevicePosition position) { XCTAssertEqualObjects(deviceTypes, requiredTypes); @@ -80,7 +79,7 @@ - (void)testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone { }; __block NSArray *resultValue; - [_cameraPlugin + [cameraPlugin availableCamerasWithCompletion:^(NSArray *_Nullable result, FlutterError *_Nullable error) { XCTAssertNil(error); @@ -97,6 +96,9 @@ - (void)testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone { } } - (void)testAvailableCamerasShouldReturnOneCameraOnSingleCameraIPhone { + MockCameraDeviceDiscoverer *mockDeviceDiscoverer = [[MockCameraDeviceDiscoverer alloc] init]; + CameraPlugin *cameraPlugin = [self createCameraPluginWithDeviceDiscoverer:mockDeviceDiscoverer]; + XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; // iPhone 8 Cameras: @@ -118,7 +120,7 @@ - (void)testAvailableCamerasShouldReturnOneCameraOnSingleCameraIPhone { NSMutableArray *cameras = [NSMutableArray array]; [cameras addObjectsFromArray:@[ wideAngleCamera, frontFacingCamera ]]; - _mockDeviceDiscoverer.discoverySessionStub = ^NSArray> *_Nullable( + mockDeviceDiscoverer.discoverySessionStub = ^NSArray> *_Nullable( NSArray *_Nonnull deviceTypes, AVMediaType _Nonnull mediaType, AVCaptureDevicePosition position) { XCTAssertEqualObjects(deviceTypes, requiredTypes); @@ -128,7 +130,7 @@ - (void)testAvailableCamerasShouldReturnOneCameraOnSingleCameraIPhone { }; __block NSArray *resultValue; - [_cameraPlugin + [cameraPlugin availableCamerasWithCompletion:^(NSArray *_Nullable result, FlutterError *_Nullable error) { XCTAssertNil(error); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h index 6fec3cb4eb5..fef942678a5 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h @@ -7,10 +7,15 @@ NS_ASSUME_NONNULL_BEGIN +/// Mock implementation of `FLTCameraDeviceDiscovering` protocol which allows injecting a custom implementation +/// for session discovery. @interface MockCameraDeviceDiscoverer : NSObject + +/// A stub that replaces the default implementation of `discoverySessionWithDeviceTypes:mediaType:position`. @property(nonatomic, copy) NSArray> *_Nullable (^discoverySessionStub) (NSArray *deviceTypes, AVMediaType mediaType, AVCaptureDevicePosition position); + @end NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h index bfd8a11e9d1..c8f2cce27b4 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h @@ -105,13 +105,24 @@ NS_ASSUME_NONNULL_BEGIN @end +/// A mocked implementation of FLTCaptureDeviceInputFactory which allows injecting a custom implementation. @interface MockCaptureInput : NSObject + +/// This property is re-declared to be read/write to allow setting a mocked value for testing. @property(nonatomic, strong) NSArray *ports; + @end +/// A mocked implementation of FLTCaptureDeviceInputFactory which allows injecting a custom implementation. @interface MockCaptureDeviceInputFactory : NSObject + +/// Initializes a new instance with the given mock device input. Whenever `deviceInputWithDevice` is called +/// on this instance, it will return the mock device input. - (nonnull instancetype)initWithMockDeviceInput:(id)mockDeviceInput; + +/// The mock device input to be returned by `deviceInputWithDevice`. @property(nonatomic, strong) id mockDeviceInput; + @end NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h index c98b212fd7f..4a7fd594031 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h @@ -10,13 +10,17 @@ NS_ASSUME_NONNULL_BEGIN +/// Mock implementation of `FLTCaptureSession` protocol which allows injecting a custom implementation. @interface MockCaptureSession : NSObject + +// Stubs that are called when the corresponding public method is called. @property(nonatomic, copy) void (^beginConfigurationStub)(void); @property(nonatomic, copy) void (^commitConfigurationStub)(void); @property(nonatomic, copy) void (^startRunningStub)(void); @property(nonatomic, copy) void (^stopRunningStub)(void); @property(nonatomic, copy) void (^setSessionPresetStub)(AVCaptureSessionPreset preset); +// Properties re-declared as read/write so a mocked value can be set during testing. @property(nonatomic, strong) NSMutableArray *inputs; @property(nonatomic, strong) NSMutableArray *outputs; @property(nonatomic, assign) BOOL canSetSessionPreset; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockEventChannel.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockEventChannel.h index baa69f8503c..d92adf35c05 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockEventChannel.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockEventChannel.h @@ -10,8 +10,12 @@ NS_ASSUME_NONNULL_BEGIN +/// A mock implementation of `FLTEventChannel` that allows injecting a custom stream handler. @interface MockEventChannel : NSObject + +/// Overrides the default implementation of setting the stream handler. @property(nonatomic, copy) void (^setStreamHandlerStub)(NSObject *); + @end NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m index dfd539ecfd3..ffa469db15e 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m @@ -11,33 +11,30 @@ #import "MockEventChannel.h" @interface ThreadSafeEventChannelTests : XCTestCase -@property(readonly, nonatomic) MockEventChannel *mockEventChannel; -@property(readonly, nonatomic) FLTThreadSafeEventChannel *threadSafeEventChannel; + @end @implementation ThreadSafeEventChannelTests -- (void)setUp { - [super setUp]; - _mockEventChannel = [[MockEventChannel alloc] init]; - _threadSafeEventChannel = - [[FLTThreadSafeEventChannel alloc] initWithEventChannel:_mockEventChannel]; -} - (void)testSetStreamHandler_shouldStayOnMainThreadIfCalledFromMainThread { + MockEventChannel *mockEventChannel = [[MockEventChannel alloc] init]; + FLTThreadSafeEventChannel *threadSafeEventChannel = + [[FLTThreadSafeEventChannel alloc] initWithEventChannel:mockEventChannel]; + XCTestExpectation *mainThreadExpectation = [self expectationWithDescription:@"setStreamHandler must be called on the main thread"]; XCTestExpectation *mainThreadCompletionExpectation = [self expectationWithDescription: @"setStreamHandler's completion block must be called on the main thread"]; - [_mockEventChannel setSetStreamHandlerStub:^(NSObject *handler) { + [mockEventChannel setSetStreamHandlerStub:^(NSObject *handler) { if (NSThread.isMainThread) { [mainThreadExpectation fulfill]; } }]; - [_threadSafeEventChannel setStreamHandler:nil + [threadSafeEventChannel setStreamHandler:nil completion:^{ if (NSThread.isMainThread) { [mainThreadCompletionExpectation fulfill]; @@ -47,21 +44,24 @@ - (void)testSetStreamHandler_shouldStayOnMainThreadIfCalledFromMainThread { } - (void)testSetStreamHandler_shouldDispatchToMainThreadIfCalledFromBackgroundThread { + MockEventChannel *mockEventChannel = [[MockEventChannel alloc] init]; + FLTThreadSafeEventChannel *threadSafeEventChannel = + [[FLTThreadSafeEventChannel alloc] initWithEventChannel:mockEventChannel]; + XCTestExpectation *mainThreadExpectation = [self expectationWithDescription:@"setStreamHandler must be called on the main thread"]; XCTestExpectation *mainThreadCompletionExpectation = [self expectationWithDescription: @"setStreamHandler's completion block must be called on the main thread"]; - [_mockEventChannel setSetStreamHandlerStub:^(NSObject *handler) { + [mockEventChannel setSetStreamHandlerStub:^(NSObject *handler) { if (NSThread.isMainThread) { [mainThreadExpectation fulfill]; } }]; - __weak typeof(self) weakSelf = self; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [weakSelf.threadSafeEventChannel setStreamHandler:nil + [threadSafeEventChannel setStreamHandler:nil completion:^{ if (NSThread.isMainThread) { [mainThreadCompletionExpectation fulfill]; @@ -72,13 +72,16 @@ - (void)testSetStreamHandler_shouldDispatchToMainThreadIfCalledFromBackgroundThr } - (void)testEventChannel_shouldBeKeptAliveWhenDispatchingBackToMainThread { + MockEventChannel *mockEventChannel = [[MockEventChannel alloc] init]; + FLTThreadSafeEventChannel *threadSafeEventChannel = + [[FLTThreadSafeEventChannel alloc] initWithEventChannel:mockEventChannel]; + XCTestExpectation *expectation = [self expectationWithDescription:@"Completion should be called."]; - __weak typeof(self) weakSelf = self; dispatch_async(dispatch_queue_create("test", NULL), ^{ FLTThreadSafeEventChannel *channel = - [[FLTThreadSafeEventChannel alloc] initWithEventChannel:weakSelf.mockEventChannel]; + [[FLTThreadSafeEventChannel alloc] initWithEventChannel:mockEventChannel]; [channel setStreamHandler:nil completion:^{ diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m index 25189ff6c3b..feaa35f55e1 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m @@ -18,10 +18,10 @@ @implementation FLTDefaultCameraDeviceDiscoverer position:position]; NSArray *devices = discoverySession.devices; - NSMutableArray> *deviceControllers = [NSMutableArray array]; + NSMutableArray> *deviceControllers = [NSMutableArray arrayWithCapacity:devices.count]; for (AVCaptureDevice *device in devices) { - [deviceControllers addObject:(id)device]; + [deviceControllers addObject:device]; } return deviceControllers; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h index dbc55e11c97..1f04fccc84d 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h @@ -25,14 +25,14 @@ typedef id _Nonnull (^CaptureNamedDeviceFactory)(NSString *nam @property(nonatomic, strong) FLTCam *_Nullable camera; /// Inject @p FlutterTextureRegistry and @p FlutterBinaryMessenger for unit testing. -- (nonnull instancetype)initWithRegistry:(NSObject *_Nullable)registry - messenger:(NSObject *_Nullable)messenger; +- (instancetype)initWithRegistry:(NSObject *)registry + messenger:(NSObject *)messenger; /// Inject @p FlutterTextureRegistry, @p FlutterBinaryMessenger, and Pigeon callback handler for /// unit testing. -- (nonnull instancetype)initWithRegistry:(NSObject *_Nullable)registry - messenger:(NSObject *_Nullable)messenger - globalAPI:(FCPCameraGlobalEventApi *_Nullable)globalAPI +- (instancetype)initWithRegistry:(NSObject *)registry + messenger:(NSObject *)messenger + globalAPI:(FCPCameraGlobalEventApi *)globalAPI deviceDiscoverer:(id)deviceDiscoverer deviceFactory:(CaptureNamedDeviceFactory)deviceFactory captureSessionFactory:(CaptureSessionFactory)captureSessionFactory @@ -40,7 +40,7 @@ typedef id _Nonnull (^CaptureNamedDeviceFactory)(NSString *nam NS_DESIGNATED_INITIALIZER; /// Hide the default public constructor. -- (nonnull instancetype)init NS_UNAVAILABLE; +- (instancetype)init NS_UNAVAILABLE; /// Called by the @c NSNotificationManager each time the device's orientation is changed. /// @@ -52,7 +52,7 @@ typedef id _Nonnull (^CaptureNamedDeviceFactory)(NSString *nam /// @param name the name of the camera. /// @param settings the creation settings. /// @param completion the callback to inform the Dart side of the plugin of creation. -- (void)createCameraOnSessionQueueWithName:(NSString *_Nullable)name +- (void)createCameraOnSessionQueueWithName:(NSString *)name settings:(FCPPlatformMediaSettings *)settings completion:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h index 09ccc2f3774..251e03b70b8 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h @@ -11,8 +11,8 @@ NS_ASSUME_NONNULL_BEGIN /// It exists to allow replacing AVCaptureDevice in tests. @protocol FLTCaptureDevice -// Device -- (NSString *)uniqueID; +// Device identifier +@property(nonatomic, readonly) NSString *uniqueID; // Position/Orientation - (AVCaptureDevicePosition)position; From 1ad59666344db5b0305cccb85fdd2058fc141be2 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Fri, 31 Jan 2025 14:52:43 +0100 Subject: [PATCH 29/31] Fix warning with nils being passed in tests by introducing new mocks --- .../ios/Runner.xcodeproj/project.pbxproj | 18 +++++ .../ios/RunnerTests/AvailableCamerasTest.m | 30 +++++---- ...eraCaptureSessionQueueRaceConditionTests.m | 26 ++++--- .../RunnerTests/CameraMethodChannelTests.m | 12 +++- .../ios/RunnerTests/CameraOrientationTests.m | 67 +++++++------------ .../ios/RunnerTests/CameraSettingsTests.m | 7 +- .../Mocks/MockCameraDeviceDiscoverer.h | 7 +- .../ios/RunnerTests/Mocks/MockCaptureDevice.h | 10 +-- .../RunnerTests/Mocks/MockCaptureSession.h | 3 +- .../Mocks/MockFlutterBinaryMessenger.h | 11 +++ .../Mocks/MockFlutterBinaryMessenger.m | 26 +++++++ .../Mocks/MockFlutterTextureRegistry.h | 11 +++ .../Mocks/MockFlutterTextureRegistry.m | 19 ++++++ .../RunnerTests/Mocks/MockGlobalEventApi.h | 21 ++++++ .../RunnerTests/Mocks/MockGlobalEventApi.m | 21 ++++++ .../RunnerTests/ThreadSafeEventChannelTests.m | 29 ++++---- .../FLTCameraDeviceDiscovering.m | 3 +- .../camera_avfoundation/CameraPlugin_Test.h | 14 ++-- 18 files changed, 235 insertions(+), 100 deletions(-) create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterBinaryMessenger.h create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterBinaryMessenger.m create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterTextureRegistry.h create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterTextureRegistry.m create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockGlobalEventApi.h create mode 100644 packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockGlobalEventApi.m diff --git a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj index 4350a7a91e1..0b28b4557b8 100644 --- a/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/camera/camera_avfoundation/example/ios/Runner.xcodeproj/project.pbxproj @@ -23,6 +23,9 @@ 7F29EB292D26A59000740257 /* MockCameraDeviceDiscoverer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F29EB282D26A59000740257 /* MockCameraDeviceDiscoverer.m */; }; 7F29EB412D281C7E00740257 /* MockCaptureSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F29EB402D281C7E00740257 /* MockCaptureSession.m */; }; 7F56D0382D1EDDCE005676A5 /* CameraPermissionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E0B0D2BA27DFF2AF00E71E4B /* CameraPermissionTests.m */; }; + 7F8FD2292D4BFABF001AF2C1 /* MockGlobalEventApi.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F8FD2282D4BFABF001AF2C1 /* MockGlobalEventApi.m */; }; + 7F8FD22C2D4D07DD001AF2C1 /* MockFlutterTextureRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F8FD22B2D4D07DD001AF2C1 /* MockFlutterTextureRegistry.m */; }; + 7F8FD22F2D4D0B88001AF2C1 /* MockFlutterBinaryMessenger.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F8FD22E2D4D0B88001AF2C1 /* MockFlutterBinaryMessenger.m */; }; 7FA99E592D22C75300582559 /* CameraExposureTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FA99E582D22C75300582559 /* CameraExposureTests.m */; }; 7FCEDD352D43C2B900EA1CA8 /* MockDeviceOrientationProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FCEDD342D43C2B900EA1CA8 /* MockDeviceOrientationProvider.m */; }; 7FCEDD362D43C2B900EA1CA8 /* MockCaptureDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FCEDD322D43C2B900EA1CA8 /* MockCaptureDevice.m */; }; @@ -88,6 +91,12 @@ 7F29EB282D26A59000740257 /* MockCameraDeviceDiscoverer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCameraDeviceDiscoverer.m; sourceTree = ""; }; 7F29EB3E2D281C5800740257 /* MockCaptureSession.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCaptureSession.h; sourceTree = ""; }; 7F29EB402D281C7E00740257 /* MockCaptureSession.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCaptureSession.m; sourceTree = ""; }; + 7F8FD2272D4BFA8D001AF2C1 /* MockGlobalEventApi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockGlobalEventApi.h; sourceTree = ""; }; + 7F8FD2282D4BFABF001AF2C1 /* MockGlobalEventApi.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockGlobalEventApi.m; sourceTree = ""; }; + 7F8FD22A2D4D07A6001AF2C1 /* MockFlutterTextureRegistry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockFlutterTextureRegistry.h; sourceTree = ""; }; + 7F8FD22B2D4D07DD001AF2C1 /* MockFlutterTextureRegistry.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockFlutterTextureRegistry.m; sourceTree = ""; }; + 7F8FD22D2D4D0B73001AF2C1 /* MockFlutterBinaryMessenger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockFlutterBinaryMessenger.h; sourceTree = ""; }; + 7F8FD22E2D4D0B88001AF2C1 /* MockFlutterBinaryMessenger.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockFlutterBinaryMessenger.m; sourceTree = ""; }; 7FA99E582D22C75300582559 /* CameraExposureTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CameraExposureTests.m; sourceTree = ""; }; 7FCEDD312D43C2B900EA1CA8 /* MockCaptureDevice.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockCaptureDevice.h; sourceTree = ""; }; 7FCEDD322D43C2B900EA1CA8 /* MockCaptureDevice.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockCaptureDevice.m; sourceTree = ""; }; @@ -182,6 +191,12 @@ 7F29EB3F2D281C6D00740257 /* Mocks */ = { isa = PBXGroup; children = ( + 7F8FD22D2D4D0B73001AF2C1 /* MockFlutterBinaryMessenger.h */, + 7F8FD22E2D4D0B88001AF2C1 /* MockFlutterBinaryMessenger.m */, + 7F8FD22A2D4D07A6001AF2C1 /* MockFlutterTextureRegistry.h */, + 7F8FD22B2D4D07DD001AF2C1 /* MockFlutterTextureRegistry.m */, + 7F8FD2282D4BFABF001AF2C1 /* MockGlobalEventApi.m */, + 7F8FD2272D4BFA8D001AF2C1 /* MockGlobalEventApi.h */, 7FCEDD312D43C2B900EA1CA8 /* MockCaptureDevice.h */, 7FCEDD322D43C2B900EA1CA8 /* MockCaptureDevice.m */, 7FCEDD332D43C2B900EA1CA8 /* MockDeviceOrientationProvider.h */, @@ -487,10 +502,12 @@ E0F95E3D27A32AB900699390 /* CameraPropertiesTests.m in Sources */, 03BB766B2665316900CE5A93 /* CameraFocusTests.m in Sources */, 7D5FCCD42AEF9D0200FB7108 /* CameraSettingsTests.m in Sources */, + 7F8FD2292D4BFABF001AF2C1 /* MockGlobalEventApi.m in Sources */, 7FA99E592D22C75300582559 /* CameraExposureTests.m in Sources */, E487C86026D686A10034AC92 /* CameraPreviewPauseTests.m in Sources */, E071CF7427B31DE4006EF3BA /* FLTCamSampleBufferTests.m in Sources */, 7F29EB222D269ED500740257 /* MockEventChannel.m in Sources */, + 7F8FD22F2D4D0B88001AF2C1 /* MockFlutterBinaryMessenger.m in Sources */, E04F108627A87CA600573D0C /* FLTSavePhotoDelegateTests.m in Sources */, 43ED1537282570DE00EB00DE /* AvailableCamerasTest.m in Sources */, E0CDBAC227CD9729002561D9 /* CameraTestUtils.m in Sources */, @@ -504,6 +521,7 @@ E01EE4A82799F3A5008C1950 /* QueueUtilsTests.m in Sources */, 7FCEDD352D43C2B900EA1CA8 /* MockDeviceOrientationProvider.m in Sources */, 7FCEDD362D43C2B900EA1CA8 /* MockCaptureDevice.m in Sources */, + 7F8FD22C2D4D07DD001AF2C1 /* MockFlutterTextureRegistry.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m index 6637a562f45..2e03d361731 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m @@ -12,6 +12,9 @@ #import "MockCameraDeviceDiscoverer.h" #import "MockCaptureDevice.h" #import "MockCaptureSession.h" +#import "MockFlutterBinaryMessenger.h" +#import "MockFlutterTextureRegistry.h" +#import "MockGlobalEventApi.h" @interface AvailableCamerasTest : XCTestCase @@ -19,18 +22,19 @@ @interface AvailableCamerasTest : XCTestCase @implementation AvailableCamerasTest -- (CameraPlugin*)createCameraPluginWithDeviceDiscoverer:(MockCameraDeviceDiscoverer*)deviceDiscoverer { - return [[CameraPlugin alloc] initWithRegistry:nil - messenger:nil - globalAPI:nil - deviceDiscoverer:deviceDiscoverer - deviceFactory:^id(NSString *name) { - return [[MockCaptureDevice alloc] init]; - } - captureSessionFactory:^id { - return [[MockCaptureSession alloc] init]; - } - captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; +- (CameraPlugin *)createCameraPluginWithDeviceDiscoverer: + (MockCameraDeviceDiscoverer *)deviceDiscoverer { + return [[CameraPlugin alloc] initWithRegistry:[[MockFlutterTextureRegistry alloc] init] + messenger:[[MockFlutterBinaryMessenger alloc] init] + globalAPI:[[MockGlobalEventApi alloc] init] + deviceDiscoverer:deviceDiscoverer + deviceFactory:^id(NSString *name) { + return [[MockCaptureDevice alloc] init]; + } + captureSessionFactory:^id { + return [[MockCaptureSession alloc] init]; + } + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; } - (void)testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone { @@ -98,7 +102,7 @@ - (void)testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone { - (void)testAvailableCamerasShouldReturnOneCameraOnSingleCameraIPhone { MockCameraDeviceDiscoverer *mockDeviceDiscoverer = [[MockCameraDeviceDiscoverer alloc] init]; CameraPlugin *cameraPlugin = [self createCameraPluginWithDeviceDiscoverer:mockDeviceDiscoverer]; - + XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; // iPhone 8 Cameras: diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m index fe6db5ca9dc..ef7f6af9bab 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m @@ -11,6 +11,9 @@ #import "MockCameraDeviceDiscoverer.h" #import "MockCaptureDevice.h" #import "MockCaptureSession.h" +#import "MockFlutterBinaryMessenger.h" +#import "MockFlutterTextureRegistry.h" +#import "MockGlobalEventApi.h" @interface CameraCaptureSessionQueueRaceConditionTests : XCTestCase @end @@ -20,17 +23,18 @@ @implementation CameraCaptureSessionQueueRaceConditionTests - (void)testFixForCaptureSessionQueueNullPointerCrashDueToRaceCondition { MockCaptureDevice *captureDevice = [[MockCaptureDevice alloc] init]; - CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil - messenger:nil - globalAPI:nil - deviceDiscoverer:[[MockCameraDeviceDiscoverer alloc] init] - deviceFactory:^id(NSString *name) { - return captureDevice; - } - captureSessionFactory:^id { - return [[MockCaptureSession alloc] init]; - } - captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; + CameraPlugin *camera = + [[CameraPlugin alloc] initWithRegistry:[[MockFlutterTextureRegistry alloc] init] + messenger:[[MockFlutterBinaryMessenger alloc] init] + globalAPI:[[MockGlobalEventApi alloc] init] + deviceDiscoverer:[[MockCameraDeviceDiscoverer alloc] init] + deviceFactory:^id(NSString *name) { + return captureDevice; + } + captureSessionFactory:^id { + return [[MockCaptureSession alloc] init]; + } + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; XCTestExpectation *disposeExpectation = [self expectationWithDescription:@"dispose's result block must be called"]; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.m index 4df1994699d..0acc392545f 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraMethodChannelTests.m @@ -10,13 +10,21 @@ @import AVFoundation; #import +#import "MockFlutterBinaryMessenger.h" +#import "MockFlutterTextureRegistry.h" + @interface CameraMethodChannelTests : XCTestCase @end @implementation CameraMethodChannelTests +- (CameraPlugin *)createCameraPlugin { + return [[CameraPlugin alloc] initWithRegistry:[[MockFlutterTextureRegistry alloc] init] + messenger:[[MockFlutterBinaryMessenger alloc] init]]; +} + - (void)testCreate_ShouldCallResultOnMainThread { - CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil]; + CameraPlugin *camera = [self createCameraPlugin]; XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; @@ -51,7 +59,7 @@ - (void)testCreate_ShouldCallResultOnMainThread { } - (void)testDisposeShouldDeallocCamera { - CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil]; + CameraPlugin *camera = [self createCameraPlugin]; id avCaptureDeviceInputMock = OCMClassMock([AVCaptureDeviceInput class]); OCMStub([avCaptureDeviceInputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg anyObjectRef]]) diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m index fe2c0e1e04d..3073eda5db3 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m @@ -13,27 +13,9 @@ #import "MockCaptureDevice.h" #import "MockCaptureSession.h" #import "MockDeviceOrientationProvider.h" - -@interface StubGlobalEventApi : FCPCameraGlobalEventApi -@property(nonatomic) BOOL called; -@property(nonatomic) FCPPlatformDeviceOrientation lastOrientation; -@end - -@implementation StubGlobalEventApi -- (void)deviceOrientationChangedOrientation:(FCPPlatformDeviceOrientation)orientation - completion:(void (^)(FlutterError *_Nullable))completion { - self.called = YES; - self.lastOrientation = orientation; - completion(nil); -} - -- (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(nonnull NSString *)channel - binaryMessageHandler: - (nullable FlutterBinaryMessageHandler)handler { - return 0; -} - -@end +#import "MockFlutterBinaryMessenger.h" +#import "MockFlutterTextureRegistry.h" +#import "MockGlobalEventApi.h" @interface MockCamera : FLTCam @property(nonatomic, copy) void (^setDeviceOrientationStub)(UIDeviceOrientation orientation); @@ -68,7 +50,7 @@ - (UIDeviceOrientation)orientation { @interface CameraOrientationTests : XCTestCase @property(readonly, nonatomic) MockCamera *camera; @property(readonly, nonatomic) MockCaptureDevice *mockDevice; -@property(readonly, nonatomic) StubGlobalEventApi *eventAPI; +@property(readonly, nonatomic) MockGlobalEventApi *eventAPI; @property(readonly, nonatomic) CameraPlugin *cameraPlugin; @property(readonly, nonatomic) MockCameraDeviceDiscoverer *deviceDiscoverer; @end @@ -79,12 +61,12 @@ - (void)setUp { [super setUp]; MockCaptureDevice *mockDevice = [[MockCaptureDevice alloc] init]; _camera = [[MockCamera alloc] init]; - _eventAPI = [[StubGlobalEventApi alloc] init]; + _eventAPI = [[MockGlobalEventApi alloc] init]; _mockDevice = mockDevice; _deviceDiscoverer = [[MockCameraDeviceDiscoverer alloc] init]; - _cameraPlugin = [[CameraPlugin alloc] initWithRegistry:nil - messenger:nil + _cameraPlugin = [[CameraPlugin alloc] initWithRegistry:[[MockFlutterTextureRegistry alloc] init] + messenger:[[MockFlutterBinaryMessenger alloc] init] globalAPI:_eventAPI deviceDiscoverer:_deviceDiscoverer deviceFactory:^id(NSString *name) { @@ -128,20 +110,22 @@ - (void)testOrientationNotifications { - (void)testOrientationNotificationsNotCalledForFaceUp { [self sendOrientation:UIDeviceOrientationFaceUp toCamera:_cameraPlugin]; - XCTAssertFalse(_eventAPI.called); + XCTAssertFalse(_eventAPI.deviceOrientationChangedCalled); } - (void)testOrientationNotificationsNotCalledForFaceDown { [self sendOrientation:UIDeviceOrientationFaceDown toCamera:_cameraPlugin]; - XCTAssertFalse(_eventAPI.called); + XCTAssertFalse(_eventAPI.deviceOrientationChangedCalled); } - (void)testOrientationUpdateMustBeOnCaptureSessionQueue { XCTestExpectation *queueExpectation = [self expectationWithDescription:@"Orientation update must happen on the capture session queue"]; - CameraPlugin *plugin = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil]; + CameraPlugin *plugin = + [[CameraPlugin alloc] initWithRegistry:[[MockFlutterTextureRegistry alloc] init] + messenger:[[MockFlutterBinaryMessenger alloc] init]]; const char *captureSessionQueueSpecific = "capture_session_queue"; dispatch_queue_set_specific(plugin.captureSessionQueue, captureSessionQueueSpecific, (void *)captureSessionQueueSpecific, NULL); @@ -165,17 +149,18 @@ - (void)testOrientationChanged_noRetainCycle { __weak MockCaptureDevice *weakDevice = _mockDevice; @autoreleasepool { - CameraPlugin *plugin = [[CameraPlugin alloc] initWithRegistry:nil - messenger:nil - globalAPI:_eventAPI - deviceDiscoverer:_deviceDiscoverer - deviceFactory:^id(NSString *name) { - return weakDevice; - } - captureSessionFactory:^id _Nonnull { - return [[MockCaptureSession alloc] init]; - } - captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; + CameraPlugin *plugin = + [[CameraPlugin alloc] initWithRegistry:[[MockFlutterTextureRegistry alloc] init] + messenger:[[MockFlutterBinaryMessenger alloc] init] + globalAPI:_eventAPI + deviceDiscoverer:_deviceDiscoverer + deviceFactory:^id(NSString *name) { + return weakDevice; + } + captureSessionFactory:^id _Nonnull { + return [[MockCaptureSession alloc] init]; + } + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; weakPlugin = plugin; plugin.captureSessionQueue = captureSessionQueue; plugin.camera = _camera; @@ -194,14 +179,14 @@ - (void)testOrientationChanged_noRetainCycle { } }; - __weak StubGlobalEventApi *weakEventAPI = _eventAPI; + __weak MockGlobalEventApi *weakEventAPI = _eventAPI; // Must check in captureSessionQueue since orientationChanged dispatches to this queue. XCTestExpectation *expectation = [self expectationWithDescription:@"Dispatched to capture session queue"]; dispatch_async(captureSessionQueue, ^{ XCTAssertFalse(setDeviceOrientationCalled); - XCTAssertFalse(weakEventAPI.called); + XCTAssertFalse(weakEventAPI.deviceOrientationChangedCalled); [expectation fulfill]; }); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m index 98e12020b59..873cc212a8a 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.m @@ -9,7 +9,10 @@ @import XCTest; @import AVFoundation; #import + #import "CameraTestUtils.h" +#import "MockFlutterBinaryMessenger.h" +#import "MockFlutterTextureRegistry.h" static const FCPPlatformResolutionPreset gTestResolutionPreset = FCPPlatformResolutionPresetMedium; static const int gTestFramesPerSecond = 15; @@ -167,7 +170,9 @@ - (void)testSettings_shouldPassConfigurationToCameraDeviceAndWriter { } - (void)testSettings_ShouldBeSupportedByMethodCall { - CameraPlugin *camera = [[CameraPlugin alloc] initWithRegistry:nil messenger:nil]; + CameraPlugin *camera = + [[CameraPlugin alloc] initWithRegistry:[[MockFlutterTextureRegistry alloc] init] + messenger:[[MockFlutterBinaryMessenger alloc] init]]; XCTestExpectation *expectation = [self expectationWithDescription:@"Result finished"]; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h index fef942678a5..074afbf47af 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h @@ -7,11 +7,12 @@ NS_ASSUME_NONNULL_BEGIN -/// Mock implementation of `FLTCameraDeviceDiscovering` protocol which allows injecting a custom implementation -/// for session discovery. +/// Mock implementation of `FLTCameraDeviceDiscovering` protocol which allows injecting a custom +/// implementation for session discovery. @interface MockCameraDeviceDiscoverer : NSObject -/// A stub that replaces the default implementation of `discoverySessionWithDeviceTypes:mediaType:position`. +/// A stub that replaces the default implementation of +/// `discoverySessionWithDeviceTypes:mediaType:position`. @property(nonatomic, copy) NSArray> *_Nullable (^discoverySessionStub) (NSArray *deviceTypes, AVMediaType mediaType, AVCaptureDevicePosition position); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h index c8f2cce27b4..18b302aee55 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h @@ -105,7 +105,8 @@ NS_ASSUME_NONNULL_BEGIN @end -/// A mocked implementation of FLTCaptureDeviceInputFactory which allows injecting a custom implementation. +/// A mocked implementation of FLTCaptureDeviceInputFactory which allows injecting a custom +/// implementation. @interface MockCaptureInput : NSObject /// This property is re-declared to be read/write to allow setting a mocked value for testing. @@ -113,11 +114,12 @@ NS_ASSUME_NONNULL_BEGIN @end -/// A mocked implementation of FLTCaptureDeviceInputFactory which allows injecting a custom implementation. +/// A mocked implementation of FLTCaptureDeviceInputFactory which allows injecting a custom +/// implementation. @interface MockCaptureDeviceInputFactory : NSObject -/// Initializes a new instance with the given mock device input. Whenever `deviceInputWithDevice` is called -/// on this instance, it will return the mock device input. +/// Initializes a new instance with the given mock device input. Whenever `deviceInputWithDevice` is +/// called on this instance, it will return the mock device input. - (nonnull instancetype)initWithMockDeviceInput:(id)mockDeviceInput; /// The mock device input to be returned by `deviceInputWithDevice`. diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h index 4a7fd594031..beb3054b776 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.h @@ -10,7 +10,8 @@ NS_ASSUME_NONNULL_BEGIN -/// Mock implementation of `FLTCaptureSession` protocol which allows injecting a custom implementation. +/// Mock implementation of `FLTCaptureSession` protocol which allows injecting a custom +/// implementation. @interface MockCaptureSession : NSObject // Stubs that are called when the corresponding public method is called. diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterBinaryMessenger.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterBinaryMessenger.h new file mode 100644 index 00000000000..7150c151611 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterBinaryMessenger.h @@ -0,0 +1,11 @@ +// 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. + +@import Flutter; + +/// Mocked implementation of `FlutterBinaryMessenger` protocol that exists to allow constructing +/// a `CameraPlugin` instance for testing. It contains an empty implementation for all protocol +/// methods. +@interface MockFlutterBinaryMessenger : NSObject +@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterBinaryMessenger.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterBinaryMessenger.m new file mode 100644 index 00000000000..a23511dfba5 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterBinaryMessenger.m @@ -0,0 +1,26 @@ +// 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. + +#import "MockFlutterBinaryMessenger.h" + +@implementation MockFlutterBinaryMessenger + +- (void)cleanUpConnection:(FlutterBinaryMessengerConnection)connection { +} + +- (void)sendOnChannel:(nonnull NSString *)channel message:(NSData *_Nullable)message { +} + +- (void)sendOnChannel:(nonnull NSString *)channel + message:(NSData *_Nullable)message + binaryReply:(FlutterBinaryReply _Nullable)callback { +} + +- (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(nonnull NSString *)channel + binaryMessageHandler: + (FlutterBinaryMessageHandler _Nullable)handler { + return 0; +} + +@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterTextureRegistry.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterTextureRegistry.h new file mode 100644 index 00000000000..37deb1e08c3 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterTextureRegistry.h @@ -0,0 +1,11 @@ +// 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. + +@import Flutter; + +/// Mocked implementation of `FlutterTextureRegistry` protocol that exists to allow constructing +/// a `CameraPlugin` instance for testing. It contains an empty implementation for all protocol +/// methods. +@interface MockFlutterTextureRegistry : NSObject +@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterTextureRegistry.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterTextureRegistry.m new file mode 100644 index 00000000000..5a1db894b94 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockFlutterTextureRegistry.m @@ -0,0 +1,19 @@ +// 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. + +#import "MockFlutterTextureRegistry.h" + +@implementation MockFlutterTextureRegistry + +- (int64_t)registerTexture:(nonnull NSObject *)texture { + return 0; +} + +- (void)textureFrameAvailable:(int64_t)textureId { +} + +- (void)unregisterTexture:(int64_t)textureId { +} + +@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockGlobalEventApi.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockGlobalEventApi.h new file mode 100644 index 00000000000..802c3e2d017 --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockGlobalEventApi.h @@ -0,0 +1,21 @@ +// 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. + +@import camera_avfoundation; +#if __has_include() +@import camera_avfoundation.Test; +#endif + +/// A mock implementation of `FCPCameraGlobalEventApi` that captures received +/// `deviceOrientationChanged` events and exposes the information whether they were received to the +/// testing code. +@interface MockGlobalEventApi : FCPCameraGlobalEventApi + +/// Whether the `deviceOrientationChanged` callback was called. +@property(nonatomic) BOOL deviceOrientationChangedCalled; + +/// The last orientation received by the `deviceOrientationChanged` callback. +@property(nonatomic) FCPPlatformDeviceOrientation lastOrientation; + +@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockGlobalEventApi.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockGlobalEventApi.m new file mode 100644 index 00000000000..d6920b89a3b --- /dev/null +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockGlobalEventApi.m @@ -0,0 +1,21 @@ +// 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. + +#import "MockGlobalEventApi.h" + +@implementation MockGlobalEventApi +- (void)deviceOrientationChangedOrientation:(FCPPlatformDeviceOrientation)orientation + completion:(void (^)(FlutterError *_Nullable))completion { + self.deviceOrientationChangedCalled = YES; + self.lastOrientation = orientation; + completion(nil); +} + +- (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(nonnull NSString *)channel + binaryMessageHandler: + (nullable FlutterBinaryMessageHandler)handler { + return 0; +} + +@end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m index ffa469db15e..64450207266 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/ThreadSafeEventChannelTests.m @@ -16,12 +16,11 @@ @interface ThreadSafeEventChannelTests : XCTestCase @implementation ThreadSafeEventChannelTests - - (void)testSetStreamHandler_shouldStayOnMainThreadIfCalledFromMainThread { MockEventChannel *mockEventChannel = [[MockEventChannel alloc] init]; FLTThreadSafeEventChannel *threadSafeEventChannel = [[FLTThreadSafeEventChannel alloc] initWithEventChannel:mockEventChannel]; - + XCTestExpectation *mainThreadExpectation = [self expectationWithDescription:@"setStreamHandler must be called on the main thread"]; XCTestExpectation *mainThreadCompletionExpectation = @@ -35,11 +34,11 @@ - (void)testSetStreamHandler_shouldStayOnMainThreadIfCalledFromMainThread { }]; [threadSafeEventChannel setStreamHandler:nil - completion:^{ - if (NSThread.isMainThread) { - [mainThreadCompletionExpectation fulfill]; - } - }]; + completion:^{ + if (NSThread.isMainThread) { + [mainThreadCompletionExpectation fulfill]; + } + }]; [self waitForExpectationsWithTimeout:1 handler:nil]; } @@ -47,7 +46,7 @@ - (void)testSetStreamHandler_shouldDispatchToMainThreadIfCalledFromBackgroundThr MockEventChannel *mockEventChannel = [[MockEventChannel alloc] init]; FLTThreadSafeEventChannel *threadSafeEventChannel = [[FLTThreadSafeEventChannel alloc] initWithEventChannel:mockEventChannel]; - + XCTestExpectation *mainThreadExpectation = [self expectationWithDescription:@"setStreamHandler must be called on the main thread"]; XCTestExpectation *mainThreadCompletionExpectation = @@ -62,20 +61,18 @@ - (void)testSetStreamHandler_shouldDispatchToMainThreadIfCalledFromBackgroundThr dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [threadSafeEventChannel setStreamHandler:nil - completion:^{ - if (NSThread.isMainThread) { - [mainThreadCompletionExpectation fulfill]; - } - }]; + completion:^{ + if (NSThread.isMainThread) { + [mainThreadCompletionExpectation fulfill]; + } + }]; }); [self waitForExpectationsWithTimeout:1 handler:nil]; } - (void)testEventChannel_shouldBeKeptAliveWhenDispatchingBackToMainThread { MockEventChannel *mockEventChannel = [[MockEventChannel alloc] init]; - FLTThreadSafeEventChannel *threadSafeEventChannel = - [[FLTThreadSafeEventChannel alloc] initWithEventChannel:mockEventChannel]; - + XCTestExpectation *expectation = [self expectationWithDescription:@"Completion should be called."]; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m index feaa35f55e1..4cf8fdf98eb 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m @@ -18,7 +18,8 @@ @implementation FLTDefaultCameraDeviceDiscoverer position:position]; NSArray *devices = discoverySession.devices; - NSMutableArray> *deviceControllers = [NSMutableArray arrayWithCapacity:devices.count]; + NSMutableArray> *deviceControllers = + [NSMutableArray arrayWithCapacity:devices.count]; for (AVCaptureDevice *device in devices) { [deviceControllers addObject:device]; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h index 1f04fccc84d..9ac4842d544 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h @@ -26,17 +26,17 @@ typedef id _Nonnull (^CaptureNamedDeviceFactory)(NSString *nam /// Inject @p FlutterTextureRegistry and @p FlutterBinaryMessenger for unit testing. - (instancetype)initWithRegistry:(NSObject *)registry - messenger:(NSObject *)messenger; + messenger:(NSObject *)messenger; /// Inject @p FlutterTextureRegistry, @p FlutterBinaryMessenger, and Pigeon callback handler for /// unit testing. - (instancetype)initWithRegistry:(NSObject *)registry - messenger:(NSObject *)messenger - globalAPI:(FCPCameraGlobalEventApi *)globalAPI - deviceDiscoverer:(id)deviceDiscoverer - deviceFactory:(CaptureNamedDeviceFactory)deviceFactory - captureSessionFactory:(CaptureSessionFactory)captureSessionFactory - captureDeviceInputFactory:(id)captureDeviceInputFactory + messenger:(NSObject *)messenger + globalAPI:(FCPCameraGlobalEventApi *)globalAPI + deviceDiscoverer:(id)deviceDiscoverer + deviceFactory:(CaptureNamedDeviceFactory)deviceFactory + captureSessionFactory:(CaptureSessionFactory)captureSessionFactory + captureDeviceInputFactory:(id)captureDeviceInputFactory NS_DESIGNATED_INITIALIZER; /// Hide the default public constructor. From 40cce5917c5c1cb699c5ac07f6977d3fc889e2a2 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Sun, 2 Feb 2025 15:49:17 +0100 Subject: [PATCH 30/31] Reintroduce default protocol wrappers and rely on NSObject for safer typing --- .../ios/RunnerTests/AvailableCamerasTest.m | 8 +- ...eraCaptureSessionQueueRaceConditionTests.m | 4 +- .../ios/RunnerTests/CameraExposureTests.m | 2 +- .../ios/RunnerTests/CameraFocusTests.m | 2 +- .../ios/RunnerTests/CameraOrientationTests.m | 10 +- .../example/ios/RunnerTests/CameraTestUtils.h | 2 +- .../example/ios/RunnerTests/CameraTestUtils.m | 24 ++- .../ios/RunnerTests/FLTCamPhotoCaptureTests.m | 2 +- .../Mocks/MockCameraDeviceDiscoverer.h | 2 +- .../Mocks/MockCameraDeviceDiscoverer.m | 2 +- .../ios/RunnerTests/Mocks/MockCaptureDevice.h | 9 +- .../ios/RunnerTests/Mocks/MockCaptureDevice.m | 14 +- .../RunnerTests/Mocks/MockCaptureSession.m | 8 +- .../camera_avfoundation/CameraPlugin.m | 27 +-- .../Sources/camera_avfoundation/FLTCam.m | 27 +-- .../camera_avfoundation/FLTCamConfiguration.m | 3 +- .../FLTCamMediaSettingsAVWrapper.m | 13 +- .../FLTCameraDeviceDiscovering.m | 6 +- .../camera_avfoundation/FLTCaptureDevice.m | 198 +++++++++++++++++- .../camera_avfoundation/FLTCaptureSession.m | 105 ++++++++++ .../camera_avfoundation/CameraPlugin_Test.h | 2 +- .../include/camera_avfoundation/FLTCam.h | 5 +- .../camera_avfoundation/FLTCamConfiguration.h | 13 +- .../FLTCamMediaSettingsAVWrapper.h | 13 +- .../FLTCameraDeviceDiscovering.h | 2 +- .../camera_avfoundation/FLTCaptureDevice.h | 24 ++- .../camera_avfoundation/FLTCaptureSession.h | 13 +- .../FLTThreadSafeEventChannel.h | 2 +- 28 files changed, 432 insertions(+), 110 deletions(-) create mode 100644 packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureSession.m diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m index 2e03d361731..516cd3c4958 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/AvailableCamerasTest.m @@ -28,10 +28,10 @@ - (CameraPlugin *)createCameraPluginWithDeviceDiscoverer: messenger:[[MockFlutterBinaryMessenger alloc] init] globalAPI:[[MockGlobalEventApi alloc] init] deviceDiscoverer:deviceDiscoverer - deviceFactory:^id(NSString *name) { + deviceFactory:^NSObject *(NSString *name) { return [[MockCaptureDevice alloc] init]; } - captureSessionFactory:^id { + captureSessionFactory:^NSObject * { return [[MockCaptureSession alloc] init]; } captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; @@ -73,7 +73,7 @@ - (void)testAvailableCamerasShouldReturnAllCamerasOnMultiCameraIPhone { [cameras addObject:ultraWideCamera]; } - mockDeviceDiscoverer.discoverySessionStub = ^NSArray> *_Nullable( + mockDeviceDiscoverer.discoverySessionStub = ^NSArray *> *_Nullable( NSArray *_Nonnull deviceTypes, AVMediaType _Nonnull mediaType, AVCaptureDevicePosition position) { XCTAssertEqualObjects(deviceTypes, requiredTypes); @@ -124,7 +124,7 @@ - (void)testAvailableCamerasShouldReturnOneCameraOnSingleCameraIPhone { NSMutableArray *cameras = [NSMutableArray array]; [cameras addObjectsFromArray:@[ wideAngleCamera, frontFacingCamera ]]; - mockDeviceDiscoverer.discoverySessionStub = ^NSArray> *_Nullable( + mockDeviceDiscoverer.discoverySessionStub = ^NSArray *> *_Nullable( NSArray *_Nonnull deviceTypes, AVMediaType _Nonnull mediaType, AVCaptureDevicePosition position) { XCTAssertEqualObjects(deviceTypes, requiredTypes); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m index ef7f6af9bab..8275ae75bb9 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m @@ -28,10 +28,10 @@ - (void)testFixForCaptureSessionQueueNullPointerCrashDueToRaceCondition { messenger:[[MockFlutterBinaryMessenger alloc] init] globalAPI:[[MockGlobalEventApi alloc] init] deviceDiscoverer:[[MockCameraDeviceDiscoverer alloc] init] - deviceFactory:^id(NSString *name) { + deviceFactory:^NSObject *(NSString *name) { return captureDevice; } - captureSessionFactory:^id { + captureSessionFactory:^NSObject * { return [[MockCaptureSession alloc] init]; } captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m index 11a7ff3ba54..e0969ad703d 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraExposureTests.m @@ -25,7 +25,7 @@ - (void)setUp { _camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( nil, nil, nil, - ^id(void) { + ^NSObject *(void) { return mockDevice; }, _mockDeviceOrientationProvider); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m index 0a8fe6f3000..5f52c9bc5ee 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraFocusTests.m @@ -28,7 +28,7 @@ - (void)setUp { _camera = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( nil, nil, nil, - ^id(void) { + ^NSObject *(void) { return mockDevice; }, _mockDeviceOrientationProvider); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m index 3073eda5db3..09f57551f0f 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraOrientationTests.m @@ -28,7 +28,7 @@ - (void)setDeviceOrientation:(UIDeviceOrientation)orientation { } } -- (void)setCaptureDevice:(id)device { +- (void)setCaptureDevice:(NSObject *)device { self.captureDevice = device; } @@ -69,10 +69,10 @@ - (void)setUp { messenger:[[MockFlutterBinaryMessenger alloc] init] globalAPI:_eventAPI deviceDiscoverer:_deviceDiscoverer - deviceFactory:^id(NSString *name) { + deviceFactory:^NSObject *(NSString *name) { return mockDevice; } - captureSessionFactory:^id _Nonnull { + captureSessionFactory:^NSObject *_Nonnull { return [[MockCaptureSession alloc] init]; } captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; @@ -154,10 +154,10 @@ - (void)testOrientationChanged_noRetainCycle { messenger:[[MockFlutterBinaryMessenger alloc] init] globalAPI:_eventAPI deviceDiscoverer:_deviceDiscoverer - deviceFactory:^id(NSString *name) { + deviceFactory:^NSObject *(NSString *name) { return weakDevice; } - captureSessionFactory:^id _Nonnull { + captureSessionFactory:^NSObject *_Nonnull { return [[MockCaptureSession alloc] init]; } captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h index 008ba9df48f..c8a5b230453 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.h @@ -29,7 +29,7 @@ extern FLTCam *FLTCreateCamWithCaptureSessionQueue(dispatch_queue_t captureSessi /// @param captureSession AVCaptureSession for video /// @param resolutionPreset preset for camera's captureSession resolution /// @return an FLTCam object. -extern FLTCam *FLTCreateCamWithVideoCaptureSession(AVCaptureSession *captureSession, +extern FLTCam *FLTCreateCamWithVideoCaptureSession(NSObject *captureSession, FCPPlatformResolutionPreset resolutionPreset); /// Creates an `FLTCam` with a given captureSession and resolutionPreset. diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m index 7dbcbd79b26..67d4432d2f4 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraTestUtils.m @@ -29,7 +29,7 @@ FLTCam *FLTCreateCamWithCaptureSessionQueueAndMediaSettings( dispatch_queue_t captureSessionQueue, FCPPlatformMediaSettings *mediaSettings, FLTCamMediaSettingsAVWrapper *mediaSettingsAVWrapper, CaptureDeviceFactory captureDeviceFactory, - id deviceOrientationProvider) { + NSObject *deviceOrientationProvider) { if (!mediaSettings) { mediaSettings = FCPGetDefaultMediaSettings(FCPPlatformResolutionPresetMedium); } @@ -93,10 +93,10 @@ FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] initWithMediaSettings:mediaSettings mediaSettingsWrapper:mediaSettingsAVWrapper - captureDeviceFactory:captureDeviceFactory ?: ^id(void) { + captureDeviceFactory:captureDeviceFactory ?: ^NSObject *(void) { return captureDeviceMock; } - captureSessionFactory:^id _Nonnull{ + captureSessionFactory:^NSObject *_Nonnull{ return videoSessionMock; } captureSessionQueue:captureSessionQueue @@ -139,7 +139,7 @@ return fltCam; } -FLTCam *FLTCreateCamWithVideoCaptureSession(id captureSession, +FLTCam *FLTCreateCamWithVideoCaptureSession(NSObject *captureSession, FCPPlatformResolutionPreset resolutionPreset) { id inputMock = OCMClassMock([AVCaptureDeviceInput class]); OCMStub([inputMock deviceInputWithDevice:[OCMArg any] error:[OCMArg setTo:nil]]) @@ -154,10 +154,10 @@ FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] - captureDeviceFactory:^id(void) { + captureDeviceFactory:^NSObject *(void) { return captureDeviceMock; } - captureSessionFactory:^id _Nonnull { + captureSessionFactory:^NSObject *_Nonnull { return captureSession; } captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL) @@ -184,18 +184,20 @@ FLTCamConfiguration *configuration = [[FLTCamConfiguration alloc] initWithMediaSettings:FCPGetDefaultMediaSettings(resolutionPreset) mediaSettingsWrapper:[[FLTCamMediaSettingsAVWrapper alloc] init] - captureDeviceFactory:^id(void) { - return captureDevice; + captureDeviceFactory:^NSObject *(void) { + return [[FLTDefaultCaptureDevice alloc] initWithDevice:captureDevice]; } - captureSessionFactory:^id _Nonnull { - return [[AVCaptureSession alloc] init]; + captureSessionFactory:^NSObject *_Nonnull { + return [[FLTDefaultCaptureSession alloc] + initWithCaptureSession:[[AVCaptureSession alloc] init]]; } captureSessionQueue:dispatch_queue_create("capture_session_queue", NULL) captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; configuration.videoDimensionsForFormat = videoDimensionsForFormat; configuration.deviceOrientationProvider = [[MockDeviceOrientationProvider alloc] init]; - configuration.videoCaptureSession = captureSession; + configuration.videoCaptureSession = + [[FLTDefaultCaptureSession alloc] initWithCaptureSession:captureSession]; configuration.audioCaptureSession = audioSessionMock; configuration.orientation = UIDeviceOrientationPortrait; diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m index f68301d86f2..dc6fd86a8b6 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamPhotoCaptureTests.m @@ -189,7 +189,7 @@ - (void)testCaptureToFile_handlesTorchMode { FLTCam *cam = FLTCreateCamWithCaptureSessionQueueAndMediaSettings( captureSessionQueue, nil, nil, - ^id(void) { + ^NSObject *(void) { return captureDeviceMock; }, nil); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h index 074afbf47af..27f72fdb409 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.h @@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN /// A stub that replaces the default implementation of /// `discoverySessionWithDeviceTypes:mediaType:position`. -@property(nonatomic, copy) NSArray> *_Nullable (^discoverySessionStub) +@property(nonatomic, copy) NSArray *> *_Nullable (^discoverySessionStub) (NSArray *deviceTypes, AVMediaType mediaType, AVCaptureDevicePosition position); diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.m index 3a8c2cc63dc..f132945338c 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCameraDeviceDiscoverer.m @@ -6,7 +6,7 @@ @implementation MockCameraDeviceDiscoverer -- (NSArray> *) +- (NSArray *> *) discoverySessionWithDeviceTypes:(NSArray *)deviceTypes mediaType:(AVMediaType)mediaType position:(AVCaptureDevicePosition)position { diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h index 18b302aee55..89dd1648827 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.h @@ -98,11 +98,6 @@ NS_ASSUME_NONNULL_BEGIN /// @param duration The maximum frame duration being set @property(nonatomic, copy) void (^setActiveVideoMaxFrameDurationStub)(CMTime duration); -// Input Creation -/// Overrides the default implementation of creating capture input. -/// @param error Error pointer to be set if creation fails -@property(nonatomic, copy) AVCaptureInput * (^createInputStub)(NSError **error); - @end /// A mocked implementation of FLTCaptureDeviceInputFactory which allows injecting a custom @@ -120,10 +115,10 @@ NS_ASSUME_NONNULL_BEGIN /// Initializes a new instance with the given mock device input. Whenever `deviceInputWithDevice` is /// called on this instance, it will return the mock device input. -- (nonnull instancetype)initWithMockDeviceInput:(id)mockDeviceInput; +- (nonnull instancetype)initWithMockDeviceInput:(NSObject *)mockDeviceInput; /// The mock device input to be returned by `deviceInputWithDevice`. -@property(nonatomic, strong) id mockDeviceInput; +@property(nonatomic, strong) NSObject *mockDeviceInput; @end diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m index 49b2da33780..8114be864b7 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureDevice.m @@ -100,17 +100,13 @@ - (BOOL)isExposureModeSupported:(AVCaptureExposureMode)mode { return self.exposureModeSupported; } -- (AVCaptureInput *)createInput:(NSError *_Nullable *_Nullable)error { - if (self.createInputStub) { - return self.createInputStub(error); - } - return NULL; -} +@synthesize device; @end @implementation MockCaptureInput @synthesize ports; +@synthesize input; @end @implementation MockCaptureDeviceInputFactory @@ -123,7 +119,8 @@ - (nonnull instancetype)init { return self; } -- (nonnull instancetype)initWithMockDeviceInput:(nonnull id)mockDeviceInput { +- (nonnull instancetype)initWithMockDeviceInput: + (nonnull NSObject *)mockDeviceInput { self = [super init]; if (self) { _mockDeviceInput = mockDeviceInput; @@ -131,7 +128,8 @@ - (nonnull instancetype)initWithMockDeviceInput:(nonnull id)moc return self; } -- (id)deviceInputWithDevice:(id)device error:(NSError **)error { +- (NSObject *)deviceInputWithDevice:(NSObject *)device + error:(NSError **)error { return _mockDeviceInput; } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.m index 3e13e6a7f02..eb1dee86495 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCaptureSession.m @@ -46,10 +46,10 @@ - (BOOL)canSetSessionPreset:(AVCaptureSessionPreset)preset { - (void)addConnection:(nonnull AVCaptureConnection *)connection { } -- (void)addInput:(nonnull AVCaptureInput *)input { +- (void)addInput:(nonnull NSObject *)input { } -- (void)addInputWithNoConnections:(nonnull AVCaptureInput *)input { +- (void)addInputWithNoConnections:(nonnull NSObject *)input { } - (void)addOutput:(nonnull AVCaptureOutput *)output { @@ -62,7 +62,7 @@ - (BOOL)canAddConnection:(nonnull AVCaptureConnection *)connection { return YES; } -- (BOOL)canAddInput:(nonnull AVCaptureInput *)input { +- (BOOL)canAddInput:(nonnull NSObject *)input { return YES; } @@ -70,7 +70,7 @@ - (BOOL)canAddOutput:(nonnull AVCaptureOutput *)output { return YES; } -- (void)removeInput:(nonnull AVCaptureInput *)input { +- (void)removeInput:(nonnull NSObject *)input { } - (void)removeOutput:(nonnull AVCaptureOutput *)output { diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m index d500348ed0b..71fb384971d 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m @@ -23,14 +23,14 @@ } @interface CameraPlugin () -@property(readonly, nonatomic) id registry; +@property(readonly, nonatomic) NSObject *registry; @property(readonly, nonatomic) NSObject *messenger; @property(nonatomic) FCPCameraGlobalEventApi *globalEventAPI; @property(readonly, nonatomic) FLTCameraPermissionManager *permissionManager; -@property(readonly, nonatomic) id deviceDiscoverer; +@property(readonly, nonatomic) NSObject *deviceDiscoverer; @property(readonly, nonatomic) CaptureNamedDeviceFactory captureDeviceFactory; @property(readonly, nonatomic) CaptureSessionFactory captureSessionFactory; -@property(readonly, nonatomic) id captureDeviceInputFactory; +@property(readonly, nonatomic) NSObject *captureDeviceInputFactory; @end @implementation CameraPlugin @@ -47,11 +47,13 @@ - (instancetype)initWithRegistry:(NSObject *)registry messenger:messenger globalAPI:[[FCPCameraGlobalEventApi alloc] initWithBinaryMessenger:messenger] deviceDiscoverer:[[FLTDefaultCameraDeviceDiscoverer alloc] init] - deviceFactory:^id(NSString *name) { - return [AVCaptureDevice deviceWithUniqueID:name]; + deviceFactory:^NSObject *(NSString *name) { + return [[FLTDefaultCaptureDevice alloc] + initWithDevice:[AVCaptureDevice deviceWithUniqueID:name]]; } - captureSessionFactory:^id(void) { - return [[AVCaptureSession alloc] init]; + captureSessionFactory:^NSObject *(void) { + return [[FLTDefaultCaptureSession alloc] + initWithCaptureSession:[[AVCaptureSession alloc] init]]; } captureDeviceInputFactory:[[FLTDefaultCaptureDeviceInputFactory alloc] init]]; } @@ -59,10 +61,11 @@ - (instancetype)initWithRegistry:(NSObject *)registry - (instancetype)initWithRegistry:(NSObject *)registry messenger:(NSObject *)messenger globalAPI:(FCPCameraGlobalEventApi *)globalAPI - deviceDiscoverer:(id)deviceDiscoverer + deviceDiscoverer:(NSObject *)deviceDiscoverer deviceFactory:(CaptureNamedDeviceFactory)deviceFactory captureSessionFactory:(CaptureSessionFactory)captureSessionFactory - captureDeviceInputFactory:(id)captureDeviceInputFactory { + captureDeviceInputFactory: + (NSObject *)captureDeviceInputFactory { self = [super init]; NSAssert(self, @"super init cannot be nil"); _registry = registry; @@ -137,13 +140,13 @@ - (void)availableCamerasWithCompletion: if (@available(iOS 13.0, *)) { [discoveryDevices addObject:AVCaptureDeviceTypeBuiltInUltraWideCamera]; } - NSArray> *devices = + NSArray *> *devices = [self.deviceDiscoverer discoverySessionWithDeviceTypes:discoveryDevices mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified]; NSMutableArray *reply = [[NSMutableArray alloc] initWithCapacity:devices.count]; - for (id device in devices) { + for (NSObject *device in devices) { FCPPlatformCameraLensDirection lensFacing; switch (device.position) { case AVCaptureDevicePositionBack: @@ -499,7 +502,7 @@ - (void)sessionQueueCreateCameraWithName:(NSString *)name FLTCamConfiguration *camConfiguration = [[FLTCamConfiguration alloc] initWithMediaSettings:settings mediaSettingsWrapper:mediaSettingsAVWrapper - captureDeviceFactory:^id _Nonnull { + captureDeviceFactory:^NSObject *_Nonnull { return self.captureDeviceFactory(name); } captureSessionFactory:_captureSessionFactory diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 5834d3bc0bb..9007e767b14 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -57,10 +57,10 @@ @interface FLTCam () videoCaptureSession; -@property(readonly, nonatomic) id audioCaptureSession; +@property(readonly, nonatomic) NSObject *videoCaptureSession; +@property(readonly, nonatomic) NSObject *audioCaptureSession; -@property(readonly, nonatomic) id captureVideoInput; +@property(readonly, nonatomic) NSObject *captureVideoInput; /// Tracks the latest pixel buffer sent from AVFoundation's sample buffer delegate callback. /// Used to deliver the latest pixel buffer to the flutter engine via the `copyPixelBuffer` API. @property(readwrite, nonatomic) CVPixelBufferRef latestPixelBuffer; @@ -106,8 +106,8 @@ @interface FLTCam () captureDeviceInputFactory; -@property(readonly, nonatomic) id deviceOrientationProvider; +@property(readonly, nonatomic) NSObject *captureDeviceInputFactory; +@property(readonly, nonatomic) NSObject *deviceOrientationProvider; /// Reports the given error message to the Dart side of the plugin. /// /// Can be called from any thread. @@ -139,7 +139,7 @@ static double bestFrameRateForFormat(AVCaptureDeviceFormat *format, double targe // as activeFormat and also updates mediaSettings.framesPerSecond to value which // bestFrameRateForFormat returned for that format. static void selectBestFormatForRequestedFrameRate( - AVCaptureDevice *captureDevice, FCPPlatformMediaSettings *mediaSettings, + NSObject *captureDevice, FCPPlatformMediaSettings *mediaSettings, VideoDimensionsForFormat videoDimensionsForFormat) { CMVideoDimensions targetResolution = videoDimensionsForFormat(captureDevice.activeFormat); double targetFrameRate = mediaSettings.framesPerSecond.doubleValue; @@ -552,7 +552,7 @@ - (BOOL)setCaptureSessionPreset:(FCPPlatformResolutionPreset)resolutionPreset /// Finds the highest available resolution in terms of pixel count for the given device. /// Preferred are formats with the same subtype as current activeFormat. - (AVCaptureDeviceFormat *)highestResolutionFormatForCaptureDevice: - (AVCaptureDevice *)captureDevice { + (NSObject *)captureDevice { FourCharCode preferredSubType = CMFormatDescriptionGetMediaSubType(_captureDevice.activeFormat.formatDescription); AVCaptureDeviceFormat *bestFormat = nil; @@ -799,13 +799,13 @@ - (void)newAudioSample:(CMSampleBufferRef)sampleBuffer { - (void)close { [self stop]; for (AVCaptureInput *input in [_videoCaptureSession inputs]) { - [_videoCaptureSession removeInput:input]; + [_videoCaptureSession removeInput:[[FLTDefaultCaptureInput alloc] initWithInput:input]]; } for (AVCaptureOutput *output in [_videoCaptureSession outputs]) { [_videoCaptureSession removeOutput:output]; } for (AVCaptureInput *input in [_audioCaptureSession inputs]) { - [_audioCaptureSession removeInput:input]; + [_audioCaptureSession removeInput:[[FLTDefaultCaptureInput alloc] initWithInput:input]]; } for (AVCaptureOutput *output in [_audioCaptureSession outputs]) { [_audioCaptureSession removeOutput:output]; @@ -1004,7 +1004,7 @@ - (void)applyFocusMode { } - (void)applyFocusMode:(FCPPlatformFocusMode)focusMode - onDevice:(id)captureDevice { + onDevice:(NSObject *)captureDevice { [captureDevice lockForConfiguration:nil]; switch (focusMode) { case FCPPlatformFocusModeLocked: @@ -1371,9 +1371,10 @@ - (void)setUpCaptureSessionForAudioIfNeeded { NSError *error = nil; // Create a device input with the device and add it to the session. // Setup the audio input. - AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; - id audioInput = [_captureDeviceInputFactory deviceInputWithDevice:audioDevice - error:&error]; + NSObject *audioDevice = [[FLTDefaultCaptureDevice alloc] + initWithDevice:[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]]; + NSObject *audioInput = + [_captureDeviceInputFactory deviceInputWithDevice:audioDevice error:&error]; if (error) { [self reportErrorMessage:error.description]; } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m index cef02879c0d..c9c2a7ca257 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamConfiguration.m @@ -11,7 +11,8 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings captureDeviceFactory:(CaptureDeviceFactory)captureDeviceFactory captureSessionFactory:(CaptureSessionFactory)captureSessionFactory captureSessionQueue:(dispatch_queue_t)captureSessionQueue - captureDeviceInputFactory:(id)captureDeviceInputFactory { + captureDeviceInputFactory: + (NSObject *)captureDeviceInputFactory { self = [super init]; if (self) { _mediaSettings = mediaSettings; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m index 5f4aab44a4b..01f18b52ebe 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCamMediaSettingsAVWrapper.m @@ -4,31 +4,32 @@ #import "./include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h" #import "./include/camera_avfoundation/FLTCaptureDevice.h" +#import "./include/camera_avfoundation/FLTCaptureSession.h" @implementation FLTCamMediaSettingsAVWrapper -- (BOOL)lockDevice:(id)captureDevice +- (BOOL)lockDevice:(NSObject *)captureDevice error:(NSError *_Nullable *_Nullable)outError { return [captureDevice lockForConfiguration:outError]; } -- (void)unlockDevice:(id)captureDevice { +- (void)unlockDevice:(NSObject *)captureDevice { return [captureDevice unlockForConfiguration]; } -- (void)beginConfigurationForSession:(AVCaptureSession *)videoCaptureSession { +- (void)beginConfigurationForSession:(NSObject *)videoCaptureSession { [videoCaptureSession beginConfiguration]; } -- (void)commitConfigurationForSession:(AVCaptureSession *)videoCaptureSession { +- (void)commitConfigurationForSession:(NSObject *)videoCaptureSession { [videoCaptureSession commitConfiguration]; } -- (void)setMinFrameDuration:(CMTime)duration onDevice:(id)captureDevice { +- (void)setMinFrameDuration:(CMTime)duration onDevice:(NSObject *)captureDevice { captureDevice.activeVideoMinFrameDuration = duration; } -- (void)setMaxFrameDuration:(CMTime)duration onDevice:(id)captureDevice { +- (void)setMaxFrameDuration:(CMTime)duration onDevice:(NSObject *)captureDevice { captureDevice.activeVideoMaxFrameDuration = duration; } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m index 4cf8fdf98eb..c4498e8dae6 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m @@ -8,7 +8,7 @@ @implementation FLTDefaultCameraDeviceDiscoverer -- (NSArray> *) +- (NSArray *> *) discoverySessionWithDeviceTypes:(NSArray *)deviceTypes mediaType:(AVMediaType)mediaType position:(AVCaptureDevicePosition)position { @@ -18,11 +18,11 @@ @implementation FLTDefaultCameraDeviceDiscoverer position:position]; NSArray *devices = discoverySession.devices; - NSMutableArray> *deviceControllers = + NSMutableArray *> *deviceControllers = [NSMutableArray arrayWithCapacity:devices.count]; for (AVCaptureDevice *device in devices) { - [deviceControllers addObject:device]; + [deviceControllers addObject:[[FLTDefaultCaptureDevice alloc] initWithDevice:device]]; } return deviceControllers; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m index 4981e580f71..d9badbfe94a 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureDevice.m @@ -6,10 +6,204 @@ #import "FLTCaptureDevice.h" +@interface FLTDefaultCaptureDevice () +@property(nonatomic, strong) AVCaptureDevice *device; +@end + +@implementation FLTDefaultCaptureDevice + +- (instancetype)initWithDevice:(AVCaptureDevice *)device { + self = [super init]; + if (self) { + _device = device; + } + return self; +} + +// Device identifier +- (NSString *)uniqueID { + return self.device.uniqueID; +} + +// Position/Orientation +- (AVCaptureDevicePosition)position { + return self.device.position; +} + +// Format/Configuration +- (AVCaptureDeviceFormat *)activeFormat { + return self.device.activeFormat; +} + +- (NSArray *)formats { + return self.device.formats; +} + +- (void)setActiveFormat:(AVCaptureDeviceFormat *)format { + self.device.activeFormat = format; +} + +// Flash/Torch +- (BOOL)hasFlash { + return self.device.hasFlash; +} + +- (BOOL)hasTorch { + return self.device.hasTorch; +} + +- (BOOL)isTorchAvailable { + return self.device.isTorchAvailable; +} + +- (AVCaptureTorchMode)torchMode { + return self.device.torchMode; +} + +- (void)setTorchMode:(AVCaptureTorchMode)torchMode { + self.device.torchMode = torchMode; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +- (BOOL)isFlashModeSupported:(AVCaptureFlashMode)mode { + return [self.device isFlashModeSupported:mode]; +} +#pragma clang diagnostic pop + +// Focus +- (BOOL)focusPointOfInterestSupported { + return self.device.focusPointOfInterestSupported; +} + +- (BOOL)isFocusModeSupported:(AVCaptureFocusMode)mode { + return [self.device isFocusModeSupported:mode]; +} + +- (void)setFocusMode:(AVCaptureFocusMode)focusMode { + self.device.focusMode = focusMode; +} + +- (void)setFocusPointOfInterest:(CGPoint)point { + self.device.focusPointOfInterest = point; +} + +// Exposure +- (BOOL)exposurePointOfInterestSupported { + return self.device.exposurePointOfInterestSupported; +} + +- (void)setExposureMode:(AVCaptureExposureMode)exposureMode { + self.device.exposureMode = exposureMode; +} + +- (void)setExposurePointOfInterest:(CGPoint)point { + self.device.exposurePointOfInterest = point; +} + +- (float)minExposureTargetBias { + return self.device.minExposureTargetBias; +} + +- (float)maxExposureTargetBias { + return self.device.maxExposureTargetBias; +} + +- (void)setExposureTargetBias:(float)bias completionHandler:(void (^)(CMTime))handler { + [self.device setExposureTargetBias:bias completionHandler:handler]; +} + +- (BOOL)isExposureModeSupported:(AVCaptureExposureMode)mode { + return [self.device isExposureModeSupported:mode]; +} + +// Zoom +- (float)maxAvailableVideoZoomFactor { + return self.device.maxAvailableVideoZoomFactor; +} + +- (float)minAvailableVideoZoomFactor { + return self.device.minAvailableVideoZoomFactor; +} + +- (float)videoZoomFactor { + return self.device.videoZoomFactor; +} + +- (void)setVideoZoomFactor:(float)factor { + self.device.videoZoomFactor = factor; +} + +// Camera Properties +- (float)lensAperture { + return self.device.lensAperture; +} + +- (CMTime)exposureDuration { + return self.device.exposureDuration; +} + +- (float)ISO { + return self.device.ISO; +} + +// Configuration Lock +- (BOOL)lockForConfiguration:(NSError **)error { + return [self.device lockForConfiguration:error]; +} + +- (void)unlockForConfiguration { + [self.device unlockForConfiguration]; +} + +- (CMTime)activeVideoMinFrameDuration { + return self.device.activeVideoMinFrameDuration; +} + +- (void)setActiveVideoMinFrameDuration:(CMTime)duration { + self.device.activeVideoMinFrameDuration = duration; +} + +- (CMTime)activeVideoMaxFrameDuration { + return self.device.activeVideoMaxFrameDuration; +} + +- (void)setActiveVideoMaxFrameDuration:(CMTime)duration { + self.device.activeVideoMaxFrameDuration = duration; +} + +@end + +@interface FLTDefaultCaptureInput () +@property(nonatomic, strong) AVCaptureInput *input; +@end + +@implementation FLTDefaultCaptureInput + +- (instancetype)initWithInput:(AVCaptureInput *)input { + self = [super init]; + if (self) { + _input = input; + } + return self; +} + +- (AVCaptureInput *)input { + return _input; +} + +- (NSArray *)ports { + return self.input.ports; +} + +@end + @implementation FLTDefaultCaptureDeviceInputFactory -- (AVCaptureInput *)deviceInputWithDevice:(id)device error:(NSError **)error { - return [AVCaptureDeviceInput deviceInputWithDevice:device error:error]; +- (NSObject *)deviceInputWithDevice:(NSObject *)device + error:(NSError **)error { + return [[FLTDefaultCaptureInput alloc] + initWithInput:[AVCaptureDeviceInput deviceInputWithDevice:device.device error:error]]; } @end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureSession.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureSession.m new file mode 100644 index 00000000000..4812d883476 --- /dev/null +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCaptureSession.m @@ -0,0 +1,105 @@ +// 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. + +#import "FLTCaptureSession.h" + +@interface FLTDefaultCaptureSession () +@property(nonatomic, strong) AVCaptureSession *captureSession; +@end + +@implementation FLTDefaultCaptureSession + +- (instancetype)initWithCaptureSession:(AVCaptureSession *)session { + self = [super init]; + if (self) { + _captureSession = session; + } + return self; +} + +- (void)beginConfiguration { + [_captureSession beginConfiguration]; +} + +- (void)commitConfiguration { + [_captureSession commitConfiguration]; +} + +- (void)startRunning { + [_captureSession startRunning]; +} + +- (void)stopRunning { + [_captureSession stopRunning]; +} + +- (BOOL)automaticallyConfiguresApplicationAudioSession { + return _captureSession.automaticallyConfiguresApplicationAudioSession; +} + +- (void)setAutomaticallyConfiguresApplicationAudioSession:(BOOL)value { + _captureSession.automaticallyConfiguresApplicationAudioSession = value; +} + +- (BOOL)canSetSessionPreset:(AVCaptureSessionPreset)preset { + return [_captureSession canSetSessionPreset:preset]; +} + +- (void)addInputWithNoConnections:(NSObject *)input { + [_captureSession addInputWithNoConnections:input.input]; +} + +- (void)addOutputWithNoConnections:(AVCaptureOutput *)output { + [_captureSession addOutputWithNoConnections:output]; +} + +- (void)addConnection:(AVCaptureConnection *)connection { + [_captureSession addConnection:connection]; +} + +- (void)addOutput:(AVCaptureOutput *)output { + [_captureSession addOutput:output]; +} + +- (void)removeInput:(NSObject *)input { + [_captureSession removeInput:input.input]; +} + +- (void)removeOutput:(AVCaptureOutput *)output { + [_captureSession removeOutput:output]; +} + +- (void)setSessionPreset:(AVCaptureSessionPreset)sessionPreset { + _captureSession.sessionPreset = sessionPreset; +} + +- (AVCaptureSessionPreset)sessionPreset { + return _captureSession.sessionPreset; +} + +- (NSArray *)inputs { + return _captureSession.inputs; +} + +- (NSArray *)outputs { + return _captureSession.outputs; +} + +- (BOOL)canAddInput:(NSObject *)input { + return [_captureSession canAddInput:input.input]; +} + +- (BOOL)canAddOutput:(AVCaptureOutput *)output { + return [_captureSession canAddOutput:output]; +} + +- (BOOL)canAddConnection:(AVCaptureConnection *)connection { + return [_captureSession canAddConnection:connection]; +} + +- (void)addInput:(NSObject *)input { + [_captureSession addInput:input.input]; +} + +@end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h index 9ac4842d544..0e119c3bb14 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraPlugin_Test.h @@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN -typedef id _Nonnull (^CaptureNamedDeviceFactory)(NSString *name); +typedef NSObject *_Nonnull (^CaptureNamedDeviceFactory)(NSString *name); /// APIs exposed for unit testing. @interface CameraPlugin () diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h index 4262bae0c05..6e22ad5b1ac 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h @@ -18,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN /// A class that manages camera's state and performs camera operations. @interface FLTCam : NSObject -@property(readonly, nonatomic) id captureDevice; +@property(readonly, nonatomic) NSObject *captureDevice; @property(readonly, nonatomic) CGSize previewSize; @property(assign, nonatomic) BOOL isPreviewPaused; @property(nonatomic, copy) void (^onFrameAvailable)(void); @@ -84,7 +84,8 @@ NS_ASSUME_NONNULL_BEGIN /// /// @param focusMode The focus mode that should be applied to the @captureDevice instance. /// @param captureDevice The AVCaptureDevice to which the @focusMode will be applied. -- (void)applyFocusMode:(FCPPlatformFocusMode)focusMode onDevice:(id)captureDevice; +- (void)applyFocusMode:(FCPPlatformFocusMode)focusMode + onDevice:(NSObject *)captureDevice; - (void)pausePreview; - (void)resumePreview; - (void)setDescriptionWhileRecording:(NSString *)cameraName diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h index fc41ee46a3e..36393009b7a 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamConfiguration.h @@ -16,9 +16,9 @@ NS_ASSUME_NONNULL_BEGIN /// Factory block returning an AVCaptureDevice. /// Used in tests to inject a device into FLTCam. -typedef id _Nonnull (^CaptureDeviceFactory)(void); +typedef NSObject *_Nonnull (^CaptureDeviceFactory)(void); -typedef id _Nonnull (^CaptureSessionFactory)(void); +typedef NSObject *_Nonnull (^CaptureSessionFactory)(void); /// Determines the video dimensions (width and height) for a given capture device format. /// Used in tests to mock CMVideoFormatDescriptionGetDimensions. @@ -33,7 +33,8 @@ typedef CMVideoDimensions (^VideoDimensionsForFormat)(AVCaptureDeviceFormat *); captureDeviceFactory:(CaptureDeviceFactory)captureDeviceFactory captureSessionFactory:(CaptureSessionFactory)captureSessionFactory captureSessionQueue:(dispatch_queue_t)captureSessionQueue - captureDeviceInputFactory:(id)captureDeviceInputFactory; + captureDeviceInputFactory: + (NSObject *)captureDeviceInputFactory; @property(nonatomic, strong) id deviceOrientationProvider; @property(nonatomic, strong) dispatch_queue_t captureSessionQueue; @@ -43,9 +44,9 @@ typedef CMVideoDimensions (^VideoDimensionsForFormat)(AVCaptureDeviceFormat *); @property(nonatomic, copy) CaptureDeviceFactory audioCaptureDeviceFactory; @property(nonatomic, copy) VideoDimensionsForFormat videoDimensionsForFormat; @property(nonatomic, assign) UIDeviceOrientation orientation; -@property(nonatomic, strong) id videoCaptureSession; -@property(nonatomic, strong) id audioCaptureSession; -@property(nonatomic, strong) id captureDeviceInputFactory; +@property(nonatomic, strong) NSObject *videoCaptureSession; +@property(nonatomic, strong) NSObject *audioCaptureSession; +@property(nonatomic, strong) NSObject *captureDeviceInputFactory; @end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h index 2baf2c406b3..fb8d7040d67 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCamMediaSettingsAVWrapper.h @@ -6,6 +6,7 @@ @import Foundation; #import "FLTCaptureDevice.h" +#import "FLTCaptureSession.h" NS_ASSUME_NONNULL_BEGIN @@ -27,7 +28,7 @@ NS_ASSUME_NONNULL_BEGIN * @param outError The optional error. * @result A BOOL indicating whether the device was successfully locked for configuration. */ -- (BOOL)lockDevice:(id)captureDevice +- (BOOL)lockDevice:(NSObject *)captureDevice error:(NSError *_Nullable *_Nullable)outError; /** @@ -35,7 +36,7 @@ NS_ASSUME_NONNULL_BEGIN * @abstract Release exclusive control over device hardware properties. * @param captureDevice The capture device. */ -- (void)unlockDevice:(id)captureDevice; +- (void)unlockDevice:(NSObject *)captureDevice; /** * @method beginConfigurationForSession: @@ -43,7 +44,7 @@ NS_ASSUME_NONNULL_BEGIN * operations on a running session into atomic updates. * @param videoCaptureSession The video capture session. */ -- (void)beginConfigurationForSession:(AVCaptureSession *)videoCaptureSession; +- (void)beginConfigurationForSession:(NSObject *)videoCaptureSession; /** * @method commitConfigurationForSession: @@ -51,7 +52,7 @@ NS_ASSUME_NONNULL_BEGIN * operations on a running session into atomic updates. * @param videoCaptureSession The video capture session. */ -- (void)commitConfigurationForSession:(AVCaptureSession *)videoCaptureSession; +- (void)commitConfigurationForSession:(NSObject *)videoCaptureSession; /** * @method setMinFrameDuration:onDevice: @@ -60,7 +61,7 @@ NS_ASSUME_NONNULL_BEGIN * @param duration The frame duration. * @param captureDevice The capture device */ -- (void)setMinFrameDuration:(CMTime)duration onDevice:(id)captureDevice; +- (void)setMinFrameDuration:(CMTime)duration onDevice:(NSObject *)captureDevice; /** * @method setMaxFrameDuration:onDevice: @@ -69,7 +70,7 @@ NS_ASSUME_NONNULL_BEGIN * @param duration The frame duration. * @param captureDevice The capture device */ -- (void)setMaxFrameDuration:(CMTime)duration onDevice:(id)captureDevice; +- (void)setMaxFrameDuration:(CMTime)duration onDevice:(NSObject *)captureDevice; /** * @method assetWriterAudioInputWithOutputSettings: diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCameraDeviceDiscovering.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCameraDeviceDiscovering.h index 73f8286bd50..e953585f4f5 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCameraDeviceDiscovering.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCameraDeviceDiscovering.h @@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN /// A protocol which abstracts the discovery of camera devices. /// It is a thin wrapper around `AVCaptureDiscoverySession` and it exists to allow mocking in tests. @protocol FLTCameraDeviceDiscovering -- (NSArray> *) +- (NSArray *> *) discoverySessionWithDeviceTypes:(NSArray *)deviceTypes mediaType:(AVMediaType)mediaType position:(AVCaptureDevicePosition)position; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h index 251e03b70b8..09344600a86 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureDevice.h @@ -11,6 +11,11 @@ NS_ASSUME_NONNULL_BEGIN /// It exists to allow replacing AVCaptureDevice in tests. @protocol FLTCaptureDevice +/// Underlying `AVCaptureDevice` instance. This is should not be used directly +/// in the plugin implementation code, but it exists so that other protocol default +/// implementation can pass the raw device to AVFoundation methods. +@property(nonatomic, readonly) AVCaptureDevice *device; + // Device identifier @property(nonatomic, readonly) NSString *uniqueID; @@ -71,20 +76,31 @@ NS_ASSUME_NONNULL_BEGIN /// A protocol which is a direct passthrough to AVCaptureInput. /// It exists to allow replacing AVCaptureInput in tests. @protocol FLTCaptureInput + +/// Underlying input instance. It is exposed as raw AVCaptureInput has to be passed to some +/// AVFoundation methods. The plugin implementation code shouldn't use it though. +@property(nonatomic, readonly) AVCaptureInput *input; + @property(nonatomic, readonly) NSArray *ports; @end /// A protocol which wraps the creation of AVCaptureDeviceInput. /// It exists to allow mocking instances of AVCaptureDeviceInput in tests. @protocol FLTCaptureDeviceInputFactory -- (nullable id)deviceInputWithDevice:(id)device - error:(NSError **)error; +- (nullable NSObject *)deviceInputWithDevice:(NSObject *)device + error:(NSError **)error; @end -@interface AVCaptureDevice (FLTCaptureDevice) +/// A default implementation of `FLTCaptureDevice` which is a direct passthrough to the underlying +/// `AVCaptureDevice`. +@interface FLTDefaultCaptureDevice : NSObject +- (instancetype)initWithDevice:(AVCaptureDevice *)device; @end -@interface AVCaptureInput (FLTCaptureInput) +/// A default implementation of `FLTCaptureInput` which is a direct passthrough to the underlying +/// `AVCaptureInput`. +@interface FLTDefaultCaptureInput : NSObject +- (instancetype)initWithInput:(AVCaptureInput *)input; @end /// A default implementation of FLTCaptureDeviceInputFactory protocol which diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h index fefa2338992..8d8aa21816e 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCaptureSession.h @@ -22,20 +22,23 @@ NS_ASSUME_NONNULL_BEGIN - (void)startRunning; - (void)stopRunning; - (BOOL)canSetSessionPreset:(AVCaptureSessionPreset)preset; -- (void)addInputWithNoConnections:(AVCaptureInput *)input; +- (void)addInputWithNoConnections:(NSObject *)input; - (void)addOutputWithNoConnections:(AVCaptureOutput *)output; - (void)addConnection:(AVCaptureConnection *)connection; - (void)addOutput:(AVCaptureOutput *)output; -- (void)removeInput:(AVCaptureInput *)input; +- (void)removeInput:(NSObject *)input; - (void)removeOutput:(AVCaptureOutput *)output; -- (BOOL)canAddInput:(AVCaptureInput *)input; +- (BOOL)canAddInput:(NSObject *)input; - (BOOL)canAddOutput:(AVCaptureOutput *)output; - (BOOL)canAddConnection:(AVCaptureConnection *)connection; -- (void)addInput:(AVCaptureInput *)input; +- (void)addInput:(NSObject *)input; @end -@interface AVCaptureSession (FLTCaptureSession) +/// A default implementation of `FLTCaptureSession` which is a direct passthrough +/// to the underlying `AVCaptureSession`. +@interface FLTDefaultCaptureSession : NSObject +- (instancetype)initWithCaptureSession:(AVCaptureSession *)session; @end NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTThreadSafeEventChannel.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTThreadSafeEventChannel.h index b942b687dc6..008e2279be0 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTThreadSafeEventChannel.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTThreadSafeEventChannel.h @@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN /// Creates a FLTThreadSafeEventChannel by wrapping a FlutterEventChannel object. /// @param channel The FlutterEventChannel object to be wrapped. -- (instancetype)initWithEventChannel:(id)channel; +- (instancetype)initWithEventChannel:(NSObject *)channel; /// Registers a handler on the main thread for stream setup requests from the Flutter side. /// The completion block runs on the main thread. From fc0e82682a0a9f43cd0432bcb61a4b8b7105da50 Mon Sep 17 00:00:00 2001 From: Marcin Chudy Date: Thu, 6 Feb 2025 17:41:21 +0100 Subject: [PATCH 31/31] Fix nits --- ...eraCaptureSessionQueueRaceConditionTests.m | 63 ++++++++++--------- .../FLTCameraDeviceDiscovering.m | 1 - 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m index 8275ae75bb9..b651fec7864 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraCaptureSessionQueueRaceConditionTests.m @@ -20,21 +20,24 @@ @interface CameraCaptureSessionQueueRaceConditionTests : XCTestCase @implementation CameraCaptureSessionQueueRaceConditionTests -- (void)testFixForCaptureSessionQueueNullPointerCrashDueToRaceCondition { +- (CameraPlugin *)createCameraPlugin { MockCaptureDevice *captureDevice = [[MockCaptureDevice alloc] init]; - CameraPlugin *camera = - [[CameraPlugin alloc] initWithRegistry:[[MockFlutterTextureRegistry alloc] init] - messenger:[[MockFlutterBinaryMessenger alloc] init] - globalAPI:[[MockGlobalEventApi alloc] init] - deviceDiscoverer:[[MockCameraDeviceDiscoverer alloc] init] - deviceFactory:^NSObject *(NSString *name) { - return captureDevice; - } - captureSessionFactory:^NSObject * { - return [[MockCaptureSession alloc] init]; - } - captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; + return [[CameraPlugin alloc] initWithRegistry:[[MockFlutterTextureRegistry alloc] init] + messenger:[[MockFlutterBinaryMessenger alloc] init] + globalAPI:[[MockGlobalEventApi alloc] init] + deviceDiscoverer:[[MockCameraDeviceDiscoverer alloc] init] + deviceFactory:^NSObject *(NSString *name) { + return captureDevice; + } + captureSessionFactory:^NSObject * { + return [[MockCaptureSession alloc] init]; + } + captureDeviceInputFactory:[[MockCaptureDeviceInputFactory alloc] init]]; +} + +- (void)testFixForCaptureSessionQueueNullPointerCrashDueToRaceCondition { + CameraPlugin *cameraPlugin = [self createCameraPlugin]; XCTestExpectation *disposeExpectation = [self expectationWithDescription:@"dispose's result block must be called"]; @@ -42,27 +45,27 @@ - (void)testFixForCaptureSessionQueueNullPointerCrashDueToRaceCondition { [self expectationWithDescription:@"create's result block must be called"]; // Mimic a dispose call followed by a create call, which can be triggered by slightly dragging the // home bar, causing the app to be inactive, and immediately regain active. - [camera disposeCamera:0 - completion:^(FlutterError *_Nullable error) { - [disposeExpectation fulfill]; - }]; - [camera createCameraOnSessionQueueWithName:@"acamera" - settings:[FCPPlatformMediaSettings - makeWithResolutionPreset: - FCPPlatformResolutionPresetMedium - framesPerSecond:nil - videoBitrate:nil - audioBitrate:nil - enableAudio:YES] - completion:^(NSNumber *_Nullable result, - FlutterError *_Nullable error) { - [createExpectation fulfill]; - }]; + [cameraPlugin disposeCamera:0 + completion:^(FlutterError *_Nullable error) { + [disposeExpectation fulfill]; + }]; + [cameraPlugin createCameraOnSessionQueueWithName:@"acamera" + settings:[FCPPlatformMediaSettings + makeWithResolutionPreset: + FCPPlatformResolutionPresetMedium + framesPerSecond:nil + videoBitrate:nil + audioBitrate:nil + enableAudio:YES] + completion:^(NSNumber *_Nullable result, + FlutterError *_Nullable error) { + [createExpectation fulfill]; + }]; [self waitForExpectationsWithTimeout:30 handler:nil]; // `captureSessionQueue` must not be nil after `create` call. Otherwise a nil // `captureSessionQueue` passed into `AVCaptureVideoDataOutput::setSampleBufferDelegate:queue:` // API will cause a crash. - XCTAssertNotNil(camera.captureSessionQueue, + XCTAssertNotNil(cameraPlugin.captureSessionQueue, @"captureSessionQueue must not be nil after create method. "); } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m index c4498e8dae6..070908aab92 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCameraDeviceDiscovering.m @@ -20,7 +20,6 @@ @implementation FLTDefaultCameraDeviceDiscoverer NSArray *devices = discoverySession.devices; NSMutableArray *> *deviceControllers = [NSMutableArray arrayWithCapacity:devices.count]; - for (AVCaptureDevice *device in devices) { [deviceControllers addObject:[[FLTDefaultCaptureDevice alloc] initWithDevice:device]]; }