github CommunityToolkit/Maui 7.0.0-camera
Camera v7.0.0 Bug Fix-A-Palooza 🎉

latest releases: 5.0.0-maps, 11.0.0-mediaelement
one hour ago

We have FINALLY implemented Device Tests! These are platform-specific unit tests that run on iOS, Android, MacCatalyst and Windows. This allows us to unit test all platform-specific code and has MASSIVELY increased our Unit Test Code Coverage to 96.7% Code Coverage on CommunityToolkit.Maui.Camera.

New APIs in This Release

  • CameraView.ErrorOccurred and ErrorOccurredEventArgs (#3299)

Breaking Changes

To fix certain bugs, and re-align features to ensure they behave the same across all platforms, we did have to modify some APIs and the associated underlying behavior. Please find the features you use, below, and update your apps accordingly.

All packages
  • API: Null arguments throw ArgumentNullException at the call. Public and protected members of the five libraries now guard the non-nullable reference parameters they cannot handle (about 275 guards).
    • A null that used to cause a NullReferenceException later (or was stored silently) fails at the call, with a ParamName. What to do: fix the caller.
    • An async member throws from the call itself, before it returns a Task.
    • Null arguments that a member handled before are still accepted, for example an IProgress<double> or a Paint background of null.
    • Feature-specific effects are listed in each feature's section.
    • BasePlatformBehavior guards only bindable. A null platform view passes through, because the Android IconTintColorBehavior accepts it.
  • Setup: CommunityToolkit.Maui.Core on Android adds a <queries> entry for the launcher (MAIN/HOME) to the app's merged manifest through the package's library manifest (src/CommunityToolkit.Maui.Core/AndroidManifest.xml). Badge needs it on Android 11 and later. If your app or Play listing reviews <queries>, check the merged manifest.
  • Setup: Dependencies: on Windows, CommunityToolkit.Maui.Core references System.Speech 10.0.11 (it was 10.0.1). No action is needed unless you pin the package. This comes from #3288 on main, not from this PR.
CameraView
API
  • Null arguments: ErrorOccurredEventArgs, MediaCaptureFailedEventArgs and CameraInfo reject null for their non-nullable members.
Behavior
  • Failures are reported through events instead of exceptions.
    • StartCameraPreview(CancellationToken) no longer throws for a camera that cannot start (except in the Android failed-connection case below). It raises ErrorOccurred on every platform.
      • A cancelled token still throws OperationCanceledException.
      • A view without a handler still throws InvalidOperationException.
    • The commands let no exception escape:
      • CaptureImageCommand, StartVideoRecordingCommand and StopVideoRecordingCommand report through MediaCaptureFailed.
      • StartCameraPreviewCommand and StopCameraPreviewCommand report through ErrorOccurred.
    • Failures of the handler's own work (connecting, switching to SelectedCamera, applying ImageCaptureResolution) raise ErrorOccurred instead of ending the app.
    • Android:
      • A preview without the camera permission now fails, is reported, and stays stopped until the activity resumes with the permission. iOS and Mac Catalyst report a denied permission the same way.
      • CaptureImage before the camera has started throws CameraException instead of waiting until its token is cancelled.
    • What to do: subscribe to ErrorOccurred and MediaCaptureFailed instead of relying on try/catch.
  • Android: one ErrorOccurred for a failed connection. A StartCameraPreview called while the CameraView connects to its camera waits for the connection.
    • When the connection fails and raises ErrorOccurred, that StartCameraPreview throws the same failure to its caller instead of raising ErrorOccurred again. StartCameraPreviewCommand doesn't report it again.
    • What to do: catch the exception where you await such a start.
  • StopCameraPreview cancels starts that still wait. StopCameraPreview and StopCameraPreviewCommand now cancel a pending StartCameraPreview, a pending StartVideoRecording (both overloads), the start the view makes when it connects its camera, and a camera switch.
    • The cancelled start throws OperationCanceledException, with no ErrorOccurred or MediaCaptureFailed. A start that a stop interrupted needs a new start.
    • What to do: do not treat that exception as a failure.
    • On iOS and Mac Catalyst, StartCameraPreview with an already-cancelled token throws and no longer starts the session.
  • Video recording.
    • Android: a StartVideoRecording during a recording replaces it: the new stream receives the video, and the earlier recording's video is discarded. Camera 6.1.0 ignored the second start; iOS and Mac Catalyst already replaced it.
    • Android, iOS, Mac Catalyst and Windows: a start that arrives while an earlier start still waits for the platform joins it. It returns once that recording has started, its stream receives no video, and it throws the earlier start's failure. On iOS and Mac Catalyst this holds for a double tap too, where Camera 6.1.0 replaced the first recording.
    • StartVideoRecording returns only once the platform has started the recording (#3311), so await it before relying on the recording. On iOS and Mac Catalyst, a start cancelled while it waits releases the recording state.
    • Windows, as on Android, iOS and Mac Catalyst:
      • StopVideoRecording waits for a pending StartVideoRecording.
      • A StartVideoRecording or a second StopVideoRecording that arrives while a stop waits for Media Foundation to finish the recording waits for that stop.
    • StopVideoRecording throws CameraException on Android, iOS and Mac Catalyst when the platform reports a recording with no playable video. A recording the platform ended early that has usable video is still returned.
    • Android: when the photo session cannot be restored after a successful export, StopVideoRecording still returns the video, and the failure is raised through ErrorOccurred. Selecting another camera during a recording waits until the recording stops or is replaced.
    • Windows: a StopVideoRecording whose token is cancelled already or while the stop finishes the video:
      • It still stops the recording and throws OperationCanceledException, as on Android, iOS and Mac Catalyst. It used to ignore the token and return the video.
      • The next StopVideoRecording returns the video. A StartVideoRecording that comes first discards it and puts its stream back, as for a replaced recording.
      • The camera that the recording turned on is off again when the cancelled stop throws.
      • A cancelled stop while a start or another stop is still pending throws without stopping anything.
      • With no recording, a cancelled StopVideoRecording returns Stream.Null on every platform.
      • StopVideoRecordingCommand ends without an event.
      • Camera 6.1.0 already handled a cancelled stop this way on Android and iOS; Mac Catalyst follows iOS.
      • Catch the OperationCanceledException and call StopVideoRecording again to get the video.
    • Windows: a StartVideoRecording during a recording ends and finishes the running recording and discards its video.
      • The running recording's stream goes back to the length and position it had when that recording started.
      • The video goes to the stream of the latest start, as on Android, iOS and Mac Catalyst. The camera stays on in between.
      • Camera 6.1.0 prepared a second recording without ending the first, so the first video was left unfinished or the new stream stayed empty.
      • If you relied on the first recording continuing, call StopVideoRecording before a new start.
    • What to do: handle ErrorOccurred and CameraException. On Android, don't rely on a second start being ignored.
  • Recording while the preview is stopped starts the camera.
    • On Android, iOS, Mac Catalyst and Windows, StartVideoRecording after StopCameraPreview, or before StartCameraPreview, starts the camera and then the recording. Android already did; Camera 6.1.0 recorded nothing on iOS, Mac Catalyst and Windows.
    • A camera that the recording turned on turns off again when the recording ends. After a cancelled StopVideoRecording on Android, iOS and Mac Catalyst, it turns off only once the next stop returns the video.
    • A preview that the app started stays on.
    • When the camera can't start, a stopped preview stays stopped. On iOS, Mac Catalyst and Windows, StartVideoRecording throws the failure: for example a CameraException without a camera or without the camera permission, or on Windows an UnauthorizedAccessException when the privacy settings block the camera. StartVideoRecordingCommand reports it through MediaCaptureFailed.
    • On Android, a StartCameraPreview after SetExtensionMode on a stopped preview shows the SelectedCamera. Camera 6.1.0 kept showing the camera that was selected when SetExtensionMode ran.
  • Windows: a start while the preview runs, and a stop during a recording.
    • StartCameraPreview while the preview already runs is a no-op.
    • A StartCameraPreview while an earlier start is still opening the camera releases that start's MediaCapture, so the camera is never held twice.
    • StopCameraPreview during a recording ends the recording, like on Android. A later StopVideoRecording returns Stream.Null, so do not expect a video from a recording that a stop ended.
Smaller changes
  • CameraView with an app's CameraViewHandler.PlatformViewFactory:
    • The camera shows in the factory's view, which the toolkit doesn't dispose.
    • On Windows, only a MediaPlayerElement shows the preview. Another element shows none, and a warning is written to the trace output.
  • CameraView on Android applies ZoomFactor and IsTorchOn again after another screen, such as FileSaver's save dialog or Home.

What's Changed

Don't miss a new Maui release

NewReleases is sending notifications on new releases.