diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 41077b35b449..2fa09eaf79c2 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 0.13.0 +* Adds `videoOutputPath` support to `startVideoRecording`. * Updates minimum supported SDK version to Flutter 3.38/Dart 3.10. ## 0.12.0+1 diff --git a/packages/camera/camera/README.md b/packages/camera/camera/README.md index 0a39b9a7478f..f61dfa7ca753 100644 --- a/packages/camera/camera/README.md +++ b/packages/camera/camera/README.md @@ -6,9 +6,9 @@ A Flutter plugin for iOS, Android and Web allowing access to the device cameras. -| | Android | iOS | Web | -|----------------|---------|-----------|------------------------| -| **Support** | SDK 24+ | iOS 13.0+ | [See `camera_web `][1] | +| | Android | iOS | Web | +| ----------- | ------- | --------- | ---------------------- | +| **Support** | SDK 24+ | iOS 13.0+ | [See `camera_web `][1] | ## Features @@ -92,6 +92,58 @@ Here is a list of all permission error codes that can be thrown: - `AudioAccessRestricted`: iOS only for now. Thrown when audio access is restricted and users cannot grant permission (parental control). +### Custom Video Recording Path + +You can optionally specify a `videoOutputPath` when calling `startVideoRecording()` to save the recorded video directly to a custom absolute file path on the device. + +```dart +// Always ensure the path ends with the .mp4 extension +await controller.startVideoRecording( + videoOutputPath: '/path/to/your/custom_video.mp4', +); +``` + +#### Platform-Specific Considerations + +**Android** + +Although it is possible to use an absolute path like `/storage/emulated/0/Download/video.mp4`, this is a fragile practice and may fail on many devices or Android versions due to **Scoped Storage** restrictions. + +- **Best Practice:** Always use the [path_provider](https://pub.dev/packages/path_provider) package to fetch a safe, writable directory. +- **Recommended Directory:** Use `getTemporaryDirectory()` or `getApplicationDocumentsDirectory()`. + +```dart +import 'package:path/path.dart' as p; +import 'package:path_provider/path_provider.dart'; + +final directory = await getTemporaryDirectory(); +final videoPath = p.join(directory.path, 'my_video.mp4'); + +await controller.startVideoRecording(videoOutputPath: videoPath); +``` + +**iOS** + +By default, files saved within the application sandbox are private. If you want the recorded videos to be visible and manageable by the user inside the native iOS **Files app**: + +1. Open your `ios/Runner/Info.plist` file. +2. Add the following keys set to `true`: + +```xml +LSSupportsOpeningDocumentsInPlace + +UISupportsDocumentBrowser + +``` + +**Windows** + +Similar to Android, ensure you use the `path_provider` package to resolve a valid system path (such as `getApplicationDocumentsDirectory()` or `getApplicationSupportDirectory()`). This helps avoid OS permission issues (`Access Denied`) when writing files directly to protected directories like the root drive. + +### Video Recording Example + +For a complete, interactive demonstration of video recording with custom file output paths, error handling, and playback, please see the [Video Recording Example](https://github.com/flutter/packages/blob/main/packages/camera/camera/example/lib/video_recording_example.dart) in our example app. + ### Example Here is a small example flutter app displaying a full screen camera preview. diff --git a/packages/camera/camera/example/ios/Runner/Info.plist b/packages/camera/camera/example/ios/Runner/Info.plist index 745494da50a6..42c3f394b0e0 100644 --- a/packages/camera/camera/example/ios/Runner/Info.plist +++ b/packages/camera/camera/example/ios/Runner/Info.plist @@ -2,6 +2,12 @@ + LSSupportsOpeningDocumentsInPlace + + UISupportsDocumentBrowser + + CADisableMinimumFrameDurationOnPhone + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName @@ -28,6 +34,8 @@ Can I use the camera please? Only for demo purpose of the app NSMicrophoneUsageDescription Only for demo purpose of the app + UIApplicationSupportsIndirectInputEvents + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -46,9 +54,5 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - diff --git a/packages/camera/camera/example/lib/video_recording_example.dart b/packages/camera/camera/example/lib/video_recording_example.dart new file mode 100644 index 000000000000..20edbc56427d --- /dev/null +++ b/packages/camera/camera/example/lib/video_recording_example.dart @@ -0,0 +1,909 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +import 'dart:async'; +import 'dart:io'; + +import 'package:camera/camera.dart'; +import 'package:flutter/material.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:video_player/video_player.dart'; + +void main() { + runApp(const VideoRecordingExampleApp()); +} + +/// Video Recording feature with custom output paths (`videoOutputPath`) +class VideoRecordingExampleApp extends StatefulWidget { + /// Default Constructor. + const VideoRecordingExampleApp({super.key}); + + @override + State createState() => + _VideoRecordingExampleAppState(); +} + +class _VideoRecordingExampleAppState extends State { + ThemeMode _themeMode = ThemeMode.light; + + void _toggleTheme() { + setState(() { + _themeMode = _themeMode == ThemeMode.dark + ? ThemeMode.light + : ThemeMode.dark; + }); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Vivid Video Recorder', + themeMode: _themeMode, + theme: ThemeData( + brightness: Brightness.light, + scaffoldBackgroundColor: const Color(0xFFF5F5FA), + colorScheme: const ColorScheme.light( + primary: Color(0xFF6C63FF), + secondary: Color(0xFF00E676), + error: Color(0xFFFF1744), + ), + useMaterial3: true, + ), + darkTheme: ThemeData( + brightness: Brightness.dark, + scaffoldBackgroundColor: const Color(0xFF0F0F1A), + colorScheme: const ColorScheme.dark( + primary: Color(0xFF6C63FF), + secondary: Color(0xFF00E676), + error: Color(0xFFFF1744), + surface: Color(0xFF1E1E30), + ), + useMaterial3: true, + ), + home: VideoRecordingHome( + themeMode: _themeMode, + onThemeToggle: _toggleTheme, + ), + ); + } +} + +/// Home widget hosting the video recording demo. +class VideoRecordingHome extends StatefulWidget { + /// Default Constructor. + const VideoRecordingHome({ + super.key, + required this.themeMode, + required this.onThemeToggle, + }); + + /// The active theme mode. + final ThemeMode themeMode; + + /// Callback to toggle between light and dark themes. + final VoidCallback onThemeToggle; + + @override + State createState() => _VideoRecordingHomeState(); +} + +class _VideoRecordingHomeState extends State + with SingleTickerProviderStateMixin { + List _cameras = []; + CameraController? _controller; + XFile? _recordedVideo; + VideoPlayerController? _videoPlayerController; + + bool _isInitializing = true; + bool _useCustomPath = false; + bool _audioEnabled = true; + + // Custom path options + String _customFileName = 'custom_video_recording.mp4'; + late TextEditingController _customFileNameController; + String? _resolvedCustomPath; + + // SnackBar / Error messaging helper + void _showNotification(String message, {bool isError = false}) { + if (!mounted) { + return; + } + final isDark = widget.themeMode == ThemeMode.dark; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Row( + children: [ + Icon( + isError ? Icons.error_outline : Icons.info_outline, + color: isError ? Colors.redAccent : Colors.greenAccent, + ), + const SizedBox(width: 12), + Expanded(child: Text(message)), + ], + ), + backgroundColor: isDark ? const Color(0xFF1A1A2E) : Colors.white, + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + ), + ); + } + + @override + void initState() { + super.initState(); + _customFileNameController = TextEditingController(text: _customFileName); + _bootstrapCameras(); + } + + Future _bootstrapCameras() async { + try { + _cameras = await availableCameras(); + if (_cameras.isNotEmpty) { + await _initializeCameraController(_cameras.first); + } else { + _showNotification('No cameras detected on this device.', isError: true); + } + } catch (e) { + _showNotification('Failed to detect cameras: $e', isError: true); + } finally { + if (mounted) { + setState(() { + _isInitializing = false; + }); + } + } + } + + Future _initializeCameraController( + CameraDescription description, + ) async { + final CameraController? oldController = _controller; + if (oldController != null) { + _controller = null; + await oldController.dispose(); + } + + final controller = CameraController( + description, + ResolutionPreset.high, + enableAudio: _audioEnabled, + ); + + _controller = controller; + + try { + await controller.initialize(); + if (!mounted) { + await controller.dispose(); + return; + } + } on CameraException catch (e) { + _showNotification('Camera error: ${e.description}', isError: true); + } + + if (mounted) { + setState(() {}); + } + } + + /// Calculates the target custom output path where the video will be saved. + Future _getDestinationPath() async { + final timestamp = DateTime.now().millisecondsSinceEpoch.toString(); + final file = File(_customFileName); + + if (file.isAbsolute) { + return _customFileName; + } + + final String uniqueName = _customFileName.replaceFirst( + '.mp4', + '_$timestamp.mp4', + ); + + // Although it is possible to use an absolute path like '/storage/emulated/0/Download/', + // this is a fragile practice and may fail on many devices or Android versions due to + // Scoped Storage restrictions. It is recommended to use path_provider to get a valid + // and writable directory. + if (Platform.isAndroid) { + final Directory? externalDir = await getExternalStorageDirectory(); + if (externalDir != null) { + return '${externalDir.path}/$uniqueName'; + } + + final Directory fallbackDir = await getApplicationDocumentsDirectory(); + return '${fallbackDir.path}/$uniqueName'; + } + + // (Save to "On My iPhone" visible app folder) + // Ensure 'LSSupportsOpeningDocumentsInPlace' and 'UISupportsDocumentBrowser' + // are set to true in your ios/Runner/Info.plist to make this folder visible in the Files app. + + if (Platform.isIOS) { + final Directory appDocDir = await getApplicationDocumentsDirectory(); + + // Setup the custom directory structure within the app's documents container + final customDirPath = '${appDocDir.path}/Movies/flutter_test'; + final destinationDir = Directory(customDirPath); + + if (!destinationDir.existsSync()) { + destinationDir.createSync(recursive: true); + } + + return '${destinationDir.path}/$uniqueName'; + } + + // Default fallback general path + final Directory fallbackDir = await getApplicationDocumentsDirectory(); + return '${fallbackDir.path}/$uniqueName'; + } + + Future _startRecording() async { + final CameraController? controller = _controller; + if (controller == null || !controller.value.isInitialized) { + _showNotification('Camera is not ready yet.', isError: true); + return; + } + + if (controller.value.isRecordingVideo) { + return; + } + + try { + String? outputPath; + if (_useCustomPath) { + outputPath = await _getDestinationPath(); + setState(() { + _resolvedCustomPath = outputPath; + }); + } else { + setState(() { + _resolvedCustomPath = null; + }); + } + + // Invokes startVideoRecording with the custom path options! + await controller.startVideoRecording(videoOutputPath: outputPath); + + _showNotification( + _useCustomPath + ? 'Recording started with custom output path!' + : 'Recording started using auto-generated path.', + ); + } on CameraException catch (e) { + _showNotification( + 'Failed to start recording: ${e.description}', + isError: true, + ); + } catch (e) { + _showNotification('Unexpected error: $e', isError: true); + } finally { + if (mounted) { + setState(() {}); + } + } + } + + Future _stopRecording() async { + final CameraController? controller = _controller; + if (controller == null || !controller.value.isRecordingVideo) { + return; + } + + try { + final XFile file = await controller.stopVideoRecording(); + setState(() { + _recordedVideo = file; + }); + + _showNotification('Recording finished successfully!'); + + await _playRecordedVideo(file); + } on CameraException catch (e) { + _showNotification( + 'Failed to stop recording: ${e.description}', + isError: true, + ); + } catch (e) { + _showNotification( + 'Unexpected error stopping recording: $e', + isError: true, + ); + } finally { + if (mounted) { + setState(() {}); + } + } + } + + Future _pauseRecording() async { + final CameraController? controller = _controller; + if (controller == null || !controller.value.isRecordingVideo) { + return; + } + + try { + await controller.pauseVideoRecording(); + _showNotification('Video recording paused.'); + } on CameraException catch (e) { + _showNotification('Pause failed: ${e.description}', isError: true); + } finally { + if (mounted) { + setState(() {}); + } + } + } + + Future _resumeRecording() async { + final CameraController? controller = _controller; + if (controller == null || !controller.value.isRecordingVideo) { + return; + } + + try { + await controller.resumeVideoRecording(); + _showNotification('Video recording resumed.'); + } on CameraException catch (e) { + _showNotification('Resume failed: ${e.description}', isError: true); + } finally { + if (mounted) { + setState(() {}); + } + } + } + + Future _playRecordedVideo(XFile file) async { + if (_videoPlayerController != null) { + await _videoPlayerController!.dispose(); + } + + final playerController = VideoPlayerController.file(File(file.path)); + + _videoPlayerController = playerController; + + try { + await playerController.initialize(); + if (!mounted) { + await playerController.dispose(); + return; + } + await playerController.setLooping(true); + await playerController.play(); + } catch (e) { + _showNotification( + 'Failed to load recorded video in player: $e', + isError: true, + ); + } + + if (mounted) { + setState(() {}); + } + } + + @override + void dispose() { + _customFileNameController.dispose(); + _controller?.dispose(); + _videoPlayerController?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final double screenWidth = MediaQuery.of(context).size.width; + final isDark = Theme.of(context).brightness == Brightness.dark; + final Color textPrimary = isDark ? Colors.white : const Color(0xFF1E1E30); + + return Scaffold( + body: SafeArea( + child: _isInitializing + ? const Center( + child: CircularProgressIndicator(color: Color(0xFF6C63FF)), + ) + : SingleChildScrollView( + padding: const EdgeInsets.all(20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildHeader(textPrimary), + const SizedBox(height: 20), + _buildCameraView(isDark), + const SizedBox(height: 20), + _buildPathSettingsCard(isDark, textPrimary), + const SizedBox(height: 20), + _buildControlsPanel(isDark), + if (_recordedVideo != null) ...[ + const SizedBox(height: 24), + _buildVideoPlayerCard(screenWidth, isDark, textPrimary), + ], + const SizedBox(height: 30), + ], + ), + ), + ), + ); + } + + Widget _buildHeader(Color textPrimary) { + final isDark = widget.themeMode == ThemeMode.dark; + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'VIVID VIDEO RECORDER', + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.w900, + letterSpacing: 1.5, + color: textPrimary, + ), + ), + const SizedBox(height: 4), + const Text( + 'Demonstrating custom output path validation & video recording.', + style: TextStyle(fontSize: 12, color: Color(0xFF8F8FA0)), + ), + ], + ), + ), + IconButton.filledTonal( + icon: Icon(isDark ? Icons.light_mode : Icons.dark_mode), + style: IconButton.styleFrom( + backgroundColor: isDark ? const Color(0xFF1E1E30) : Colors.white, + foregroundColor: const Color(0xFF6C63FF), + ), + onPressed: widget.onThemeToggle, + ), + ], + ); + } + + Widget _buildCameraView(bool isDark) { + final CameraController? controller = _controller; + final bool isRecording = controller?.value.isRecordingVideo ?? false; + final bool isPaused = controller?.value.isRecordingPaused ?? false; + + return Container( + height: 380, + decoration: BoxDecoration( + color: Colors.black, + borderRadius: BorderRadius.circular(24), + border: Border.all( + color: isRecording + ? (isPaused ? Colors.amber : const Color(0xFFFF1744)) + : (isDark ? const Color(0xFF2C2C40) : const Color(0xFFE2E2EC)), + width: 2, + ), + boxShadow: [ + BoxShadow( + color: isRecording + ? (isPaused + ? Colors.amber.withOpacity(0.15) + : const Color(0xFFFF1744).withOpacity(0.15)) + : Colors.transparent, + blurRadius: 16, + spreadRadius: 4, + ), + ], + ), + clipBehavior: Clip.antiAlias, + child: Stack( + fit: StackFit.expand, + children: [ + if (controller != null) + CameraPreview(controller) + else + const Center( + child: Text( + 'Camera pipeline is uninitialized.', + style: TextStyle(color: Colors.grey), + ), + ), + // Recording Status Overlay + if (isRecording) + Positioned( + top: 16, + left: 16, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 6, + ), + decoration: BoxDecoration( + color: (isDark ? const Color(0xFF1E1E30) : Colors.white) + .withOpacity(0.85), + borderRadius: BorderRadius.circular(30), + border: Border.all( + color: isPaused ? Colors.amber : const Color(0xFFFF1744), + width: 1.5, + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 8, + height: 8, + decoration: BoxDecoration( + color: isPaused + ? Colors.amber + : const Color(0xFFFF1744), + shape: BoxShape.circle, + ), + ), + const SizedBox(width: 8), + Text( + isPaused ? 'RECORDING PAUSED' : 'LIVE RECORDING', + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + color: isPaused + ? Colors.amber + : const Color(0xFFFF1744), + letterSpacing: 1.0, + ), + ), + ], + ), + ), + ), + ], + ), + ); + } + + Widget _buildPathSettingsCard(bool isDark, Color textPrimary) { + final Color cardBgColor = isDark ? const Color(0xFF161626) : Colors.white; + final borderBgColor = isDark + ? const Color(0xFF2C2C40) + : const Color(0xFFE2E2EC); + final subBgColor = isDark + ? const Color(0xFF0F0F1A) + : const Color(0xFFF5F5FA); + final textSecondary = isDark + ? const Color(0xFF8F8FA0) + : const Color(0xFF6E6E7E); + + return Container( + decoration: BoxDecoration( + color: cardBgColor, + borderRadius: BorderRadius.circular(16), + border: Border.all(color: borderBgColor), + boxShadow: isDark + ? const [] + : [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 10, + offset: const Offset(0, 4), + ), + ], + ), + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + const Icon( + Icons.folder_open, + color: Color(0xFF6C63FF), + size: 20, + ), + const SizedBox(width: 8), + Text( + 'Custom Output Path', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 15, + color: textPrimary, + ), + ), + ], + ), + Switch.adaptive( + value: _useCustomPath, + activeColor: const Color(0xFF6C63FF), + onChanged: (bool value) { + setState(() { + _useCustomPath = value; + }); + }, + ), + ], + ), + if (_useCustomPath) ...[ + const SizedBox(height: 12), + TextField( + style: TextStyle(color: textPrimary), + decoration: InputDecoration( + labelText: 'Filename or absolute path', + labelStyle: TextStyle(color: textSecondary, fontSize: 13), + hintText: 'my_video.mp4 or /storage/...', + prefixIcon: Icon( + Icons.description, + size: 18, + color: textSecondary, + ), + filled: true, + fillColor: subBgColor, + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide(color: borderBgColor), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: const BorderSide( + color: Color(0xFF6C63FF), + width: 1.5, + ), + ), + ), + controller: _customFileNameController, + onChanged: (String val) { + _customFileName = val; + }, + ), + const SizedBox(height: 12), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: subBgColor, + borderRadius: BorderRadius.circular(10), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'VALIDATION ENFORCEMENT RULES', + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + color: textSecondary, + letterSpacing: 0.5, + ), + ), + const SizedBox(height: 6), + _buildValidationBullet( + 'Must end with supported extension (.mp4)', + isDark, + ), + _buildValidationBullet( + 'Cannot be an existing directory', + isDark, + ), + _buildValidationBullet( + 'Parent folder must exist on device storage', + isDark, + ), + ], + ), + ), + ], + ], + ), + ); + } + + Widget _buildValidationBullet(String text, bool isDark) { + final textSecondary = isDark + ? const Color(0xFFB0B0C0) + : const Color(0xFF5A5A6A); + return Padding( + padding: const EdgeInsets.only(bottom: 4.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon(Icons.check_circle, size: 12, color: Color(0xFF00E676)), + const SizedBox(width: 8), + Expanded( + child: Text( + text, + style: TextStyle(fontSize: 11, color: textSecondary), + ), + ), + ], + ), + ); + } + + Widget _buildControlsPanel(bool isDark) { + final CameraController? controller = _controller; + final bool isRecording = controller?.value.isRecordingVideo ?? false; + final bool isPaused = controller?.value.isRecordingPaused ?? false; + final Color controlBgColor = isDark + ? const Color(0xFF1E1E30) + : Colors.white; + + return Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + // Audio Toggle + IconButton.filledTonal( + icon: Icon(_audioEnabled ? Icons.mic : Icons.mic_off), + style: IconButton.styleFrom( + backgroundColor: controlBgColor, + foregroundColor: _audioEnabled + ? const Color(0xFF00E676) + : Colors.grey, + padding: const EdgeInsets.all(14), + side: isDark + ? BorderSide.none + : const BorderSide(color: Color(0xFFE2E2EC)), + ), + onPressed: isRecording + ? null + : () { + setState(() { + _audioEnabled = !_audioEnabled; + if (_controller != null) { + _initializeCameraController(_controller!.description); + } + }); + }, + ), + + // Primary Record / Stop Button + GestureDetector( + onTap: isRecording ? _stopRecording : _startRecording, + child: Container( + height: 76, + width: 76, + decoration: BoxDecoration( + color: isRecording + ? const Color(0xFFFF1744) + : const Color(0xFF6C63FF), + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: + (isRecording + ? const Color(0xFFFF1744) + : const Color(0xFF6C63FF)) + .withOpacity(0.3), + blurRadius: 12, + spreadRadius: 2, + ), + ], + ), + child: Icon( + isRecording ? Icons.stop : Icons.videocam, + size: 32, + color: Colors.white, + ), + ), + ), + + // Pause / Resume Toggle + IconButton.filledTonal( + icon: Icon(isPaused ? Icons.play_arrow : Icons.pause), + style: IconButton.styleFrom( + backgroundColor: controlBgColor, + foregroundColor: const Color(0xFF6C63FF), + padding: const EdgeInsets.all(14), + side: isDark + ? BorderSide.none + : const BorderSide(color: Color(0xFFE2E2EC)), + ), + onPressed: isRecording + ? (isPaused ? _resumeRecording : _pauseRecording) + : null, + ), + ], + ); + } + + Widget _buildVideoPlayerCard( + double screenWidth, + bool isDark, + Color textPrimary, + ) { + final VideoPlayerController? playerController = _videoPlayerController; + final Color cardBgColor = isDark ? const Color(0xFF161626) : Colors.white; + final borderBgColor = isDark + ? const Color(0xFF2C2C40) + : const Color(0xFFE2E2EC); + + return Container( + decoration: BoxDecoration( + color: cardBgColor, + borderRadius: BorderRadius.circular(20), + border: Border.all(color: borderBgColor), + boxShadow: isDark + ? const [] + : [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 10, + offset: const Offset(0, 4), + ), + ], + ), + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + children: [ + const Icon( + Icons.video_library, + color: Color(0xFF00E676), + size: 20, + ), + const SizedBox(width: 8), + Text( + 'Recorded Video Output', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 15, + color: textPrimary, + ), + ), + ], + ), + const SizedBox(height: 12), + if (playerController != null && playerController.value.isInitialized) + ClipRRect( + borderRadius: BorderRadius.circular(12), + child: AspectRatio( + aspectRatio: playerController.value.aspectRatio, + child: VideoPlayer(playerController), + ), + ) + else + const Center( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 24.0), + child: CircularProgressIndicator(color: Color(0xFF00E676)), + ), + ), + const SizedBox(height: 12), + Text( + 'Saved Location Path:', + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + color: Colors.grey[600], + ), + ), + const SizedBox(height: 4), + SelectableText( + _recordedVideo?.path ?? 'Unknown', + style: const TextStyle( + fontSize: 11, + fontFamily: 'Courier', + color: Color(0xFF00E676), + ), + ), + if (_resolvedCustomPath != null) ...[ + const SizedBox(height: 10), + Text( + 'Requested Custom Path:', + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + color: Colors.grey[600], + ), + ), + const SizedBox(height: 4), + SelectableText( + _resolvedCustomPath!, + style: const TextStyle( + fontSize: 11, + fontFamily: 'Courier', + color: Color(0xFF6C63FF), + ), + ), + ], + ], + ), + ); + } +} diff --git a/packages/camera/camera/example/pubspec.yaml b/packages/camera/camera/example/pubspec.yaml index d94d8bef8cfa..ee8615db2247 100644 --- a/packages/camera/camera/example/pubspec.yaml +++ b/packages/camera/camera/example/pubspec.yaml @@ -31,3 +31,10 @@ dev_dependencies: flutter: uses-material-design: true +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + camera_android_camerax: {path: ../../../../packages/camera/camera_android_camerax} + camera_avfoundation: {path: ../../../../packages/camera/camera_avfoundation} + camera_platform_interface: {path: ../../../../packages/camera/camera_platform_interface} + camera_web: {path: ../../../../packages/camera/camera_web} diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index d941c2e85f66..38de580e2200 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -576,6 +576,7 @@ class CameraController extends ValueNotifier { Future startVideoRecording({ onLatestImageAvailable? onAvailable, bool enablePersistentRecording = true, + String? videoOutputPath, }) async { _throwIfNotInitialized('startVideoRecording'); if (value.isRecordingVideo) { @@ -585,6 +586,16 @@ class CameraController extends ValueNotifier { ); } + if (videoOutputPath != null) { + final String lowerPath = videoOutputPath.toLowerCase(); + if (!lowerPath.endsWith('.mp4')) { + throw CameraException( + 'InvalidFilePath', + 'Invalid video extension. Supported: .mp4', + ); + } + } + void Function(CameraImageData image)? streamCallback; if (onAvailable != null) { streamCallback = (CameraImageData imageData) { @@ -598,6 +609,7 @@ class CameraController extends ValueNotifier { _cameraId, streamCallback: streamCallback, enablePersistentRecording: enablePersistentRecording, + videoOutputPath: videoOutputPath, ), ); value = value.copyWith( diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index f2cecaf6a7bc..eae0a04481aa 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -4,7 +4,7 @@ description: A Flutter plugin for controlling the camera. Supports previewing Dart. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.12.0+1 +version: 0.13.0 environment: sdk: ^3.10.0 @@ -23,7 +23,7 @@ flutter: dependencies: camera_android_camerax: ^0.7.0 camera_avfoundation: ^0.10.0 - camera_platform_interface: ^2.12.0 + camera_platform_interface: ^2.14.0 camera_web: ^0.3.3 flutter: sdk: flutter @@ -38,3 +38,10 @@ dev_dependencies: topics: - camera +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + camera_android_camerax: {path: ../../../packages/camera/camera_android_camerax} + camera_avfoundation: {path: ../../../packages/camera/camera_avfoundation} + camera_platform_interface: {path: ../../../packages/camera/camera_platform_interface} + camera_web: {path: ../../../packages/camera/camera_web} diff --git a/packages/camera/camera/test/camera_image_stream_test.dart b/packages/camera/camera/test/camera_image_stream_test.dart index 0a9644fcd8df..f6ef7c29e827 100644 --- a/packages/camera/camera/test/camera_image_stream_test.dart +++ b/packages/camera/camera/test/camera_image_stream_test.dart @@ -261,10 +261,17 @@ class MockStreamingCameraPlatform extends MockCameraPlatform { } @override - Future startVideoRecording(int cameraId, {Duration? maxVideoDuration}) { + Future startVideoRecording( + int cameraId, { + Duration? maxVideoDuration, + String? videoOutputPath, + }) { streamCallLog.add('startVideoRecording'); // Ignore maxVideoDuration, as it is unimplemented and deprecated. - return super.startVideoRecording(cameraId); + return super.startVideoRecording( + cameraId, + videoOutputPath: videoOutputPath, + ); } @override diff --git a/packages/camera/camera/test/camera_preview_test.dart b/packages/camera/camera/test/camera_preview_test.dart index 912a583e9255..f87cd036cd70 100644 --- a/packages/camera/camera/test/camera_preview_test.dart +++ b/packages/camera/camera/test/camera_preview_test.dart @@ -113,6 +113,7 @@ class FakeController extends ValueNotifier Future startVideoRecording({ onLatestImageAvailable? onAvailable, bool enablePersistentRecording = true, + String? videoOutputPath, }) async {} @override diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index 913d3391cd9e..d7594ac08410 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -4019,9 +4019,15 @@ class MockCameraPlatform extends Mock super.noSuchMethod(Invocation.method(#prepareForVideoRecording, null)); @override - Future startVideoRecording(int cameraId, {Duration? maxVideoDuration}) { + Future startVideoRecording( + int cameraId, { + Duration? maxVideoDuration, + String? videoOutputPath, + }) { // Ignore maxVideoDuration, as it is unimplemented and deprecated. - return startVideoCapturing(VideoCaptureOptions(cameraId)); + return startVideoCapturing( + VideoCaptureOptions(cameraId, videoOutputPath: videoOutputPath), + ); } @override diff --git a/packages/camera/camera_android/CHANGELOG.md b/packages/camera/camera_android/CHANGELOG.md index b7bb3e538c37..a33d15ac0fca 100644 --- a/packages/camera/camera_android/CHANGELOG.md +++ b/packages/camera/camera_android/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 0.10.11 +* Adds support for custom video output path in video recording. * Updates minimum supported SDK version to Flutter 3.38/Dart 3.10. ## 0.10.10+17 diff --git a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java index 1d543bd86559..39f85ad08625 100644 --- a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -869,8 +869,9 @@ void unlockAutoFocus() { dartMessenger.error(flutterResult, errorCode, errorMessage, null)); } - public void startVideoRecording(@Nullable EventChannel imageStreamChannel) { - prepareRecording(); + public void startVideoRecording( + @Nullable EventChannel imageStreamChannel, @Nullable String videoOutputPath) { + prepareRecording(videoOutputPath); if (imageStreamChannel != null) { setStreamHandler(imageStreamChannel); @@ -1296,13 +1297,19 @@ public void onError(@NonNull String errorCode, @NonNull String errorMessage) { } @VisibleForTesting - void prepareRecording() { - final File outputDir = applicationContext.getCacheDir(); - try { - captureFile = File.createTempFile("REC", ".mp4", outputDir); - } catch (IOException | SecurityException e) { - throw new Messages.FlutterError("cannotCreateFile", e.getMessage(), null); + void prepareRecording(@Nullable String videoOutputPath) { + if (videoOutputPath != null) { + validateOutputPath(videoOutputPath); + captureFile = new File(videoOutputPath); + } else { + final File outputDir = applicationContext.getCacheDir(); + try { + captureFile = File.createTempFile("REC", ".mp4", outputDir); + } catch (IOException | SecurityException e) { + throw new Messages.FlutterError("cannotCreateFile", e.getMessage(), null); + } } + try { prepareMediaRecorder(captureFile.getAbsolutePath()); } catch (IOException e) { @@ -1317,6 +1324,23 @@ void prepareRecording() { setFpsCameraFeatureForRecording(cameraProperties); } + private void validateOutputPath(String path) { + File file = new File(path); + if (file.isDirectory()) { + throw new Messages.FlutterError("IOError", "The output path is a directory: " + path, null); + } + File parent = file.getParentFile(); + if (parent != null && !parent.exists()) { + throw new Messages.FlutterError( + "IOError", "The parent directory does not exist: " + parent.getAbsolutePath(), null); + } + + String lowerPath = path.toLowerCase(Locale.ROOT); + if (!lowerPath.endsWith(".mp4")) { + throw new Messages.FlutterError("IOError", "Invalid video extension. Supported: .mp4", null); + } + } + private void setStreamHandler(EventChannel imageStreamChannel) { imageStreamChannel.setStreamHandler( new EventChannel.StreamHandler() { diff --git a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/CameraApiImpl.java b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/CameraApiImpl.java index b3b04d5309e5..95a8d210b0af 100644 --- a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/CameraApiImpl.java +++ b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/CameraApiImpl.java @@ -175,8 +175,8 @@ public void takePicture(@NonNull Messages.Result result) { } @Override - public void startVideoRecording(@NonNull Boolean enableStream) { - camera.startVideoRecording(enableStream ? imageStreamChannel : null); + public void startVideoRecording(@NonNull Boolean enableStream, @Nullable String videoOutputPath) { + camera.startVideoRecording(enableStream ? imageStreamChannel : null, videoOutputPath); } @NonNull diff --git a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Messages.java b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Messages.java index e61e0c48c199..ce916c0161b2 100644 --- a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Messages.java +++ b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Messages.java @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v26.1.0), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon package io.flutter.plugins.camera; @@ -21,13 +21,171 @@ import java.lang.annotation.Target; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Objects; +import java.util.Map; /** Generated class from Pigeon. */ @SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression", "serial"}) public class Messages { + static boolean pigeonDoubleEquals(double a, double b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == 0.0 ? 0.0 : a) == (b == 0.0 ? 0.0 : b) || (Double.isNaN(a) && Double.isNaN(b)); + } + + static boolean pigeonFloatEquals(float a, float b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == 0.0f ? 0.0f : a) == (b == 0.0f ? 0.0f : b) || (Float.isNaN(a) && Float.isNaN(b)); + } + + static int pigeonDoubleHashCode(double d) { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + if (d == 0.0) { + d = 0.0; + } + long bits = Double.doubleToLongBits(d); + return (int) (bits ^ (bits >>> 32)); + } + + static int pigeonFloatHashCode(float f) { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + if (f == 0.0f) { + f = 0.0f; + } + return Float.floatToIntBits(f); + } + + static boolean pigeonDeepEquals(Object a, Object b) { + if (a == b) { + return true; + } + if (a == null || b == null) { + return false; + } + if (a instanceof byte[] && b instanceof byte[]) { + return Arrays.equals((byte[]) a, (byte[]) b); + } + if (a instanceof int[] && b instanceof int[]) { + return Arrays.equals((int[]) a, (int[]) b); + } + if (a instanceof long[] && b instanceof long[]) { + return Arrays.equals((long[]) a, (long[]) b); + } + if (a instanceof double[] && b instanceof double[]) { + double[] da = (double[]) a; + double[] db = (double[]) b; + if (da.length != db.length) { + return false; + } + for (int i = 0; i < da.length; i++) { + if (!pigeonDoubleEquals(da[i], db[i])) { + return false; + } + } + return true; + } + if (a instanceof List && b instanceof List) { + List listA = (List) a; + List listB = (List) b; + if (listA.size() != listB.size()) { + return false; + } + for (int i = 0; i < listA.size(); i++) { + if (!pigeonDeepEquals(listA.get(i), listB.get(i))) { + return false; + } + } + return true; + } + if (a instanceof Map && b instanceof Map) { + Map mapA = (Map) a; + Map mapB = (Map) b; + if (mapA.size() != mapB.size()) { + return false; + } + for (Map.Entry entryA : mapA.entrySet()) { + Object keyA = entryA.getKey(); + Object valueA = entryA.getValue(); + boolean found = false; + for (Map.Entry entryB : mapB.entrySet()) { + Object keyB = entryB.getKey(); + if (pigeonDeepEquals(keyA, keyB)) { + Object valueB = entryB.getValue(); + if (pigeonDeepEquals(valueA, valueB)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; + } + if (a instanceof Double && b instanceof Double) { + return pigeonDoubleEquals((double) a, (double) b); + } + if (a instanceof Float && b instanceof Float) { + return pigeonFloatEquals((float) a, (float) b); + } + return a.equals(b); + } + + static int pigeonDeepHashCode(Object value) { + if (value == null) { + return 0; + } + if (value instanceof byte[]) { + return Arrays.hashCode((byte[]) value); + } + if (value instanceof int[]) { + return Arrays.hashCode((int[]) value); + } + if (value instanceof long[]) { + return Arrays.hashCode((long[]) value); + } + if (value instanceof double[]) { + double[] da = (double[]) value; + int result = 1; + for (double d : da) { + result = 31 * result + pigeonDoubleHashCode(d); + } + return result; + } + if (value instanceof List) { + int result = 1; + for (Object item : (List) value) { + result = 31 * result + pigeonDeepHashCode(item); + } + return result; + } + if (value instanceof Map) { + int result = 0; + for (Map.Entry entry : ((Map) value).entrySet()) { + result += + ((pigeonDeepHashCode(entry.getKey()) * 31) ^ pigeonDeepHashCode(entry.getValue())); + } + return result; + } + if (value instanceof Object[]) { + int result = 1; + for (Object item : (Object[]) value) { + result = 31 * result + pigeonDeepHashCode(item); + } + return result; + } + if (value instanceof Double) { + return pigeonDoubleHashCode((double) value); + } + if (value instanceof Float) { + return pigeonFloatHashCode((float) value); + } + return value.hashCode(); + } /** Error class for passing custom error details to Flutter via a thrown PlatformException. */ public static class FlutterError extends RuntimeException { @@ -224,14 +382,15 @@ public boolean equals(Object o) { return false; } PlatformCameraDescription that = (PlatformCameraDescription) o; - return name.equals(that.name) - && lensDirection.equals(that.lensDirection) - && sensorOrientation.equals(that.sensorOrientation); + return pigeonDeepEquals(name, that.name) + && pigeonDeepEquals(lensDirection, that.lensDirection) + && pigeonDeepEquals(sensorOrientation, that.sensorOrientation); } @Override public int hashCode() { - return Objects.hash(name, lensDirection, sensorOrientation); + Object[] fields = new Object[] {getClass(), name, lensDirection, sensorOrientation}; + return pigeonDeepHashCode(fields); } public static final class Builder { @@ -373,17 +532,25 @@ public boolean equals(Object o) { return false; } PlatformCameraState that = (PlatformCameraState) o; - return previewSize.equals(that.previewSize) - && exposureMode.equals(that.exposureMode) - && focusMode.equals(that.focusMode) - && exposurePointSupported.equals(that.exposurePointSupported) - && focusPointSupported.equals(that.focusPointSupported); + return pigeonDeepEquals(previewSize, that.previewSize) + && pigeonDeepEquals(exposureMode, that.exposureMode) + && pigeonDeepEquals(focusMode, that.focusMode) + && pigeonDeepEquals(exposurePointSupported, that.exposurePointSupported) + && pigeonDeepEquals(focusPointSupported, that.focusPointSupported); } @Override public int hashCode() { - return Objects.hash( - previewSize, exposureMode, focusMode, exposurePointSupported, focusPointSupported); + Object[] fields = + new Object[] { + getClass(), + previewSize, + exposureMode, + focusMode, + exposurePointSupported, + focusPointSupported + }; + return pigeonDeepHashCode(fields); } public static final class Builder { @@ -510,12 +677,13 @@ public boolean equals(Object o) { return false; } PlatformSize that = (PlatformSize) o; - return width.equals(that.width) && height.equals(that.height); + return pigeonDeepEquals(width, that.width) && pigeonDeepEquals(height, that.height); } @Override public int hashCode() { - return Objects.hash(width, height); + Object[] fields = new Object[] {getClass(), width, height}; + return pigeonDeepHashCode(fields); } public static final class Builder { @@ -606,12 +774,13 @@ public boolean equals(Object o) { return false; } PlatformPoint that = (PlatformPoint) o; - return x.equals(that.x) && y.equals(that.y); + return pigeonDeepEquals(x, that.x) && pigeonDeepEquals(y, that.y); } @Override public int hashCode() { - return Objects.hash(x, y); + Object[] fields = new Object[] {getClass(), x, y}; + return pigeonDeepHashCode(fields); } public static final class Builder { @@ -732,16 +901,18 @@ public boolean equals(Object o) { return false; } PlatformMediaSettings that = (PlatformMediaSettings) o; - return resolutionPreset.equals(that.resolutionPreset) - && Objects.equals(fps, that.fps) - && Objects.equals(videoBitrate, that.videoBitrate) - && Objects.equals(audioBitrate, that.audioBitrate) - && enableAudio.equals(that.enableAudio); + return pigeonDeepEquals(resolutionPreset, that.resolutionPreset) + && pigeonDeepEquals(fps, that.fps) + && pigeonDeepEquals(videoBitrate, that.videoBitrate) + && pigeonDeepEquals(audioBitrate, that.audioBitrate) + && pigeonDeepEquals(enableAudio, that.enableAudio); } @Override public int hashCode() { - return Objects.hash(resolutionPreset, fps, videoBitrate, audioBitrate, enableAudio); + Object[] fields = + new Object[] {getClass(), resolutionPreset, fps, videoBitrate, audioBitrate, enableAudio}; + return pigeonDeepHashCode(fields); } public static final class Builder { @@ -993,7 +1164,7 @@ void create( void takePicture(@NonNull Result result); /** Starts recording a video on the camera with the given ID. */ - void startVideoRecording(@NonNull Boolean enableStream); + void startVideoRecording(@NonNull Boolean enableStream, @Nullable String videoOutputPath); /** * Ends video recording on the camera with the given ID and returns the path to the resulting @@ -1285,8 +1456,9 @@ public void error(Throwable error) { ArrayList wrapped = new ArrayList<>(); ArrayList args = (ArrayList) message; Boolean enableStreamArg = (Boolean) args.get(0); + String videoOutputPathArg = (String) args.get(1); try { - api.startVideoRecording(enableStreamArg); + api.startVideoRecording(enableStreamArg, videoOutputPathArg); wrapped.add(0, null); } catch (Throwable exception) { wrapped = wrapError(exception); diff --git a/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest.java b/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest.java index 3cf677190a2a..8b7d4ecf778e 100644 --- a/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest.java +++ b/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest.java @@ -52,6 +52,7 @@ import io.flutter.plugins.camera.features.sensororientation.SensorOrientationFeature; import io.flutter.plugins.camera.features.zoomlevel.ZoomLevelFeature; import io.flutter.plugins.camera.media.ImageStreamReader; +import io.flutter.plugins.camera.media.MediaRecorderBuilder; import io.flutter.view.TextureRegistry; import java.io.Closeable; import java.io.File; @@ -206,6 +207,14 @@ public void before() { camera.captureSession = mockCaptureSession; camera.previewRequestBuilder = mockPreviewRequestBuilder; + + final SensorOrientationFeature mockSensorOrientationFeature = + mockCameraFeatureFactory.createSensorOrientationFeature( + mockCameraProperties, mockActivity, mockDartMessenger); + final DeviceOrientationManager mockDeviceOrientationManager = + mock(DeviceOrientationManager.class); + when(mockSensorOrientationFeature.getDeviceOrientationManager()) + .thenReturn(mockDeviceOrientationManager); } @After @@ -711,6 +720,113 @@ public void resumeVideoRecording_shouldCallPauseWhenRecording() { verify(mockMediaRecorder, times(1)).resume(); } + @Test + public void startVideoRecording_usesCustomPath() throws IOException, CameraAccessException { + final String customPath = + new File(System.getProperty("java.io.tmpdir"), "custom_video.mp4").getAbsolutePath(); + final MediaRecorder mockMediaRecorder = mock(MediaRecorder.class); + + final ArrayList mockRequestBuilders = new ArrayList<>(); + CaptureRequest.Builder mockRequestBuilder = mock(CaptureRequest.Builder.class); + mockRequestBuilders.add(mockRequestBuilder); + final SurfaceTexture mockSurfaceTexture = mock(SurfaceTexture.class); + final Size mockSize = mock(Size.class); + final ImageReader mockPictureImageReader = mock(ImageReader.class); + camera.pictureImageReader = mockPictureImageReader; + final CameraDeviceWrapper fakeCamera = + new FakeCameraDeviceWrapper(mockRequestBuilders, mockCaptureSession); + + camera.cameraDevice = fakeCamera; + + TextureRegistry.SurfaceTextureEntry cameraFlutterTexture = camera.flutterTexture; + ResolutionFeature resolutionFeature = mockCameraFeatureFactory.mockResolutionFeature; + + assertNotNull(cameraFlutterTexture); + when(cameraFlutterTexture.surfaceTexture()).thenReturn(mockSurfaceTexture); + + assertNotNull(resolutionFeature); + when(resolutionFeature.getPreviewSize()).thenReturn(mockSize); + + try (MockedConstruction mockedBuilder = + Mockito.mockConstruction( + MediaRecorderBuilder.class, + (mock, context) -> { + MediaRecorderBuilder.RecordingParameters params = + (MediaRecorderBuilder.RecordingParameters) context.arguments().get(1); + assertEquals(customPath, params.outputFilePath); + when(mock.setEnableAudio(anyBoolean())).thenReturn(mock); + when(mock.setMediaOrientation(anyInt())).thenReturn(mock); + when(mock.build()).thenReturn(mockMediaRecorder); + })) { + + camera.startVideoRecording(null, customPath); + + assertEquals(1, mockedBuilder.constructed().size()); + } + } + + @SuppressWarnings("try") + @Test + public void startVideoRecording_errorsOnInvalidPath() throws IOException, CameraAccessException { + final String invalidPath = "/non/existent/path.mp4"; + + try (MockedConstruction mockedBuilder = + Mockito.mockConstruction( + MediaRecorderBuilder.class, + (mock, context) -> { + when(mock.setEnableAudio(anyBoolean())).thenReturn(mock); + when(mock.setMediaOrientation(anyInt())).thenReturn(mock); + when(mock.build()).thenThrow(new IOException("Invalid path")); + })) { + + Messages.FlutterError error = + assertThrows( + Messages.FlutterError.class, + () -> { + camera.startVideoRecording(null, invalidPath); + }); + // The old test asserted "Invalid path" message. Wait, validateOutputPath will throw first! + // Actually, if validateOutputPath throws, it will throw IOError before building. + // So this test as originally written was flawed because validateOutputPath catches the + // invalidPath before build(). + // Let's just assert the IOError from validateOutputPath for this test. + assertEquals("IOError", error.code); + } + } + + @Test + public void startVideoRecording_errorsOnDirectoryPath() { + Messages.FlutterError error = + assertThrows( + Messages.FlutterError.class, + () -> { + camera.startVideoRecording(null, "/"); + }); + assertEquals("IOError", error.code); + } + + @Test + public void startVideoRecording_errorsOnNonExistentParentPath() { + Messages.FlutterError error = + assertThrows( + Messages.FlutterError.class, + () -> { + camera.startVideoRecording(null, "/non/existent/parent/file.mp4"); + }); + assertEquals("IOError", error.code); + } + + @Test + public void startVideoRecording_errorsOnInvalidExtension() { + Messages.FlutterError error = + assertThrows( + Messages.FlutterError.class, + () -> { + camera.startVideoRecording(null, "file.txt"); + }); + assertEquals("IOError", error.code); + } + @Test public void setDescriptionWhileRecording_errorsWhenUnsupported() { MediaRecorder mockMediaRecorder = mock(MediaRecorder.class); @@ -939,9 +1055,9 @@ public void startVideoRecording_shouldPullStreamsFromMediaRecorderAndImageReader when(cameraFlutterTexture.surfaceTexture()).thenReturn(mockSurfaceTexture); when(resolutionFeature.getPreviewSize()).thenReturn(mockSize); - doNothing().when(cameraSpy).prepareRecording(); + doNothing().when(cameraSpy).prepareRecording(any()); - cameraSpy.startVideoRecording(null); + cameraSpy.startVideoRecording(null, null); verify(mockMediaRecorder, times(1)) .getSurface(); // stream pulled from media recorder's surface. verify( @@ -1361,7 +1477,7 @@ public void startVideoRecording_shouldApplySettingsToMediaRecorder() assertNotNull(resolutionFeature); when(resolutionFeature.getPreviewSize()).thenReturn(mockSize); - camera.startVideoRecording(null); + camera.startVideoRecording(null, null); // region Check that FPS parameter affects AE range at which the camera captures frames. assertEquals(camera.cameraFeatures.getFpsRange().getValue().getLower(), Integer.valueOf(fps)); diff --git a/packages/camera/camera_android/example/lib/camera_controller.dart b/packages/camera/camera_android/example/lib/camera_controller.dart index 33cafe13e447..6233124fe280 100644 --- a/packages/camera/camera_android/example/lib/camera_controller.dart +++ b/packages/camera/camera_android/example/lib/camera_controller.dart @@ -326,9 +326,24 @@ class CameraController extends ValueNotifier { /// Throws a [CameraException] if the capture fails. Future startVideoRecording({ void Function(CameraImageData image)? streamCallback, + String? videoOutputPath, }) async { + if (videoOutputPath != null) { + final String lowerPath = videoOutputPath.toLowerCase(); + if (!lowerPath.endsWith('.mp4')) { + throw CameraException( + 'InvalidFilePath', + 'Invalid video extension. Supported: .mp4', + ); + } + } + await CameraPlatform.instance.startVideoCapturing( - VideoCaptureOptions(_cameraId, streamCallback: streamCallback), + VideoCaptureOptions( + _cameraId, + streamCallback: streamCallback, + videoOutputPath: videoOutputPath, + ), ); value = value.copyWith( isRecordingVideo: true, diff --git a/packages/camera/camera_android/example/pubspec.yaml b/packages/camera/camera_android/example/pubspec.yaml index de76b088a7f3..0ed07bcf5c26 100644 --- a/packages/camera/camera_android/example/pubspec.yaml +++ b/packages/camera/camera_android/example/pubspec.yaml @@ -31,3 +31,7 @@ dev_dependencies: flutter: uses-material-design: true +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + camera_platform_interface: {path: ../../../../packages/camera/camera_platform_interface} diff --git a/packages/camera/camera_android/lib/src/android_camera.dart b/packages/camera/camera_android/lib/src/android_camera.dart index 9f7d580f2364..8a0ff99ab5e0 100644 --- a/packages/camera/camera_android/lib/src/android_camera.dart +++ b/packages/camera/camera_android/lib/src/android_camera.dart @@ -207,14 +207,20 @@ class AndroidCamera extends CameraPlatform { Future startVideoRecording( int cameraId, { Duration? maxVideoDuration, + String? videoOutputPath, }) async { // Ignore maxVideoDuration, as it is unimplemented and deprecated. - return startVideoCapturing(VideoCaptureOptions(cameraId)); + return startVideoCapturing( + VideoCaptureOptions(cameraId, videoOutputPath: videoOutputPath), + ); } @override Future startVideoCapturing(VideoCaptureOptions options) async { - await _hostApi.startVideoRecording(options.streamCallback != null); + await _hostApi.startVideoRecording( + options.streamCallback != null, + videoOutputPath: options.videoOutputPath, + ); if (options.streamCallback != null) { _installStreamController().stream.listen(options.streamCallback); diff --git a/packages/camera/camera_android/lib/src/messages.g.dart b/packages/camera/camera_android/lib/src/messages.g.dart index e4c047452511..28e2a6049d1a 100644 --- a/packages/camera/camera_android/lib/src/messages.g.dart +++ b/packages/camera/camera_android/lib/src/messages.g.dart @@ -1,21 +1,40 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v26.1.0), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon -// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers +// ignore_for_file: unused_import, unused_shown_name +// ignore_for_file: type=lint import 'dart:async'; -import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; +import 'dart:typed_data' show Float64List, Int32List, Int64List; -import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; import 'package:flutter/services.dart'; +import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; -PlatformException _createConnectionError(String channelName) { - return PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel: "$channelName".', - ); +Object? _extractReplyValueOrThrow( + List? replyList, + String channelName, { + required bool isNullValid, +}) { + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (!isNullValid && (replyList.isNotEmpty && replyList[0] == null)) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } + return replyList.firstOrNull; } List wrapResponse({ @@ -33,6 +52,15 @@ List wrapResponse({ } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == b; + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -40,16 +68,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + /// Pigeon equivalent of [CameraLensDirection]. enum PlatformCameraLensDirection { front, back, external } @@ -122,12 +186,14 @@ class PlatformCameraDescription { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(name, other.name) && + _deepEquals(lensDirection, other.lensDirection) && + _deepEquals(sensorOrientation, other.sensorOrientation); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// Data needed for [CameraInitializedEvent]. @@ -184,12 +250,16 @@ class PlatformCameraState { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(previewSize, other.previewSize) && + _deepEquals(exposureMode, other.exposureMode) && + _deepEquals(focusMode, other.focusMode) && + _deepEquals(exposurePointSupported, other.exposurePointSupported) && + _deepEquals(focusPointSupported, other.focusPointSupported); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// Pigeon equivalent of [Size]. @@ -225,12 +295,12 @@ class PlatformSize { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(width, other.width) && _deepEquals(height, other.height); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// Pigeon equivalent of [Point]. @@ -263,12 +333,12 @@ class PlatformPoint { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(x, other.x) && _deepEquals(y, other.y); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// Pigeon equivalent of [MediaSettings]. @@ -325,12 +395,16 @@ class PlatformMediaSettings { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(resolutionPreset, other.resolutionPreset) && + _deepEquals(fps, other.fps) && + _deepEquals(videoBitrate, other.videoBitrate) && + _deepEquals(audioBitrate, other.audioBitrate) && + _deepEquals(enableAudio, other.enableAudio); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { @@ -385,25 +459,25 @@ class _PigeonCodec extends StandardMessageCodec { Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { case 129: - final int? value = readValue(buffer) as int?; + final value = readValue(buffer) as int?; return value == null ? null : PlatformCameraLensDirection.values[value]; case 130: - final int? value = readValue(buffer) as int?; + final value = readValue(buffer) as int?; return value == null ? null : PlatformDeviceOrientation.values[value]; case 131: - final int? value = readValue(buffer) as int?; + final value = readValue(buffer) as int?; return value == null ? null : PlatformExposureMode.values[value]; case 132: - final int? value = readValue(buffer) as int?; + final value = readValue(buffer) as int?; return value == null ? null : PlatformFocusMode.values[value]; case 133: - final int? value = readValue(buffer) as int?; + final value = readValue(buffer) as int?; return value == null ? null : PlatformResolutionPreset.values[value]; case 134: - final int? value = readValue(buffer) as int?; + final value = readValue(buffer) as int?; return value == null ? null : PlatformImageFormatGroup.values[value]; case 135: - final int? value = readValue(buffer) as int?; + final value = readValue(buffer) as int?; return value == null ? null : PlatformFlashMode.values[value]; case 136: return PlatformCameraDescription.decode(readValue(buffer)!); @@ -441,34 +515,23 @@ class CameraApi { /// Returns the list of available cameras. Future> getAvailableCameras() async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.getAvailableCameras$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as List?)! - .cast(); - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return (pigeonVar_replyValue! as List) + .cast(); } /// Creates a new camera with the given name and settings and returns its ID. @@ -476,784 +539,562 @@ class CameraApi { String cameraName, PlatformMediaSettings mediaSettings, ) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.create$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [cameraName, mediaSettings], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as int?)!; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as int; } /// Initializes the camera with the given ID for the given image format. Future initialize(PlatformImageFormatGroup imageFormat) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.initialize$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [imageFormat], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Disposes of the camera with the given ID. Future dispose() async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.dispose$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Locks the camera with the given ID to the given orientation. Future lockCaptureOrientation( PlatformDeviceOrientation orientation, ) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.lockCaptureOrientation$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [orientation], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Unlocks the orientation for the camera with the given ID. Future unlockCaptureOrientation() async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.unlockCaptureOrientation$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Takes a picture on the camera with the given ID and returns a path to the /// resulting file. Future takePicture() async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.takePicture$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as String?)!; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as String; } /// Starts recording a video on the camera with the given ID. - Future startVideoRecording(bool enableStream) async { - final String pigeonVar_channelName = + Future startVideoRecording( + bool enableStream, { + String? videoOutputPath, + }) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.startVideoRecording$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [enableStream], - ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + [enableStream, videoOutputPath], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Ends video recording on the camera with the given ID and returns the path /// to the resulting file. Future stopVideoRecording() async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.stopVideoRecording$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as String?)!; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as String; } /// Pauses video recording on the camera with the given ID. Future pauseVideoRecording() async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.pauseVideoRecording$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Resumes previously paused video recording on the camera with the given ID. Future resumeVideoRecording() async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.resumeVideoRecording$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Begins streaming frames from the camera. Future startImageStream() async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.startImageStream$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Stops streaming frames from the camera. Future stopImageStream() async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.stopImageStream$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Sets the flash mode of the camera with the given ID. Future setFlashMode(PlatformFlashMode flashMode) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.setFlashMode$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [flashMode], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Sets the exposure mode of the camera with the given ID. Future setExposureMode(PlatformExposureMode exposureMode) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.setExposureMode$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [exposureMode], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Sets the exposure point of the camera with the given ID. /// /// A null value resets to the default exposure point. Future setExposurePoint(PlatformPoint? point) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.setExposurePoint$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [point], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Returns the minimum exposure offset of the camera with the given ID. Future getMinExposureOffset() async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.getMinExposureOffset$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as double?)!; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as double; } /// Returns the maximum exposure offset of the camera with the given ID. Future getMaxExposureOffset() async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.getMaxExposureOffset$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as double?)!; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as double; } /// Returns the exposure step size of the camera with the given ID. Future getExposureOffsetStepSize() async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.getExposureOffsetStepSize$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as double?)!; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as double; } /// Sets the exposure offset of the camera with the given ID and returns the /// actual exposure offset. Future setExposureOffset(double offset) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.setExposureOffset$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [offset], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as double?)!; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as double; } /// Sets the focus mode of the camera with the given ID. Future setFocusMode(PlatformFocusMode focusMode) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.setFocusMode$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [focusMode], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Sets the focus point of the camera with the given ID. /// /// A null value resets to the default focus point. Future setFocusPoint(PlatformPoint? point) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.setFocusPoint$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [point], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Returns the maximum zoom level of the camera with the given ID. Future getMaxZoomLevel() async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.getMaxZoomLevel$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as double?)!; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as double; } /// Returns the minimum zoom level of the camera with the given ID. Future getMinZoomLevel() async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.getMinZoomLevel$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as double?)!; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as double; } /// Sets the zoom level of the camera with the given ID. Future setZoomLevel(double zoom) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.setZoomLevel$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [zoom], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Pauses streaming of preview frames. Future pausePreview() async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.pausePreview$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Resumes previously paused streaming of preview frames. Future resumePreview() async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.resumePreview$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Changes the camera while recording video. /// /// This should be called only while video recording is active. Future setDescriptionWhileRecording(String description) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_android.CameraApi.setDescriptionWhileRecording$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [description], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } } @@ -1273,8 +1114,7 @@ abstract class CameraGlobalEventApi { ? '.$messageChannelSuffix' : ''; { - final BasicMessageChannel - pigeonVar_channel = BasicMessageChannel( + final pigeonVar_channel = BasicMessageChannel( 'dev.flutter.pigeon.camera_android.CameraGlobalEventApi.deviceOrientationChanged$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger, @@ -1283,19 +1123,11 @@ abstract class CameraGlobalEventApi { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android.CameraGlobalEventApi.deviceOrientationChanged was null.', - ); - final List args = (message as List?)!; - final PlatformDeviceOrientation? arg_orientation = - (args[0] as PlatformDeviceOrientation?); - assert( - arg_orientation != null, - 'Argument for dev.flutter.pigeon.camera_android.CameraGlobalEventApi.deviceOrientationChanged was null, expected non-null PlatformDeviceOrientation.', - ); + final List args = message! as List; + final PlatformDeviceOrientation arg_orientation = + args[0]! as PlatformDeviceOrientation; try { - api.deviceOrientationChanged(arg_orientation!); + api.deviceOrientationChanged(arg_orientation); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); @@ -1332,8 +1164,7 @@ abstract class CameraEventApi { ? '.$messageChannelSuffix' : ''; { - final BasicMessageChannel - pigeonVar_channel = BasicMessageChannel( + final pigeonVar_channel = BasicMessageChannel( 'dev.flutter.pigeon.camera_android.CameraEventApi.initialized$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger, @@ -1342,19 +1173,11 @@ abstract class CameraEventApi { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android.CameraEventApi.initialized was null.', - ); - final List args = (message as List?)!; - final PlatformCameraState? arg_initialState = - (args[0] as PlatformCameraState?); - assert( - arg_initialState != null, - 'Argument for dev.flutter.pigeon.camera_android.CameraEventApi.initialized was null, expected non-null PlatformCameraState.', - ); + final List args = message! as List; + final PlatformCameraState arg_initialState = + args[0]! as PlatformCameraState; try { - api.initialized(arg_initialState!); + api.initialized(arg_initialState); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); @@ -1367,8 +1190,7 @@ abstract class CameraEventApi { } } { - final BasicMessageChannel - pigeonVar_channel = BasicMessageChannel( + final pigeonVar_channel = BasicMessageChannel( 'dev.flutter.pigeon.camera_android.CameraEventApi.error$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger, @@ -1377,18 +1199,10 @@ abstract class CameraEventApi { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android.CameraEventApi.error was null.', - ); - final List args = (message as List?)!; - final String? arg_message = (args[0] as String?); - assert( - arg_message != null, - 'Argument for dev.flutter.pigeon.camera_android.CameraEventApi.error was null, expected non-null String.', - ); + final List args = message! as List; + final String arg_message = args[0]! as String; try { - api.error(arg_message!); + api.error(arg_message); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); @@ -1401,8 +1215,7 @@ abstract class CameraEventApi { } } { - final BasicMessageChannel - pigeonVar_channel = BasicMessageChannel( + final pigeonVar_channel = BasicMessageChannel( 'dev.flutter.pigeon.camera_android.CameraEventApi.closed$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger, diff --git a/packages/camera/camera_android/pigeons/messages.dart b/packages/camera/camera_android/pigeons/messages.dart index 4489fe3f6fb8..a03b57ad595b 100644 --- a/packages/camera/camera_android/pigeons/messages.dart +++ b/packages/camera/camera_android/pigeons/messages.dart @@ -132,7 +132,7 @@ abstract class CameraApi { String takePicture(); /// Starts recording a video on the camera with the given ID. - void startVideoRecording(bool enableStream); + void startVideoRecording(bool enableStream, {String? videoOutputPath}); /// Ends video recording on the camera with the given ID and returns the path /// to the resulting file. diff --git a/packages/camera/camera_android/pubspec.yaml b/packages/camera/camera_android/pubspec.yaml index 0d95eb81fa70..319177ba281a 100644 --- a/packages/camera/camera_android/pubspec.yaml +++ b/packages/camera/camera_android/pubspec.yaml @@ -3,7 +3,7 @@ description: Android implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.10.10+17 +version: 0.10.11 environment: sdk: ^3.10.0 @@ -36,3 +36,7 @@ dev_dependencies: topics: - camera +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + camera_platform_interface: {path: ../../../packages/camera/camera_platform_interface} diff --git a/packages/camera/camera_android/test/android_camera_test.mocks.dart b/packages/camera/camera_android/test/android_camera_test.mocks.dart index 53cd6e9489a1..9c9d6b314bc1 100644 --- a/packages/camera/camera_android/test/android_camera_test.mocks.dart +++ b/packages/camera/camera_android/test/android_camera_test.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.4.4 from annotations +// Mocks generated by Mockito 5.4.6 from annotations // in camera_android/test/android_camera_test.dart. // Do not manually edit this file. @@ -17,10 +17,12 @@ import 'package:mockito/src/dummies.dart' as _i3; // ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable // ignore_for_file: prefer_const_constructors // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member /// A class which mocks [CameraApi]. /// @@ -119,9 +121,16 @@ class MockCameraApi extends _i1.Mock implements _i2.CameraApi { as _i4.Future); @override - _i4.Future startVideoRecording(bool? enableStream) => + _i4.Future startVideoRecording( + bool? enableStream, { + String? videoOutputPath, + }) => (super.noSuchMethod( - Invocation.method(#startVideoRecording, [enableStream]), + Invocation.method( + #startVideoRecording, + [enableStream], + {#videoOutputPath: videoOutputPath}, + ), returnValue: _i4.Future.value(), returnValueForMissingStub: _i4.Future.value(), ) diff --git a/packages/camera/camera_android_camerax/CHANGELOG.md b/packages/camera/camera_android_camerax/CHANGELOG.md index 954d384e8c86..665f73bec626 100644 --- a/packages/camera/camera_android_camerax/CHANGELOG.md +++ b/packages/camera/camera_android_camerax/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 0.8.0 +* Adds support for custom video output path in video recording. * Updates minimum supported SDK version to Flutter 3.38/Dart 3.10. ## 0.7.2 diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraXLibrary.g.kt b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraXLibrary.g.kt index 2bdf4371dfed..2c11e70678a8 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraXLibrary.g.kt +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraXLibrary.g.kt @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v26.1.7), do not edit directly. +// Autogenerated from Pigeon (v26.3.2), do not edit directly. // See also: https://pub.dev/packages/pigeon @file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") @@ -1301,7 +1301,7 @@ enum class CameraStateType(val raw: Int) { } } -/** The types (T) properly wrapped to be used as a LiveData. */ +/** The types (T) properly wrapped to be used as a `LiveData`. */ enum class LiveDataSupportedType(val raw: Int) { CAMERA_STATE(0), ZOOM_STATE(1); diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/RecorderProxyApi.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/RecorderProxyApi.java index 9ed772ccb6ae..3bfeb24bb000 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/RecorderProxyApi.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/RecorderProxyApi.java @@ -60,6 +60,7 @@ public long getTargetVideoEncodingBitRate(Recorder pigeonInstance) { @NonNull @Override public PendingRecording prepareRecording(Recorder pigeonInstance, @NonNull String path) { + validateOutputPath(path); final File temporaryCaptureFile = openTempFile(path); final FileOutputOptions fileOutputOptions = new FileOutputOptions.Builder(temporaryCaptureFile).build(); @@ -70,12 +71,31 @@ public PendingRecording prepareRecording(Recorder pigeonInstance, @NonNull Strin return pendingRecording; } + private void validateOutputPath(@NonNull String path) { + File file = new File(path); + if (file.isDirectory()) { + throw new GeneratedCameraXLibrary.FlutterError( + "IOError", "The output path is a directory: " + path, null); + } + File parent = file.getParentFile(); + if (parent != null && !parent.exists()) { + throw new GeneratedCameraXLibrary.FlutterError( + "IOError", "The parent directory does not exist: " + parent.getAbsolutePath(), null); + } + + String lowerPath = path.toLowerCase(Locale.ROOT); + if (!lowerPath.endsWith(".mp4")) { + throw new GeneratedCameraXLibrary.FlutterError( + "IOError", "Invalid video extension. Supported: .mp4", null); + } + } + @NonNull File openTempFile(@NonNull String path) { try { return new File(path); } catch (NullPointerException | SecurityException e) { - throw new RuntimeException(e); + throw new GeneratedCameraXLibrary.FlutterError("IOError", e.getMessage(), null); } } diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/RecorderTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/RecorderTest.java index 68fba0da8b37..886b4c116118 100644 --- a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/RecorderTest.java +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/RecorderTest.java @@ -80,4 +80,33 @@ public void prepareRecording_returnsExpectedPendingRecording() { assertEquals(mockPendingRecording, api.prepareRecording(mockRecorder, "myFile.mp4")); } + + @Test(expected = GeneratedCameraXLibrary.FlutterError.class) + public void prepareRecording_errorsOnDirectoryPath() { + final PigeonApiRecorder api = new TestProxyApiRegistrar().getPigeonApiRecorder(); + final Recorder mockRecorder = mock(Recorder.class); + + // Pass a path that is a directory (e.g. root "/") + api.prepareRecording(mockRecorder, "/"); + } + + @Test(expected = GeneratedCameraXLibrary.FlutterError.class) + public void prepareRecording_errorsOnNonExistentParent() { + final PigeonApiRecorder api = new TestProxyApiRegistrar().getPigeonApiRecorder(); + final Recorder mockRecorder = mock(Recorder.class); + + api.prepareRecording(mockRecorder, "/non/existent/parent/file.mp4"); + } + + @Test(expected = GeneratedCameraXLibrary.FlutterError.class) + public void prepareRecording_errorsOnInvalidExtension() { + final PigeonApiRecorder api = new TestProxyApiRegistrar().getPigeonApiRecorder(); + final Recorder mockRecorder = mock(Recorder.class); + + // A path that has an invalid extension, but whose parent exists (we can just use an empty + // parent or relative path if needed, but since it checks parent existence, let's use a known + // valid parent like current directory, or mock it. Actually, `new + // File("file.txt").getParentFile()` is null, which bypasses the parent existence check!) + api.prepareRecording(mockRecorder, "file.txt"); + } } diff --git a/packages/camera/camera_android_camerax/example/lib/camera_controller.dart b/packages/camera/camera_android_camerax/example/lib/camera_controller.dart index 7d456043fa4a..4a72904441e6 100644 --- a/packages/camera/camera_android_camerax/example/lib/camera_controller.dart +++ b/packages/camera/camera_android_camerax/example/lib/camera_controller.dart @@ -502,6 +502,7 @@ class CameraController extends ValueNotifier { Future startVideoRecording({ onLatestImageAvailable? onAvailable, bool enablePersistentRecording = true, + String? videoOutputPath, }) async { _throwIfNotInitialized('startVideoRecording'); if (value.isRecordingVideo) { @@ -511,6 +512,16 @@ class CameraController extends ValueNotifier { ); } + if (videoOutputPath != null) { + final String lowerPath = videoOutputPath.toLowerCase(); + if (!lowerPath.endsWith('.mp4')) { + throw CameraException( + 'InvalidFilePath', + 'Invalid video extension. Supported: .mp4', + ); + } + } + void Function(CameraImageData image)? streamCallback; if (onAvailable != null) { streamCallback = (CameraImageData imageData) { @@ -524,6 +535,7 @@ class CameraController extends ValueNotifier { _cameraId, streamCallback: streamCallback, enablePersistentRecording: enablePersistentRecording, + videoOutputPath: videoOutputPath, ), ); value = value.copyWith( diff --git a/packages/camera/camera_android_camerax/example/pubspec.yaml b/packages/camera/camera_android_camerax/example/pubspec.yaml index 04df4cb6830f..085eca05a4d1 100644 --- a/packages/camera/camera_android_camerax/example/pubspec.yaml +++ b/packages/camera/camera_android_camerax/example/pubspec.yaml @@ -28,4 +28,8 @@ dev_dependencies: flutter: uses-material-design: true +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + camera_platform_interface: {path: ../../../../packages/camera/camera_platform_interface} diff --git a/packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart b/packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart index e52e4bd09cf1..a116d4a5e73c 100644 --- a/packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart +++ b/packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart @@ -12,6 +12,7 @@ import 'package:flutter/services.dart' show DeviceOrientation, PlatformException; import 'package:flutter/widgets.dart' show Texture, Widget, visibleForTesting; import 'package:stream_transform/stream_transform.dart'; + import 'camerax_library.dart'; import 'rotated_preview_delegate.dart'; @@ -1148,9 +1149,12 @@ class AndroidCameraCameraX extends CameraPlatform { Future startVideoRecording( int cameraId, { Duration? maxVideoDuration, + String? videoOutputPath, }) async { // Ignore maxVideoDuration, as it is unimplemented and deprecated. - return startVideoCapturing(VideoCaptureOptions(cameraId)); + return startVideoCapturing( + VideoCaptureOptions(cameraId, videoOutputPath: videoOutputPath), + ); } /// Starts a video recording and/or streaming session. @@ -1183,10 +1187,9 @@ class AndroidCameraCameraX extends CameraPlatform { ); } - videoOutputPath = await systemServicesManager.getTempFilePath( - videoPrefix, - '.mp4', - ); + videoOutputPath = + options.videoOutputPath ?? + await systemServicesManager.getTempFilePath(videoPrefix, '.mp4'); pendingRecording = await recorder!.prepareRecording(videoOutputPath!); if (options.enablePersistentRecording) { diff --git a/packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart b/packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart index dca2b8d08f80..b71b22024ae5 100644 --- a/packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart +++ b/packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart @@ -1,24 +1,42 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v26.1.7), do not edit directly. +// Autogenerated from Pigeon (v26.3.2), do not edit directly. // See also: https://pub.dev/packages/pigeon -// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, omit_obvious_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers +// ignore_for_file: unused_import, unused_shown_name +// ignore_for_file: type=lint import 'dart:async'; import 'dart:io' show Platform; -import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; +import 'dart:typed_data' show Float64List, Int32List, Int64List; -import 'package:flutter/foundation.dart' - show ReadBuffer, WriteBuffer, immutable, protected, visibleForTesting; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart' show WidgetsFlutterBinding; +import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; -PlatformException _createConnectionError(String channelName) { - return PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel: "$channelName".', - ); +Object? _extractReplyValueOrThrow( + List? replyList, + String channelName, { + required bool isNullValid, +}) { + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (!isNullValid && (replyList.isNotEmpty && replyList[0] == null)) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } + return replyList.firstOrNull; } List wrapResponse({ @@ -757,19 +775,11 @@ class _PigeonInternalInstanceManagerApi { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.PigeonInternalInstanceManager.removeStrongReference was null.', - ); - final List args = (message as List?)!; - final int? arg_identifier = (args[0] as int?); - assert( - arg_identifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.PigeonInternalInstanceManager.removeStrongReference was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_identifier = args[0]! as int; try { (instanceManager ?? PigeonInstanceManager.instance).remove( - arg_identifier!, + arg_identifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -796,17 +806,12 @@ class _PigeonInternalInstanceManagerApi { [identifier], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Clear the native `PigeonInstanceManager`. @@ -822,17 +827,12 @@ class _PigeonInternalInstanceManagerApi { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } } @@ -926,7 +926,7 @@ enum CameraStateType { unknown, } -/// The types (T) properly wrapped to be used as a LiveData. +/// The types (T) properly wrapped to be used as a `LiveData`. enum LiveDataSupportedType { cameraState, zoomState } /// Video quality constraints that will be used by a QualitySelector to choose @@ -1234,17 +1234,12 @@ class CameraSize extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -1290,37 +1285,21 @@ class CameraSize extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraSize.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraSize.pigeon_newInstance was null, expected non-null int.', - ); - final int? arg_width = (args[1] as int?); - assert( - arg_width != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraSize.pigeon_newInstance was null, expected non-null int.', - ); - final int? arg_height = (args[2] as int?); - assert( - arg_height != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraSize.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; + final int arg_width = args[1]! as int; + final int arg_height = args[2]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( - pigeon_newInstance?.call(arg_width!, arg_height!) ?? + pigeon_newInstance?.call(arg_width, arg_height) ?? CameraSize.pigeon_detached( pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, - width: arg_width!, - height: arg_height!, + width: arg_width, + height: arg_height, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -1386,31 +1365,19 @@ class ResolutionInfo extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ResolutionInfo.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ResolutionInfo.pigeon_newInstance was null, expected non-null int.', - ); - final CameraSize? arg_resolution = (args[1] as CameraSize?); - assert( - arg_resolution != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ResolutionInfo.pigeon_newInstance was null, expected non-null CameraSize.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; + final CameraSize arg_resolution = args[1]! as CameraSize; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( - pigeon_newInstance?.call(arg_resolution!) ?? + pigeon_newInstance?.call(arg_resolution) ?? ResolutionInfo.pigeon_detached( pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, - resolution: arg_resolution!, + resolution: arg_resolution, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -1485,17 +1452,12 @@ class CameraIntegerRange extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -1543,37 +1505,21 @@ class CameraIntegerRange extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraIntegerRange.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraIntegerRange.pigeon_newInstance was null, expected non-null int.', - ); - final int? arg_lower = (args[1] as int?); - assert( - arg_lower != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraIntegerRange.pigeon_newInstance was null, expected non-null int.', - ); - final int? arg_upper = (args[2] as int?); - assert( - arg_upper != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraIntegerRange.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; + final int arg_lower = args[1]! as int; + final int arg_upper = args[2]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( - pigeon_newInstance?.call(arg_lower!, arg_upper!) ?? + pigeon_newInstance?.call(arg_lower, arg_upper) ?? CameraIntegerRange.pigeon_detached( pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, - lower: arg_lower!, - upper: arg_upper!, + lower: arg_lower, + upper: arg_upper, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -1634,16 +1580,8 @@ class VideoRecordEvent extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.VideoRecordEvent.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.VideoRecordEvent.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -1652,7 +1590,7 @@ class VideoRecordEvent extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -1711,16 +1649,8 @@ class VideoRecordEventStart extends VideoRecordEvent { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.VideoRecordEventStart.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.VideoRecordEventStart.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -1729,7 +1659,7 @@ class VideoRecordEventStart extends VideoRecordEvent { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -1788,16 +1718,8 @@ class VideoRecordEventFinalize extends VideoRecordEvent { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.VideoRecordEventFinalize.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.VideoRecordEventFinalize.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -1806,7 +1728,7 @@ class VideoRecordEventFinalize extends VideoRecordEvent { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -1869,16 +1791,8 @@ class MeteringPoint extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.MeteringPoint.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.MeteringPoint.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -1887,7 +1801,7 @@ class MeteringPoint extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -1921,22 +1835,13 @@ class MeteringPoint extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as double?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as double; } @override @@ -1990,17 +1895,12 @@ class Observer extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -2060,25 +1960,13 @@ class Observer extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Observer.onChanged was null.', - ); - final List args = (message as List?)!; - final Observer? arg_pigeon_instance = (args[0] as Observer?); - assert( - arg_pigeon_instance != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Observer.onChanged was null, expected non-null Observer.', - ); - final Object? arg_value = (args[1] as Object?); - assert( - arg_value != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Observer.onChanged was null, expected non-null Object.', - ); + final List args = message! as List; + final Observer arg_pigeon_instance = args[0]! as Observer; + final Object arg_value = args[1]!; try { - (onChanged ?? arg_pigeon_instance!.onChanged).call( - arg_pigeon_instance!, - arg_value!, + (onChanged ?? arg_pigeon_instance.onChanged).call( + arg_pigeon_instance, + arg_value, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -2159,47 +2047,27 @@ class CameraInfo extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraInfo.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraInfo.pigeon_newInstance was null, expected non-null int.', - ); - final int? arg_sensorRotationDegrees = (args[1] as int?); - assert( - arg_sensorRotationDegrees != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraInfo.pigeon_newInstance was null, expected non-null int.', - ); - final LensFacing? arg_lensFacing = (args[2] as LensFacing?); - assert( - arg_lensFacing != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraInfo.pigeon_newInstance was null, expected non-null LensFacing.', - ); - final ExposureState? arg_exposureState = (args[3] as ExposureState?); - assert( - arg_exposureState != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraInfo.pigeon_newInstance was null, expected non-null ExposureState.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; + final int arg_sensorRotationDegrees = args[1]! as int; + final LensFacing arg_lensFacing = args[2]! as LensFacing; + final ExposureState arg_exposureState = args[3]! as ExposureState; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( pigeon_newInstance?.call( - arg_sensorRotationDegrees!, - arg_lensFacing!, - arg_exposureState!, + arg_sensorRotationDegrees, + arg_lensFacing, + arg_exposureState, ) ?? CameraInfo.pigeon_detached( pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, - sensorRotationDegrees: arg_sensorRotationDegrees!, - lensFacing: arg_lensFacing!, - exposureState: arg_exposureState!, + sensorRotationDegrees: arg_sensorRotationDegrees, + lensFacing: arg_lensFacing, + exposureState: arg_exposureState, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -2230,22 +2098,13 @@ class CameraInfo extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as LiveData?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as LiveData; } /// A LiveData of ZoomState. @@ -2264,22 +2123,13 @@ class CameraInfo extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as LiveData?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as LiveData; } @override @@ -2347,17 +2197,12 @@ class CameraSelector extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -2411,16 +2256,8 @@ class CameraSelector extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraSelector.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraSelector.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -2429,7 +2266,7 @@ class CameraSelector extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -2464,17 +2301,12 @@ class CameraSelector extends PigeonInternalProxyApiBaseClass { [pigeonVar_instanceIdentifier], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); return pigeonVar_instance; } @@ -2499,17 +2331,12 @@ class CameraSelector extends PigeonInternalProxyApiBaseClass { [pigeonVar_instanceIdentifier], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); return pigeonVar_instance; } @@ -2531,22 +2358,13 @@ class CameraSelector extends PigeonInternalProxyApiBaseClass { [this, cameraInfos], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as List?)!.cast(); - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return (pigeonVar_replyValue! as List).cast(); } @override @@ -2599,16 +2417,8 @@ class ProcessCameraProvider extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ProcessCameraProvider.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ProcessCameraProvider.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -2617,7 +2427,7 @@ class ProcessCameraProvider extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -2654,22 +2464,13 @@ class ProcessCameraProvider extends PigeonInternalProxyApiBaseClass { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as ProcessCameraProvider?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as ProcessCameraProvider; } /// The `CameraInfo` instances of the available cameras. @@ -2688,22 +2489,13 @@ class ProcessCameraProvider extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as List?)!.cast(); - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return (pigeonVar_replyValue! as List).cast(); } /// Binds the collection of `UseCase` to a `LifecycleOwner`. @@ -2725,22 +2517,13 @@ class ProcessCameraProvider extends PigeonInternalProxyApiBaseClass { [this, cameraSelector, useCases], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as Camera?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as Camera; } /// Returns true if the `UseCase` is bound to a lifecycle. @@ -2759,22 +2542,13 @@ class ProcessCameraProvider extends PigeonInternalProxyApiBaseClass { [this, useCase], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as bool?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as bool; } /// Unbinds all specified use cases from the lifecycle provider. @@ -2793,17 +2567,12 @@ class ProcessCameraProvider extends PigeonInternalProxyApiBaseClass { [this, useCases], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Unbinds all use cases from the lifecycle provider and removes them from @@ -2823,17 +2592,12 @@ class ProcessCameraProvider extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } @override @@ -2880,16 +2644,8 @@ class UseCase extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.UseCase.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.UseCase.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -2898,7 +2654,7 @@ class UseCase extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -2966,31 +2722,19 @@ class Camera extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Camera.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Camera.pigeon_newInstance was null, expected non-null int.', - ); - final CameraControl? arg_cameraControl = (args[1] as CameraControl?); - assert( - arg_cameraControl != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Camera.pigeon_newInstance was null, expected non-null CameraControl.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; + final CameraControl arg_cameraControl = args[1]! as CameraControl; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( - pigeon_newInstance?.call(arg_cameraControl!) ?? + pigeon_newInstance?.call(arg_cameraControl) ?? Camera.pigeon_detached( pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, - cameraControl: arg_cameraControl!, + cameraControl: arg_cameraControl, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -3021,22 +2765,13 @@ class Camera extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as CameraInfo?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as CameraInfo; } @override @@ -3095,17 +2830,12 @@ class SystemServicesManager extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -3175,26 +2905,14 @@ class SystemServicesManager extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.SystemServicesManager.onCameraError was null.', - ); - final List args = (message as List?)!; - final SystemServicesManager? arg_pigeon_instance = - (args[0] as SystemServicesManager?); - assert( - arg_pigeon_instance != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.SystemServicesManager.onCameraError was null, expected non-null SystemServicesManager.', - ); - final String? arg_errorDescription = (args[1] as String?); - assert( - arg_errorDescription != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.SystemServicesManager.onCameraError was null, expected non-null String.', - ); + final List args = message! as List; + final SystemServicesManager arg_pigeon_instance = + args[0]! as SystemServicesManager; + final String arg_errorDescription = args[1]! as String; try { - (onCameraError ?? arg_pigeon_instance!.onCameraError).call( - arg_pigeon_instance!, - arg_errorDescription!, + (onCameraError ?? arg_pigeon_instance.onCameraError).call( + arg_pigeon_instance, + arg_errorDescription, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -3226,17 +2944,13 @@ class SystemServicesManager extends PigeonInternalProxyApiBaseClass { [this, enableAudio], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return (pigeonVar_replyList[0] as CameraPermissionsError?); - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + return pigeonVar_replyValue as CameraPermissionsError?; } /// Returns a path to be used to create a temp file in the current cache @@ -3256,22 +2970,13 @@ class SystemServicesManager extends PigeonInternalProxyApiBaseClass { [this, prefix, suffix], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as String?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as String; } @override @@ -3324,37 +3029,21 @@ class CameraPermissionsError extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraPermissionsError.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraPermissionsError.pigeon_newInstance was null, expected non-null int.', - ); - final String? arg_errorCode = (args[1] as String?); - assert( - arg_errorCode != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraPermissionsError.pigeon_newInstance was null, expected non-null String.', - ); - final String? arg_description = (args[2] as String?); - assert( - arg_description != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraPermissionsError.pigeon_newInstance was null, expected non-null String.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; + final String arg_errorCode = args[1]! as String; + final String arg_description = args[2]! as String; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( - pigeon_newInstance?.call(arg_errorCode!, arg_description!) ?? + pigeon_newInstance?.call(arg_errorCode, arg_description) ?? CameraPermissionsError.pigeon_detached( pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, - errorCode: arg_errorCode!, - description: arg_description!, + errorCode: arg_errorCode, + description: arg_description, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -3427,17 +3116,12 @@ class DeviceOrientationManager extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -3504,26 +3188,14 @@ class DeviceOrientationManager extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.DeviceOrientationManager.onDeviceOrientationChanged was null.', - ); - final List args = (message as List?)!; - final DeviceOrientationManager? arg_pigeon_instance = - (args[0] as DeviceOrientationManager?); - assert( - arg_pigeon_instance != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.DeviceOrientationManager.onDeviceOrientationChanged was null, expected non-null DeviceOrientationManager.', - ); - final String? arg_orientation = (args[1] as String?); - assert( - arg_orientation != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.DeviceOrientationManager.onDeviceOrientationChanged was null, expected non-null String.', - ); + final List args = message! as List; + final DeviceOrientationManager arg_pigeon_instance = + args[0]! as DeviceOrientationManager; + final String arg_orientation = args[1]! as String; try { (onDeviceOrientationChanged ?? - arg_pigeon_instance!.onDeviceOrientationChanged) - .call(arg_pigeon_instance!, arg_orientation!); + arg_pigeon_instance.onDeviceOrientationChanged) + .call(arg_pigeon_instance, arg_orientation); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); @@ -3552,17 +3224,12 @@ class DeviceOrientationManager extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future stopListeningForDeviceOrientationChange() async { @@ -3580,17 +3247,12 @@ class DeviceOrientationManager extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } Future getDefaultDisplayRotation() async { @@ -3608,22 +3270,13 @@ class DeviceOrientationManager extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as int?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as int; } Future getUiOrientation() async { @@ -3641,22 +3294,13 @@ class DeviceOrientationManager extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as String?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as String; } @override @@ -3725,17 +3369,12 @@ class Preview extends UseCase { ]); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -3777,18 +3416,10 @@ class Preview extends UseCase { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Preview.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Preview.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; final ResolutionSelector? arg_resolutionSelector = - (args[1] as ResolutionSelector?); + args[1] as ResolutionSelector?; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -3798,7 +3429,7 @@ class Preview extends UseCase { pigeon_instanceManager: pigeon_instanceManager, resolutionSelector: arg_resolutionSelector, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -3838,22 +3469,13 @@ class Preview extends UseCase { [this, systemServicesManager], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as int?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as int; } /// Releases the `SurfaceProducer` created in `setSurfaceProvider` if one was @@ -3873,17 +3495,12 @@ class Preview extends UseCase { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Gets selected resolution information of the `Preview`. @@ -3902,17 +3519,13 @@ class Preview extends UseCase { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return (pigeonVar_replyList[0] as ResolutionInfo?); - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + return pigeonVar_replyValue as ResolutionInfo?; } /// Sets the target rotation. @@ -3931,17 +3544,12 @@ class Preview extends UseCase { [this, rotation], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Returns whether or not the preview's surface producer handles correctly @@ -3961,22 +3569,13 @@ class Preview extends UseCase { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as bool?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as bool; } @override @@ -4039,17 +3638,12 @@ class VideoCapture extends UseCase { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -4087,16 +3681,8 @@ class VideoCapture extends UseCase { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.VideoCapture.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.VideoCapture.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -4105,7 +3691,7 @@ class VideoCapture extends UseCase { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -4136,22 +3722,13 @@ class VideoCapture extends UseCase { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as VideoOutput?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as VideoOutput; } /// Sets the desired rotation of the output video. @@ -4170,17 +3747,12 @@ class VideoCapture extends UseCase { [this, rotation], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } @override @@ -4227,16 +3799,8 @@ class VideoOutput extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.VideoOutput.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.VideoOutput.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -4245,7 +3809,7 @@ class VideoOutput extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -4326,17 +3890,12 @@ class Recorder extends PigeonInternalProxyApiBaseClass implements VideoOutput { ]); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -4374,16 +3933,8 @@ class Recorder extends PigeonInternalProxyApiBaseClass implements VideoOutput { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Recorder.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Recorder.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -4392,7 +3943,7 @@ class Recorder extends PigeonInternalProxyApiBaseClass implements VideoOutput { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -4423,22 +3974,13 @@ class Recorder extends PigeonInternalProxyApiBaseClass implements VideoOutput { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as int?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as int; } /// Gets the target video encoding bitrate of this Recorder. @@ -4457,22 +3999,13 @@ class Recorder extends PigeonInternalProxyApiBaseClass implements VideoOutput { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as int?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as int; } /// The quality selector of this Recorder. @@ -4491,22 +4024,13 @@ class Recorder extends PigeonInternalProxyApiBaseClass implements VideoOutput { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as QualitySelector?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as QualitySelector; } /// Prepares a recording that will be saved to a File. @@ -4525,22 +4049,13 @@ class Recorder extends PigeonInternalProxyApiBaseClass implements VideoOutput { [this, path], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as PendingRecording?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as PendingRecording; } @override @@ -4596,18 +4111,13 @@ class VideoRecordEventListener extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } - }(); + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + }(); } /// Constructs [VideoRecordEventListener] without creating the associated native object. @@ -4676,26 +4186,14 @@ class VideoRecordEventListener extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.VideoRecordEventListener.onEvent was null.', - ); - final List args = (message as List?)!; - final VideoRecordEventListener? arg_pigeon_instance = - (args[0] as VideoRecordEventListener?); - assert( - arg_pigeon_instance != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.VideoRecordEventListener.onEvent was null, expected non-null VideoRecordEventListener.', - ); - final VideoRecordEvent? arg_event = (args[1] as VideoRecordEvent?); - assert( - arg_event != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.VideoRecordEventListener.onEvent was null, expected non-null VideoRecordEvent.', - ); + final List args = message! as List; + final VideoRecordEventListener arg_pigeon_instance = + args[0]! as VideoRecordEventListener; + final VideoRecordEvent arg_event = args[1]! as VideoRecordEvent; try { - (onEvent ?? arg_pigeon_instance!.onEvent).call( - arg_pigeon_instance!, - arg_event!, + (onEvent ?? arg_pigeon_instance.onEvent).call( + arg_pigeon_instance, + arg_event, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -4758,16 +4256,8 @@ class PendingRecording extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.PendingRecording.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.PendingRecording.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -4776,7 +4266,7 @@ class PendingRecording extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -4807,22 +4297,13 @@ class PendingRecording extends PigeonInternalProxyApiBaseClass { [this, initialMuted], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as PendingRecording?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as PendingRecording; } /// Configures the recording to be a persistent recording. @@ -4849,22 +4330,13 @@ class PendingRecording extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as PendingRecording?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as PendingRecording; } /// Starts the recording, making it an active recording. @@ -4883,22 +4355,13 @@ class PendingRecording extends PigeonInternalProxyApiBaseClass { [this, listener], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as Recording?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as Recording; } @override @@ -4948,16 +4411,8 @@ class Recording extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Recording.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Recording.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -4966,7 +4421,7 @@ class Recording extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -4997,17 +4452,12 @@ class Recording extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Pauses the current recording if active. @@ -5026,17 +4476,12 @@ class Recording extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Resumes the current recording if paused. @@ -5055,17 +4500,12 @@ class Recording extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Stops the recording, as if calling `close`. @@ -5086,17 +4526,12 @@ class Recording extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } @override @@ -5155,26 +4590,22 @@ class ImageCapture extends UseCase { pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel - .send([ - pigeonVar_instanceIdentifier, - resolutionSelector, - targetRotation, - flashMode, - ]); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [ + pigeonVar_instanceIdentifier, + resolutionSelector, + targetRotation, + flashMode, + ], + ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -5216,18 +4647,10 @@ class ImageCapture extends UseCase { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ImageCapture.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ImageCapture.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; final ResolutionSelector? arg_resolutionSelector = - (args[1] as ResolutionSelector?); + args[1] as ResolutionSelector?; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -5237,7 +4660,7 @@ class ImageCapture extends UseCase { pigeon_instanceManager: pigeon_instanceManager, resolutionSelector: arg_resolutionSelector, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -5268,17 +4691,12 @@ class ImageCapture extends UseCase { [this, flashMode], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Captures a new still image for in memory access. @@ -5299,22 +4717,13 @@ class ImageCapture extends UseCase { [this, systemServicesManager], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as String?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as String; } /// Sets the desired rotation of the output image. @@ -5333,17 +4742,12 @@ class ImageCapture extends UseCase { [this, rotation], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } @override @@ -5405,17 +4809,12 @@ class ResolutionStrategy extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -5464,16 +4863,8 @@ class ResolutionStrategy extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ResolutionStrategy.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ResolutionStrategy.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -5482,7 +4873,7 @@ class ResolutionStrategy extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -5518,17 +4909,12 @@ class ResolutionStrategy extends PigeonInternalProxyApiBaseClass { [pigeonVar_instanceIdentifier], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); return pigeonVar_instance; } @@ -5549,17 +4935,13 @@ class ResolutionStrategy extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return (pigeonVar_replyList[0] as CameraSize?); - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + return pigeonVar_replyValue as CameraSize?; } /// The fallback rule for choosing an alternate size when the specified bound @@ -5579,22 +4961,13 @@ class ResolutionStrategy extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as ResolutionStrategyFallbackRule?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as ResolutionStrategyFallbackRule; } @override @@ -5663,17 +5036,12 @@ class ResolutionSelector extends PigeonInternalProxyApiBaseClass { ]); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -5725,20 +5093,12 @@ class ResolutionSelector extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ResolutionSelector.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ResolutionSelector.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; final ResolutionFilter? arg_resolutionFilter = - (args[1] as ResolutionFilter?); + args[1] as ResolutionFilter?; final ResolutionStrategy? arg_resolutionStrategy = - (args[2] as ResolutionStrategy?); + args[2] as ResolutionStrategy?; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -5752,7 +5112,7 @@ class ResolutionSelector extends PigeonInternalProxyApiBaseClass { resolutionFilter: arg_resolutionFilter, resolutionStrategy: arg_resolutionStrategy, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -5785,22 +5145,13 @@ class ResolutionSelector extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as AspectRatioStrategy?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as AspectRatioStrategy; } @override @@ -5871,17 +5222,12 @@ class AspectRatioStrategy extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -5943,16 +5289,8 @@ class AspectRatioStrategy extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.AspectRatioStrategy.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.AspectRatioStrategy.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -5961,7 +5299,7 @@ class AspectRatioStrategy extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -5997,17 +5335,12 @@ class AspectRatioStrategy extends PigeonInternalProxyApiBaseClass { [pigeonVar_instanceIdentifier], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); return pigeonVar_instance; } @@ -6033,17 +5366,12 @@ class AspectRatioStrategy extends PigeonInternalProxyApiBaseClass { [pigeonVar_instanceIdentifier], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); return pigeonVar_instance; } @@ -6065,22 +5393,13 @@ class AspectRatioStrategy extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as AspectRatioStrategyFallbackRule?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as AspectRatioStrategyFallbackRule; } /// The specified preferred aspect ratio. @@ -6099,22 +5418,13 @@ class AspectRatioStrategy extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as AspectRatio?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as AspectRatio; } @override @@ -6170,34 +5480,22 @@ class CameraState extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraState.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraState.pigeon_newInstance was null, expected non-null int.', - ); - final CameraStateType? arg_type = (args[1] as CameraStateType?); - assert( - arg_type != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraState.pigeon_newInstance was null, expected non-null CameraStateType.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; + final CameraStateType arg_type = args[1]! as CameraStateType; final CameraStateStateError? arg_error = - (args[2] as CameraStateStateError?); + args[2] as CameraStateStateError?; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( - pigeon_newInstance?.call(arg_type!, arg_error) ?? + pigeon_newInstance?.call(arg_type, arg_error) ?? CameraState.pigeon_detached( pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, - type: arg_type!, + type: arg_type, error: arg_error, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -6271,42 +5569,26 @@ class ExposureState extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ExposureState.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ExposureState.pigeon_newInstance was null, expected non-null int.', - ); - final CameraIntegerRange? arg_exposureCompensationRange = - (args[1] as CameraIntegerRange?); - assert( - arg_exposureCompensationRange != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ExposureState.pigeon_newInstance was null, expected non-null CameraIntegerRange.', - ); - final double? arg_exposureCompensationStep = (args[2] as double?); - assert( - arg_exposureCompensationStep != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ExposureState.pigeon_newInstance was null, expected non-null double.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; + final CameraIntegerRange arg_exposureCompensationRange = + args[1]! as CameraIntegerRange; + final double arg_exposureCompensationStep = args[2]! as double; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( pigeon_newInstance?.call( - arg_exposureCompensationRange!, - arg_exposureCompensationStep!, + arg_exposureCompensationRange, + arg_exposureCompensationStep, ) ?? ExposureState.pigeon_detached( pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, exposureCompensationRange: - arg_exposureCompensationRange!, - exposureCompensationStep: arg_exposureCompensationStep!, + arg_exposureCompensationRange, + exposureCompensationStep: arg_exposureCompensationStep, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -6376,40 +5658,24 @@ class ZoomState extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ZoomState.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ZoomState.pigeon_newInstance was null, expected non-null int.', - ); - final double? arg_minZoomRatio = (args[1] as double?); - assert( - arg_minZoomRatio != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ZoomState.pigeon_newInstance was null, expected non-null double.', - ); - final double? arg_maxZoomRatio = (args[2] as double?); - assert( - arg_maxZoomRatio != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ZoomState.pigeon_newInstance was null, expected non-null double.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; + final double arg_minZoomRatio = args[1]! as double; + final double arg_maxZoomRatio = args[2]! as double; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( pigeon_newInstance?.call( - arg_minZoomRatio!, - arg_maxZoomRatio!, + arg_minZoomRatio, + arg_maxZoomRatio, ) ?? ZoomState.pigeon_detached( pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, - minZoomRatio: arg_minZoomRatio!, - maxZoomRatio: arg_maxZoomRatio!, + minZoomRatio: arg_minZoomRatio, + maxZoomRatio: arg_maxZoomRatio, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -6497,17 +5763,12 @@ class ImageAnalysis extends UseCase { ]); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -6549,18 +5810,10 @@ class ImageAnalysis extends UseCase { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ImageAnalysis.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ImageAnalysis.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; final ResolutionSelector? arg_resolutionSelector = - (args[1] as ResolutionSelector?); + args[1] as ResolutionSelector?; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -6570,7 +5823,7 @@ class ImageAnalysis extends UseCase { pigeon_instanceManager: pigeon_instanceManager, resolutionSelector: arg_resolutionSelector, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -6601,17 +5854,12 @@ class ImageAnalysis extends UseCase { [this, analyzer], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Removes a previously set analyzer. @@ -6630,17 +5878,12 @@ class ImageAnalysis extends UseCase { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Sets the target rotation. @@ -6659,17 +5902,12 @@ class ImageAnalysis extends UseCase { [this, rotation], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } @override @@ -6724,17 +5962,12 @@ class Analyzer extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -6794,25 +6027,13 @@ class Analyzer extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Analyzer.analyze was null.', - ); - final List args = (message as List?)!; - final Analyzer? arg_pigeon_instance = (args[0] as Analyzer?); - assert( - arg_pigeon_instance != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Analyzer.analyze was null, expected non-null Analyzer.', - ); - final ImageProxy? arg_image = (args[1] as ImageProxy?); - assert( - arg_image != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Analyzer.analyze was null, expected non-null ImageProxy.', - ); + final List args = message! as List; + final Analyzer arg_pigeon_instance = args[0]! as Analyzer; + final ImageProxy arg_image = args[1]! as ImageProxy; try { - (analyze ?? arg_pigeon_instance!.analyze).call( - arg_pigeon_instance!, - arg_image!, + (analyze ?? arg_pigeon_instance.analyze).call( + arg_pigeon_instance, + arg_image, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -6877,32 +6098,20 @@ class CameraStateStateError extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraStateStateError.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraStateStateError.pigeon_newInstance was null, expected non-null int.', - ); - final CameraStateErrorCode? arg_code = - (args[1] as CameraStateErrorCode?); - assert( - arg_code != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraStateStateError.pigeon_newInstance was null, expected non-null CameraStateErrorCode.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; + final CameraStateErrorCode arg_code = + args[1]! as CameraStateErrorCode; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( - pigeon_newInstance?.call(arg_code!) ?? + pigeon_newInstance?.call(arg_code) ?? CameraStateStateError.pigeon_detached( pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, - code: arg_code!, + code: arg_code, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -6973,32 +6182,20 @@ class LiveData extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.LiveData.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.LiveData.pigeon_newInstance was null, expected non-null int.', - ); - final LiveDataSupportedType? arg_type = - (args[1] as LiveDataSupportedType?); - assert( - arg_type != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.LiveData.pigeon_newInstance was null, expected non-null LiveDataSupportedType.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; + final LiveDataSupportedType arg_type = + args[1]! as LiveDataSupportedType; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( - pigeon_newInstance?.call(arg_type!) ?? + pigeon_newInstance?.call(arg_type) ?? LiveData.pigeon_detached( pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, - type: arg_type!, + type: arg_type, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -7030,17 +6227,12 @@ class LiveData extends PigeonInternalProxyApiBaseClass { [this, observer], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Removes all observers that are tied to the given `LifecycleOwner`. @@ -7059,17 +6251,12 @@ class LiveData extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Returns the current value. @@ -7088,17 +6275,13 @@ class LiveData extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return pigeonVar_replyList[0]; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + return pigeonVar_replyValue; } @override @@ -7161,47 +6344,23 @@ class ImageProxy extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ImageProxy.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ImageProxy.pigeon_newInstance was null, expected non-null int.', - ); - final int? arg_format = (args[1] as int?); - assert( - arg_format != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ImageProxy.pigeon_newInstance was null, expected non-null int.', - ); - final int? arg_width = (args[2] as int?); - assert( - arg_width != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ImageProxy.pigeon_newInstance was null, expected non-null int.', - ); - final int? arg_height = (args[3] as int?); - assert( - arg_height != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ImageProxy.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; + final int arg_format = args[1]! as int; + final int arg_width = args[2]! as int; + final int arg_height = args[3]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( - pigeon_newInstance?.call( - arg_format!, - arg_width!, - arg_height!, - ) ?? + pigeon_newInstance?.call(arg_format, arg_width, arg_height) ?? ImageProxy.pigeon_detached( pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, - format: arg_format!, - width: arg_width!, - height: arg_height!, + format: arg_format, + width: arg_width, + height: arg_height, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -7232,22 +6391,13 @@ class ImageProxy extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as List?)!.cast(); - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return (pigeonVar_replyValue! as List).cast(); } /// Closes the underlying `android.media.Image`. @@ -7266,17 +6416,12 @@ class ImageProxy extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } @override @@ -7327,16 +6472,8 @@ class ImageProxyUtils extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ImageProxyUtils.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ImageProxyUtils.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -7345,7 +6482,7 @@ class ImageProxyUtils extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -7391,22 +6528,13 @@ class ImageProxyUtils extends PigeonInternalProxyApiBaseClass { [imageWidth, imageHeight, planes], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as Uint8List?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as Uint8List; } @override @@ -7467,47 +6595,27 @@ class PlaneProxy extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.PlaneProxy.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.PlaneProxy.pigeon_newInstance was null, expected non-null int.', - ); - final Uint8List? arg_buffer = (args[1] as Uint8List?); - assert( - arg_buffer != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.PlaneProxy.pigeon_newInstance was null, expected non-null Uint8List.', - ); - final int? arg_pixelStride = (args[2] as int?); - assert( - arg_pixelStride != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.PlaneProxy.pigeon_newInstance was null, expected non-null int.', - ); - final int? arg_rowStride = (args[3] as int?); - assert( - arg_rowStride != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.PlaneProxy.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; + final Uint8List arg_buffer = args[1]! as Uint8List; + final int arg_pixelStride = args[2]! as int; + final int arg_rowStride = args[3]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( pigeon_newInstance?.call( - arg_buffer!, - arg_pixelStride!, - arg_rowStride!, + arg_buffer, + arg_pixelStride, + arg_rowStride, ) ?? PlaneProxy.pigeon_detached( pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, - buffer: arg_buffer!, - pixelStride: arg_pixelStride!, - rowStride: arg_rowStride!, + buffer: arg_buffer, + pixelStride: arg_pixelStride, + rowStride: arg_rowStride, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -7585,17 +6693,12 @@ class QualitySelector extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -7645,17 +6748,12 @@ class QualitySelector extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -7693,16 +6791,8 @@ class QualitySelector extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.QualitySelector.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.QualitySelector.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -7711,7 +6801,7 @@ class QualitySelector extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -7755,17 +6845,13 @@ class QualitySelector extends PigeonInternalProxyApiBaseClass { [cameraInfo, quality], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return (pigeonVar_replyList[0] as CameraSize?); - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + return pigeonVar_replyValue as CameraSize?; } @override @@ -7827,17 +6913,12 @@ class FallbackStrategy extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -7885,17 +6966,12 @@ class FallbackStrategy extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -7943,17 +7019,12 @@ class FallbackStrategy extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -8001,17 +7072,12 @@ class FallbackStrategy extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -8049,16 +7115,8 @@ class FallbackStrategy extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.FallbackStrategy.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.FallbackStrategy.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -8067,7 +7125,7 @@ class FallbackStrategy extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -8131,16 +7189,8 @@ class CameraControl extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraControl.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraControl.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -8149,7 +7199,7 @@ class CameraControl extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -8180,17 +7230,12 @@ class CameraControl extends PigeonInternalProxyApiBaseClass { [this, torch], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Sets current zoom by ratio. @@ -8209,17 +7254,12 @@ class CameraControl extends PigeonInternalProxyApiBaseClass { [this, ratio], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Starts a focus and metering action configured by the @@ -8241,17 +7281,13 @@ class CameraControl extends PigeonInternalProxyApiBaseClass { [this, action], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return (pigeonVar_replyList[0] as FocusMeteringResult?); - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + return pigeonVar_replyValue as FocusMeteringResult?; } /// Cancels current FocusMeteringAction and clears AF/AE/AWB regions. @@ -8270,17 +7306,12 @@ class CameraControl extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Set the exposure compensation value for the camera. @@ -8299,17 +7330,13 @@ class CameraControl extends PigeonInternalProxyApiBaseClass { [this, index], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return (pigeonVar_replyList[0] as int?); - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + return pigeonVar_replyValue as int?; } @override @@ -8367,17 +7394,12 @@ class FocusMeteringActionBuilder extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -8427,17 +7449,12 @@ class FocusMeteringActionBuilder extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -8477,16 +7494,8 @@ class FocusMeteringActionBuilder extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.FocusMeteringActionBuilder.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.FocusMeteringActionBuilder.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -8495,7 +7504,7 @@ class FocusMeteringActionBuilder extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -8526,17 +7535,12 @@ class FocusMeteringActionBuilder extends PigeonInternalProxyApiBaseClass { [this, point], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Adds another MeteringPoint with specified meteringMode. @@ -8555,17 +7559,12 @@ class FocusMeteringActionBuilder extends PigeonInternalProxyApiBaseClass { [this, point, mode], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Disables the auto-cancel. @@ -8584,17 +7583,12 @@ class FocusMeteringActionBuilder extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Builds the `FocusMeteringAction` instance. @@ -8613,22 +7607,13 @@ class FocusMeteringActionBuilder extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as FocusMeteringAction?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as FocusMeteringAction; } @override @@ -8697,57 +7682,33 @@ class FocusMeteringAction extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.FocusMeteringAction.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.FocusMeteringAction.pigeon_newInstance was null, expected non-null int.', - ); - final List? arg_meteringPointsAe = - (args[1] as List?)?.cast(); - assert( - arg_meteringPointsAe != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.FocusMeteringAction.pigeon_newInstance was null, expected non-null List.', - ); - final List? arg_meteringPointsAf = - (args[2] as List?)?.cast(); - assert( - arg_meteringPointsAf != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.FocusMeteringAction.pigeon_newInstance was null, expected non-null List.', - ); - final List? arg_meteringPointsAwb = - (args[3] as List?)?.cast(); - assert( - arg_meteringPointsAwb != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.FocusMeteringAction.pigeon_newInstance was null, expected non-null List.', - ); - final bool? arg_isAutoCancelEnabled = (args[4] as bool?); - assert( - arg_isAutoCancelEnabled != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.FocusMeteringAction.pigeon_newInstance was null, expected non-null bool.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; + final List arg_meteringPointsAe = + (args[1]! as List).cast(); + final List arg_meteringPointsAf = + (args[2]! as List).cast(); + final List arg_meteringPointsAwb = + (args[3]! as List).cast(); + final bool arg_isAutoCancelEnabled = args[4]! as bool; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( pigeon_newInstance?.call( - arg_meteringPointsAe!, - arg_meteringPointsAf!, - arg_meteringPointsAwb!, - arg_isAutoCancelEnabled!, + arg_meteringPointsAe, + arg_meteringPointsAf, + arg_meteringPointsAwb, + arg_isAutoCancelEnabled, ) ?? FocusMeteringAction.pigeon_detached( pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, - meteringPointsAe: arg_meteringPointsAe!, - meteringPointsAf: arg_meteringPointsAf!, - meteringPointsAwb: arg_meteringPointsAwb!, - isAutoCancelEnabled: arg_isAutoCancelEnabled!, + meteringPointsAe: arg_meteringPointsAe, + meteringPointsAf: arg_meteringPointsAf, + meteringPointsAwb: arg_meteringPointsAwb, + isAutoCancelEnabled: arg_isAutoCancelEnabled, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -8814,31 +7775,19 @@ class FocusMeteringResult extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.FocusMeteringResult.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.FocusMeteringResult.pigeon_newInstance was null, expected non-null int.', - ); - final bool? arg_isFocusSuccessful = (args[1] as bool?); - assert( - arg_isFocusSuccessful != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.FocusMeteringResult.pigeon_newInstance was null, expected non-null bool.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; + final bool arg_isFocusSuccessful = args[1]! as bool; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( - pigeon_newInstance?.call(arg_isFocusSuccessful!) ?? + pigeon_newInstance?.call(arg_isFocusSuccessful) ?? FocusMeteringResult.pigeon_detached( pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, - isFocusSuccessful: arg_isFocusSuccessful!, + isFocusSuccessful: arg_isFocusSuccessful, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -8933,16 +7882,8 @@ class CaptureRequest extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CaptureRequest.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CaptureRequest.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -8951,7 +7892,7 @@ class CaptureRequest extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -8987,17 +7928,12 @@ class CaptureRequest extends PigeonInternalProxyApiBaseClass { [pigeonVar_instanceIdentifier], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); return pigeonVar_instance; } @@ -9023,17 +7959,12 @@ class CaptureRequest extends PigeonInternalProxyApiBaseClass { [pigeonVar_instanceIdentifier], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); return pigeonVar_instance; } @@ -9083,16 +8014,8 @@ class CaptureRequestKey extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CaptureRequestKey.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CaptureRequestKey.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -9101,7 +8024,7 @@ class CaptureRequestKey extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -9167,17 +8090,12 @@ class CaptureRequestOptions extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -9217,16 +8135,8 @@ class CaptureRequestOptions extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CaptureRequestOptions.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CaptureRequestOptions.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -9235,7 +8145,7 @@ class CaptureRequestOptions extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -9267,17 +8177,13 @@ class CaptureRequestOptions extends PigeonInternalProxyApiBaseClass { [this, key], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return pigeonVar_replyList[0]; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + return pigeonVar_replyValue; } @override @@ -9336,17 +8242,12 @@ class Camera2CameraControl extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -9386,16 +8287,8 @@ class Camera2CameraControl extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Camera2CameraControl.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Camera2CameraControl.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -9404,7 +8297,7 @@ class Camera2CameraControl extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -9436,17 +8329,12 @@ class Camera2CameraControl extends PigeonInternalProxyApiBaseClass { [this, bundle], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } @override @@ -9503,17 +8391,12 @@ class ResolutionFilter extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -9551,16 +8434,8 @@ class ResolutionFilter extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ResolutionFilter.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.ResolutionFilter.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -9569,7 +8444,7 @@ class ResolutionFilter extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -9629,16 +8504,8 @@ class CameraCharacteristicsKey extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraCharacteristicsKey.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraCharacteristicsKey.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -9647,7 +8514,7 @@ class CameraCharacteristicsKey extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -9763,16 +8630,8 @@ class CameraCharacteristics extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraCharacteristics.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.CameraCharacteristics.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -9781,7 +8640,7 @@ class CameraCharacteristics extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -9817,17 +8676,12 @@ class CameraCharacteristics extends PigeonInternalProxyApiBaseClass { [pigeonVar_instanceIdentifier], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); return pigeonVar_instance; } @@ -9853,17 +8707,12 @@ class CameraCharacteristics extends PigeonInternalProxyApiBaseClass { [pigeonVar_instanceIdentifier], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); return pigeonVar_instance; } @@ -9890,17 +8739,12 @@ class CameraCharacteristics extends PigeonInternalProxyApiBaseClass { [pigeonVar_instanceIdentifier], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); return pigeonVar_instance; } @@ -9958,17 +8802,12 @@ class Camera2CameraInfo extends PigeonInternalProxyApiBaseClass { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -10008,16 +8847,8 @@ class Camera2CameraInfo extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Camera2CameraInfo.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.Camera2CameraInfo.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -10026,7 +8857,7 @@ class Camera2CameraInfo extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -10057,22 +8888,13 @@ class Camera2CameraInfo extends PigeonInternalProxyApiBaseClass { [this], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as String?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as String; } /// Gets a camera characteristic value. @@ -10091,17 +8913,13 @@ class Camera2CameraInfo extends PigeonInternalProxyApiBaseClass { [this, key], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return pigeonVar_replyList[0]; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); + return pigeonVar_replyValue; } @override @@ -10153,16 +8971,8 @@ class MeteringPointFactory extends PigeonInternalProxyApiBaseClass { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.MeteringPointFactory.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.MeteringPointFactory.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -10171,7 +8981,7 @@ class MeteringPointFactory extends PigeonInternalProxyApiBaseClass { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { @@ -10202,22 +9012,13 @@ class MeteringPointFactory extends PigeonInternalProxyApiBaseClass { [this, x, y], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as MeteringPoint?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as MeteringPoint; } /// Creates a MeteringPoint by x, y, size. @@ -10240,22 +9041,13 @@ class MeteringPointFactory extends PigeonInternalProxyApiBaseClass { [this, x, y, size], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as MeteringPoint?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as MeteringPoint; } @override @@ -10327,17 +9119,12 @@ class DisplayOrientedMeteringPointFactory extends MeteringPointFactory { ); () async { final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); }(); } @@ -10376,16 +9163,8 @@ class DisplayOrientedMeteringPointFactory extends MeteringPointFactory { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.DisplayOrientedMeteringPointFactory.pigeon_newInstance was null.', - ); - final List args = (message as List?)!; - final int? arg_pigeon_instanceIdentifier = (args[0] as int?); - assert( - arg_pigeon_instanceIdentifier != null, - 'Argument for dev.flutter.pigeon.camera_android_camerax.DisplayOrientedMeteringPointFactory.pigeon_newInstance was null, expected non-null int.', - ); + final List args = message! as List; + final int arg_pigeon_instanceIdentifier = args[0]! as int; try { (pigeon_instanceManager ?? PigeonInstanceManager.instance) .addHostCreatedInstance( @@ -10394,7 +9173,7 @@ class DisplayOrientedMeteringPointFactory extends MeteringPointFactory { pigeon_binaryMessenger: pigeon_binaryMessenger, pigeon_instanceManager: pigeon_instanceManager, ), - arg_pigeon_instanceIdentifier!, + arg_pigeon_instanceIdentifier, ); return wrapResponse(empty: true); } on PlatformException catch (e) { diff --git a/packages/camera/camera_android_camerax/pubspec.yaml b/packages/camera/camera_android_camerax/pubspec.yaml index a1d93d1210dd..ef3d2f9c86fa 100644 --- a/packages/camera/camera_android_camerax/pubspec.yaml +++ b/packages/camera/camera_android_camerax/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_android_camerax description: Android implementation of the camera plugin using the CameraX library. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_android_camerax issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.7.2 +version: 0.8.0 environment: sdk: ^3.10.0 @@ -35,3 +35,7 @@ dev_dependencies: topics: - camera +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + camera_platform_interface: {path: ../../../packages/camera/camera_platform_interface} diff --git a/packages/camera/camera_android_camerax/test/android_camera_camerax_test.dart b/packages/camera/camera_android_camerax/test/android_camera_camerax_test.dart index 71ed3d58ccde..db29dd6f2dbc 100644 --- a/packages/camera/camera_android_camerax/test/android_camera_camerax_test.dart +++ b/packages/camera/camera_android_camerax/test/android_camera_camerax_test.dart @@ -2887,6 +2887,94 @@ void main() { }, ); + test( + 'startVideoCapturing uses the provided videoOutputPath if available', + () async { + // Set up mocks and constants. + final camera = AndroidCameraCameraX(); + final mockPendingRecording = MockPendingRecording(); + final mockRecording = MockRecording(); + final mockCamera = MockCamera(); + final mockCameraInfo = MockCameraInfo(); + final mockCamera2CameraInfo = MockCamera2CameraInfo(); + const videoOutputPath = '/test/custom/path.mp4'; + + // Set directly for test versus calling createCamera. + camera.processCameraProvider = MockProcessCameraProvider(); + camera.recorder = MockRecorder(); + camera.videoCapture = MockVideoCapture(); + camera.cameraSelector = MockCameraSelector(); + camera.cameraInfo = MockCameraInfo(); + camera.imageAnalysis = MockImageAnalysis(); + camera.enableRecordingAudio = false; + + // Ignore setting target rotation for this test; tested separately. + camera.captureOrientationLocked = true; + + // Tell plugin to create detached Observer when camera info updated. + GenericsPigeonOverrides.observerNew = + ({required void Function(Observer, T) onChanged}) { + return Observer.detached(onChanged: onChanged); + }; + + PigeonOverrides.camera2CameraInfo_from = + ({required dynamic cameraInfo}) => mockCamera2CameraInfo; + PigeonOverrides.videoRecordEventListener_new = + ({ + required void Function(VideoRecordEventListener, VideoRecordEvent) + onEvent, + }) { + return VideoRecordEventListener.pigeon_detached(onEvent: onEvent); + }; + PigeonOverrides.cameraCharacteristics_infoSupportedHardwareLevel = + MockCameraCharacteristicsKey(); + + // Mock method calls. + when( + camera.recorder!.prepareRecording(videoOutputPath), + ).thenAnswer((_) async => mockPendingRecording); + when( + mockPendingRecording.withAudioEnabled(any), + ).thenAnswer((_) async => mockPendingRecording); + when( + mockPendingRecording.asPersistentRecording(), + ).thenAnswer((_) async => mockPendingRecording); + when( + mockPendingRecording.start(any), + ).thenAnswer((_) async => mockRecording); + when( + camera.processCameraProvider!.isBound(camera.videoCapture!), + ).thenAnswer((_) async => false); + when( + camera.processCameraProvider!.bindToLifecycle( + camera.cameraSelector!, + [camera.videoCapture!], + ), + ).thenAnswer((_) async => mockCamera); + when( + mockCamera.getCameraInfo(), + ).thenAnswer((_) => Future.value(mockCameraInfo)); + when( + mockCameraInfo.getCameraState(), + ).thenAnswer((_) async => MockLiveCameraState()); + when( + mockCamera2CameraInfo.getCameraCharacteristic(any), + ).thenAnswer((_) async => InfoSupportedHardwareLevel.limited); + + // Simulate video recording being started so startVideoRecording completes. + AndroidCameraCameraX.videoRecordingEventStreamController.add( + VideoRecordEventStart.pigeon_detached(), + ); + + await camera.startVideoCapturing( + const VideoCaptureOptions(1, videoOutputPath: videoOutputPath), + ); + + verify(camera.recorder!.prepareRecording(videoOutputPath)).called(1); + expect(camera.videoOutputPath, videoOutputPath); + }, + ); + test( 'startVideoCapturing called with stream options starts image streaming', () async { diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index f4f30dd13301..4ba31e99b074 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 0.11.0 +* Adds support for custom video output path in video recording. * Updates minimum supported SDK version to Flutter 3.38/Dart 3.10. ## 0.10.1 diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift index 34a306b511d7..cc51c2494269 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraPluginDelegatingMethodTests.swift @@ -295,13 +295,13 @@ final class CameraPluginDelegatingMethodTests: XCTestCase { let expectation = expectation(description: "Call completed") var startVideoRecordingCalled = false - mockCamera.startVideoRecordingStub = { completion, messenger in + mockCamera.startVideoRecordingStub = { path, completion, messenger in XCTAssertNotNil(messenger) completion(.success(())) startVideoRecordingCalled = true } - cameraPlugin.startVideoRecording(enableStream: true) { result in + cameraPlugin.startVideoRecording(enableStream: true, videoOutputPath: nil) { result in let _ = self.assertSuccess(result) expectation.fulfill() } @@ -316,13 +316,13 @@ final class CameraPluginDelegatingMethodTests: XCTestCase { let expectation = expectation(description: "Call completed") var startVideoRecordingCalled = false - mockCamera.startVideoRecordingStub = { completion, messenger in + mockCamera.startVideoRecordingStub = { path, completion, messenger in XCTAssertNil(messenger) completion(.success(())) startVideoRecordingCalled = true } - cameraPlugin.startVideoRecording(enableStream: false) { result in + cameraPlugin.startVideoRecording(enableStream: false, videoOutputPath: nil) { result in let _ = self.assertSuccess(result) expectation.fulfill() } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift index 0c9f45e5e50a..467f529cec6b 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/CameraSettingsTests.swift @@ -353,4 +353,104 @@ final class CameraSettingsTests: XCTestCase { "Camera should have ignored the lossy and square formats, safely falling back to 4K." ) } + + func test_startVideoRecording_usesCustomPath() { + let customPath = (NSTemporaryDirectory() as NSString).appendingPathComponent("path.mp4") + let configuration = CameraTestUtils.createTestCameraConfiguration() + + var capturedOutputURL: URL? + configuration.assetWriterFactory = { outputURL, _ in + capturedOutputURL = outputURL + return MockAssetWriter() + } + + let camera = CameraTestUtils.createTestCamera(configuration) + + let expectation = self.expectation(description: "startVideoRecording finished") + camera.startVideoRecording( + videoOutputPath: customPath, + completion: { _ in + expectation.fulfill() + }, messengerForStreaming: nil) + + waitForExpectations(timeout: 1) + + XCTAssertEqual(capturedOutputURL?.path, customPath) + } + + func test_startVideoRecording_errorsOnDirectoryPath() { + let directoryPath = "/" + let configuration = CameraTestUtils.createTestCameraConfiguration() + let camera = CameraTestUtils.createTestCamera(configuration) + + let expectation = self.expectation(description: "startVideoRecording finished") + camera.startVideoRecording( + videoOutputPath: directoryPath, + completion: { result in + switch result { + case .success: + XCTFail("Expected failure") + case .failure(let error): + if let pigeonError = error as? PigeonError { + XCTAssertEqual(pigeonError.code, "IOError") + } else { + XCTFail("Expected PigeonError") + } + } + expectation.fulfill() + }, messengerForStreaming: nil) + + waitForExpectations(timeout: 1) + } + + func test_startVideoRecording_errorsOnNonExistentParentPath() { + let nonExistentPath = "/non/existent/parent/file.mp4" + let configuration = CameraTestUtils.createTestCameraConfiguration() + let camera = CameraTestUtils.createTestCamera(configuration) + + let expectation = self.expectation(description: "startVideoRecording finished") + camera.startVideoRecording( + videoOutputPath: nonExistentPath, + completion: { result in + switch result { + case .success: + XCTFail("Expected failure") + case .failure(let error): + if let pigeonError = error as? PigeonError { + XCTAssertEqual(pigeonError.code, "IOError") + } else { + XCTFail("Expected PigeonError") + } + } + expectation.fulfill() + }, messengerForStreaming: nil) + + waitForExpectations(timeout: 1) + } + + func test_startVideoRecording_errorsOnInvalidExtension() { + let invalidExtensionPath = (NSTemporaryDirectory() as NSString).appendingPathComponent( + "file.txt") + let configuration = CameraTestUtils.createTestCameraConfiguration() + let camera = CameraTestUtils.createTestCamera(configuration) + + let expectation = self.expectation(description: "startVideoRecording finished") + camera.startVideoRecording( + videoOutputPath: invalidExtensionPath, + completion: { result in + switch result { + case .success: + XCTFail("Expected failure") + case .failure(let error): + if let pigeonError = error as? PigeonError { + XCTAssertEqual(pigeonError.code, "IOError") + } else { + XCTFail("Expected PigeonError") + } + } + expectation.fulfill() + }, messengerForStreaming: nil) + + waitForExpectations(timeout: 1) + } } diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCamera.swift b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCamera.swift index ec6e6fd88f9c..ec586933dfdb 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCamera.swift +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/Mocks/MockCamera.swift @@ -18,7 +18,7 @@ final class MockCamera: NSObject, Camera { var receivedImageStreamDataStub: (() -> Void)? var startStub: (() -> Void)? var startVideoRecordingStub: - ((@escaping (Result) -> Void, FlutterBinaryMessenger?) -> Void)? + ((String?, @escaping (Result) -> Void, FlutterBinaryMessenger?) -> Void)? var pauseVideoRecordingStub: (() -> Void)? var resumeVideoRecordingStub: (() -> Void)? var stopVideoRecordingStub: ((@escaping (Result) -> Void) -> Void)? @@ -110,10 +110,11 @@ final class MockCamera: NSObject, Camera { func stop() {} func startVideoRecording( + videoOutputPath: String?, completion: @escaping (Result) -> Void, messengerForStreaming messenger: FlutterBinaryMessenger? ) { - startVideoRecordingStub?(completion, messenger) + startVideoRecordingStub?(videoOutputPath, completion, messenger) } func pauseVideoRecording() { diff --git a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart index ed3a8e5a953d..7484bd17e082 100644 --- a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart +++ b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart @@ -342,9 +342,14 @@ class CameraController extends ValueNotifier { /// Throws a [CameraException] if the capture fails. Future startVideoRecording({ void Function(CameraImageData image)? streamCallback, + String? videoOutputPath, }) async { await CameraPlatform.instance.startVideoCapturing( - VideoCaptureOptions(_cameraId, streamCallback: streamCallback), + VideoCaptureOptions( + _cameraId, + streamCallback: streamCallback, + videoOutputPath: videoOutputPath, + ), ); value = value.copyWith( isRecordingVideo: true, diff --git a/packages/camera/camera_avfoundation/example/pubspec.yaml b/packages/camera/camera_avfoundation/example/pubspec.yaml index e7450716a9d5..be24e5c96235 100644 --- a/packages/camera/camera_avfoundation/example/pubspec.yaml +++ b/packages/camera/camera_avfoundation/example/pubspec.yaml @@ -29,3 +29,7 @@ dev_dependencies: flutter: uses-material-design: true +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + camera_platform_interface: {path: ../../../../packages/camera/camera_platform_interface} diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Camera.swift b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Camera.swift index 117fd909d32e..bf1a07a84689 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Camera.swift +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Camera.swift @@ -49,6 +49,7 @@ protocol Camera: FlutterTexture, AVCaptureVideoDataOutputSampleBufferDelegate, /// /// @param messenger Nullable messenger for capturing each frame. func startVideoRecording( + videoOutputPath: String?, completion: @escaping (Result) -> Void, messengerForStreaming: FlutterBinaryMessenger? ) @@ -130,3 +131,16 @@ protocol Camera: FlutterTexture, AVCaptureVideoDataOutputSampleBufferDelegate, func close() } + +extension Camera { + func startVideoRecording( + completion: @escaping (Result) -> Void, + messengerForStreaming messenger: FlutterBinaryMessenger? + ) { + self.startVideoRecording( + videoOutputPath: nil, + completion: completion, + messengerForStreaming: messenger + ) + } +} diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.swift b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.swift index 43ef5f48916c..4eef93e08377 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.swift +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.swift @@ -379,11 +379,13 @@ extension CameraPlugin: CameraApi { } func startVideoRecording( - enableStream: Bool, completion: @escaping (Result) -> Void + enableStream: Bool, videoOutputPath: String?, + completion: @escaping (Result) -> Void ) { captureSessionQueue.async { [weak self] in guard let strongSelf = self else { return } strongSelf.camera?.startVideoRecording( + videoOutputPath: videoOutputPath, completion: completion, messengerForStreaming: enableStream ? strongSelf.messenger : nil) } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/DefaultCamera.swift b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/DefaultCamera.swift index 16d1637d23fa..76de7d470459 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/DefaultCamera.swift +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/DefaultCamera.swift @@ -504,6 +504,7 @@ final class DefaultCamera: NSObject, Camera { } func startVideoRecording( + videoOutputPath: String?, completion: @escaping (Result) -> Void, messengerForStreaming messenger: FlutterBinaryMessenger? ) { @@ -519,27 +520,38 @@ final class DefaultCamera: NSObject, Camera { if let messenger = messenger { startImageStream(with: messenger) { [weak self] error in - self?.setUpVideoRecording(completion: completion) + self?.setUpVideoRecording(videoOutputPath: videoOutputPath, completion: completion) } return } - setUpVideoRecording(completion: completion) + setUpVideoRecording(videoOutputPath: videoOutputPath, completion: completion) } /// Main logic to setup the video recording. - private func setUpVideoRecording(completion: @escaping (Result) -> Void) { - let videoRecordingPath: String - do { - videoRecordingPath = try getTemporaryFilePath( - withExtension: "mp4", - subfolder: "videos", - prefix: "REC_") - self.videoRecordingPath = videoRecordingPath - } catch let error as NSError { - completion(.failure(DefaultCamera.pigeonErrorFromNSError(error))) - return + private func setUpVideoRecording( + videoOutputPath: String?, completion: @escaping (Result) -> Void + ) { + if let videoOutputPath = videoOutputPath { + do { + try validateOutputPath(videoOutputPath) + } catch { + completion(.failure(error)) + return + } + videoRecordingPath = videoOutputPath + } else { + do { + videoRecordingPath = try getTemporaryFilePath( + withExtension: "mp4", + subfolder: "videos", + prefix: "REC_") + } catch let error as NSError { + completion(.failure(DefaultCamera.pigeonErrorFromNSError(error))) + return + } } + self.videoRecordingPath = videoRecordingPath guard setupWriter(forPath: videoRecordingPath) else { completion( @@ -576,6 +588,34 @@ final class DefaultCamera: NSObject, Camera { completion(.success(())) } + private func validateOutputPath(_ path: String) throws { + var isDir: ObjCBool = false + if FileManager.default.fileExists(atPath: path, isDirectory: &isDir), isDir.boolValue { + throw PigeonError(code: "IOError", message: "Path is a directory: \(path)", details: nil) + } + let parentPath = (path as NSString).deletingLastPathComponent + if !parentPath.isEmpty && !FileManager.default.fileExists(atPath: parentPath) { + throw PigeonError( + code: "IOError", message: "Parent directory does not exist: \(parentPath)", details: nil) + } + + let lowerPath = path.lowercased() + let validExtensions = [".mp4"] + if !validExtensions.contains(where: { lowerPath.hasSuffix($0) }) { + throw PigeonError( + code: "IOError", + message: "Invalid video extension. Supported: \(validExtensions.joined(separator: ", "))", + details: nil) + } + + // AVAssetWriter will fail to initialize if a file already exists at the destination path. + // Delete any existing file to ensure consistent behavior with Android (which overwrites + // automatically) and prevent recording failures when reusing a custom path. + if FileManager.default.fileExists(atPath: path) { + try FileManager.default.removeItem(atPath: path) + } + } + private func setupWriter(forPath path: String) -> Bool { setUpCaptureSessionForAudioIfNeeded() diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Messages.swift b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Messages.swift index 47e6abbbe750..d900a6a63a31 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Messages.swift +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/Messages.swift @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v26.1.5), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon import Foundation @@ -53,7 +53,7 @@ private func wrapError(_ error: Any) -> [Any?] { } return [ "\(error)", - "\(type(of: error))", + "\(Swift.type(of: error))", "Stacktrace: \(Thread.callStackSymbols)", ] } @@ -73,6 +73,19 @@ private func nilOrValue(_ value: Any?) -> T? { return value as! T? } +private func doubleEqualsMessages(_ lhs: Double, _ rhs: Double) -> Bool { + return (lhs.isNaN && rhs.isNaN) || lhs == rhs +} + +private func doubleHashMessages(_ value: Double, _ hasher: inout Hasher) { + if value.isNaN { + hasher.combine(0x7FF8_0000_0000_0000) + } else { + // Normalize -0.0 to 0.0 + hasher.combine(value == 0 ? 0 : value) + } +} + func deepEqualsMessages(_ lhs: Any?, _ rhs: Any?) -> Bool { let cleanLhs = nilOrValue(lhs) as Any? let cleanRhs = nilOrValue(rhs) as Any? @@ -83,56 +96,90 @@ func deepEqualsMessages(_ lhs: Any?, _ rhs: Any?) -> Bool { case (nil, _), (_, nil): return false - case is (Void, Void): + case (let lhs as AnyObject, let rhs as AnyObject) where lhs === rhs: return true - case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable): - return cleanLhsHashable == cleanRhsHashable + case is (Void, Void): + return true - case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]): - guard cleanLhsArray.count == cleanRhsArray.count else { return false } - for (index, element) in cleanLhsArray.enumerated() { - if !deepEqualsMessages(element, cleanRhsArray[index]) { + case (let lhsArray, let rhsArray) as ([Any?], [Any?]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !deepEqualsMessages(element, rhsArray[index]) { return false } } return true - case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): - guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false } - for (key, cleanLhsValue) in cleanLhsDictionary { - guard cleanRhsDictionary.index(forKey: key) != nil else { return false } - if !deepEqualsMessages(cleanLhsValue, cleanRhsDictionary[key]!) { + case (let lhsArray, let rhsArray) as ([Double], [Double]): + guard lhsArray.count == rhsArray.count else { return false } + for (index, element) in lhsArray.enumerated() { + if !doubleEqualsMessages(element, rhsArray[index]) { return false } } return true + case (let lhsDictionary, let rhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): + guard lhsDictionary.count == rhsDictionary.count else { return false } + for (lhsKey, lhsValue) in lhsDictionary { + var found = false + for (rhsKey, rhsValue) in rhsDictionary { + if deepEqualsMessages(lhsKey, rhsKey) { + if deepEqualsMessages(lhsValue, rhsValue) { + found = true + break + } else { + return false + } + } + } + if !found { return false } + } + return true + + case (let lhs as Double, let rhs as Double): + return doubleEqualsMessages(lhs, rhs) + + case (let lhsHashable, let rhsHashable) as (AnyHashable, AnyHashable): + return lhsHashable == rhsHashable + default: - // Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue. return false } } func deepHashMessages(value: Any?, hasher: inout Hasher) { - if let valueList = value as? [AnyHashable] { - for item in valueList { deepHashMessages(value: item, hasher: &hasher) } - return - } - - if let valueDict = value as? [AnyHashable: AnyHashable] { - for key in valueDict.keys { - hasher.combine(key) - deepHashMessages(value: valueDict[key]!, hasher: &hasher) + let cleanValue = nilOrValue(value) as Any? + if let cleanValue = cleanValue { + if let doubleValue = cleanValue as? Double { + doubleHashMessages(doubleValue, &hasher) + } else if let valueList = cleanValue as? [Any?] { + for item in valueList { + deepHashMessages(value: item, hasher: &hasher) + } + } else if let valueList = cleanValue as? [Double] { + for item in valueList { + doubleHashMessages(item, &hasher) + } + } else if let valueDict = cleanValue as? [AnyHashable: Any?] { + var result = 0 + for (key, value) in valueDict { + var entryKeyHasher = Hasher() + deepHashMessages(value: key, hasher: &entryKeyHasher) + var entryValueHasher = Hasher() + deepHashMessages(value: value, hasher: &entryValueHasher) + result = result &+ ((entryKeyHasher.finalize() &* 31) ^ entryValueHasher.finalize()) + } + hasher.combine(result) + } else if let hashableValue = cleanValue as? AnyHashable { + hasher.combine(hashableValue) + } else { + hasher.combine(String(describing: cleanValue)) } - return + } else { + hasher.combine(0) } - - if let hashableValue = value as? AnyHashable { - hasher.combine(hashableValue.hashValue) - } - - return hasher.combine(String(describing: value)) } enum PlatformCameraLensDirection: Int { @@ -235,10 +282,19 @@ struct PlatformCameraDescription: Hashable { ] } static func == (lhs: PlatformCameraDescription, rhs: PlatformCameraDescription) -> Bool { - return deepEqualsMessages(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsMessages(lhs.name, rhs.name) + && deepEqualsMessages(lhs.lensDirection, rhs.lensDirection) + && deepEqualsMessages(lhs.lensType, rhs.lensType) } + func hash(into hasher: inout Hasher) { - deepHashMessages(value: toList(), hasher: &hasher) + hasher.combine("PlatformCameraDescription") + deepHashMessages(value: name, hasher: &hasher) + deepHashMessages(value: lensDirection, hasher: &hasher) + deepHashMessages(value: lensType, hasher: &hasher) } } @@ -281,10 +337,23 @@ struct PlatformCameraState: Hashable { ] } static func == (lhs: PlatformCameraState, rhs: PlatformCameraState) -> Bool { - return deepEqualsMessages(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsMessages(lhs.previewSize, rhs.previewSize) + && deepEqualsMessages(lhs.exposureMode, rhs.exposureMode) + && deepEqualsMessages(lhs.focusMode, rhs.focusMode) + && deepEqualsMessages(lhs.exposurePointSupported, rhs.exposurePointSupported) + && deepEqualsMessages(lhs.focusPointSupported, rhs.focusPointSupported) } + func hash(into hasher: inout Hasher) { - deepHashMessages(value: toList(), hasher: &hasher) + hasher.combine("PlatformCameraState") + deepHashMessages(value: previewSize, hasher: &hasher) + deepHashMessages(value: exposureMode, hasher: &hasher) + deepHashMessages(value: focusMode, hasher: &hasher) + deepHashMessages(value: exposurePointSupported, hasher: &hasher) + deepHashMessages(value: focusPointSupported, hasher: &hasher) } } @@ -331,10 +400,26 @@ struct PlatformCameraImageData: Hashable { ] } static func == (lhs: PlatformCameraImageData, rhs: PlatformCameraImageData) -> Bool { - return deepEqualsMessages(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsMessages(lhs.formatCode, rhs.formatCode) + && deepEqualsMessages(lhs.width, rhs.width) && deepEqualsMessages(lhs.height, rhs.height) + && deepEqualsMessages(lhs.planes, rhs.planes) + && deepEqualsMessages(lhs.lensAperture, rhs.lensAperture) + && deepEqualsMessages(lhs.sensorExposureTimeNanoseconds, rhs.sensorExposureTimeNanoseconds) + && deepEqualsMessages(lhs.sensorSensitivity, rhs.sensorSensitivity) } + func hash(into hasher: inout Hasher) { - deepHashMessages(value: toList(), hasher: &hasher) + hasher.combine("PlatformCameraImageData") + deepHashMessages(value: formatCode, hasher: &hasher) + deepHashMessages(value: width, hasher: &hasher) + deepHashMessages(value: height, hasher: &hasher) + deepHashMessages(value: planes, hasher: &hasher) + deepHashMessages(value: lensAperture, hasher: &hasher) + deepHashMessages(value: sensorExposureTimeNanoseconds, hasher: &hasher) + deepHashMessages(value: sensorSensitivity, hasher: &hasher) } } @@ -368,10 +453,20 @@ struct PlatformCameraImagePlane: Hashable { ] } static func == (lhs: PlatformCameraImagePlane, rhs: PlatformCameraImagePlane) -> Bool { - return deepEqualsMessages(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsMessages(lhs.bytes, rhs.bytes) + && deepEqualsMessages(lhs.bytesPerRow, rhs.bytesPerRow) + && deepEqualsMessages(lhs.width, rhs.width) && deepEqualsMessages(lhs.height, rhs.height) } + func hash(into hasher: inout Hasher) { - deepHashMessages(value: toList(), hasher: &hasher) + hasher.combine("PlatformCameraImagePlane") + deepHashMessages(value: bytes, hasher: &hasher) + deepHashMessages(value: bytesPerRow, hasher: &hasher) + deepHashMessages(value: width, hasher: &hasher) + deepHashMessages(value: height, hasher: &hasher) } } @@ -409,10 +504,23 @@ struct PlatformMediaSettings: Hashable { ] } static func == (lhs: PlatformMediaSettings, rhs: PlatformMediaSettings) -> Bool { - return deepEqualsMessages(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsMessages(lhs.resolutionPreset, rhs.resolutionPreset) + && deepEqualsMessages(lhs.framesPerSecond, rhs.framesPerSecond) + && deepEqualsMessages(lhs.videoBitrate, rhs.videoBitrate) + && deepEqualsMessages(lhs.audioBitrate, rhs.audioBitrate) + && deepEqualsMessages(lhs.enableAudio, rhs.enableAudio) } + func hash(into hasher: inout Hasher) { - deepHashMessages(value: toList(), hasher: &hasher) + hasher.combine("PlatformMediaSettings") + deepHashMessages(value: resolutionPreset, hasher: &hasher) + deepHashMessages(value: framesPerSecond, hasher: &hasher) + deepHashMessages(value: videoBitrate, hasher: &hasher) + deepHashMessages(value: audioBitrate, hasher: &hasher) + deepHashMessages(value: enableAudio, hasher: &hasher) } } @@ -438,10 +546,16 @@ struct PlatformPoint: Hashable { ] } static func == (lhs: PlatformPoint, rhs: PlatformPoint) -> Bool { - return deepEqualsMessages(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsMessages(lhs.x, rhs.x) && deepEqualsMessages(lhs.y, rhs.y) } + func hash(into hasher: inout Hasher) { - deepHashMessages(value: toList(), hasher: &hasher) + hasher.combine("PlatformPoint") + deepHashMessages(value: x, hasher: &hasher) + deepHashMessages(value: y, hasher: &hasher) } } @@ -467,10 +581,16 @@ struct PlatformSize: Hashable { ] } static func == (lhs: PlatformSize, rhs: PlatformSize) -> Bool { - return deepEqualsMessages(lhs.toList(), rhs.toList()) + if Swift.type(of: lhs) != Swift.type(of: rhs) { + return false + } + return deepEqualsMessages(lhs.width, rhs.width) && deepEqualsMessages(lhs.height, rhs.height) } + func hash(into hasher: inout Hasher) { - deepHashMessages(value: toList(), hasher: &hasher) + hasher.combine("PlatformSize") + deepHashMessages(value: width, hasher: &hasher) + deepHashMessages(value: height, hasher: &hasher) } } @@ -671,7 +791,9 @@ protocol CameraApi { func prepareForVideoRecording(completion: @escaping (Result) -> Void) /// Begins recording video, optionally enabling streaming to Dart at the same /// time. - func startVideoRecording(enableStream: Bool, completion: @escaping (Result) -> Void) + func startVideoRecording( + enableStream: Bool, videoOutputPath: String?, + completion: @escaping (Result) -> Void) /// Stops recording video, and results the path to the resulting file. func stopVideoRecording(completion: @escaping (Result) -> Void) /// Pauses video recording. @@ -960,7 +1082,9 @@ class CameraApiSetup { startVideoRecordingChannel.setMessageHandler { message, reply in let args = message as! [Any?] let enableStreamArg = args[0] as! Bool - api.startVideoRecording(enableStream: enableStreamArg) { result in + let videoOutputPathArg: String? = nilOrValue(args[1]) + api.startVideoRecording(enableStream: enableStreamArg, videoOutputPath: videoOutputPathArg) + { result in switch result { case .success: reply(wrapResult(nil)) diff --git a/packages/camera/camera_avfoundation/lib/src/avfoundation_camera.dart b/packages/camera/camera_avfoundation/lib/src/avfoundation_camera.dart index 3907ed89219b..7b694b8e351f 100644 --- a/packages/camera/camera_avfoundation/lib/src/avfoundation_camera.dart +++ b/packages/camera/camera_avfoundation/lib/src/avfoundation_camera.dart @@ -206,15 +206,21 @@ class AVFoundationCamera extends CameraPlatform { Future startVideoRecording( int cameraId, { Duration? maxVideoDuration, + String? videoOutputPath, }) async { // Ignore maxVideoDuration, as it is unimplemented and deprecated. - return startVideoCapturing(VideoCaptureOptions(cameraId)); + return startVideoCapturing( + VideoCaptureOptions(cameraId, videoOutputPath: videoOutputPath), + ); } @override Future startVideoCapturing(VideoCaptureOptions options) async { // Max video duration is currently not supported. - await _hostApi.startVideoRecording(options.streamCallback != null); + await _hostApi.startVideoRecording( + options.streamCallback != null, + options.videoOutputPath, + ); if (options.streamCallback != null) { _frameStreamController = _createStreamController(); diff --git a/packages/camera/camera_avfoundation/lib/src/messages.g.dart b/packages/camera/camera_avfoundation/lib/src/messages.g.dart index 46c94d58f8a1..b2929886b864 100644 --- a/packages/camera/camera_avfoundation/lib/src/messages.g.dart +++ b/packages/camera/camera_avfoundation/lib/src/messages.g.dart @@ -1,21 +1,40 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v26.1.5), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon -// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, omit_obvious_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers +// ignore_for_file: unused_import, unused_shown_name +// ignore_for_file: type=lint import 'dart:async'; -import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; +import 'dart:typed_data' show Float64List, Int32List, Int64List; -import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; import 'package:flutter/services.dart'; +import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; -PlatformException _createConnectionError(String channelName) { - return PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel: "$channelName".', - ); +Object? _extractReplyValueOrThrow( + List? replyList, + String channelName, { + required bool isNullValid, +}) { + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (!isNullValid && (replyList.isNotEmpty && replyList[0] == null)) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } + return replyList.firstOrNull; } List wrapResponse({ @@ -33,6 +52,15 @@ List wrapResponse({ } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == b; + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -40,16 +68,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + enum PlatformCameraLensDirection { /// Front facing camera (a user looking at the screen is seen by the camera). front, @@ -145,12 +209,14 @@ class PlatformCameraDescription { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(name, other.name) && + _deepEquals(lensDirection, other.lensDirection) && + _deepEquals(lensType, other.lensType); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class PlatformCameraState { @@ -211,12 +277,16 @@ class PlatformCameraState { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(previewSize, other.previewSize) && + _deepEquals(exposureMode, other.exposureMode) && + _deepEquals(focusMode, other.focusMode) && + _deepEquals(exposurePointSupported, other.exposurePointSupported) && + _deepEquals(focusPointSupported, other.focusPointSupported); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class PlatformCameraImageData { @@ -267,7 +337,7 @@ class PlatformCameraImageData { formatCode: result[0]! as int, width: result[1]! as int, height: result[2]! as int, - planes: (result[3] as List?)!.cast(), + planes: (result[3]! as List).cast(), lensAperture: result[4]! as double, sensorExposureTimeNanoseconds: result[5]! as int, sensorSensitivity: result[6]! as double, @@ -283,12 +353,21 @@ class PlatformCameraImageData { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(formatCode, other.formatCode) && + _deepEquals(width, other.width) && + _deepEquals(height, other.height) && + _deepEquals(planes, other.planes) && + _deepEquals(lensAperture, other.lensAperture) && + _deepEquals( + sensorExposureTimeNanoseconds, + other.sensorExposureTimeNanoseconds, + ) && + _deepEquals(sensorSensitivity, other.sensorSensitivity); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class PlatformCameraImagePlane { @@ -335,12 +414,15 @@ class PlatformCameraImagePlane { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(bytes, other.bytes) && + _deepEquals(bytesPerRow, other.bytesPerRow) && + _deepEquals(width, other.width) && + _deepEquals(height, other.height); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class PlatformMediaSettings { @@ -396,12 +478,16 @@ class PlatformMediaSettings { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(resolutionPreset, other.resolutionPreset) && + _deepEquals(framesPerSecond, other.framesPerSecond) && + _deepEquals(videoBitrate, other.videoBitrate) && + _deepEquals(audioBitrate, other.audioBitrate) && + _deepEquals(enableAudio, other.enableAudio); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class PlatformPoint { @@ -433,12 +519,12 @@ class PlatformPoint { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(x, other.x) && _deepEquals(y, other.y); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class PlatformSize { @@ -473,12 +559,12 @@ class PlatformSize { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(width, other.width) && _deepEquals(height, other.height); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { @@ -631,23 +717,14 @@ class CameraApi { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as List?)! - .cast(); - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return (pigeonVar_replyValue! as List) + .cast(); } /// Create a new camera with the given settings, and returns its ID. @@ -663,22 +740,13 @@ class CameraApi { [cameraName, settings], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as int?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as int; } /// Initializes the camera with the given ID. @@ -697,17 +765,12 @@ class CameraApi { [cameraId, imageFormat], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Begins streaming frames from the camera. @@ -721,17 +784,12 @@ class CameraApi { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Stops streaming frames from the camera. @@ -745,17 +803,12 @@ class CameraApi { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Called by the Dart side of the plugin when it has received the last image @@ -772,17 +825,12 @@ class CameraApi { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Indicates that the given camera is no longer being used on the Dart side, @@ -799,17 +847,12 @@ class CameraApi { [cameraId], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Locks the camera capture to the current device orientation. @@ -827,17 +870,12 @@ class CameraApi { [orientation], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Unlocks camera capture orientation, allowing it to automatically adapt to @@ -852,17 +890,12 @@ class CameraApi { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Takes a picture with the current settings, and returns the path to the @@ -877,22 +910,13 @@ class CameraApi { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as String?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as String; } /// Does any preprocessing necessary before beginning to record video. @@ -906,22 +930,20 @@ class CameraApi { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Begins recording video, optionally enabling streaming to Dart at the same /// time. - Future startVideoRecording(bool enableStream) async { + Future startVideoRecording( + bool enableStream, + String? videoOutputPath, + ) async { final pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.startVideoRecording$pigeonVar_messageChannelSuffix'; final pigeonVar_channel = BasicMessageChannel( @@ -930,20 +952,15 @@ class CameraApi { binaryMessenger: pigeonVar_binaryMessenger, ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [enableStream], + [enableStream, videoOutputPath], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Stops recording video, and results the path to the resulting file. @@ -957,22 +974,13 @@ class CameraApi { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as String?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as String; } /// Pauses video recording. @@ -986,17 +994,12 @@ class CameraApi { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Resumes a previously paused video recording. @@ -1010,17 +1013,12 @@ class CameraApi { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Switches the camera to the given flash mode. @@ -1036,17 +1034,12 @@ class CameraApi { [mode], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Switches the camera to the given exposure mode. @@ -1062,17 +1055,12 @@ class CameraApi { [mode], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Anchors auto-exposure to the given point in (0,1) coordinate space. @@ -1090,17 +1078,12 @@ class CameraApi { [point], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Returns the minimum exposure offset supported by the camera. @@ -1114,22 +1097,13 @@ class CameraApi { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as double?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as double; } /// Returns the maximum exposure offset supported by the camera. @@ -1143,22 +1117,13 @@ class CameraApi { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as double?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as double; } /// Sets the exposure offset manually to the given value. @@ -1174,17 +1139,12 @@ class CameraApi { [offset], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Switches the camera to the given focus mode. @@ -1200,17 +1160,12 @@ class CameraApi { [mode], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Anchors auto-focus to the given point in (0,1) coordinate space. @@ -1228,17 +1183,12 @@ class CameraApi { [point], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Returns the minimum zoom level supported by the camera. @@ -1252,22 +1202,13 @@ class CameraApi { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as double?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as double; } /// Returns the maximum zoom level supported by the camera. @@ -1281,22 +1222,13 @@ class CameraApi { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as double?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as double; } /// Sets the zoom factor. @@ -1312,17 +1244,12 @@ class CameraApi { [zoom], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Sets the video stabilization mode. @@ -1340,17 +1267,12 @@ class CameraApi { [mode], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Gets if the given video stabilization mode is supported. @@ -1368,22 +1290,13 @@ class CameraApi { [mode], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as bool?)!; - } + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as bool; } /// Pauses streaming of preview frames. @@ -1397,17 +1310,12 @@ class CameraApi { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Resumes a previously paused preview stream. @@ -1421,17 +1329,12 @@ class CameraApi { ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Changes the camera used while recording video. @@ -1449,17 +1352,12 @@ class CameraApi { [cameraName], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Sets the file format used for taking pictures. @@ -1475,17 +1373,12 @@ class CameraApi { [format], ); final pigeonVar_replyList = await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } } @@ -1527,19 +1420,11 @@ abstract class CameraGlobalEventApi { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_avfoundation.CameraGlobalEventApi.deviceOrientationChanged was null.', - ); - final List args = (message as List?)!; - final PlatformDeviceOrientation? arg_orientation = - (args[0] as PlatformDeviceOrientation?); - assert( - arg_orientation != null, - 'Argument for dev.flutter.pigeon.camera_avfoundation.CameraGlobalEventApi.deviceOrientationChanged was null, expected non-null PlatformDeviceOrientation.', - ); + final List args = message! as List; + final PlatformDeviceOrientation arg_orientation = + args[0]! as PlatformDeviceOrientation; try { - api.deviceOrientationChanged(arg_orientation!); + api.deviceOrientationChanged(arg_orientation); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); @@ -1587,19 +1472,11 @@ abstract class CameraEventApi { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_avfoundation.CameraEventApi.initialized was null.', - ); - final List args = (message as List?)!; - final PlatformCameraState? arg_initialState = - (args[0] as PlatformCameraState?); - assert( - arg_initialState != null, - 'Argument for dev.flutter.pigeon.camera_avfoundation.CameraEventApi.initialized was null, expected non-null PlatformCameraState.', - ); + final List args = message! as List; + final PlatformCameraState arg_initialState = + args[0]! as PlatformCameraState; try { - api.initialized(arg_initialState!); + api.initialized(arg_initialState); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); @@ -1621,18 +1498,10 @@ abstract class CameraEventApi { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_avfoundation.CameraEventApi.error was null.', - ); - final List args = (message as List?)!; - final String? arg_message = (args[0] as String?); - assert( - arg_message != null, - 'Argument for dev.flutter.pigeon.camera_avfoundation.CameraEventApi.error was null, expected non-null String.', - ); + final List args = message! as List; + final String arg_message = args[0]! as String; try { - api.error(arg_message!); + api.error(arg_message); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); diff --git a/packages/camera/camera_avfoundation/pigeons/messages.dart b/packages/camera/camera_avfoundation/pigeons/messages.dart index b4976758cf47..3ffa4d2e1bdd 100644 --- a/packages/camera/camera_avfoundation/pigeons/messages.dart +++ b/packages/camera/camera_avfoundation/pigeons/messages.dart @@ -247,8 +247,8 @@ abstract class CameraApi { /// Begins recording video, optionally enabling streaming to Dart at the same /// time. @async - @ObjCSelector('startVideoRecordingWithStreaming:') - void startVideoRecording(bool enableStream); + @ObjCSelector('startVideoRecordingWithStreaming:videoOutputPath:') + void startVideoRecording(bool enableStream, String? videoOutputPath); /// Stops recording video, and results the path to the resulting file. @async diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index f5065fb411b9..30a98f20df23 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.10.1 +version: 0.11.0 environment: sdk: ^3.10.0 @@ -33,3 +33,7 @@ dev_dependencies: topics: - camera +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + camera_platform_interface: {path: ../../../packages/camera/camera_platform_interface} diff --git a/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart b/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart index 53d7965c6bac..d18af8dc4541 100644 --- a/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart +++ b/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart @@ -470,7 +470,7 @@ void main() { test('Should start recording a video', () async { await camera.startVideoRecording(cameraId); - verify(mockApi.startVideoRecording(any)); + verify(mockApi.startVideoRecording(any, any)); }); test( @@ -483,7 +483,7 @@ void main() { ), ); - verify(mockApi.startVideoRecording(true)); + verify(mockApi.startVideoRecording(true, any)); }, ); diff --git a/packages/camera/camera_avfoundation/test/avfoundation_camera_test.mocks.dart b/packages/camera/camera_avfoundation/test/avfoundation_camera_test.mocks.dart index 225eac9931c6..27ce5dfcc3fa 100644 --- a/packages/camera/camera_avfoundation/test/avfoundation_camera_test.mocks.dart +++ b/packages/camera/camera_avfoundation/test/avfoundation_camera_test.mocks.dart @@ -22,6 +22,7 @@ import 'package:mockito/src/dummies.dart' as _i3; // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member /// A class which mocks [CameraApi]. /// @@ -159,9 +160,15 @@ class MockCameraApi extends _i1.Mock implements _i2.CameraApi { as _i4.Future); @override - _i4.Future startVideoRecording(bool? enableStream) => + _i4.Future startVideoRecording( + bool? enableStream, + String? videoOutputPath, + ) => (super.noSuchMethod( - Invocation.method(#startVideoRecording, [enableStream]), + Invocation.method(#startVideoRecording, [ + enableStream, + videoOutputPath, + ]), returnValue: _i4.Future.value(), returnValueForMissingStub: _i4.Future.value(), ) diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index 889501a04383..1f12cae21711 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 2.14.0 +* Adds `videoOutputPath` support to `MethodChannelCamera.startVideoRecording`. * Updates minimum supported SDK version to Flutter 3.38/Dart 3.10. ## 2.13.0 diff --git a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart index 97c4107668f5..6ff7ed05ed4a 100644 --- a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart +++ b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart @@ -254,9 +254,14 @@ class MethodChannelCamera extends CameraPlatform { Future startVideoRecording( int cameraId, { Duration? maxVideoDuration, + String? videoOutputPath, }) async { return startVideoCapturing( - VideoCaptureOptions(cameraId, maxDuration: maxVideoDuration), + VideoCaptureOptions( + cameraId, + maxDuration: maxVideoDuration, + videoOutputPath: videoOutputPath, + ), ); } @@ -266,6 +271,7 @@ class MethodChannelCamera extends CameraPlatform { 'cameraId': options.cameraId, 'maxVideoDuration': options.maxDuration?.inMilliseconds, 'enableStream': options.streamCallback != null, + 'videoOutputPath': options.videoOutputPath, }); if (options.streamCallback != null) { diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart index 192bce8b0134..e1548f378af8 100644 --- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -150,6 +150,7 @@ abstract class CameraPlatform extends PlatformInterface { 'This parameter is unused, and will be ignored on all platforms', ) Duration? maxVideoDuration, + String? videoOutputPath, }) { throw UnimplementedError('startVideoRecording() is not implemented.'); } @@ -159,7 +160,10 @@ abstract class CameraPlatform extends PlatformInterface { /// Please see [VideoCaptureOptions] for documentation on the /// configuration options. Future startVideoCapturing(VideoCaptureOptions options) { - return startVideoRecording(options.cameraId); + return startVideoRecording( + options.cameraId, + videoOutputPath: options.videoOutputPath, + ); } /// Stops the video recording and returns the file where it was saved. diff --git a/packages/camera/camera_platform_interface/lib/src/types/video_capture_options.dart b/packages/camera/camera_platform_interface/lib/src/types/video_capture_options.dart index dda06fb4ce84..af1a8fd73887 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/video_capture_options.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/video_capture_options.dart @@ -19,6 +19,7 @@ class VideoCaptureOptions { this.streamCallback, this.streamOptions, this.enablePersistentRecording = true, + this.videoOutputPath, }) : assert( streamOptions == null || streamCallback != null, 'Must specify streamCallback if providing streamOptions.', @@ -55,6 +56,11 @@ class VideoCaptureOptions { /// Defaults to `true`. final bool enablePersistentRecording; + /// The path where the video should be saved. + /// + /// If null, the platform will generate a temporary path. + final String? videoOutputPath; + @override bool operator ==(Object other) => identical(this, other) || @@ -64,7 +70,8 @@ class VideoCaptureOptions { maxDuration == other.maxDuration && streamCallback == other.streamCallback && streamOptions == other.streamOptions && - enablePersistentRecording == other.enablePersistentRecording; + enablePersistentRecording == other.enablePersistentRecording && + videoOutputPath == other.videoOutputPath; @override int get hashCode => Object.hash( @@ -73,5 +80,6 @@ class VideoCaptureOptions { streamCallback, streamOptions, enablePersistentRecording, + videoOutputPath, ); } diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index 804bead11e33..6102c20a7fd4 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -4,7 +4,7 @@ repository: https://github.com/flutter/packages/tree/main/packages/camera/camera issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 2.13.0 +version: 2.14.0 environment: sdk: ^3.10.0 diff --git a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart index a52d725cf442..9a2797d6368f 100644 --- a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart +++ b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart @@ -683,6 +683,7 @@ void main() { 'cameraId': cameraId, 'maxVideoDuration': null, 'enableStream': false, + 'videoOutputPath': null, }, ), ]); diff --git a/packages/camera/camera_web/example/pubspec.yaml b/packages/camera/camera_web/example/pubspec.yaml index 260fbc719408..ef786ec3cb1f 100644 --- a/packages/camera/camera_web/example/pubspec.yaml +++ b/packages/camera/camera_web/example/pubspec.yaml @@ -2,8 +2,8 @@ name: camera_web_integration_tests publish_to: none environment: - sdk: ^3.10.0 - flutter: ">=3.38.0" + sdk: ^3.9.0 + flutter: ">=3.35.0" dependencies: camera_platform_interface: ^2.6.0 diff --git a/packages/camera/camera_web/lib/src/camera_web.dart b/packages/camera/camera_web/lib/src/camera_web.dart index 90033681d28a..e48b8f75d69d 100644 --- a/packages/camera/camera_web/lib/src/camera_web.dart +++ b/packages/camera/camera_web/lib/src/camera_web.dart @@ -461,7 +461,11 @@ class CameraPlugin extends CameraPlatform { } @override - Future startVideoRecording(int cameraId, {Duration? maxVideoDuration}) { + Future startVideoRecording( + int cameraId, { + Duration? maxVideoDuration, + String? videoOutputPath, + }) { // Ignore maxVideoDuration, as it is deprecated. return startVideoCapturing(VideoCaptureOptions(cameraId)); } diff --git a/packages/camera/camera_web/pubspec.yaml b/packages/camera/camera_web/pubspec.yaml index bba4fae6d144..4b3603756387 100644 --- a/packages/camera/camera_web/pubspec.yaml +++ b/packages/camera/camera_web/pubspec.yaml @@ -5,8 +5,8 @@ issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+ version: 0.3.5+3 environment: - sdk: ^3.10.0 - flutter: ">=3.38.0" + sdk: ^3.9.0 + flutter: ">=3.35.0" flutter: plugin: diff --git a/packages/camera/camera_windows/CHANGELOG.md b/packages/camera/camera_windows/CHANGELOG.md index 57f56ceaf788..87e0bc5f664b 100644 --- a/packages/camera/camera_windows/CHANGELOG.md +++ b/packages/camera/camera_windows/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 0.3.0 +* Adds support for custom video output path in video recording. * Updates minimum supported SDK version to Flutter 3.38/Dart 3.10. ## 0.2.6+4 diff --git a/packages/camera/camera_windows/example/pubspec.yaml b/packages/camera/camera_windows/example/pubspec.yaml index 211cfd402b0a..d190556532bd 100644 --- a/packages/camera/camera_windows/example/pubspec.yaml +++ b/packages/camera/camera_windows/example/pubspec.yaml @@ -27,3 +27,7 @@ dev_dependencies: flutter: uses-material-design: true +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + camera_platform_interface: {path: ../../../../packages/camera/camera_platform_interface} diff --git a/packages/camera/camera_windows/lib/camera_windows.dart b/packages/camera/camera_windows/lib/camera_windows.dart index 80005024b143..de3975842917 100644 --- a/packages/camera/camera_windows/lib/camera_windows.dart +++ b/packages/camera/camera_windows/lib/camera_windows.dart @@ -199,9 +199,12 @@ class CameraWindows extends CameraPlatform { Future startVideoRecording( int cameraId, { Duration? maxVideoDuration, + String? videoOutputPath, }) async { // Ignore maxVideoDuration, as it is unimplemented and deprecated. - return startVideoCapturing(VideoCaptureOptions(cameraId)); + return startVideoCapturing( + VideoCaptureOptions(cameraId, videoOutputPath: videoOutputPath), + ); } @override @@ -213,7 +216,10 @@ class CameraWindows extends CameraPlatform { } // Currently none of `options` is supported on Windows, so it's not passed. - await _hostApi.startVideoRecording(options.cameraId); + await _hostApi.startVideoRecording( + options.cameraId, + options.videoOutputPath, + ); } @override diff --git a/packages/camera/camera_windows/lib/src/messages.g.dart b/packages/camera/camera_windows/lib/src/messages.g.dart index 79407a5f97e2..031c23308d12 100644 --- a/packages/camera/camera_windows/lib/src/messages.g.dart +++ b/packages/camera/camera_windows/lib/src/messages.g.dart @@ -1,21 +1,40 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v26.1.0), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon -// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers +// ignore_for_file: unused_import, unused_shown_name +// ignore_for_file: type=lint import 'dart:async'; -import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; +import 'dart:typed_data' show Float64List, Int32List, Int64List; -import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; import 'package:flutter/services.dart'; +import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; -PlatformException _createConnectionError(String channelName) { - return PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel: "$channelName".', - ); +Object? _extractReplyValueOrThrow( + List? replyList, + String channelName, { + required bool isNullValid, +}) { + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (!isNullValid && (replyList.isNotEmpty && replyList[0] == null)) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } + return replyList.firstOrNull; } List wrapResponse({ @@ -33,6 +52,15 @@ List wrapResponse({ } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == b; + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -40,16 +68,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + /// Pigeon version of platform interface's ResolutionPreset. enum PlatformResolutionPreset { low, medium, high, veryHigh, ultraHigh, max } @@ -107,12 +171,16 @@ class PlatformMediaSettings { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(resolutionPreset, other.resolutionPreset) && + _deepEquals(framesPerSecond, other.framesPerSecond) && + _deepEquals(videoBitrate, other.videoBitrate) && + _deepEquals(audioBitrate, other.audioBitrate) && + _deepEquals(enableAudio, other.enableAudio); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// A representation of a size from the native camera APIs. @@ -148,12 +216,12 @@ class PlatformSize { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(width, other.width) && _deepEquals(height, other.height); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { @@ -181,7 +249,7 @@ class _PigeonCodec extends StandardMessageCodec { Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { case 129: - final int? value = readValue(buffer) as int?; + final value = readValue(buffer) as int?; return value == null ? null : PlatformResolutionPreset.values[value]; case 130: return PlatformMediaSettings.decode(readValue(buffer)!); @@ -212,279 +280,199 @@ class CameraApi { /// Returns the names of all of the available capture devices. Future> getAvailableCameras() async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_windows.CameraApi.getAvailableCameras$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as List?)!.cast(); - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return (pigeonVar_replyValue! as List).cast(); } /// Creates a camera instance for the given device name and settings. Future create(String cameraName, PlatformMediaSettings settings) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_windows.CameraApi.create$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [cameraName, settings], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as int?)!; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as int; } /// Initializes a camera, and returns the size of its preview. Future initialize(int cameraId) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_windows.CameraApi.initialize$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [cameraId], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as PlatformSize?)!; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as PlatformSize; } /// Disposes a camera that is no longer in use. Future dispose(int cameraId) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_windows.CameraApi.dispose$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [cameraId], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Takes a picture with the given camera, and returns the path to the /// resulting file. Future takePicture(int cameraId) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_windows.CameraApi.takePicture$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [cameraId], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as String?)!; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as String; } /// Starts recording video with the given camera. - Future startVideoRecording(int cameraId) async { - final String pigeonVar_channelName = + Future startVideoRecording( + int cameraId, + String? videoOutputPath, + ) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_windows.CameraApi.startVideoRecording$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( - [cameraId], + [cameraId, videoOutputPath], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } } /// Finishes recording video with the given camera, and returns the path to /// the resulting file. Future stopVideoRecording(int cameraId) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_windows.CameraApi.stopVideoRecording$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [cameraId], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as String?)!; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ); + return pigeonVar_replyValue! as String; } /// Starts the preview stream for the given camera. Future pausePreview(int cameraId) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_windows.CameraApi.pausePreview$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [cameraId], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } /// Resumes the preview stream for the given camera. Future resumePreview(int cameraId) async { - final String pigeonVar_channelName = + final pigeonVar_channelName = 'dev.flutter.pigeon.camera_windows.CameraApi.resumePreview$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); final Future pigeonVar_sendFuture = pigeonVar_channel.send( [cameraId], ); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ); } } @@ -506,8 +494,7 @@ abstract class CameraEventApi { ? '.$messageChannelSuffix' : ''; { - final BasicMessageChannel - pigeonVar_channel = BasicMessageChannel( + final pigeonVar_channel = BasicMessageChannel( 'dev.flutter.pigeon.camera_windows.CameraEventApi.cameraClosing$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger, @@ -530,8 +517,7 @@ abstract class CameraEventApi { } } { - final BasicMessageChannel - pigeonVar_channel = BasicMessageChannel( + final pigeonVar_channel = BasicMessageChannel( 'dev.flutter.pigeon.camera_windows.CameraEventApi.error$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger, @@ -540,18 +526,10 @@ abstract class CameraEventApi { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for dev.flutter.pigeon.camera_windows.CameraEventApi.error was null.', - ); - final List args = (message as List?)!; - final String? arg_errorMessage = (args[0] as String?); - assert( - arg_errorMessage != null, - 'Argument for dev.flutter.pigeon.camera_windows.CameraEventApi.error was null, expected non-null String.', - ); + final List args = message! as List; + final String arg_errorMessage = args[0]! as String; try { - api.error(arg_errorMessage!); + api.error(arg_errorMessage); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); diff --git a/packages/camera/camera_windows/pigeons/messages.dart b/packages/camera/camera_windows/pigeons/messages.dart index eadc11c52bb2..e03cf11ef021 100644 --- a/packages/camera/camera_windows/pigeons/messages.dart +++ b/packages/camera/camera_windows/pigeons/messages.dart @@ -64,7 +64,7 @@ abstract class CameraApi { /// Starts recording video with the given camera. @async - void startVideoRecording(int cameraId); + void startVideoRecording(int cameraId, String? videoOutputPath); /// Finishes recording video with the given camera, and returns the path to /// the resulting file. diff --git a/packages/camera/camera_windows/pubspec.yaml b/packages/camera/camera_windows/pubspec.yaml index 2272addba57c..cf74655e5cf8 100644 --- a/packages/camera/camera_windows/pubspec.yaml +++ b/packages/camera/camera_windows/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_windows description: A Flutter plugin for getting information about and controlling the camera on Windows. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_windows issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.2.6+4 +version: 0.3.0 environment: sdk: ^3.10.0 @@ -34,3 +34,7 @@ dev_dependencies: topics: - camera +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + camera_platform_interface: {path: ../../../packages/camera/camera_platform_interface} diff --git a/packages/camera/camera_windows/test/camera_windows_test.dart b/packages/camera/camera_windows/test/camera_windows_test.dart index dcd35d3d3fa2..162e44c6a94a 100644 --- a/packages/camera/camera_windows/test/camera_windows_test.dart +++ b/packages/camera/camera_windows/test/camera_windows_test.dart @@ -380,7 +380,20 @@ void main() { await plugin.startVideoRecording(cameraId); // Assert - verify(mockApi.startVideoRecording(any)); + verify(mockApi.startVideoRecording(any, any)); + }); + + test('Should start recording a video with a custom path', () async { + // Arrange + const path = '/test/video.mp4'; + + // Act + await plugin.startVideoCapturing( + const VideoCaptureOptions(1, videoOutputPath: path), + ); + + // Assert + verify(mockApi.startVideoRecording(1, path)); }); test('capturing fails if trying to stream', () async { diff --git a/packages/camera/camera_windows/test/camera_windows_test.mocks.dart b/packages/camera/camera_windows/test/camera_windows_test.mocks.dart index c81dceca765f..98629e624074 100644 --- a/packages/camera/camera_windows/test/camera_windows_test.mocks.dart +++ b/packages/camera/camera_windows/test/camera_windows_test.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.4.4 from annotations +// Mocks generated by Mockito 5.4.6 from annotations // in camera_windows/test/camera_windows_test.dart. // Do not manually edit this file. @@ -17,10 +17,12 @@ import 'package:mockito/src/dummies.dart' as _i3; // ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable // ignore_for_file: prefer_const_constructors // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member class _FakePlatformSize_0 extends _i1.SmartFake implements _i2.PlatformSize { _FakePlatformSize_0(Object parent, Invocation parentInvocation) @@ -117,9 +119,15 @@ class MockCameraApi extends _i1.Mock implements _i2.CameraApi { as _i4.Future); @override - _i4.Future startVideoRecording(int? cameraId) => + _i4.Future startVideoRecording( + int? cameraId, + String? videoOutputPath, + ) => (super.noSuchMethod( - Invocation.method(#startVideoRecording, [cameraId]), + Invocation.method(#startVideoRecording, [ + cameraId, + videoOutputPath, + ]), returnValue: _i4.Future.value(), returnValueForMissingStub: _i4.Future.value(), ) @@ -144,24 +152,6 @@ class MockCameraApi extends _i1.Mock implements _i2.CameraApi { ) as _i4.Future); - @override - _i4.Future startImageStream(int? cameraId) => - (super.noSuchMethod( - Invocation.method(#startImageStream, [cameraId]), - returnValue: _i4.Future.value(), - returnValueForMissingStub: _i4.Future.value(), - ) - as _i4.Future); - - @override - _i4.Future stopImageStream(int? cameraId) => - (super.noSuchMethod( - Invocation.method(#stopImageStream, [cameraId]), - returnValue: _i4.Future.value(), - returnValueForMissingStub: _i4.Future.value(), - ) - as _i4.Future); - @override _i4.Future pausePreview(int? cameraId) => (super.noSuchMethod( diff --git a/packages/camera/camera_windows/windows/camera_plugin.cpp b/packages/camera/camera_windows/windows/camera_plugin.cpp index c01db2603caa..f7348158c738 100644 --- a/packages/camera/camera_windows/windows/camera_plugin.cpp +++ b/packages/camera/camera_windows/windows/camera_plugin.cpp @@ -295,7 +295,7 @@ void CameraPlugin::ResumePreview( } void CameraPlugin::StartVideoRecording( - int64_t camera_id, + int64_t camera_id, const std::string* video_output_path, std::function reply)> result) { auto camera = GetCameraByCameraId(camera_id); if (!camera) { @@ -307,7 +307,13 @@ void CameraPlugin::StartVideoRecording( FlutterError("camera_error", "Pending start recording request exists")); } - std::optional path = GetFilePathForVideo(); + std::optional path; + if (video_output_path && !video_output_path->empty()) { + path = *video_output_path; + } else { + path = GetFilePathForVideo(); + } + if (path) { if (camera->AddPendingVoidResult(PendingResultType::kStartRecord, std::move(result))) { diff --git a/packages/camera/camera_windows/windows/camera_plugin.h b/packages/camera/camera_windows/windows/camera_plugin.h index 27eeba325682..942b16d5443d 100644 --- a/packages/camera/camera_windows/windows/camera_plugin.h +++ b/packages/camera/camera_windows/windows/camera_plugin.h @@ -63,7 +63,7 @@ class CameraPlugin : public flutter::Plugin, int64_t camera_id, std::function reply)> result) override; void StartVideoRecording( - int64_t camera_id, + int64_t camera_id, const std::string* video_output_path, std::function reply)> result) override; void StopVideoRecording( int64_t camera_id, diff --git a/packages/camera/camera_windows/windows/capture_controller.cpp b/packages/camera/camera_windows/windows/capture_controller.cpp index 1afa5c0a8c45..f5799adffc98 100644 --- a/packages/camera/camera_windows/windows/capture_controller.cpp +++ b/packages/camera/camera_windows/windows/capture_controller.cpp @@ -501,6 +501,43 @@ void CaptureControllerImpl::StartRecord(const std::string& file_path) { "disposed and reinitialized."); } + if (!file_path.empty()) { + std::wstring wpath = Utf16FromUtf8(file_path); + DWORD dwAttrib = GetFileAttributesW(wpath.c_str()); + if (dwAttrib != INVALID_FILE_ATTRIBUTES && + (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) { + return OnRecordStarted(CameraResult::kError, + "The output path is a directory."); + } + + size_t last_slash = file_path.find_last_of("\\/"); + if (last_slash != std::string::npos) { + std::string parent_path = file_path.substr(0, last_slash); + if (!parent_path.empty()) { + DWORD dwParentAttrib = + GetFileAttributesW(Utf16FromUtf8(parent_path).c_str()); + if (dwParentAttrib == INVALID_FILE_ATTRIBUTES || + !(dwParentAttrib & FILE_ATTRIBUTE_DIRECTORY)) { + return OnRecordStarted(CameraResult::kError, + "The parent directory does not exist."); + } + } + } + + size_t last_dot = file_path.find_last_of("."); + if (last_dot == std::string::npos || + (last_slash != std::string::npos && last_dot < last_slash)) { + return OnRecordStarted(CameraResult::kError, + "The output path has no extension."); + } + std::string ext = file_path.substr(last_dot); + for (auto& c : ext) c = (char)tolower(c); + if (ext != ".mp4") { + return OnRecordStarted(CameraResult::kError, + "Invalid video extension. Supported: .mp4"); + } + } + HRESULT hr = S_OK; if (!base_capture_media_type_) { diff --git a/packages/camera/camera_windows/windows/messages.g.cpp b/packages/camera/camera_windows/windows/messages.g.cpp index 7133d7cd2504..59f032a38ce7 100644 --- a/packages/camera/camera_windows/windows/messages.g.cpp +++ b/packages/camera/camera_windows/windows/messages.g.cpp @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v26.1.0), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon #undef _HAS_EXCEPTIONS @@ -13,16 +13,18 @@ #include #include +#include +#include #include #include #include namespace camera_windows { -using flutter::BasicMessageChannel; -using flutter::CustomEncodableValue; -using flutter::EncodableList; -using flutter::EncodableMap; -using flutter::EncodableValue; +using ::flutter::BasicMessageChannel; +using ::flutter::CustomEncodableValue; +using ::flutter::EncodableList; +using ::flutter::EncodableMap; +using ::flutter::EncodableValue; FlutterError CreateConnectionError(const std::string channel_name) { return FlutterError( @@ -31,6 +33,212 @@ FlutterError CreateConnectionError(const std::string channel_name) { EncodableValue("")); } +namespace { +template +bool PigeonInternalDeepEquals(const T& a, const T& b); + +bool PigeonInternalDeepEquals(const double& a, const double& b); + +template +bool PigeonInternalDeepEquals(const std::vector& a, const std::vector& b); + +template +bool PigeonInternalDeepEquals(const std::map& a, const std::map& b); + +template +bool PigeonInternalDeepEquals(const std::optional& a, + const std::optional& b); + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, + const std::unique_ptr& b); + +bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, + const ::flutter::EncodableValue& b); + +template +bool PigeonInternalDeepEquals(const T& a, const T& b) { + return a == b; +} + +template +bool PigeonInternalDeepEquals(const std::vector& a, + const std::vector& b) { + if (a.size() != b.size()) { + return false; + } + for (size_t i = 0; i < a.size(); ++i) { + if (!PigeonInternalDeepEquals(a[i], b[i])) { + return false; + } + } + return true; +} + +template +bool PigeonInternalDeepEquals(const std::map& a, + const std::map& b) { + if (a.size() != b.size()) { + return false; + } + for (const auto& kv : a) { + bool found = false; + for (const auto& b_kv : b) { + if (PigeonInternalDeepEquals(kv.first, b_kv.first)) { + if (PigeonInternalDeepEquals(kv.second, b_kv.second)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; +} + +bool PigeonInternalDeepEquals(const double& a, const double& b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == b) || (std::isnan(a) && std::isnan(b)); +} + +template +bool PigeonInternalDeepEquals(const std::optional& a, + const std::optional& b) { + if (!a && !b) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, + const std::unique_ptr& b) { + if (a.get() == b.get()) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, + const ::flutter::EncodableValue& b) { + if (a.index() != b.index()) { + return false; + } + if (const double* da = std::get_if(&a)) { + return PigeonInternalDeepEquals(*da, std::get(b)); + } else if (const ::flutter::EncodableList* la = + std::get_if<::flutter::EncodableList>(&a)) { + return PigeonInternalDeepEquals(*la, std::get<::flutter::EncodableList>(b)); + } else if (const ::flutter::EncodableMap* ma = + std::get_if<::flutter::EncodableMap>(&a)) { + return PigeonInternalDeepEquals(*ma, std::get<::flutter::EncodableMap>(b)); + } + return a == b; +} + +template +size_t PigeonInternalDeepHash(const T& v); + +size_t PigeonInternalDeepHash(const double& v); + +template +size_t PigeonInternalDeepHash(const std::vector& v); + +template +size_t PigeonInternalDeepHash(const std::map& v); + +template +size_t PigeonInternalDeepHash(const std::optional& v); + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v); + +size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v); + +template +size_t PigeonInternalDeepHash(const T& v) { + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::vector& v) { + size_t result = 1; + for (const auto& item : v) { + result = result * 31 + PigeonInternalDeepHash(item); + } + return result; +} + +template +size_t PigeonInternalDeepHash(const std::map& v) { + size_t result = 0; + for (const auto& kv : v) { + result += ((PigeonInternalDeepHash(kv.first) * 31) ^ + PigeonInternalDeepHash(kv.second)); + } + return result; +} + +size_t PigeonInternalDeepHash(const double& v) { + if (std::isnan(v)) { + // Normalize NaN to a consistent hash. + return std::hash()(std::numeric_limits::quiet_NaN()); + } + if (v == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return std::hash()(0.0); + } + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::optional& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v) { + size_t result = v.index(); + if (const double* dv = std::get_if(&v)) { + result = result * 31 + PigeonInternalDeepHash(*dv); + } else if (const ::flutter::EncodableList* lv = + std::get_if<::flutter::EncodableList>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*lv); + } else if (const ::flutter::EncodableMap* mv = + std::get_if<::flutter::EncodableMap>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*mv); + } else { + std::visit( + [&result](const auto& val) { + using T = std::decay_t; + if constexpr (!std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v) { + result = result * 31 + PigeonInternalDeepHash(val); + } + }, + v); + } + return result; +} + +} // namespace // PlatformMediaSettings PlatformMediaSettings::PlatformMediaSettings( @@ -141,6 +349,36 @@ PlatformMediaSettings PlatformMediaSettings::FromEncodableList( return decoded; } +bool PlatformMediaSettings::operator==( + const PlatformMediaSettings& other) const { + return PigeonInternalDeepEquals(resolution_preset_, + other.resolution_preset_) && + PigeonInternalDeepEquals(frames_per_second_, + other.frames_per_second_) && + PigeonInternalDeepEquals(video_bitrate_, other.video_bitrate_) && + PigeonInternalDeepEquals(audio_bitrate_, other.audio_bitrate_) && + PigeonInternalDeepEquals(enable_audio_, other.enable_audio_); +} + +bool PlatformMediaSettings::operator!=( + const PlatformMediaSettings& other) const { + return !(*this == other); +} + +size_t PlatformMediaSettings::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(resolution_preset_); + result = result * 31 + PigeonInternalDeepHash(frames_per_second_); + result = result * 31 + PigeonInternalDeepHash(video_bitrate_); + result = result * 31 + PigeonInternalDeepHash(audio_bitrate_); + result = result * 31 + PigeonInternalDeepHash(enable_audio_); + return result; +} + +size_t PigeonInternalDeepHash(const PlatformMediaSettings& v) { + return v.Hash(); +} + // PlatformSize PlatformSize::PlatformSize(double width, double height) @@ -167,10 +405,28 @@ PlatformSize PlatformSize::FromEncodableList(const EncodableList& list) { return decoded; } +bool PlatformSize::operator==(const PlatformSize& other) const { + return PigeonInternalDeepEquals(width_, other.width_) && + PigeonInternalDeepEquals(height_, other.height_); +} + +bool PlatformSize::operator!=(const PlatformSize& other) const { + return !(*this == other); +} + +size_t PlatformSize::Hash() const { + size_t result = 1; + result = result * 31 + PigeonInternalDeepHash(width_); + result = result * 31 + PigeonInternalDeepHash(height_); + return result; +} + +size_t PigeonInternalDeepHash(const PlatformSize& v) { return v.Hash(); } + PigeonInternalCodecSerializer::PigeonInternalCodecSerializer() {} EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( - uint8_t type, flutter::ByteStreamReader* stream) const { + uint8_t type, ::flutter::ByteStreamReader* stream) const { switch (type) { case 129: { const auto& encodable_enum_arg = ReadValue(stream); @@ -190,12 +446,12 @@ EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( std::get(ReadValue(stream)))); } default: - return flutter::StandardCodecSerializer::ReadValueOfType(type, stream); + return ::flutter::StandardCodecSerializer::ReadValueOfType(type, stream); } } void PigeonInternalCodecSerializer::WriteValue( - const EncodableValue& value, flutter::ByteStreamWriter* stream) const { + const EncodableValue& value, ::flutter::ByteStreamWriter* stream) const { if (const CustomEncodableValue* custom_value = std::get_if(&value)) { if (custom_value->type() == typeid(PlatformResolutionPreset)) { @@ -222,23 +478,23 @@ void PigeonInternalCodecSerializer::WriteValue( return; } } - flutter::StandardCodecSerializer::WriteValue(value, stream); + ::flutter::StandardCodecSerializer::WriteValue(value, stream); } /// The codec used by CameraApi. -const flutter::StandardMessageCodec& CameraApi::GetCodec() { - return flutter::StandardMessageCodec::GetInstance( +const ::flutter::StandardMessageCodec& CameraApi::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance( &PigeonInternalCodecSerializer::GetInstance()); } // Sets up an instance of `CameraApi` to handle messages through the // `binary_messenger`. -void CameraApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void CameraApi::SetUp(::flutter::BinaryMessenger* binary_messenger, CameraApi* api) { CameraApi::SetUp(binary_messenger, api, ""); } -void CameraApi::SetUp(flutter::BinaryMessenger* binary_messenger, +void CameraApi::SetUp(::flutter::BinaryMessenger* binary_messenger, CameraApi* api, const std::string& message_channel_suffix) { const std::string prepended_suffix = @@ -254,7 +510,7 @@ void CameraApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { ErrorOr output = api->GetAvailableCameras(); if (output.has_error()) { @@ -280,7 +536,7 @@ void CameraApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_camera_name_arg = args.at(0); @@ -326,7 +582,7 @@ void CameraApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_camera_id_arg = args.at(0); @@ -363,7 +619,7 @@ void CameraApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_camera_id_arg = args.at(0); @@ -397,7 +653,7 @@ void CameraApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_camera_id_arg = args.at(0); @@ -434,7 +690,7 @@ void CameraApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_camera_id_arg = args.at(0); @@ -443,8 +699,12 @@ void CameraApi::SetUp(flutter::BinaryMessenger* binary_messenger, return; } const int64_t camera_id_arg = encodable_camera_id_arg.LongValue(); + const auto& encodable_video_output_path_arg = args.at(1); + const auto* video_output_path_arg = + std::get_if(&encodable_video_output_path_arg); api->StartVideoRecording( - camera_id_arg, [reply](std::optional&& output) { + camera_id_arg, video_output_path_arg, + [reply](std::optional&& output) { if (output.has_value()) { reply(WrapError(output.value())); return; @@ -470,7 +730,7 @@ void CameraApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_camera_id_arg = args.at(0); @@ -507,7 +767,7 @@ void CameraApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_camera_id_arg = args.at(0); @@ -543,7 +803,7 @@ void CameraApi::SetUp(flutter::BinaryMessenger* binary_messenger, if (api != nullptr) { channel.SetMessageHandler( [api](const EncodableValue& message, - const flutter::MessageReply& reply) { + const ::flutter::MessageReply& reply) { try { const auto& args = std::get(message); const auto& encodable_camera_id_arg = args.at(0); @@ -586,18 +846,18 @@ EncodableValue CameraApi::WrapError(const FlutterError& error) { // Generated class from Pigeon that represents Flutter messages that can be // called from C++. -CameraEventApi::CameraEventApi(flutter::BinaryMessenger* binary_messenger) +CameraEventApi::CameraEventApi(::flutter::BinaryMessenger* binary_messenger) : binary_messenger_(binary_messenger), message_channel_suffix_("") {} -CameraEventApi::CameraEventApi(flutter::BinaryMessenger* binary_messenger, +CameraEventApi::CameraEventApi(::flutter::BinaryMessenger* binary_messenger, const std::string& message_channel_suffix) : binary_messenger_(binary_messenger), message_channel_suffix_(message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : "") {} -const flutter::StandardMessageCodec& CameraEventApi::GetCodec() { - return flutter::StandardMessageCodec::GetInstance( +const ::flutter::StandardMessageCodec& CameraEventApi::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance( &PigeonInternalCodecSerializer::GetInstance()); } diff --git a/packages/camera/camera_windows/windows/messages.g.h b/packages/camera/camera_windows/windows/messages.g.h index ebce11993b98..a04b3d5d945d 100644 --- a/packages/camera/camera_windows/windows/messages.g.h +++ b/packages/camera/camera_windows/windows/messages.g.h @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v26.1.0), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon #ifndef PIGEON_MESSAGES_G_H_ @@ -25,17 +25,17 @@ class FlutterError { explicit FlutterError(const std::string& code, const std::string& message) : code_(code), message_(message) {} explicit FlutterError(const std::string& code, const std::string& message, - const flutter::EncodableValue& details) + const ::flutter::EncodableValue& details) : code_(code), message_(message), details_(details) {} const std::string& code() const { return code_; } const std::string& message() const { return message_; } - const flutter::EncodableValue& details() const { return details_; } + const ::flutter::EncodableValue& details() const { return details_; } private: std::string code_; std::string message_; - flutter::EncodableValue details_; + ::flutter::EncodableValue details_; }; template @@ -102,10 +102,16 @@ class PlatformMediaSettings { bool enable_audio() const; void set_enable_audio(bool value_arg); + bool operator==(const PlatformMediaSettings& other) const; + bool operator!=(const PlatformMediaSettings& other) const; + /// Returns a hash code value for the object. This method is supported for the + /// benefit of hash tables. + size_t Hash() const; + private: static PlatformMediaSettings FromEncodableList( - const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class CameraApi; friend class CameraEventApi; friend class PigeonInternalCodecSerializer; @@ -130,9 +136,15 @@ class PlatformSize { double height() const; void set_height(double value_arg); + bool operator==(const PlatformSize& other) const; + bool operator!=(const PlatformSize& other) const; + /// Returns a hash code value for the object. This method is supported for the + /// benefit of hash tables. + size_t Hash() const; + private: - static PlatformSize FromEncodableList(const flutter::EncodableList& list); - flutter::EncodableList ToEncodableList() const; + static PlatformSize FromEncodableList(const ::flutter::EncodableList& list); + ::flutter::EncodableList ToEncodableList() const; friend class CameraApi; friend class CameraEventApi; friend class PigeonInternalCodecSerializer; @@ -140,7 +152,8 @@ class PlatformSize { double height_; }; -class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { +class PigeonInternalCodecSerializer + : public ::flutter::StandardCodecSerializer { public: PigeonInternalCodecSerializer(); inline static PigeonInternalCodecSerializer& GetInstance() { @@ -148,12 +161,12 @@ class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { return sInstance; } - void WriteValue(const flutter::EncodableValue& value, - flutter::ByteStreamWriter* stream) const override; + void WriteValue(const ::flutter::EncodableValue& value, + ::flutter::ByteStreamWriter* stream) const override; protected: - flutter::EncodableValue ReadValueOfType( - uint8_t type, flutter::ByteStreamReader* stream) const override; + ::flutter::EncodableValue ReadValueOfType( + uint8_t type, ::flutter::ByteStreamReader* stream) const override; }; // Generated interface from Pigeon that represents a handler of messages from @@ -164,7 +177,7 @@ class CameraApi { CameraApi& operator=(const CameraApi&) = delete; virtual ~CameraApi() {} // Returns the names of all of the available capture devices. - virtual ErrorOr GetAvailableCameras() = 0; + virtual ErrorOr<::flutter::EncodableList> GetAvailableCameras() = 0; // Creates a camera instance for the given device name and settings. virtual void Create(const std::string& camera_name, const PlatformMediaSettings& settings, @@ -182,7 +195,7 @@ class CameraApi { std::function reply)> result) = 0; // Starts recording video with the given camera. virtual void StartVideoRecording( - int64_t camera_id, + int64_t camera_id, const std::string* video_output_path, std::function reply)> result) = 0; // Finishes recording video with the given camera, and returns the path to // the resulting file. @@ -199,14 +212,15 @@ class CameraApi { std::function reply)> result) = 0; // The codec used by CameraApi. - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); // Sets up an instance of `CameraApi` to handle messages through the // `binary_messenger`. - static void SetUp(flutter::BinaryMessenger* binary_messenger, CameraApi* api); - static void SetUp(flutter::BinaryMessenger* binary_messenger, CameraApi* api, - const std::string& message_channel_suffix); - static flutter::EncodableValue WrapError(std::string_view error_message); - static flutter::EncodableValue WrapError(const FlutterError& error); + static void SetUp(::flutter::BinaryMessenger* binary_messenger, + CameraApi* api); + static void SetUp(::flutter::BinaryMessenger* binary_messenger, + CameraApi* api, const std::string& message_channel_suffix); + static ::flutter::EncodableValue WrapError(std::string_view error_message); + static ::flutter::EncodableValue WrapError(const FlutterError& error); protected: CameraApi() = default; @@ -215,10 +229,10 @@ class CameraApi { // called from C++. class CameraEventApi { public: - CameraEventApi(flutter::BinaryMessenger* binary_messenger); - CameraEventApi(flutter::BinaryMessenger* binary_messenger, + CameraEventApi(::flutter::BinaryMessenger* binary_messenger); + CameraEventApi(::flutter::BinaryMessenger* binary_messenger, const std::string& message_channel_suffix); - static const flutter::StandardMessageCodec& GetCodec(); + static const ::flutter::StandardMessageCodec& GetCodec(); // Called when the camera instance is closing on the native side. void CameraClosing(std::function&& on_success, std::function&& on_error); @@ -228,7 +242,7 @@ class CameraEventApi { std::function&& on_error); private: - flutter::BinaryMessenger* binary_messenger_; + ::flutter::BinaryMessenger* binary_messenger_; std::string message_channel_suffix_; }; diff --git a/packages/camera/camera_windows/windows/test/camera_plugin_test.cpp b/packages/camera/camera_windows/windows/test/camera_plugin_test.cpp index 1072f9b5609a..9cbacdefee99 100644 --- a/packages/camera/camera_windows/windows/test/camera_plugin_test.cpp +++ b/packages/camera/camera_windows/windows/test/camera_plugin_test.cpp @@ -566,7 +566,77 @@ TEST(CameraPlugin, StartVideoRecordingHandlerCallsStartRecordWithPath) { EXPECT_FALSE(reply); }; - plugin.StartVideoRecording(mock_camera_id, std::move(start_video_result)); + plugin.StartVideoRecording(mock_camera_id, nullptr, + std::move(start_video_result)); + + EXPECT_TRUE(result_called); +} + +TEST(CameraPlugin, StartVideoRecordingHandlerCallsStartRecordWithCustomPath) { + int64_t mock_camera_id = 1234; + std::string custom_path = "C:\\test\\video.mp4"; + + std::unique_ptr camera = + std::make_unique(MOCK_DEVICE_ID); + + std::unique_ptr capture_controller = + std::make_unique(); + + EXPECT_CALL(*camera, HasCameraId(Eq(mock_camera_id))) + .Times(1) + .WillOnce([cam = camera.get()](int64_t camera_id) { + return cam->camera_id_ == camera_id; + }); + + EXPECT_CALL(*camera, + HasPendingResultByType(Eq(PendingResultType::kStartRecord))) + .Times(1) + .WillOnce(Return(false)); + + EXPECT_CALL(*camera, + AddPendingVoidResult(Eq(PendingResultType::kStartRecord), _)) + .Times(1) + .WillOnce([cam = camera.get()]( + PendingResultType type, + std::function)> result) { + cam->pending_void_result_ = std::move(result); + return true; + }); + + EXPECT_CALL(*camera, GetCaptureController) + .Times(1) + .WillOnce([cam = camera.get()]() { + assert(cam->pending_void_result_); + return cam->capture_controller_.get(); + }); + + EXPECT_CALL(*capture_controller, StartRecord(Eq(custom_path))) + .Times(1) + .WillOnce([cam = camera.get()](const std::string& file_path) { + assert(cam->pending_void_result_); + return cam->pending_void_result_(std::nullopt); + }); + + camera->camera_id_ = mock_camera_id; + camera->capture_controller_ = std::move(capture_controller); + + MockCameraPlugin plugin(std::make_unique().get(), + std::make_unique().get(), + std::make_unique()); + + // Add mocked camera to plugins camera list. + plugin.AddCamera(std::move(camera)); + + bool result_called = false; + std::function)> start_video_result = + [&result_called](std::optional reply) { + EXPECT_FALSE(result_called); // Ensure only one reply call. + result_called = true; + EXPECT_FALSE(reply); + }; + + plugin.StartVideoRecording(mock_camera_id, &custom_path, + std::move(start_video_result)); EXPECT_TRUE(result_called); } @@ -609,7 +679,68 @@ TEST(CameraPlugin, StartVideoRecordingHandlerErrorOnInvalidCameraId) { EXPECT_TRUE(reply); }; - plugin.StartVideoRecording(missing_camera_id, std::move(start_video_result)); + plugin.StartVideoRecording(missing_camera_id, nullptr, + std::move(start_video_result)); + + EXPECT_TRUE(result_called); +} + +TEST(CameraPlugin, StartVideoRecordingHandlerReturnsErrorOnStartRecordFailure) { + int64_t mock_camera_id = 1234; + std::string custom_path = "C:\\invalid\\video.mp4"; + + std::unique_ptr camera = + std::make_unique(MOCK_DEVICE_ID); + + std::unique_ptr capture_controller = + std::make_unique(); + + EXPECT_CALL(*camera, HasCameraId(Eq(mock_camera_id))) + .Times(1) + .WillOnce(Return(true)); + + EXPECT_CALL(*camera, + AddPendingVoidResult(Eq(PendingResultType::kStartRecord), _)) + .Times(1) + .WillOnce([cam = camera.get()]( + PendingResultType type, + std::function)> result) { + cam->pending_void_result_ = std::move(result); + return true; + }); + + EXPECT_CALL(*camera, GetCaptureController) + .Times(1) + .WillOnce(Return(capture_controller.get())); + + EXPECT_CALL(*capture_controller, StartRecord(Eq(custom_path))) + .Times(1) + .WillOnce([cam = camera.get()](const std::string& file_path) { + assert(cam->pending_void_result_); + cam->pending_void_result_(FlutterError("error", "Invalid path")); + }); + + camera->camera_id_ = mock_camera_id; + camera->capture_controller_ = std::move(capture_controller); + + MockCameraPlugin plugin(std::make_unique().get(), + std::make_unique().get(), + std::make_unique()); + + // Add mocked camera to plugins camera list. + plugin.AddCamera(std::move(camera)); + + bool result_called = false; + std::function)> start_video_result = + [&result_called](std::optional reply) { + EXPECT_FALSE(result_called); // Ensure only one reply call. + result_called = true; + EXPECT_TRUE(reply); + EXPECT_EQ(reply->message(), "Invalid path"); + }; + + plugin.StartVideoRecording(mock_camera_id, &custom_path, + std::move(start_video_result)); EXPECT_TRUE(result_called); }