@@ -124,9 +124,13 @@ public async partial ValueTask UpdateCaptureResolution(Size resolution, Cancella
124124 resolutionSelector ? . Dispose ( ) ;
125125
126126 resolutionSelector = new ResolutionSelector . Builder ( )
127- . SetAllowedResolutionMode ( ResolutionSelector . PreferHigherResolutionOverCaptureRate )
127+ . SetAllowedResolutionMode ( ResolutionSelector . PreferHigherResolutionOverCaptureRate ) ?
128128 . SetResolutionFilter ( resolutionFilter )
129- . Build ( ) ;
129+ ? . Build ( ) ?? throw new InvalidOperationException ( "Unable to Set Resolution Filter" ) ;
130+
131+ // `.SetResolutionFilter()` should never return null
132+ // According to the Android docs, `ResolutionSelector.Builder.setResolutionFilter(ResolutionFilter)` returns a `NonNull` object
133+ // `ResolutionSelector.Builder.SetResolutionFilter(ResolutionFilter)` returning a nullable object in .NET for Android is likely a C# Binding mistake
130134
131135 if ( IsInitialized )
132136 {
@@ -229,23 +233,33 @@ protected async Task StartUseCase(CancellationToken token)
229233 videoCapture ? . Dispose ( ) ;
230234 videoRecorder ? . Dispose ( ) ;
231235
232- cameraPreview = new Preview . Builder ( ) . SetResolutionSelector ( resolutionSelector ) . Build ( ) ;
233- cameraPreview . SetSurfaceProvider ( cameraExecutor , previewView ? . SurfaceProvider ) ;
236+ cameraPreview = new Preview . Builder ( ) . SetResolutionSelector ( resolutionSelector ) ? . Build ( ) ;
237+ cameraPreview ? . SetSurfaceProvider ( cameraExecutor , previewView ? . SurfaceProvider ) ;
234238
235239 imageCapture = new ImageCapture . Builder ( )
236- . SetCaptureMode ( ImageCapture . CaptureModeMaximizeQuality )
240+ . SetCaptureMode ( ImageCapture . CaptureModeMaximizeQuality ) ?
237241 . SetResolutionSelector ( resolutionSelector )
238- . Build ( ) ;
242+ ? . Build ( ) ?? throw new InvalidOperationException ( "Unable to set resolution selector" ) ;
243+
244+ // `.SetResolutionFilter()` should never return null
245+ // According to the Android docs, `ResolutionSelector.Builder.SetResolutionFilter(ResolutionFilter)` returns a `NonNull` object
246+ // `ResolutionSelector.Builder.SetResolutionFilter(ResolutionFilter)` returning a nullable object in .NET for Android is likely a C# Binding mistake
247+ // https://developer.android.com/reference/androidx/camera/core/resolutionselector/ResolutionSelector.Builder#setResolutionFilter(androidx.camera.core.resolutionselector.ResolutionFilter)
239248
240249 var videoRecorderBuilder = new Recorder . Builder ( )
241- . SetExecutor ( cameraExecutor ) ;
250+ . SetExecutor ( cameraExecutor ) ?? throw new InvalidOperationException ( "Unable to set video recorder executor" ) ;
251+
252+ // `.SetExecutor()` should never return null
253+ // According to the Android docs, `ResolutionSelector.Builder.setExecutor(ResolutionFilter)` returns a `NonNull` object
254+ // `ResolutionSelector.Builder.SetExecutor(ResolutionFilter)` returning a nullable object in .NET for Android is likely a C# Binding mistake
255+ // https://developer.android.com/reference/androidx/camera/video/Recorder.Builder#setExecutor(java.util.concurrent.Executor)
242256
243257 if ( Quality . Highest is not null )
244258 {
245- videoRecorderBuilder = videoRecorderBuilder . SetQualitySelector ( QualitySelector . From ( Quality . Highest ) ) ;
259+ videoRecorderBuilder = videoRecorderBuilder ? . SetQualitySelector ( QualitySelector . From ( Quality . Highest ) ) ;
246260 }
247261
248- videoRecorder = videoRecorderBuilder . Build ( ) ;
262+ videoRecorder = videoRecorderBuilder ? . Build ( ) ;
249263 videoCapture = VideoCapture . WithOutput ( videoRecorder ) ;
250264
251265 await StartCameraPreview ( token ) ;
@@ -271,9 +285,9 @@ protected virtual async partial Task PlatformStartCameraPreview(CancellationToke
271285 camera = await RebindCamera ( processCameraProvider , cameraView . SelectedCamera , token , cameraPreview , imageCapture , videoCapture ) ;
272286 cameraControl = camera . CameraControl ;
273287
274- var point = previewView . MeteringPointFactory . CreatePoint ( previewView . Width / 2.0f , previewView . Height / 2.0f , 0.1f ) ;
288+ var point = previewView . MeteringPointFactory ? . CreatePoint ( previewView . Width / 2.0f , previewView . Height / 2.0f , 0.1f ) ;
275289 var action = new FocusMeteringAction . Builder ( point ) . Build ( ) ;
276- camera . CameraControl . StartFocusAndMetering ( action ) ;
290+ camera . CameraControl ? . StartFocusAndMetering ( action ) ;
277291
278292 IsInitialized = true ;
279293 OnLoaded . Invoke ( ) ;
@@ -344,8 +358,13 @@ protected virtual async partial Task PlatformStartVideoRecording(Stream stream,
344358 var executor = ContextCompat . GetMainExecutor ( context ) ?? throw new CameraException ( $ "Unable to retrieve { nameof ( IExecutorService ) } ") ;
345359 videoRecording = videoRecorder
346360 . PrepareRecording ( context , outputOptions )
347- . WithAudioEnabled ( )
348- . Start ( executor , captureListener ) ;
361+ ? . WithAudioEnabled ( )
362+ . Start ( executor , captureListener ) ?? throw new InvalidOperationException ( "Unable to prepare recording" ) ;
363+
364+ // `.PrepareRecording()` should never return null
365+ // According to the Android docs, `Recorder.prepareRecording(Context, eMediaSoreOutputOptions)` returns a `NonNull` object
366+ // `Recorder.PrepareRecording(Context, eMediaSoreOutputOptions)` returning a nullable object in .NET for Android is likely a C# Binding mistake
367+ // https://developer.android.com/reference/androidx/camera/video/Recorder#prepareRecording(android.content.Context,androidx.camera.video.MediaStoreOutputOptions)
349368 }
350369
351370 protected virtual async partial Task < Stream > PlatformStopVideoRecording ( CancellationToken token )
@@ -415,7 +434,9 @@ async Task<CameraSelector> EnableModes(CameraInfo selectedCamera, CancellationTo
415434 return ;
416435 }
417436
418- var extensionsManagerFuture = ExtensionsManager . GetInstanceAsync ( context , cameraProviderInstance ) ;
437+ var extensionsManagerFuture = ExtensionsManager . GetInstanceAsync ( context , cameraProviderInstance )
438+ ?? throw new InvalidOperationException ( "Unable to get listenable future for camera provider" ) ; ;
439+
419440 extensionsManagerFuture . AddListener ( new Runnable ( ( ) =>
420441 {
421442 var extensionsManager = ( ExtensionsManager ? ) extensionsManagerFuture . Get ( ) ;
@@ -455,10 +476,10 @@ void SetImageCaptureTargetRotation(int rotation)
455476
456477 sealed class ImageCallBack ( ICameraView cameraView ) : ImageCapture . OnImageCapturedCallback
457478 {
458- public override void OnCaptureSuccess ( IImageProxy image )
479+ public override void OnCaptureSuccess ( IImageProxy ? image )
459480 {
460481 base . OnCaptureSuccess ( image ) ;
461- var img = image . Image ;
482+ var img = image ? . Image ;
462483
463484 if ( img is null )
464485 {
@@ -471,7 +492,7 @@ public override void OnCaptureSuccess(IImageProxy image)
471492 if ( buffer is null )
472493 {
473494 cameraView . OnMediaCapturedFailed ( "Unable to obtain a buffer for the image plane." ) ;
474- image . Close ( ) ;
495+ image ? . Close ( ) ;
475496 return ;
476497 }
477498
@@ -489,7 +510,7 @@ public override void OnCaptureSuccess(IImageProxy image)
489510 }
490511 finally
491512 {
492- image . Close ( ) ;
513+ image ? . Close ( ) ;
493514 }
494515
495516 static Image . Plane ? GetFirstPlane ( Image . Plane [ ] ? planes )
@@ -503,24 +524,26 @@ public override void OnCaptureSuccess(IImageProxy image)
503524 }
504525 }
505526
506- public override void OnError ( ImageCaptureException exception )
527+ public override void OnError ( ImageCaptureException ? exception )
507528 {
508529 base . OnError ( exception ) ;
509- cameraView . OnMediaCapturedFailed ( exception . Message ?? "An unknown error occurred." ) ;
530+ cameraView . OnMediaCapturedFailed ( exception ? . Message ?? "An unknown error occurred." ) ;
510531 }
511532 }
512533
513534 sealed class ResolutionFilter ( Android . Util . Size size ) : Object , IResolutionFilter
514535 {
515536 public Android . Util . Size TargetSize { get ; set ; } = size ;
516537
517- public IList < Android . Util . Size > Filter ( IList < Android . Util . Size > supportedSizes , int rotationDegrees )
538+ public IList < Android . Util . Size > Filter ( IList < Android . Util . Size > ? supportedSizes , int rotationDegrees )
518539 {
519- var filteredList = supportedSizes
540+ var filteredList = supportedSizes ?
520541 . Where ( size => size . Width <= TargetSize . Width && size . Height <= TargetSize . Height )
521542 . OrderByDescending ( size => size . Width * size . Height ) . ToList ( ) ;
522543
523- return filteredList . Count is 0 ? supportedSizes : filteredList ;
544+ return filteredList is null || filteredList . Count is 0
545+ ? supportedSizes ?? [ ]
546+ : filteredList ;
524547 }
525548 }
526549
0 commit comments