diff --git a/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/CameraViewPage.xaml b/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/CameraViewPage.xaml
index e517746091..7dacdbf27e 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">
-
+
-
+
-
+
@@ -61,6 +60,12 @@
+
+
{
readonly string imagePath;
- int pageCount;
public CameraViewPage(CameraViewViewModel viewModel, IFileSystem fileSystem) : base(viewModel)
{
@@ -16,30 +14,20 @@ 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();
- var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(3));
- await BindingContext.RefreshCamerasCommand.ExecuteAsync(cancellationTokenSource.Token);
+ await BindingContext.InitializeAsync();
}
- // 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 +45,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 +57,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/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/CameraView/CameraViewViewModel.cs b/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/CameraView/CameraViewViewModel.cs
index 055637f821..bdd6854357 100644
--- a/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/CameraView/CameraViewViewModel.cs
+++ b/samples/CommunityToolkit.Maui.Sample/ViewModels/Views/CameraView/CameraViewViewModel.cs
@@ -1,5 +1,5 @@
-using CommunityToolkit.Maui.Core;
-using CommunityToolkit.Maui.Core.Primitives;
+using System.Collections.ObjectModel;
+using CommunityToolkit.Maui.Core;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
@@ -9,10 +9,12 @@ public partial class CameraViewViewModel(ICameraProvider cameraProvider) : BaseV
{
readonly ICameraProvider cameraProvider = cameraProvider;
- public IReadOnlyList Cameras => cameraProvider.AvailableCameras ?? [];
+ bool isInitialized = false;
public CancellationToken Token => CancellationToken.None;
+ public ObservableCollection Cameras { get; } = [];
+
public ICollection FlashModes { get; } = Enum.GetValues();
[ObservableProperty]
@@ -42,6 +44,22 @@ public partial class CameraViewViewModel(ICameraProvider cameraProvider) : BaseV
[ObservableProperty]
public partial string ResolutionText { get; set; } = string.Empty;
+ public async ValueTask InitializeAsync()
+ {
+ if (isInitialized)
+ {
+ return;
+ }
+
+ await cameraProvider.InitializeAsync(CancellationToken.None);
+ foreach (var camera in cameraProvider.AvailableCameras ?? [])
+ {
+ Cameras.Add(camera);
+ }
+
+ isInitialized = true;
+ }
+
[RelayCommand]
async Task RefreshCameras(CancellationToken token) => await cameraProvider.RefreshAvailableCameras(token);
@@ -60,6 +78,22 @@ partial void OnSelectedResolutionChanged(Size value)
UpdateResolutionText();
}
+ partial void OnSelectedCameraChanged(CameraInfo? oldValue, CameraInfo? newValue)
+ {
+ UpdateCameraInfoText();
+ }
+
+ void UpdateCameraInfoText()
+ {
+ if (SelectedCamera is null)
+ {
+ return;
+ }
+ CameraNameText = $"{SelectedCamera.Name}";
+ ZoomRangeText = $"Min Zoom: {SelectedCamera.MinimumZoomFactor}, Max Zoom: {SelectedCamera.MaximumZoomFactor}";
+ UpdateFlashModeText();
+ }
+
void UpdateFlashModeText()
{
if (SelectedCamera is null)
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..4678183bcb 100644
--- a/src/CommunityToolkit.Maui.Camera/CameraManager.shared.cs
+++ b/src/CommunityToolkit.Maui.Camera/CameraManager.shared.cs
@@ -33,7 +33,18 @@ 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 (await ArePermissionsGranted() is false)
+ {
+ throw new PermissionException("Camera permissions not granted");
+ }
+
+ await cameraProvider.InitializeAsync(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..07bf1a2780 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,22 @@ 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)
+ if (mediaCapture.VideoDeviceController.Id != cameraView.SelectedCamera.DeviceId)
{
- await cameraProvider.RefreshAvailableCameras(token);
- cameraView.SelectedCamera = cameraProvider.AvailableCameras?.FirstOrDefault() ?? throw new CameraException("No camera available on device");
+ return;
}
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..646731179b 100644
--- a/src/CommunityToolkit.Maui.Camera/Handlers/CameraViewHandler.shared.cs
+++ b/src/CommunityToolkit.Maui.Camera/Handlers/CameraViewHandler.shared.cs
@@ -87,10 +87,7 @@ void Init(ICameraView view)
protected override async void ConnectHandler(NativePlatformCameraPreviewView platformView)
{
base.ConnectHandler(platformView);
-
- await CameraManager.ArePermissionsGranted();
await CameraManager.ConnectCamera(CancellationToken.None);
- await cameraProvider.RefreshAvailableCameras(CancellationToken.None);
}
///
diff --git a/src/CommunityToolkit.Maui.Camera/Interfaces/ICameraProvider.shared.cs b/src/CommunityToolkit.Maui.Camera/Interfaces/ICameraProvider.shared.cs
index 3f0090e2ec..dff17dd2aa 100644
--- a/src/CommunityToolkit.Maui.Camera/Interfaces/ICameraProvider.shared.cs
+++ b/src/CommunityToolkit.Maui.Camera/Interfaces/ICameraProvider.shared.cs
@@ -11,15 +11,33 @@ public interface ICameraProvider
/// Cameras available on device
///
///
- /// List is initialized using
+ /// List is initialized using , and can be refreshed using
///
IReadOnlyList? AvailableCameras { get; }
///
- /// Assigns with the cameras available on device
+ /// Gets a value indicating whether the camera provider has been successfully initialized.
///
+ bool IsInitialized { get; }
+
+ ///
+ /// Refreshes the on device, regardless of the current initialization state.
+ ///
+ ///
+ /// This ensures the list is up to date if available cameras have changed after initialization.
+ ///
///
///
[MemberNotNull(nameof(AvailableCameras))]
- ValueTask RefreshAvailableCameras(CancellationToken token);
+ Task RefreshAvailableCameras(CancellationToken token);
+
+ ///
+ /// Initialize the camera provider by refreshing the .
+ /// This performs a one-time discovery of available cameras. Subsequent calls are no-ops unless initialization failed previously.
+ ///
+ ///
+ /// To force a refresh after the provider is initialized, call .
+ ///
+ ValueTask InitializeAsync(CancellationToken token);
+
}
\ No newline at end of file
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 adf24f9846..f1dc9da8c6 100644
--- a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.shared.cs
+++ b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.shared.cs
@@ -3,11 +3,81 @@
///
/// Implementation that provides the ability to discover cameras that are attached to the current device.
///
-partial class CameraProvider : ICameraProvider
+partial class CameraProvider : ICameraProvider, IDisposable
{
+ readonly SemaphoreSlim refreshAvailableCamerasSemaphore = new(1, 1);
+ Task? refreshAvailableCamerasTask;
+
+ ~CameraProvider()
+ {
+ Dispose(false);
+ }
+
+ ///
+ public bool IsInitialized => refreshAvailableCamerasTask?.IsCompletedSuccessfully is true;
+
///
public IReadOnlyList? AvailableCameras { get; private set; }
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ Task GetRefreshTask(CancellationToken token)
+ {
+ if (refreshAvailableCamerasTask is null || refreshAvailableCamerasTask.IsCompleted)
+ {
+ refreshAvailableCamerasTask = PlatformRefreshAvailableCameras(token).AsTask();
+ }
+
+ return refreshAvailableCamerasTask;
+ }
+
+ ///
+ public async ValueTask InitializeAsync(CancellationToken token)
+ {
+ await refreshAvailableCamerasSemaphore.WaitAsync(token);
+
+ try
+ {
+ if (!IsInitialized)
+ {
+ await GetRefreshTask(token);
+ }
+ }
+ finally
+ {
+ refreshAvailableCamerasSemaphore.Release();
+ }
+ }
+
///
- public partial ValueTask RefreshAvailableCameras(CancellationToken token);
+ public async Task RefreshAvailableCameras(CancellationToken token)
+ {
+ await refreshAvailableCamerasSemaphore.WaitAsync(token);
+
+ try
+ {
+ await GetRefreshTask(token);
+ }
+ finally
+ {
+ refreshAvailableCamerasSemaphore.Release();
+ }
+ }
+
+ void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ refreshAvailableCamerasSemaphore.Dispose();
+
+ refreshAvailableCamerasTask?.Dispose();
+ refreshAvailableCamerasTask = null;
+ }
+ }
+
+ private partial ValueTask PlatformRefreshAvailableCameras(CancellationToken token);
}
\ 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 b25c54b4d8..f7c24cf785 100644
--- a/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.windows.cs
+++ b/src/CommunityToolkit.Maui.Camera/Providers/CameraProvider.windows.cs
@@ -9,17 +9,17 @@ 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);
var videoCaptureSourceGroup = mediaFrameSourceGroup.Where(sourceGroup => deviceInfoCollection.Any(deviceInfo => deviceInfo.Id == sourceGroup.Id)).ToList();
- var mediaCapture = new MediaCapture();
var availableCameras = new List();
foreach (var sourceGroup in videoCaptureSourceGroup)
{
+ var mediaCapture = new MediaCapture();
await mediaCapture.InitializeCameraForCameraView(sourceGroup.Id, token);
CameraPosition position = CameraPosition.Unknown;
@@ -63,9 +63,11 @@ public async partial ValueTask RefreshAvailableCameras(CancellationToken token)
imageEncodingPropertiesList);
availableCameras.Add(cameraInfo);
+
+ mediaCapture.Dispose();
}
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..2a4735dcce 100644
--- a/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs
+++ b/src/CommunityToolkit.Maui.Camera/Views/CameraView.shared.cs
@@ -204,17 +204,8 @@ public void Dispose()
///
public async ValueTask> GetAvailableCameras(CancellationToken token)
{
- 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;
+ await CameraProvider.InitializeAsync(token);
+ return CameraProvider.AvailableCameras ?? throw new CameraException("No camera available on device");
}
///
diff --git a/src/CommunityToolkit.Maui.UnitTests/Mocks/MockCameraProvider.cs b/src/CommunityToolkit.Maui.UnitTests/Mocks/MockCameraProvider.cs
index aa42ebeabd..8ef976513d 100644
--- a/src/CommunityToolkit.Maui.UnitTests/Mocks/MockCameraProvider.cs
+++ b/src/CommunityToolkit.Maui.UnitTests/Mocks/MockCameraProvider.cs
@@ -1,5 +1,4 @@
using CommunityToolkit.Maui.Core;
-using CommunityToolkit.Maui.Core.Primitives;
namespace CommunityToolkit.Maui.UnitTests.Mocks;
@@ -7,7 +6,18 @@ public class MockCameraProvider : ICameraProvider
{
public IReadOnlyList? AvailableCameras { get; private set; }
- public ValueTask RefreshAvailableCameras(CancellationToken token)
+ public bool IsInitialized { get; private set; }
+
+ public async ValueTask InitializeAsync(CancellationToken token)
+ {
+ if (!IsInitialized)
+ {
+ await RefreshAvailableCameras(token);
+ IsInitialized = true;
+ }
+ }
+
+ public Task RefreshAvailableCameras(CancellationToken token)
{
AvailableCameras =
[
@@ -22,6 +32,6 @@ public ValueTask RefreshAvailableCameras(CancellationToken token)
])
];
- return ValueTask.CompletedTask;
+ return Task.CompletedTask;
}
}
\ No newline at end of file