Repository navigation
Camera v7.0.0 Bug Fix-A-Palooza 🎉
·
7 commits
to main
since this release
Immutable
release. Only release title and notes can be modified.
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.ErrorOccurredandErrorOccurredEventArgs(#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
ArgumentNullExceptionat 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
NullReferenceExceptionlater (or was stored silently) fails at the call, with aParamName. 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 aPaintbackground of null. - Feature-specific effects are listed in each feature's section.
BasePlatformBehaviorguards onlybindable. A null platform view passes through, because the AndroidIconTintColorBehavioraccepts it.
- A null that used to cause a
- 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.Speech10.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,MediaCaptureFailedEventArgsandCameraInforeject 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 raisesErrorOccurredon every platform.- A cancelled token still throws
OperationCanceledException. - A view without a handler still throws
InvalidOperationException.
- A cancelled token still throws
- The commands let no exception escape:
CaptureImageCommand,StartVideoRecordingCommandandStopVideoRecordingCommandreport throughMediaCaptureFailed.StartCameraPreviewCommandandStopCameraPreviewCommandreport throughErrorOccurred.
- Failures of the handler's own work (connecting, switching to
SelectedCamera, applyingImageCaptureResolution) raiseErrorOccurredinstead 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.
CaptureImagebefore the camera has started throwsCameraExceptioninstead of waiting until its token is cancelled.
- What to do: subscribe to
ErrorOccurredandMediaCaptureFailedinstead of relying on try/catch.
- Android: one
ErrorOccurredfor a failed connection. AStartCameraPreviewcalled while theCameraViewconnects to its camera waits for the connection.- When the connection fails and raises
ErrorOccurred, thatStartCameraPreviewthrows the same failure to its caller instead of raisingErrorOccurredagain.StartCameraPreviewCommanddoesn't report it again. - What to do: catch the exception where you await such a start.
- When the connection fails and raises
StopCameraPreviewcancels starts that still wait.StopCameraPreviewandStopCameraPreviewCommandnow cancel a pendingStartCameraPreview, a pendingStartVideoRecording(both overloads), the start the view makes when it connects its camera, and a camera switch.- The cancelled start throws
OperationCanceledException, with noErrorOccurredorMediaCaptureFailed. 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,
StartCameraPreviewwith an already-cancelled token throws and no longer starts the session.
- The cancelled start throws
- Video recording.
- Android: a
StartVideoRecordingduring 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.
StartVideoRecordingreturns only once the platform has started the recording (#3311), soawaitit 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:
StopVideoRecordingwaits for a pendingStartVideoRecording.- A
StartVideoRecordingor a secondStopVideoRecordingthat arrives while a stop waits for Media Foundation to finish the recording waits for that stop.
StopVideoRecordingthrowsCameraExceptionon 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,
StopVideoRecordingstill returns the video, and the failure is raised throughErrorOccurred. Selecting another camera during a recording waits until the recording stops or is replaced. - Windows: a
StopVideoRecordingwhose 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
StopVideoRecordingreturns the video. AStartVideoRecordingthat 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
StopVideoRecordingreturnsStream.Nullon every platform. StopVideoRecordingCommandends without an event.- Camera 6.1.0 already handled a cancelled stop this way on Android and iOS; Mac Catalyst follows iOS.
- Catch the
OperationCanceledExceptionand callStopVideoRecordingagain to get the video.
- It still stops the recording and throws
- Windows: a
StartVideoRecordingduring 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
StopVideoRecordingbefore a new start.
- What to do: handle
ErrorOccurredandCameraException. On Android, don't rely on a second start being ignored.
- Android: a
- Recording while the preview is stopped starts the camera.
- On Android, iOS, Mac Catalyst and Windows,
StartVideoRecordingafterStopCameraPreview, or beforeStartCameraPreview, 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
StopVideoRecordingon 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,
StartVideoRecordingthrows the failure: for example aCameraExceptionwithout a camera or without the camera permission, or on Windows anUnauthorizedAccessExceptionwhen the privacy settings block the camera.StartVideoRecordingCommandreports it throughMediaCaptureFailed. - On Android, a
StartCameraPreviewafterSetExtensionModeon a stopped preview shows theSelectedCamera. Camera 6.1.0 kept showing the camera that was selected whenSetExtensionModeran.
- On Android, iOS, Mac Catalyst and Windows,
- Windows: a start while the preview runs, and a stop during a recording.
StartCameraPreviewwhile the preview already runs is a no-op.- A
StartCameraPreviewwhile an earlier start is still opening the camera releases that start'sMediaCapture, so the camera is never held twice. StopCameraPreviewduring a recording ends the recording, like on Android. A laterStopVideoRecordingreturnsStream.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
MediaPlayerElementshows the preview. Another element shows none, and a warning is written to the trace output.
- CameraView on Android applies
ZoomFactorandIsTorchOnagain after another screen, such as FileSaver's save dialog or Home.
- Null arguments:
What's Changed
- CameraView: Fixed crash on Windows when app has no camera access anymore by @MFinkBK in #3299
- Add Device Tests, Apply Fixes for Bugs Found by @TheCodeTraveler in #3344