From 4713b19e9529b49fd4a8a8a9e18c0b84f1c49cf7 Mon Sep 17 00:00:00 2001 From: Zhitao Pan Date: Wed, 15 Oct 2025 16:33:33 +1100 Subject: [PATCH 1/3] Refactor camera refresh logic * Add PlatformRefreshAvailableCameras * Don't invoke refresh camera task when one is in progress * Remove redundant refresh camera calls in CameraManager --- .../Views/CameraView/CameraViewPage.xaml | 3 +- .../Views/CameraView/CameraViewPage.xaml.cs | 28 +++++----------- .../CameraManager.android.cs | 26 +++------------ .../CameraManager.macios.cs | 31 ++++------------- .../CameraManager.shared.cs | 10 +++++- .../CameraManager.windows.cs | 33 ++++--------------- .../Handlers/CameraViewHandler.shared.cs | 1 - .../Providers/CameraProvider.android.cs | 2 +- .../Providers/CameraProvider.macios.cs | 2 +- .../Providers/CameraProvider.net.cs | 2 +- .../Providers/CameraProvider.shared.cs | 19 ++++++++--- .../Providers/CameraProvider.tizen.cs | 2 +- .../Providers/CameraProvider.windows.cs | 4 +-- .../Views/CameraView.shared.cs | 8 +---- 14 files changed, 59 insertions(+), 112 deletions(-) diff --git a/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/CameraViewPage.xaml b/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/CameraViewPage.xaml index f34ac7d3a7..a77b635c7e 100644 --- a/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/CameraViewPage.xaml +++ b/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/CameraViewPage.xaml @@ -5,12 +5,11 @@ xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" xmlns:viewModels="clr-namespace:CommunityToolkit.Maui.Sample.ViewModels.Views" Title="CameraView" - Unloaded="OnUnloaded" x:Class="CommunityToolkit.Maui.Sample.Pages.Views.CameraViewPage" x:TypeArguments="viewModels:CameraViewViewModel" x:DataType="viewModels:CameraViewViewModel"> - + { readonly string imagePath; - int pageCount; + bool isInitialized = false; public CameraViewPage(CameraViewViewModel viewModel, IFileSystem fileSystem) : base(viewModel) { @@ -16,30 +15,27 @@ public CameraViewPage(CameraViewViewModel viewModel, IFileSystem fileSystem) : b imagePath = Path.Combine(fileSystem.CacheDirectory, "camera-view-image.jpg"); Camera.MediaCaptured += OnMediaCaptured; - - Loaded += (s, e) => - { - pageCount = Navigation.NavigationStack.Count; - }; } protected override async void OnAppearing() { base.OnAppearing(); + if (isInitialized) + { + return; + } + var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(3)); await BindingContext.RefreshCamerasCommand.ExecuteAsync(cancellationTokenSource.Token); + isInitialized = true; } - // https://github.com/dotnet/maui/issues/16697 - // https://github.com/dotnet/maui/issues/15833 protected override void OnNavigatedFrom(NavigatedFromEventArgs args) { base.OnNavigatedFrom(args); - Debug.WriteLine($"< < OnNavigatedFrom {pageCount} {Navigation.NavigationStack.Count}"); - - if (Navigation.NavigationStack.Count < pageCount) + if (!Shell.Current.Navigation.NavigationStack.Contains(this)) { Cleanup(); } @@ -57,12 +53,6 @@ async void OnImageTapped(object? sender, TappedEventArgs args) void Cleanup() { Camera.MediaCaptured -= OnMediaCaptured; - Camera.Handler?.DisconnectHandler(); - } - - void OnUnloaded(object? sender, EventArgs e) - { - //Cleanup(); } void OnMediaCaptured(object? sender, MediaCapturedEventArgs e) @@ -75,7 +65,7 @@ void OnMediaCaptured(object? sender, MediaCapturedEventArgs e) { // workaround for https://github.com/dotnet/maui/issues/13858 #if ANDROID - image.Source = ImageSource.FromStream(() => File.OpenRead(imagePath)); + image.Source = ImageSource.FromStream(() => File.OpenRead(imagePath)); #else image.Source = ImageSource.FromFile(imagePath); #endif diff --git a/src/CommunityToolkit.Maui.Camera/CameraManager.android.cs b/src/CommunityToolkit.Maui.Camera/CameraManager.android.cs index c642ca4218..4f7eaddf48 100644 --- a/src/CommunityToolkit.Maui.Camera/CameraManager.android.cs +++ b/src/CommunityToolkit.Maui.Camera/CameraManager.android.cs @@ -129,6 +129,7 @@ protected virtual void Dispose(bool disposing) previewView?.Dispose(); previewView = null; + processCameraProvider?.UnbindAll(); processCameraProvider?.Dispose(); processCameraProvider = null; @@ -158,16 +159,6 @@ protected virtual async partial Task PlatformConnectCamera(CancellationToken tok { processCameraProvider = (ProcessCameraProvider)(cameraProviderFuture.Get() ?? throw new CameraException($"Unable to retrieve {nameof(ProcessCameraProvider)}")); - if (cameraProvider.AvailableCameras is null) - { - await cameraProvider.RefreshAvailableCameras(token); - - if (cameraProvider.AvailableCameras is null) - { - throw new CameraException("Unable to refresh available cameras"); - } - } - await StartUseCase(token); cameraProviderTCS.SetResult(); @@ -200,22 +191,14 @@ protected async Task StartUseCase(CancellationToken token) await StartCameraPreview(token); } - protected virtual async partial Task PlatformStartCameraPreview(CancellationToken token) + protected virtual partial Task PlatformStartCameraPreview(CancellationToken token) { if (previewView is null || processCameraProvider is null || cameraPreview is null || imageCapture is null) { - return; + return Task.CompletedTask; } - if (cameraView.SelectedCamera is null) - { - if (cameraProvider.AvailableCameras is null) - { - await cameraProvider.RefreshAvailableCameras(token); - } - - cameraView.SelectedCamera = cameraProvider.AvailableCameras?.FirstOrDefault() ?? throw new CameraException("No camera available on device"); - } + cameraView.SelectedCamera ??= cameraProvider.AvailableCameras?.FirstOrDefault() ?? throw new CameraException("No camera available on device"); var cameraSelector = cameraView.SelectedCamera.CameraSelector ?? throw new CameraException($"Unable to retrieve {nameof(CameraSelector)}"); @@ -231,6 +214,7 @@ protected virtual async partial Task PlatformStartCameraPreview(CancellationToke IsInitialized = true; OnLoaded.Invoke(); + return Task.CompletedTask; } protected virtual partial void PlatformStopCameraPreview() diff --git a/src/CommunityToolkit.Maui.Camera/CameraManager.macios.cs b/src/CommunityToolkit.Maui.Camera/CameraManager.macios.cs index 17941d0cf7..178e0c621d 100644 --- a/src/CommunityToolkit.Maui.Camera/CameraManager.macios.cs +++ b/src/CommunityToolkit.Maui.Camera/CameraManager.macios.cs @@ -77,24 +77,18 @@ public partial void UpdateZoom(float zoomLevel) captureDevice.UnlockForConfiguration(); } - public async partial ValueTask UpdateCaptureResolution(Size resolution, CancellationToken token) + public partial ValueTask UpdateCaptureResolution(Size resolution, CancellationToken token) { - if (captureDevice is null) + if (captureDevice is null || cameraView.SelectedCamera is null) { - return; + return ValueTask.CompletedTask; } captureDevice.LockForConfiguration(out NSError? error); if (error is not null) { Trace.WriteLine(error); - return; - } - - if (cameraView.SelectedCamera is null) - { - await cameraProvider.RefreshAvailableCameras(token); - cameraView.SelectedCamera = cameraProvider.AvailableCameras?.FirstOrDefault() ?? throw new CameraException("No camera available on device"); + return ValueTask.CompletedTask; } var filteredFormatList = cameraView.SelectedCamera.SupportedFormats.Where(f => @@ -116,20 +110,11 @@ public async partial ValueTask UpdateCaptureResolution(Size resolution, Cancella } captureDevice.UnlockForConfiguration(); + return ValueTask.CompletedTask; } protected virtual async partial Task PlatformConnectCamera(CancellationToken token) { - if (cameraProvider.AvailableCameras is null) - { - await cameraProvider.RefreshAvailableCameras(token); - - if (cameraProvider.AvailableCameras is null) - { - throw new CameraException("Unable to refresh cameras"); - } - } - await PlatformStartCameraPreview(token); } @@ -148,11 +133,7 @@ protected virtual async partial Task PlatformStartCameraPreview(CancellationToke input.Dispose(); } - if (cameraView.SelectedCamera is null) - { - await cameraProvider.RefreshAvailableCameras(token); - cameraView.SelectedCamera = cameraProvider.AvailableCameras?.FirstOrDefault() ?? throw new CameraException("No camera available on device"); - } + cameraView.SelectedCamera ??= cameraProvider.AvailableCameras?.FirstOrDefault() ?? throw new CameraException("No camera available on device"); captureDevice = cameraView.SelectedCamera.CaptureDevice ?? throw new CameraException($"No Camera found"); captureInput = new AVCaptureDeviceInput(captureDevice, out _); diff --git a/src/CommunityToolkit.Maui.Camera/CameraManager.shared.cs b/src/CommunityToolkit.Maui.Camera/CameraManager.shared.cs index d7703d2572..7869d07c98 100644 --- a/src/CommunityToolkit.Maui.Camera/CameraManager.shared.cs +++ b/src/CommunityToolkit.Maui.Camera/CameraManager.shared.cs @@ -33,7 +33,15 @@ public async Task ArePermissionsGranted() /// Connects to the camera. /// /// A that can be awaited. - public Task ConnectCamera(CancellationToken token) => PlatformConnectCamera(token); + public async Task ConnectCamera(CancellationToken token) + { + if (cameraProvider.AvailableCameras is null) + { + await cameraProvider.RefreshAvailableCameras(token); + } + cameraView.SelectedCamera ??= cameraProvider.AvailableCameras?.FirstOrDefault() ?? throw new CameraException("No camera available on device"); + await PlatformConnectCamera(token); + } /// /// Disconnects from the camera. diff --git a/src/CommunityToolkit.Maui.Camera/CameraManager.windows.cs b/src/CommunityToolkit.Maui.Camera/CameraManager.windows.cs index 5edf33fc77..49565f1d11 100644 --- a/src/CommunityToolkit.Maui.Camera/CameraManager.windows.cs +++ b/src/CommunityToolkit.Maui.Camera/CameraManager.windows.cs @@ -119,16 +119,6 @@ protected virtual void Dispose(bool disposing) protected virtual async partial Task PlatformConnectCamera(CancellationToken token) { - if (cameraProvider.AvailableCameras is null) - { - await cameraProvider.RefreshAvailableCameras(token); - - if (cameraProvider.AvailableCameras is null) - { - throw new CameraException("Unable to refresh cameras"); - } - } - await StartCameraPreview(token); } @@ -139,13 +129,9 @@ protected virtual async partial Task PlatformStartCameraPreview(CancellationToke return; } - mediaCapture = new MediaCapture(); + cameraView.SelectedCamera ??= cameraProvider.AvailableCameras?.FirstOrDefault() ?? throw new CameraException("No camera available on device"); - if (cameraView.SelectedCamera is null) - { - await cameraProvider.RefreshAvailableCameras(token); - cameraView.SelectedCamera = cameraProvider.AvailableCameras?.FirstOrDefault() ?? throw new CameraException("No camera available on device"); - } + mediaCapture = new MediaCapture(); await mediaCapture.InitializeCameraForCameraView(cameraView.SelectedCamera.DeviceId, token); @@ -180,22 +166,17 @@ protected virtual partial void PlatformStopCameraPreview() protected async Task PlatformUpdateResolution(Size resolution, CancellationToken token) { - if (!IsInitialized || mediaCapture is null) + if (!IsInitialized || mediaCapture is null || cameraView.SelectedCamera is null) { return; } - if (cameraView.SelectedCamera is null) - { - await cameraProvider.RefreshAvailableCameras(token); - cameraView.SelectedCamera = cameraProvider.AvailableCameras?.FirstOrDefault() ?? throw new CameraException("No camera available on device"); - } - var filteredPropertiesList = cameraView.SelectedCamera.ImageEncodingProperties.Where(p => p.Width <= resolution.Width && p.Height <= resolution.Height).ToList(); - filteredPropertiesList = filteredPropertiesList.Count is not 0 - ? filteredPropertiesList - : [.. cameraView.SelectedCamera.ImageEncodingProperties.OrderByDescending(p => p.Width * p.Height)]; + if (filteredPropertiesList.Count is 0) + { + filteredPropertiesList = [.. cameraView.SelectedCamera.ImageEncodingProperties.OrderByDescending(p => p.Width * p.Height)]; + } if (filteredPropertiesList.Count is not 0) { diff --git a/src/CommunityToolkit.Maui.Camera/Handlers/CameraViewHandler.shared.cs b/src/CommunityToolkit.Maui.Camera/Handlers/CameraViewHandler.shared.cs index 9f4b12f36c..2b56a50015 100644 --- a/src/CommunityToolkit.Maui.Camera/Handlers/CameraViewHandler.shared.cs +++ b/src/CommunityToolkit.Maui.Camera/Handlers/CameraViewHandler.shared.cs @@ -90,7 +90,6 @@ protected override async void ConnectHandler(NativePlatformCameraPreviewView pla await CameraManager.ArePermissionsGranted(); await CameraManager.ConnectCamera(CancellationToken.None); - await cameraProvider.RefreshAvailableCameras(CancellationToken.None); } /// diff --git a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.android.cs b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.android.cs index f908040cd0..ad25030de9 100644 --- a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.android.cs +++ b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.android.cs @@ -16,7 +16,7 @@ partial class CameraProvider { readonly Context context = Android.App.Application.Context; - public async partial ValueTask RefreshAvailableCameras(CancellationToken token) + private async partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token) { var cameraProviderFuture = ProcessCameraProvider.GetInstance(context); diff --git a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.macios.cs b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.macios.cs index 1a93631309..5a9a9bad6b 100644 --- a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.macios.cs +++ b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.macios.cs @@ -9,7 +9,7 @@ partial class CameraProvider { static readonly AVCaptureDeviceType[] captureDevices = InitializeCaptureDevices(); - public partial ValueTask RefreshAvailableCameras(CancellationToken token) + private partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token) { var discoverySession = AVCaptureDeviceDiscoverySession.Create(captureDevices, AVMediaTypes.Video, AVCaptureDevicePosition.Unspecified); var availableCameras = new List(); diff --git a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.net.cs b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.net.cs index d4c7daf353..57a58ae47d 100644 --- a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.net.cs +++ b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.net.cs @@ -2,5 +2,5 @@ namespace CommunityToolkit.Maui.Core; partial class CameraProvider { - public partial ValueTask RefreshAvailableCameras(CancellationToken token) => throw new NotSupportedException(); + private partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token) => throw new NotSupportedException(); } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.shared.cs b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.shared.cs index 7e7298461d..0e2b6de76b 100644 --- a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.shared.cs +++ b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.shared.cs @@ -6,7 +6,8 @@ partial class CameraProvider : ICameraProvider { readonly WeakEventManager availableCamerasChangedEventManager = new(); - + Task? refreshAvailableCamerasTask; + public event EventHandler?> AvailableCamerasChanged { add => availableCamerasChangedEventManager.AddEventHandler(value); @@ -22,13 +23,23 @@ private set if (!AreCameraInfoListsEqual(field, value)) { field = value; - availableCamerasChangedEventManager.HandleEvent(this, value, nameof(AvailableCamerasChanged)); + availableCamerasChangedEventManager.HandleEvent(this, value, nameof(AvailableCamerasChanged)); } } } + private partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token); + /// - public partial ValueTask RefreshAvailableCameras(CancellationToken token); + public async ValueTask RefreshAvailableCameras(CancellationToken token) + { + if (refreshAvailableCamerasTask is null || refreshAvailableCamerasTask.IsCompleted) + { + refreshAvailableCamerasTask = PlatformRefreshAvailableCameras(token).AsTask(); + } + + await refreshAvailableCamerasTask; + } internal static bool AreCameraInfoListsEqual(in IReadOnlyList? cameraInfoList1, in IReadOnlyList? cameraInfoList2) { @@ -47,4 +58,4 @@ internal static bool AreCameraInfoListsEqual(in IReadOnlyList? camer return cameraInfosInList1ButNotInList2.Count is 0 && cameraInfosInList2ButNotInList1.Count is 0; } -} \ No newline at end of file +} diff --git a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.tizen.cs b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.tizen.cs index 03140011e6..5ae4c99da8 100644 --- a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.tizen.cs +++ b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.tizen.cs @@ -2,5 +2,5 @@ partial class CameraProvider { - public partial ValueTask RefreshAvailableCameras(CancellationToken token) => throw new NotSupportedException(); + private partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token) => throw new NotSupportedException(); } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.windows.cs b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.windows.cs index c8064b0b49..40b48e6609 100644 --- a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.windows.cs +++ b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.windows.cs @@ -9,7 +9,7 @@ namespace CommunityToolkit.Maui.Core; partial class CameraProvider { - public async partial ValueTask RefreshAvailableCameras(CancellationToken token) + private async partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token) { var deviceInfoCollection = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture).AsTask(token); var mediaFrameSourceGroup = await MediaFrameSourceGroup.FindAllAsync().AsTask(token); @@ -68,4 +68,4 @@ public async partial ValueTask RefreshAvailableCameras(CancellationToken token) AvailableCameras = availableCameras; } -} \ No newline at end of file +} diff --git a/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs b/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs index edbd26460d..6115a9b0b9 100644 --- a/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs +++ b/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs @@ -207,14 +207,8 @@ public async ValueTask> GetAvailableCameras(Cancellati if (CameraProvider.AvailableCameras is null) { await CameraProvider.RefreshAvailableCameras(token); - - if (CameraProvider.AvailableCameras is null) - { - throw new CameraException("Unable to refresh available cameras"); - } } - - return CameraProvider.AvailableCameras; + return CameraProvider.AvailableCameras ?? throw new CameraException("No camera available on device"); } /// From b9e9345d7d53fbd749c1621d516c719451a45835 Mon Sep 17 00:00:00 2001 From: Zhitao Pan Date: Fri, 24 Oct 2025 13:28:15 +1100 Subject: [PATCH 2/3] Remove Refresh in StartVideoRecording --- .../CameraManager.android.cs | 48 ++++++++----------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/src/CommunityToolkit.Maui.Camera/CameraManager.android.cs b/src/CommunityToolkit.Maui.Camera/CameraManager.android.cs index d525e9d291..c759d78aea 100644 --- a/src/CommunityToolkit.Maui.Camera/CameraManager.android.cs +++ b/src/CommunityToolkit.Maui.Camera/CameraManager.android.cs @@ -1,6 +1,5 @@ using System.Runtime.Versioning; using Android.Content; -using Android.Provider; using Android.Runtime; using Android.Views; using AndroidX.Camera.Core; @@ -48,10 +47,10 @@ public async Task SetExtensionMode(int mode, CancellationToken token) { extensionMode = mode; if (cameraView.SelectedCamera is null - || processCameraProvider is null - || cameraPreview is null - || imageCapture is null - || videoCapture is null) + || processCameraProvider is null + || cameraPreview is null + || imageCapture is null + || videoCapture is null) { return; } @@ -104,7 +103,7 @@ public async partial ValueTask UpdateCaptureResolution(Size resolution, Cancella if (resolutionFilter is not null) { if (Math.Abs(resolutionFilter.TargetSize.Width - resolution.Width) < double.Epsilon && - Math.Abs(resolutionFilter.TargetSize.Height - resolution.Height) < double.Epsilon) + Math.Abs(resolutionFilter.TargetSize.Height - resolution.Height) < double.Epsilon) { return; } @@ -242,11 +241,11 @@ protected async Task StartUseCase(CancellationToken token) await StartCameraPreview(token); } - protected virtual partial Task PlatformStartCameraPreview(CancellationToken token) + protected virtual async partial Task PlatformStartCameraPreview(CancellationToken token) { if (previewView is null || processCameraProvider is null || cameraPreview is null || imageCapture is null || videoCapture is null) { - return Task.CompletedTask; + return; } cameraView.SelectedCamera ??= cameraProvider.AvailableCameras?.FirstOrDefault() ?? throw new CameraException("No camera available on device"); @@ -260,7 +259,6 @@ protected virtual partial Task PlatformStartCameraPreview(CancellationToken toke IsInitialized = true; OnLoaded.Invoke(); - return Task.CompletedTask; } protected virtual partial void PlatformStopCameraPreview() @@ -290,27 +288,19 @@ protected virtual partial ValueTask PlatformTakePicture(CancellationToken token) protected virtual async partial Task PlatformStartVideoRecording(Stream stream, CancellationToken token) { if (previewView is null - || processCameraProvider is null - || cameraPreview is null - || imageCapture is null - || videoCapture is null - || videoRecorder is null - || videoRecordingFile is not null) + || processCameraProvider is null + || cameraPreview is null + || imageCapture is null + || videoCapture is null + || videoRecorder is null + || videoRecordingFile is not null) { return; } videoRecordingStream = stream; - if (cameraView.SelectedCamera is null) - { - if (cameraProvider.AvailableCameras is null) - { - await cameraProvider.RefreshAvailableCameras(token); - } - - cameraView.SelectedCamera = cameraProvider.AvailableCameras?.FirstOrDefault() ?? throw new CameraException("No camera available on device"); - } + cameraView.SelectedCamera ??= cameraProvider.AvailableCameras?.FirstOrDefault() ?? throw new CameraException("No camera available on device"); if (camera is null || !IsVideoCaptureAlreadyBound()) { @@ -336,9 +326,9 @@ protected virtual async partial Task PlatformStopVideoRecording(Cancella { ArgumentNullException.ThrowIfNull(cameraExecutor); if (videoRecording is null - || videoRecordingFile is null - || videoRecordingFinalizeTcs is null - || videoRecordingStream is null) + || videoRecordingFile is null + || videoRecordingFinalizeTcs is null + || videoRecordingStream is null) { return Stream.Null; } @@ -357,8 +347,8 @@ protected virtual async partial Task PlatformStopVideoRecording(Cancella bool IsVideoCaptureAlreadyBound() { return processCameraProvider is not null - && videoCapture is not null - && processCameraProvider.IsBound(videoCapture); + && videoCapture is not null + && processCameraProvider.IsBound(videoCapture); } void CleanupVideoRecordingResources() From 9cf7487e89090fe66d23a27d7048744d2b6f34a6 Mon Sep 17 00:00:00 2001 From: Zhitao Pan Date: Sun, 26 Oct 2025 14:41:02 +1100 Subject: [PATCH 3/3] Change from private to internal --- .../Providers/CameraProvider.android.cs | 2 +- .../Providers/CameraProvider.macios.cs | 2 +- .../Providers/CameraProvider.net.cs | 2 +- .../Providers/CameraProvider.shared.cs | 2 +- .../Providers/CameraProvider.tizen.cs | 2 +- .../Providers/CameraProvider.windows.cs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.android.cs b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.android.cs index ad25030de9..3112dcb543 100644 --- a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.android.cs +++ b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.android.cs @@ -16,7 +16,7 @@ partial class CameraProvider { readonly Context context = Android.App.Application.Context; - private async partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token) + internal async partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token) { var cameraProviderFuture = ProcessCameraProvider.GetInstance(context); diff --git a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.macios.cs b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.macios.cs index 5a9a9bad6b..115c74579f 100644 --- a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.macios.cs +++ b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.macios.cs @@ -9,7 +9,7 @@ partial class CameraProvider { static readonly AVCaptureDeviceType[] captureDevices = InitializeCaptureDevices(); - private partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token) + internal partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token) { var discoverySession = AVCaptureDeviceDiscoverySession.Create(captureDevices, AVMediaTypes.Video, AVCaptureDevicePosition.Unspecified); var availableCameras = new List(); diff --git a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.net.cs b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.net.cs index 57a58ae47d..d46bfa94ee 100644 --- a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.net.cs +++ b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.net.cs @@ -2,5 +2,5 @@ namespace CommunityToolkit.Maui.Core; partial class CameraProvider { - private partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token) => throw new NotSupportedException(); + internal partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token) => throw new NotSupportedException(); } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.shared.cs b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.shared.cs index 0e2b6de76b..7c2cfd127b 100644 --- a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.shared.cs +++ b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.shared.cs @@ -28,7 +28,7 @@ private set } } - private partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token); + internal partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token); /// public async ValueTask RefreshAvailableCameras(CancellationToken token) diff --git a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.tizen.cs b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.tizen.cs index 5ae4c99da8..b72ed1924a 100644 --- a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.tizen.cs +++ b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.tizen.cs @@ -2,5 +2,5 @@ partial class CameraProvider { - private partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token) => throw new NotSupportedException(); + internal partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token) => throw new NotSupportedException(); } \ No newline at end of file diff --git a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.windows.cs b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.windows.cs index 40b48e6609..d89398f5ba 100644 --- a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.windows.cs +++ b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.windows.cs @@ -9,7 +9,7 @@ namespace CommunityToolkit.Maui.Core; partial class CameraProvider { - private async partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token) + internal async partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token) { var deviceInfoCollection = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture).AsTask(token); var mediaFrameSourceGroup = await MediaFrameSourceGroup.FindAllAsync().AsTask(token);