[camera_windows] Use `CameraAccessDenied` error code for camera permission errors (#6154)

diff --git a/packages/camera/camera_windows/CHANGELOG.md b/packages/camera/camera_windows/CHANGELOG.md
index a7b8023..ef0fad4 100644
--- a/packages/camera/camera_windows/CHANGELOG.md
+++ b/packages/camera/camera_windows/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.2.0
+
+**BREAKING CHANGES**:
+  * `CameraException.code` now has value `"CameraAccessDenied"` if camera access permission was denied.
+  * `CameraException.code` now has value `"camera_error"` if error occurs during capture.
+
 ## 0.1.0+5
 
 * Fixes bugs in in error handling.
diff --git a/packages/camera/camera_windows/pubspec.yaml b/packages/camera/camera_windows/pubspec.yaml
index 690ac9f..9cf1793 100644
--- a/packages/camera/camera_windows/pubspec.yaml
+++ b/packages/camera/camera_windows/pubspec.yaml
@@ -2,7 +2,7 @@
 description: A Flutter plugin for getting information about and controlling the camera on Windows.
 repository: https://github.com/flutter/plugins/tree/main/packages/camera/camera_windows
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
-version: 0.1.0+5
+version: 0.2.0
 
 environment:
   sdk: ">=2.12.0 <3.0.0"
diff --git a/packages/camera/camera_windows/windows/camera.cpp b/packages/camera/camera_windows/windows/camera.cpp
index 794b20d..6a09447 100644
--- a/packages/camera/camera_windows/windows/camera.cpp
+++ b/packages/camera/camera_windows/windows/camera.cpp
@@ -16,6 +16,25 @@
 constexpr char kCameraClosingEvent[] = "camera_closing";
 constexpr char kErrorEvent[] = "error";
 
+// Camera error codes
+constexpr char kCameraAccessDenied[] = "CameraAccessDenied";
+constexpr char kCameraError[] = "camera_error";
+constexpr char kPluginDisposed[] = "plugin_disposed";
+
+std::string GetErrorCode(CameraResult result) {
+  assert(result != CameraResult::kSuccess);
+
+  switch (result) {
+    case CameraResult::kAccessDenied:
+      return kCameraAccessDenied;
+
+    case CameraResult::kSuccess:
+    case CameraResult::kError:
+    default:
+      return kCameraError;
+  }
+}
+
 CameraImpl::CameraImpl(const std::string& device_id)
     : device_id_(device_id), Camera(device_id) {}
 
@@ -24,7 +43,7 @@
   OnCameraClosing();
 
   capture_controller_ = nullptr;
-  SendErrorForPendingResults("plugin_disposed",
+  SendErrorForPendingResults(kPluginDisposed,
                              "Plugin disposed before request was handled");
 }
 
@@ -121,11 +140,13 @@
   }
 }
 
-void CameraImpl::OnCreateCaptureEngineFailed(const std::string& error) {
+void CameraImpl::OnCreateCaptureEngineFailed(CameraResult result,
+                                             const std::string& error) {
   auto pending_result =
       GetPendingResultByType(PendingResultType::kCreateCamera);
   if (pending_result) {
-    pending_result->Error("camera_error", error);
+    std::string error_code = GetErrorCode(result);
+    pending_result->Error(error_code, error);
   }
 }
 
@@ -141,10 +162,12 @@
   }
 };
 
-void CameraImpl::OnStartPreviewFailed(const std::string& error) {
+void CameraImpl::OnStartPreviewFailed(CameraResult result,
+                                      const std::string& error) {
   auto pending_result = GetPendingResultByType(PendingResultType::kInitialize);
   if (pending_result) {
-    pending_result->Error("camera_error", error);
+    std::string error_code = GetErrorCode(result);
+    pending_result->Error(error_code, error);
   }
 };
 
@@ -156,11 +179,13 @@
   }
 }
 
-void CameraImpl::OnResumePreviewFailed(const std::string& error) {
+void CameraImpl::OnResumePreviewFailed(CameraResult result,
+                                       const std::string& error) {
   auto pending_result =
       GetPendingResultByType(PendingResultType::kResumePreview);
   if (pending_result) {
-    pending_result->Error("camera_error", error);
+    std::string error_code = GetErrorCode(result);
+    pending_result->Error(error_code, error);
   }
 }
 
@@ -172,11 +197,13 @@
   }
 }
 
-void CameraImpl::OnPausePreviewFailed(const std::string& error) {
+void CameraImpl::OnPausePreviewFailed(CameraResult result,
+                                      const std::string& error) {
   auto pending_result =
       GetPendingResultByType(PendingResultType::kPausePreview);
   if (pending_result) {
-    pending_result->Error("camera_error", error);
+    std::string error_code = GetErrorCode(result);
+    pending_result->Error(error_code, error);
   }
 }
 
@@ -187,10 +214,12 @@
   }
 };
 
-void CameraImpl::OnStartRecordFailed(const std::string& error) {
+void CameraImpl::OnStartRecordFailed(CameraResult result,
+                                     const std::string& error) {
   auto pending_result = GetPendingResultByType(PendingResultType::kStartRecord);
   if (pending_result) {
-    pending_result->Error("camera_error", error);
+    std::string error_code = GetErrorCode(result);
+    pending_result->Error(error_code, error);
   }
 };
 
@@ -201,10 +230,12 @@
   }
 };
 
-void CameraImpl::OnStopRecordFailed(const std::string& error) {
+void CameraImpl::OnStopRecordFailed(CameraResult result,
+                                    const std::string& error) {
   auto pending_result = GetPendingResultByType(PendingResultType::kStopRecord);
   if (pending_result) {
-    pending_result->Error("camera_error", error);
+    std::string error_code = GetErrorCode(result);
+    pending_result->Error(error_code, error);
   }
 };
 
@@ -215,11 +246,13 @@
   }
 };
 
-void CameraImpl::OnTakePictureFailed(const std::string& error) {
+void CameraImpl::OnTakePictureFailed(CameraResult result,
+                                     const std::string& error) {
   auto pending_take_picture_result =
       GetPendingResultByType(PendingResultType::kTakePicture);
   if (pending_take_picture_result) {
-    pending_take_picture_result->Error("camera_error", error);
+    std::string error_code = GetErrorCode(result);
+    pending_take_picture_result->Error(error_code, error);
   }
 };
 
@@ -238,9 +271,10 @@
   }
 }
 
-void CameraImpl::OnVideoRecordFailed(const std::string& error){};
+void CameraImpl::OnVideoRecordFailed(CameraResult result,
+                                     const std::string& error){};
 
-void CameraImpl::OnCaptureError(const std::string& error) {
+void CameraImpl::OnCaptureError(CameraResult result, const std::string& error) {
   if (messenger_ && camera_id_ >= 0) {
     auto channel = GetMethodChannel();
 
@@ -250,7 +284,8 @@
     channel->InvokeMethod(kErrorEvent, std::move(message_data));
   }
 
-  SendErrorForPendingResults("capture_error", error);
+  std::string error_code = GetErrorCode(result);
+  SendErrorForPendingResults(error_code, error);
 }
 
 void CameraImpl::OnCameraClosing() {
diff --git a/packages/camera/camera_windows/windows/camera.h b/packages/camera/camera_windows/windows/camera.h
index 7374228..8508da1 100644
--- a/packages/camera/camera_windows/windows/camera.h
+++ b/packages/camera/camera_windows/windows/camera.h
@@ -87,23 +87,31 @@
 
   // CaptureControllerListener
   void OnCreateCaptureEngineSucceeded(int64_t texture_id) override;
-  void OnCreateCaptureEngineFailed(const std::string& error) override;
+  void OnCreateCaptureEngineFailed(CameraResult result,
+                                   const std::string& error) override;
   void OnStartPreviewSucceeded(int32_t width, int32_t height) override;
-  void OnStartPreviewFailed(const std::string& error) override;
+  void OnStartPreviewFailed(CameraResult result,
+                            const std::string& error) override;
   void OnPausePreviewSucceeded() override;
-  void OnPausePreviewFailed(const std::string& error) override;
+  void OnPausePreviewFailed(CameraResult result,
+                            const std::string& error) override;
   void OnResumePreviewSucceeded() override;
-  void OnResumePreviewFailed(const std::string& error) override;
+  void OnResumePreviewFailed(CameraResult result,
+                             const std::string& error) override;
   void OnStartRecordSucceeded() override;
-  void OnStartRecordFailed(const std::string& error) override;
+  void OnStartRecordFailed(CameraResult result,
+                           const std::string& error) override;
   void OnStopRecordSucceeded(const std::string& file_path) override;
-  void OnStopRecordFailed(const std::string& error) override;
+  void OnStopRecordFailed(CameraResult result,
+                          const std::string& error) override;
   void OnTakePictureSucceeded(const std::string& file_path) override;
-  void OnTakePictureFailed(const std::string& error) override;
+  void OnTakePictureFailed(CameraResult result,
+                           const std::string& error) override;
   void OnVideoRecordSucceeded(const std::string& file_path,
                               int64_t video_duration) override;
-  void OnVideoRecordFailed(const std::string& error) override;
-  void OnCaptureError(const std::string& error) override;
+  void OnVideoRecordFailed(CameraResult result,
+                           const std::string& error) override;
+  void OnCaptureError(CameraResult result, const std::string& error) override;
 
   // Camera
   bool HasDeviceId(std::string& device_id) const override {
diff --git a/packages/camera/camera_windows/windows/capture_controller.cpp b/packages/camera/camera_windows/windows/capture_controller.cpp
index 0294ce8..384c86a 100644
--- a/packages/camera/camera_windows/windows/capture_controller.cpp
+++ b/packages/camera/camera_windows/windows/capture_controller.cpp
@@ -22,6 +22,15 @@
 
 using Microsoft::WRL::ComPtr;
 
+CameraResult GetCameraResult(HRESULT hr) {
+  if (SUCCEEDED(hr)) {
+    return CameraResult::kSuccess;
+  }
+
+  return hr == E_ACCESSDENIED ? CameraResult::kAccessDenied
+                              : CameraResult::kError;
+}
+
 CaptureControllerImpl::CaptureControllerImpl(
     CaptureControllerListener* listener)
     : capture_controller_listener_(listener), CaptureController(){};
@@ -297,11 +306,11 @@
 
   if (IsInitialized()) {
     capture_controller_listener_->OnCreateCaptureEngineFailed(
-        "Capture device already initialized");
+        CameraResult::kError, "Capture device already initialized");
     return false;
   } else if (capture_engine_state_ == CaptureEngineState::kInitializing) {
     capture_controller_listener_->OnCreateCaptureEngineFailed(
-        "Capture device already initializing");
+        CameraResult::kError, "Capture device already initializing");
     return false;
   }
 
@@ -317,7 +326,7 @@
 
     if (FAILED(hr)) {
       capture_controller_listener_->OnCreateCaptureEngineFailed(
-          "Failed to create camera");
+          GetCameraResult(hr), "Failed to create camera");
       ResetCaptureController();
       return false;
     }
@@ -328,7 +337,7 @@
   HRESULT hr = CreateCaptureEngine();
   if (FAILED(hr)) {
     capture_controller_listener_->OnCreateCaptureEngineFailed(
-        "Failed to create camera");
+        GetCameraResult(hr), "Failed to create camera");
     ResetCaptureController();
     return false;
   }
@@ -341,29 +350,34 @@
   assert(capture_engine_);
 
   if (!IsInitialized()) {
-    return OnPicture(false, "Not initialized");
+    return OnPicture(CameraResult::kError, "Not initialized");
   }
 
+  HRESULT hr = S_OK;
+
   if (!base_capture_media_type_) {
     // Enumerates mediatypes and finds media type for video capture.
-    if (FAILED(FindBaseMediaTypes())) {
-      return OnPicture(false, "Failed to initialize photo capture");
+    hr = FindBaseMediaTypes();
+    if (FAILED(hr)) {
+      return OnPicture(GetCameraResult(hr),
+                       "Failed to initialize photo capture");
     }
   }
 
   if (!photo_handler_) {
     photo_handler_ = std::make_unique<PhotoHandler>();
   } else if (photo_handler_->IsTakingPhoto()) {
-    return OnPicture(false, "Photo already requested");
+    return OnPicture(CameraResult::kError, "Photo already requested");
   }
 
   // Check MF_CAPTURE_ENGINE_PHOTO_TAKEN event handling
   // for response process.
-  if (!photo_handler_->TakePhoto(file_path, capture_engine_.Get(),
-                                 base_capture_media_type_.Get())) {
+  hr = photo_handler_->TakePhoto(file_path, capture_engine_.Get(),
+                                 base_capture_media_type_.Get());
+  if (FAILED(hr)) {
     // Destroy photo handler on error cases to make sure state is resetted.
     photo_handler_ = nullptr;
-    return OnPicture(false, "Failed to take photo");
+    return OnPicture(GetCameraResult(hr), "Failed to take photo");
   }
 }
 
@@ -487,15 +501,19 @@
   assert(capture_engine_);
 
   if (!IsInitialized()) {
-    return OnRecordStarted(false,
+    return OnRecordStarted(CameraResult::kError,
                            "Camera not initialized. Camera should be "
                            "disposed and reinitialized.");
   }
 
+  HRESULT hr = S_OK;
+
   if (!base_capture_media_type_) {
     // Enumerates mediatypes and finds media type for video capture.
-    if (FAILED(FindBaseMediaTypes())) {
-      return OnRecordStarted(false, "Failed to initialize video recording");
+    hr = FindBaseMediaTypes();
+    if (FAILED(hr)) {
+      return OnRecordStarted(GetCameraResult(hr),
+                             "Failed to initialize video recording");
     }
   }
 
@@ -503,19 +521,21 @@
     record_handler_ = std::make_unique<RecordHandler>(record_audio_);
   } else if (!record_handler_->CanStart()) {
     return OnRecordStarted(
-        false,
+        CameraResult::kError,
         "Recording cannot be started. Previous recording must be stopped "
         "first.");
   }
 
   // Check MF_CAPTURE_ENGINE_RECORD_STARTED event handling for response
   // process.
-  if (!record_handler_->StartRecord(file_path, max_video_duration_ms,
+  hr = record_handler_->StartRecord(file_path, max_video_duration_ms,
                                     capture_engine_.Get(),
-                                    base_capture_media_type_.Get())) {
+                                    base_capture_media_type_.Get());
+  if (FAILED(hr)) {
     // Destroy record handler on error cases to make sure state is resetted.
     record_handler_ = nullptr;
-    return OnRecordStarted(false, "Failed to start video recording");
+    return OnRecordStarted(GetCameraResult(hr),
+                           "Failed to start video recording");
   }
 }
 
@@ -523,19 +543,22 @@
   assert(capture_controller_listener_);
 
   if (!IsInitialized()) {
-    return OnRecordStopped(false,
+    return OnRecordStopped(CameraResult::kError,
                            "Camera not initialized. Camera should be "
                            "disposed and reinitialized.");
   }
 
   if (!record_handler_ && !record_handler_->CanStop()) {
-    return OnRecordStopped(false, "Recording cannot be stopped.");
+    return OnRecordStopped(CameraResult::kError,
+                           "Recording cannot be stopped.");
   }
 
   // Check MF_CAPTURE_ENGINE_RECORD_STOPPED event handling for response
   // process.
-  if (!record_handler_->StopRecord(capture_engine_.Get())) {
-    return OnRecordStopped(false, "Failed to stop video recording");
+  HRESULT hr = record_handler_->StopRecord(capture_engine_.Get());
+  if (FAILED(hr)) {
+    return OnRecordStopped(GetCameraResult(hr),
+                           "Failed to stop video recording");
   }
 }
 
@@ -547,11 +570,12 @@
     return;
   }
 
-  if (!record_handler_->StopRecord(capture_engine_.Get())) {
+  HRESULT hr = record_handler_->StopRecord(capture_engine_.Get());
+  if (FAILED(hr)) {
     // Destroy record handler on error cases to make sure state is resetted.
     record_handler_ = nullptr;
     return capture_controller_listener_->OnVideoRecordFailed(
-        "Failed to record video");
+        GetCameraResult(hr), "Failed to record video");
   }
 }
 
@@ -563,15 +587,19 @@
   assert(texture_handler_);
 
   if (!IsInitialized() || !texture_handler_) {
-    return OnPreviewStarted(false,
+    return OnPreviewStarted(CameraResult::kError,
                             "Camera not initialized. Camera should be "
                             "disposed and reinitialized.");
   }
 
+  HRESULT hr = S_OK;
+
   if (!base_preview_media_type_) {
     // Enumerates mediatypes and finds media type for video capture.
-    if (FAILED(FindBaseMediaTypes())) {
-      return OnPreviewStarted(false, "Failed to initialize video preview");
+    hr = FindBaseMediaTypes();
+    if (FAILED(hr)) {
+      return OnPreviewStarted(GetCameraResult(hr),
+                              "Failed to initialize video preview");
     }
   }
 
@@ -583,19 +611,22 @@
   if (!preview_handler_) {
     preview_handler_ = std::make_unique<PreviewHandler>();
   } else if (preview_handler_->IsInitialized()) {
-    return OnPreviewStarted(true, "");
+    return OnPreviewStarted(CameraResult::kSuccess, "");
   } else {
-    return OnPreviewStarted(false, "Preview already exists");
+    return OnPreviewStarted(CameraResult::kError, "Preview already exists");
   }
 
   // Check MF_CAPTURE_ENGINE_PREVIEW_STARTED event handling for response
   // process.
-  if (!preview_handler_->StartPreview(capture_engine_.Get(),
+  hr = preview_handler_->StartPreview(capture_engine_.Get(),
                                       base_preview_media_type_.Get(),
-                                      capture_engine_callback_handler_.Get())) {
+                                      capture_engine_callback_handler_.Get());
+
+  if (FAILED(hr)) {
     // Destroy preview handler on error cases to make sure state is resetted.
     preview_handler_ = nullptr;
-    return OnPreviewStarted(false, "Failed to start video preview");
+    return OnPreviewStarted(GetCameraResult(hr),
+                            "Failed to start video preview");
   }
 }
 
@@ -604,15 +635,15 @@
 // pausing and resuming the preview.
 // Check MF_CAPTURE_ENGINE_PREVIEW_STOPPED event handling for response
 // process.
-void CaptureControllerImpl::StopPreview() {
+HRESULT CaptureControllerImpl::StopPreview() {
   assert(capture_engine_);
 
   if (!IsInitialized() || !preview_handler_) {
-    return;
+    return S_OK;
   }
 
   // Requests to stop preview.
-  preview_handler_->StopPreview(capture_engine_.Get());
+  return preview_handler_->StopPreview(capture_engine_.Get());
 }
 
 // Marks preview as paused.
@@ -623,14 +654,14 @@
 
   if (!preview_handler_ || !preview_handler_->IsInitialized()) {
     return capture_controller_listener_->OnPausePreviewFailed(
-        "Preview not started");
+        CameraResult::kError, "Preview not started");
   }
 
   if (preview_handler_->PausePreview()) {
     capture_controller_listener_->OnPausePreviewSucceeded();
   } else {
     capture_controller_listener_->OnPausePreviewFailed(
-        "Failed to pause preview");
+        CameraResult::kError, "Failed to pause preview");
   }
 }
 
@@ -642,14 +673,14 @@
 
   if (!preview_handler_ || !preview_handler_->IsInitialized()) {
     return capture_controller_listener_->OnResumePreviewFailed(
-        "Preview not started");
+        CameraResult::kError, "Preview not started");
   }
 
   if (preview_handler_->ResumePreview()) {
     capture_controller_listener_->OnResumePreviewSucceeded();
   } else {
     capture_controller_listener_->OnResumePreviewFailed(
-        "Failed to pause preview");
+        CameraResult::kError, "Failed to pause preview");
   }
 }
 
@@ -677,22 +708,23 @@
       error = Utf8FromUtf16(err.ErrorMessage());
     }
 
+    CameraResult event_result = GetCameraResult(event_hr);
     if (extended_type_guid == MF_CAPTURE_ENGINE_ERROR) {
-      OnCaptureEngineError(event_hr, error);
+      OnCaptureEngineError(event_result, error);
     } else if (extended_type_guid == MF_CAPTURE_ENGINE_INITIALIZED) {
-      OnCaptureEngineInitialized(SUCCEEDED(event_hr), error);
+      OnCaptureEngineInitialized(event_result, error);
     } else if (extended_type_guid == MF_CAPTURE_ENGINE_PREVIEW_STARTED) {
       // Preview is marked as started after first frame is captured.
       // This is because, CaptureEngine might inform that preview is started
       // even if error is thrown right after.
     } else if (extended_type_guid == MF_CAPTURE_ENGINE_PREVIEW_STOPPED) {
-      OnPreviewStopped(SUCCEEDED(event_hr), error);
+      OnPreviewStopped(event_result, error);
     } else if (extended_type_guid == MF_CAPTURE_ENGINE_RECORD_STARTED) {
-      OnRecordStarted(SUCCEEDED(event_hr), error);
+      OnRecordStarted(event_result, error);
     } else if (extended_type_guid == MF_CAPTURE_ENGINE_RECORD_STOPPED) {
-      OnRecordStopped(SUCCEEDED(event_hr), error);
+      OnRecordStopped(event_result, error);
     } else if (extended_type_guid == MF_CAPTURE_ENGINE_PHOTO_TAKEN) {
-      OnPicture(SUCCEEDED(event_hr), error);
+      OnPicture(event_result, error);
     } else if (extended_type_guid == MF_CAPTURE_ENGINE_CAMERA_STREAM_BLOCKED) {
       // TODO: Inform capture state to flutter.
     } else if (extended_type_guid ==
@@ -703,8 +735,9 @@
 }
 
 // Handles Picture event and informs CaptureControllerListener.
-void CaptureControllerImpl::OnPicture(bool success, const std::string& error) {
-  if (success && photo_handler_) {
+void CaptureControllerImpl::OnPicture(CameraResult result,
+                                      const std::string& error) {
+  if (result == CameraResult::kSuccess && photo_handler_) {
     if (capture_controller_listener_) {
       std::string path = photo_handler_->GetPhotoPath();
       capture_controller_listener_->OnTakePictureSucceeded(path);
@@ -712,7 +745,7 @@
     photo_handler_->OnPhotoTaken();
   } else {
     if (capture_controller_listener_) {
-      capture_controller_listener_->OnTakePictureFailed(error);
+      capture_controller_listener_->OnTakePictureFailed(result, error);
     }
     // Destroy photo handler on error cases to make sure state is resetted.
     photo_handler_ = nullptr;
@@ -722,11 +755,11 @@
 // Handles CaptureEngineInitialized event and informs
 // CaptureControllerListener.
 void CaptureControllerImpl::OnCaptureEngineInitialized(
-    bool success, const std::string& error) {
+    CameraResult result, const std::string& error) {
   if (capture_controller_listener_) {
-    if (!success) {
+    if (result != CameraResult::kSuccess) {
       capture_controller_listener_->OnCreateCaptureEngineFailed(
-          "Failed to initialize capture engine");
+          result, "Failed to initialize capture engine");
       ResetCaptureController();
       return;
     }
@@ -740,7 +773,7 @@
       capture_engine_state_ = CaptureEngineState::kInitialized;
     } else {
       capture_controller_listener_->OnCreateCaptureEngineFailed(
-          "Failed to create texture_id");
+          CameraResult::kError, "Failed to create texture_id");
       // Reset state
       ResetCaptureController();
     }
@@ -748,10 +781,10 @@
 }
 
 // Handles CaptureEngineError event and informs CaptureControllerListener.
-void CaptureControllerImpl::OnCaptureEngineError(HRESULT hr,
+void CaptureControllerImpl::OnCaptureEngineError(CameraResult result,
                                                  const std::string& error) {
   if (capture_controller_listener_) {
-    capture_controller_listener_->OnCaptureError(error);
+    capture_controller_listener_->OnCaptureError(result, error);
   }
 
   // TODO: If MF_CAPTURE_ENGINE_ERROR is returned,
@@ -761,9 +794,9 @@
 // Handles PreviewStarted event and informs CaptureControllerListener.
 // This should be called only after first frame has been received or
 // in error cases.
-void CaptureControllerImpl::OnPreviewStarted(bool success,
+void CaptureControllerImpl::OnPreviewStarted(CameraResult result,
                                              const std::string& error) {
-  if (preview_handler_ && success) {
+  if (preview_handler_ && result == CameraResult::kSuccess) {
     preview_handler_->OnPreviewStarted();
   } else {
     // Destroy preview handler on error cases to make sure state is resetted.
@@ -771,17 +804,18 @@
   }
 
   if (capture_controller_listener_) {
-    if (success && preview_frame_width_ > 0 && preview_frame_height_ > 0) {
+    if (result == CameraResult::kSuccess && preview_frame_width_ > 0 &&
+        preview_frame_height_ > 0) {
       capture_controller_listener_->OnStartPreviewSucceeded(
           preview_frame_width_, preview_frame_height_);
     } else {
-      capture_controller_listener_->OnStartPreviewFailed(error);
+      capture_controller_listener_->OnStartPreviewFailed(result, error);
     }
   }
 };
 
 // Handles PreviewStopped event.
-void CaptureControllerImpl::OnPreviewStopped(bool success,
+void CaptureControllerImpl::OnPreviewStopped(CameraResult result,
                                              const std::string& error) {
   // Preview handler is destroyed if preview is stopped as it
   // does not have any use anymore.
@@ -789,16 +823,16 @@
 };
 
 // Handles RecordStarted event and informs CaptureControllerListener.
-void CaptureControllerImpl::OnRecordStarted(bool success,
+void CaptureControllerImpl::OnRecordStarted(CameraResult result,
                                             const std::string& error) {
-  if (success && record_handler_) {
+  if (result == CameraResult::kSuccess && record_handler_) {
     record_handler_->OnRecordStarted();
     if (capture_controller_listener_) {
       capture_controller_listener_->OnStartRecordSucceeded();
     }
   } else {
     if (capture_controller_listener_) {
-      capture_controller_listener_->OnStartRecordFailed(error);
+      capture_controller_listener_->OnStartRecordFailed(result, error);
     }
 
     // Destroy record handler on error cases to make sure state is resetted.
@@ -807,13 +841,13 @@
 };
 
 // Handles RecordStopped event and informs CaptureControllerListener.
-void CaptureControllerImpl::OnRecordStopped(bool success,
+void CaptureControllerImpl::OnRecordStopped(CameraResult result,
                                             const std::string& error) {
   if (capture_controller_listener_ && record_handler_) {
     // Always calls OnStopRecord listener methods
     // to handle separate stop record request for timed records.
 
-    if (success) {
+    if (result == CameraResult::kSuccess) {
       std::string path = record_handler_->GetRecordPath();
       capture_controller_listener_->OnStopRecordSucceeded(path);
       if (record_handler_->IsTimedRecording()) {
@@ -821,14 +855,14 @@
             path, (record_handler_->GetRecordedDuration() / 1000));
       }
     } else {
-      capture_controller_listener_->OnStopRecordFailed(error);
+      capture_controller_listener_->OnStopRecordFailed(result, error);
       if (record_handler_->IsTimedRecording()) {
-        capture_controller_listener_->OnVideoRecordFailed(error);
+        capture_controller_listener_->OnVideoRecordFailed(result, error);
       }
     }
   }
 
-  if (success && record_handler_) {
+  if (result == CameraResult::kSuccess && record_handler_) {
     record_handler_->OnRecordStopped();
   } else {
     // Destroy record handler on error cases to make sure state is resetted.
@@ -859,7 +893,7 @@
   if (preview_handler_ && preview_handler_->IsStarting()) {
     // Informs that first frame is captured successfully and preview has
     // started.
-    OnPreviewStarted(true, "");
+    OnPreviewStarted(CameraResult::kSuccess, "");
   }
 
   // Checks if max_video_duration_ms is passed.
diff --git a/packages/camera/camera_windows/windows/capture_controller.h b/packages/camera/camera_windows/windows/capture_controller.h
index 0b7ab66..9536be7 100644
--- a/packages/camera/camera_windows/windows/capture_controller.h
+++ b/packages/camera/camera_windows/windows/capture_controller.h
@@ -207,28 +207,29 @@
   void StopTimedRecord();
 
   // Stops preview. Called internally on camera reset and dispose.
-  void StopPreview();
+  HRESULT StopPreview();
 
   // Handles capture engine initalization event.
-  void OnCaptureEngineInitialized(bool success, const std::string& error);
+  void OnCaptureEngineInitialized(CameraResult result,
+                                  const std::string& error);
 
   // Handles capture engine errors.
-  void OnCaptureEngineError(HRESULT hr, const std::string& error);
+  void OnCaptureEngineError(CameraResult result, const std::string& error);
 
   // Handles picture events.
-  void OnPicture(bool success, const std::string& error);
+  void OnPicture(CameraResult result, const std::string& error);
 
   // Handles preview started events.
-  void OnPreviewStarted(bool success, const std::string& error);
+  void OnPreviewStarted(CameraResult result, const std::string& error);
 
   // Handles preview stopped events.
-  void OnPreviewStopped(bool success, const std::string& error);
+  void OnPreviewStopped(CameraResult result, const std::string& error);
 
   // Handles record started events.
-  void OnRecordStarted(bool success, const std::string& error);
+  void OnRecordStarted(CameraResult result, const std::string& error);
 
   // Handles record stopped events.
-  void OnRecordStopped(bool success, const std::string& error);
+  void OnRecordStopped(CameraResult result, const std::string& error);
 
   bool media_foundation_started_ = false;
   bool record_audio_ = false;
diff --git a/packages/camera/camera_windows/windows/capture_controller_listener.h b/packages/camera/camera_windows/windows/capture_controller_listener.h
index 0e713ea..bc7a173 100644
--- a/packages/camera/camera_windows/windows/capture_controller_listener.h
+++ b/packages/camera/camera_windows/windows/capture_controller_listener.h
@@ -9,6 +9,18 @@
 
 namespace camera_windows {
 
+// Results that can occur when interacting with the camera.
+enum class CameraResult {
+  // Camera operation succeeded.
+  kSuccess,
+
+  // Camera operation failed.
+  kError,
+
+  // Camera access permission is denied.
+  kAccessDenied,
+};
+
 // Interface for classes that receives callbacks on events from the associated
 // |CaptureController|.
 class CaptureControllerListener {
@@ -22,8 +34,10 @@
 
   // Called by CaptureController if initializing the capture engine fails.
   //
+  // result: The kind of result.
   // error: A string describing the error.
-  virtual void OnCreateCaptureEngineFailed(const std::string& error) = 0;
+  virtual void OnCreateCaptureEngineFailed(CameraResult result,
+                                           const std::string& error) = 0;
 
   // Called by CaptureController on successfully started preview.
   //
@@ -33,32 +47,40 @@
 
   // Called by CaptureController if starting the preview fails.
   //
+  // result: The kind of result.
   // error: A string describing the error.
-  virtual void OnStartPreviewFailed(const std::string& error) = 0;
+  virtual void OnStartPreviewFailed(CameraResult result,
+                                    const std::string& error) = 0;
 
   // Called by CaptureController on successfully paused preview.
   virtual void OnPausePreviewSucceeded() = 0;
 
   // Called by CaptureController if pausing the preview fails.
   //
+  // result: The kind of result.
   // error: A string describing the error.
-  virtual void OnPausePreviewFailed(const std::string& error) = 0;
+  virtual void OnPausePreviewFailed(CameraResult result,
+                                    const std::string& error) = 0;
 
   // Called by CaptureController on successfully resumed preview.
   virtual void OnResumePreviewSucceeded() = 0;
 
   // Called by CaptureController if resuming the preview fails.
   //
+  // result: The kind of result.
   // error: A string describing the error.
-  virtual void OnResumePreviewFailed(const std::string& error) = 0;
+  virtual void OnResumePreviewFailed(CameraResult result,
+                                     const std::string& error) = 0;
 
   // Called by CaptureController on successfully started recording.
   virtual void OnStartRecordSucceeded() = 0;
 
   // Called by CaptureController if starting the recording fails.
   //
+  // result: The kind of result.
   // error: A string describing the error.
-  virtual void OnStartRecordFailed(const std::string& error) = 0;
+  virtual void OnStartRecordFailed(CameraResult result,
+                                   const std::string& error) = 0;
 
   // Called by CaptureController on successfully stopped recording.
   //
@@ -67,8 +89,10 @@
 
   // Called by CaptureController if stopping the recording fails.
   //
+  // result: The kind of result.
   // error: A string describing the error.
-  virtual void OnStopRecordFailed(const std::string& error) = 0;
+  virtual void OnStopRecordFailed(CameraResult result,
+                                  const std::string& error) = 0;
 
   // Called by CaptureController on successfully captured picture.
   //
@@ -77,8 +101,10 @@
 
   // Called by CaptureController if taking picture fails.
   //
+  // result: The kind of result.
   // error: A string describing the error.
-  virtual void OnTakePictureFailed(const std::string& error) = 0;
+  virtual void OnTakePictureFailed(CameraResult result,
+                                   const std::string& error) = 0;
 
   // Called by CaptureController when timed recording is successfully recorded.
   //
@@ -89,14 +115,18 @@
 
   // Called by CaptureController if timed recording fails.
   //
+  // result: The kind of result.
   // error: A string describing the error.
-  virtual void OnVideoRecordFailed(const std::string& error) = 0;
+  virtual void OnVideoRecordFailed(CameraResult result,
+                                   const std::string& error) = 0;
 
   // Called by CaptureController if capture engine returns error.
   // For example when camera is disconnected while on use.
   //
+  // result: The kind of result.
   // error: A string describing the error.
-  virtual void OnCaptureError(const std::string& error) = 0;
+  virtual void OnCaptureError(CameraResult result,
+                              const std::string& error) = 0;
 };
 
 }  // namespace camera_windows
diff --git a/packages/camera/camera_windows/windows/photo_handler.cpp b/packages/camera/camera_windows/windows/photo_handler.cpp
index 10df230..479f0d3 100644
--- a/packages/camera/camera_windows/windows/photo_handler.cpp
+++ b/packages/camera/camera_windows/windows/photo_handler.cpp
@@ -116,21 +116,23 @@
   return hr;
 }
 
-bool PhotoHandler::TakePhoto(const std::string& file_path,
-                             IMFCaptureEngine* capture_engine,
-                             IMFMediaType* base_media_type) {
+HRESULT PhotoHandler::TakePhoto(const std::string& file_path,
+                                IMFCaptureEngine* capture_engine,
+                                IMFMediaType* base_media_type) {
   assert(!file_path.empty());
   assert(capture_engine);
   assert(base_media_type);
 
   file_path_ = file_path;
 
-  if (FAILED(InitPhotoSink(capture_engine, base_media_type))) {
-    return false;
+  HRESULT hr = InitPhotoSink(capture_engine, base_media_type);
+  if (FAILED(hr)) {
+    return hr;
   }
 
   photo_state_ = PhotoState::kTakingPhoto;
-  return SUCCEEDED(capture_engine->TakePhoto());
+
+  return capture_engine->TakePhoto();
 }
 
 void PhotoHandler::OnPhotoTaken() {
diff --git a/packages/camera/camera_windows/windows/photo_handler.h b/packages/camera/camera_windows/windows/photo_handler.h
index c12643b..4d6ddf1 100644
--- a/packages/camera/camera_windows/windows/photo_handler.h
+++ b/packages/camera/camera_windows/windows/photo_handler.h
@@ -41,15 +41,15 @@
   // to take photo.
   //
   // Sets photo state to: kTakingPhoto.
-  // Returns false if photo cannot be taken.
   //
   // capture_engine:  A pointer to capture engine instance.
   //                  Called to take the photo.
   // base_media_type: A pointer to base media type used as a base
   //                  for the actual photo capture media type.
   // file_path:       A string that hold file path for photo capture.
-  bool TakePhoto(const std::string& file_path, IMFCaptureEngine* capture_engine,
-                 IMFMediaType* base_media_type);
+  HRESULT TakePhoto(const std::string& file_path,
+                    IMFCaptureEngine* capture_engine,
+                    IMFMediaType* base_media_type);
 
   // Set the photo handler recording state to: kIdle.
   void OnPhotoTaken();
diff --git a/packages/camera/camera_windows/windows/preview_handler.cpp b/packages/camera/camera_windows/windows/preview_handler.cpp
index d7fb272..538754c 100644
--- a/packages/camera/camera_windows/windows/preview_handler.cpp
+++ b/packages/camera/camera_windows/windows/preview_handler.cpp
@@ -113,29 +113,31 @@
   return hr;
 }
 
-bool PreviewHandler::StartPreview(IMFCaptureEngine* capture_engine,
-                                  IMFMediaType* base_media_type,
-                                  CaptureEngineListener* sample_callback) {
+HRESULT PreviewHandler::StartPreview(IMFCaptureEngine* capture_engine,
+                                     IMFMediaType* base_media_type,
+                                     CaptureEngineListener* sample_callback) {
   assert(capture_engine);
   assert(base_media_type);
 
-  if (FAILED(
-          InitPreviewSink(capture_engine, base_media_type, sample_callback))) {
-    return false;
+  HRESULT hr =
+      InitPreviewSink(capture_engine, base_media_type, sample_callback);
+
+  if (FAILED(hr)) {
+    return hr;
   }
 
   preview_state_ = PreviewState::kStarting;
-  return SUCCEEDED(capture_engine->StartPreview());
+  return capture_engine->StartPreview();
 }
 
-bool PreviewHandler::StopPreview(IMFCaptureEngine* capture_engine) {
+HRESULT PreviewHandler::StopPreview(IMFCaptureEngine* capture_engine) {
   if (preview_state_ == PreviewState::kStarting ||
       preview_state_ == PreviewState::kRunning ||
       preview_state_ == PreviewState::kPaused) {
     preview_state_ = PreviewState::kStopping;
-    return SUCCEEDED(capture_engine->StopPreview());
+    return capture_engine->StopPreview();
   }
-  return false;
+  return E_FAIL;
 }
 
 bool PreviewHandler::PausePreview() {
diff --git a/packages/camera/camera_windows/windows/preview_handler.h b/packages/camera/camera_windows/windows/preview_handler.h
index a10ba63..311cf5a 100644
--- a/packages/camera/camera_windows/windows/preview_handler.h
+++ b/packages/camera/camera_windows/windows/preview_handler.h
@@ -45,7 +45,6 @@
 
   // Initializes preview sink and requests capture engine to start previewing.
   // Sets preview state to: starting.
-  // Returns false if recording cannot be started.
   //
   // capture_engine:  A pointer to capture engine instance. Used to start
   //                  the actual recording.
@@ -53,16 +52,15 @@
   //                  for the actual video capture media type.
   // sample_callback: A pointer to capture engine listener.
   //                  This is set as sample callback for preview sink.
-  bool StartPreview(IMFCaptureEngine* capture_engine,
-                    IMFMediaType* base_media_type,
-                    CaptureEngineListener* sample_callback);
+  HRESULT StartPreview(IMFCaptureEngine* capture_engine,
+                       IMFMediaType* base_media_type,
+                       CaptureEngineListener* sample_callback);
 
   // Stops existing recording.
-  // Returns false if recording cannot be stopped.
   //
   // capture_engine:  A pointer to capture engine instance. Used to stop
   //                  the ongoing recording.
-  bool StopPreview(IMFCaptureEngine* capture_engine);
+  HRESULT StopPreview(IMFCaptureEngine* capture_engine);
 
   // Set the preview handler recording state to: paused.
   bool PausePreview();
diff --git a/packages/camera/camera_windows/windows/record_handler.cpp b/packages/camera/camera_windows/windows/record_handler.cpp
index 2e16527..0f71925 100644
--- a/packages/camera/camera_windows/windows/record_handler.cpp
+++ b/packages/camera/camera_windows/windows/record_handler.cpp
@@ -192,10 +192,10 @@
   return hr;
 }
 
-bool RecordHandler::StartRecord(const std::string& file_path,
-                                int64_t max_duration,
-                                IMFCaptureEngine* capture_engine,
-                                IMFMediaType* base_media_type) {
+HRESULT RecordHandler::StartRecord(const std::string& file_path,
+                                   int64_t max_duration,
+                                   IMFCaptureEngine* capture_engine,
+                                   IMFMediaType* base_media_type) {
   assert(!file_path.empty());
   assert(capture_engine);
   assert(base_media_type);
@@ -206,23 +206,21 @@
   recording_start_timestamp_us_ = -1;
   recording_duration_us_ = 0;
 
-  if (FAILED(InitRecordSink(capture_engine, base_media_type))) {
-    return false;
+  HRESULT hr = InitRecordSink(capture_engine, base_media_type);
+  if (FAILED(hr)) {
+    return hr;
   }
 
   recording_state_ = RecordState::kStarting;
-  capture_engine->StartRecord();
-
-  return true;
+  return capture_engine->StartRecord();
 }
 
-bool RecordHandler::StopRecord(IMFCaptureEngine* capture_engine) {
+HRESULT RecordHandler::StopRecord(IMFCaptureEngine* capture_engine) {
   if (recording_state_ == RecordState::kRunning) {
     recording_state_ = RecordState::kStopping;
-    HRESULT hr = capture_engine->StopRecord(true, false);
-    return SUCCEEDED(hr);
+    return capture_engine->StopRecord(true, false);
   }
-  return false;
+  return E_FAIL;
 }
 
 void RecordHandler::OnRecordStarted() {
diff --git a/packages/camera/camera_windows/windows/record_handler.h b/packages/camera/camera_windows/windows/record_handler.h
index 4cbe499..0c87bf9 100644
--- a/packages/camera/camera_windows/windows/record_handler.h
+++ b/packages/camera/camera_windows/windows/record_handler.h
@@ -45,7 +45,6 @@
   // Initializes record sink and requests capture engine to start recording.
   //
   // Sets record state to: starting.
-  // Returns false if recording cannot be started.
   //
   // file_path:       A string that hold file path for video capture.
   // max_duration:    A int64 value of maximun recording duration.
@@ -55,16 +54,15 @@
   //                  the actual recording.
   // base_media_type: A pointer to base media type used as a base
   //                  for the actual video capture media type.
-  bool StartRecord(const std::string& file_path, int64_t max_duration,
-                   IMFCaptureEngine* capture_engine,
-                   IMFMediaType* base_media_type);
+  HRESULT StartRecord(const std::string& file_path, int64_t max_duration,
+                      IMFCaptureEngine* capture_engine,
+                      IMFMediaType* base_media_type);
 
   // Stops existing recording.
-  // Returns false if recording cannot be stopped.
   //
   // capture_engine:  A pointer to capture engine instance. Used to stop
   //                  the ongoing recording.
-  bool StopRecord(IMFCaptureEngine* capture_engine);
+  HRESULT StopRecord(IMFCaptureEngine* capture_engine);
 
   // Set the record handler recording state to: running.
   void OnRecordStarted();
diff --git a/packages/camera/camera_windows/windows/test/camera_test.cpp b/packages/camera/camera_windows/windows/test/camera_test.cpp
index 50f4953..158a2c2 100644
--- a/packages/camera/camera_windows/windows/test/camera_test.cpp
+++ b/packages/camera/camera_windows/windows/test/camera_test.cpp
@@ -137,14 +137,31 @@
   std::unique_ptr<MockMethodResult> result =
       std::make_unique<MockMethodResult>();
 
-  std::string error_text = "error_text";
+  const std::string error_text = "error_text";
 
   EXPECT_CALL(*result, SuccessInternal).Times(0);
   EXPECT_CALL(*result, ErrorInternal(Eq("camera_error"), Eq(error_text), _));
 
   camera->AddPendingResult(PendingResultType::kCreateCamera, std::move(result));
 
-  camera->OnCreateCaptureEngineFailed(error_text);
+  camera->OnCreateCaptureEngineFailed(CameraResult::kError, error_text);
+}
+
+TEST(Camera, CreateCaptureEngineReportsAccessDenied) {
+  std::unique_ptr<CameraImpl> camera =
+      std::make_unique<CameraImpl>(MOCK_DEVICE_ID);
+  std::unique_ptr<MockMethodResult> result =
+      std::make_unique<MockMethodResult>();
+
+  const std::string error_text = "error_text";
+
+  EXPECT_CALL(*result, SuccessInternal).Times(0);
+  EXPECT_CALL(*result,
+              ErrorInternal(Eq("CameraAccessDenied"), Eq(error_text), _));
+
+  camera->AddPendingResult(PendingResultType::kCreateCamera, std::move(result));
+
+  camera->OnCreateCaptureEngineFailed(CameraResult::kAccessDenied, error_text);
 }
 
 TEST(Camera, OnStartPreviewSucceededReturnsFrameSize) {
@@ -175,14 +192,31 @@
   std::unique_ptr<MockMethodResult> result =
       std::make_unique<MockMethodResult>();
 
-  std::string error_text = "error_text";
+  const std::string error_text = "error_text";
 
   EXPECT_CALL(*result, SuccessInternal).Times(0);
   EXPECT_CALL(*result, ErrorInternal(Eq("camera_error"), Eq(error_text), _));
 
   camera->AddPendingResult(PendingResultType::kInitialize, std::move(result));
 
-  camera->OnStartPreviewFailed(error_text);
+  camera->OnStartPreviewFailed(CameraResult::kError, error_text);
+}
+
+TEST(Camera, StartPreviewReportsAccessDenied) {
+  std::unique_ptr<CameraImpl> camera =
+      std::make_unique<CameraImpl>(MOCK_DEVICE_ID);
+  std::unique_ptr<MockMethodResult> result =
+      std::make_unique<MockMethodResult>();
+
+  const std::string error_text = "error_text";
+
+  EXPECT_CALL(*result, SuccessInternal).Times(0);
+  EXPECT_CALL(*result,
+              ErrorInternal(Eq("CameraAccessDenied"), Eq(error_text), _));
+
+  camera->AddPendingResult(PendingResultType::kInitialize, std::move(result));
+
+  camera->OnStartPreviewFailed(CameraResult::kAccessDenied, error_text);
 }
 
 TEST(Camera, OnPausePreviewSucceededReturnsSuccess) {
@@ -205,14 +239,31 @@
   std::unique_ptr<MockMethodResult> result =
       std::make_unique<MockMethodResult>();
 
-  std::string error_text = "error_text";
+  const std::string error_text = "error_text";
 
   EXPECT_CALL(*result, SuccessInternal).Times(0);
   EXPECT_CALL(*result, ErrorInternal(Eq("camera_error"), Eq(error_text), _));
 
   camera->AddPendingResult(PendingResultType::kPausePreview, std::move(result));
 
-  camera->OnPausePreviewFailed(error_text);
+  camera->OnPausePreviewFailed(CameraResult::kError, error_text);
+}
+
+TEST(Camera, PausePreviewReportsAccessDenied) {
+  std::unique_ptr<CameraImpl> camera =
+      std::make_unique<CameraImpl>(MOCK_DEVICE_ID);
+  std::unique_ptr<MockMethodResult> result =
+      std::make_unique<MockMethodResult>();
+
+  const std::string error_text = "error_text";
+
+  EXPECT_CALL(*result, SuccessInternal).Times(0);
+  EXPECT_CALL(*result,
+              ErrorInternal(Eq("CameraAccessDenied"), Eq(error_text), _));
+
+  camera->AddPendingResult(PendingResultType::kPausePreview, std::move(result));
+
+  camera->OnPausePreviewFailed(CameraResult::kAccessDenied, error_text);
 }
 
 TEST(Camera, OnResumePreviewSucceededReturnsSuccess) {
@@ -236,7 +287,7 @@
   std::unique_ptr<MockMethodResult> result =
       std::make_unique<MockMethodResult>();
 
-  std::string error_text = "error_text";
+  const std::string error_text = "error_text";
 
   EXPECT_CALL(*result, SuccessInternal).Times(0);
   EXPECT_CALL(*result, ErrorInternal(Eq("camera_error"), Eq(error_text), _));
@@ -244,7 +295,25 @@
   camera->AddPendingResult(PendingResultType::kResumePreview,
                            std::move(result));
 
-  camera->OnResumePreviewFailed(error_text);
+  camera->OnResumePreviewFailed(CameraResult::kError, error_text);
+}
+
+TEST(Camera, OnResumePreviewPermissionFailureReturnsError) {
+  std::unique_ptr<CameraImpl> camera =
+      std::make_unique<CameraImpl>(MOCK_DEVICE_ID);
+  std::unique_ptr<MockMethodResult> result =
+      std::make_unique<MockMethodResult>();
+
+  const std::string error_text = "error_text";
+
+  EXPECT_CALL(*result, SuccessInternal).Times(0);
+  EXPECT_CALL(*result,
+              ErrorInternal(Eq("CameraAccessDenied"), Eq(error_text), _));
+
+  camera->AddPendingResult(PendingResultType::kResumePreview,
+                           std::move(result));
+
+  camera->OnResumePreviewFailed(CameraResult::kAccessDenied, error_text);
 }
 
 TEST(Camera, OnStartRecordSucceededReturnsSuccess) {
@@ -267,14 +336,31 @@
   std::unique_ptr<MockMethodResult> result =
       std::make_unique<MockMethodResult>();
 
-  std::string error_text = "error_text";
+  const std::string error_text = "error_text";
 
   EXPECT_CALL(*result, SuccessInternal).Times(0);
   EXPECT_CALL(*result, ErrorInternal(Eq("camera_error"), Eq(error_text), _));
 
   camera->AddPendingResult(PendingResultType::kStartRecord, std::move(result));
 
-  camera->OnStartRecordFailed(error_text);
+  camera->OnStartRecordFailed(CameraResult::kError, error_text);
+}
+
+TEST(Camera, StartRecordReportsAccessDenied) {
+  std::unique_ptr<CameraImpl> camera =
+      std::make_unique<CameraImpl>(MOCK_DEVICE_ID);
+  std::unique_ptr<MockMethodResult> result =
+      std::make_unique<MockMethodResult>();
+
+  const std::string error_text = "error_text";
+
+  EXPECT_CALL(*result, SuccessInternal).Times(0);
+  EXPECT_CALL(*result,
+              ErrorInternal(Eq("CameraAccessDenied"), Eq(error_text), _));
+
+  camera->AddPendingResult(PendingResultType::kStartRecord, std::move(result));
+
+  camera->OnStartRecordFailed(CameraResult::kAccessDenied, error_text);
 }
 
 TEST(Camera, OnStopRecordSucceededReturnsSuccess) {
@@ -283,7 +369,7 @@
   std::unique_ptr<MockMethodResult> result =
       std::make_unique<MockMethodResult>();
 
-  std::string file_path = "C:\temp\filename.mp4";
+  const std::string file_path = "C:\temp\filename.mp4";
 
   EXPECT_CALL(*result, ErrorInternal).Times(0);
   EXPECT_CALL(*result, SuccessInternal(Pointee(EncodableValue(file_path))));
@@ -299,14 +385,31 @@
   std::unique_ptr<MockMethodResult> result =
       std::make_unique<MockMethodResult>();
 
-  std::string error_text = "error_text";
+  const std::string error_text = "error_text";
 
   EXPECT_CALL(*result, SuccessInternal).Times(0);
   EXPECT_CALL(*result, ErrorInternal(Eq("camera_error"), Eq(error_text), _));
 
   camera->AddPendingResult(PendingResultType::kStopRecord, std::move(result));
 
-  camera->OnStopRecordFailed(error_text);
+  camera->OnStopRecordFailed(CameraResult::kError, error_text);
+}
+
+TEST(Camera, StopRecordReportsAccessDenied) {
+  std::unique_ptr<CameraImpl> camera =
+      std::make_unique<CameraImpl>(MOCK_DEVICE_ID);
+  std::unique_ptr<MockMethodResult> result =
+      std::make_unique<MockMethodResult>();
+
+  const std::string error_text = "error_text";
+
+  EXPECT_CALL(*result, SuccessInternal).Times(0);
+  EXPECT_CALL(*result,
+              ErrorInternal(Eq("CameraAccessDenied"), Eq(error_text), _));
+
+  camera->AddPendingResult(PendingResultType::kStopRecord, std::move(result));
+
+  camera->OnStopRecordFailed(CameraResult::kAccessDenied, error_text);
 }
 
 TEST(Camera, OnTakePictureSucceededReturnsSuccess) {
@@ -315,7 +418,7 @@
   std::unique_ptr<MockMethodResult> result =
       std::make_unique<MockMethodResult>();
 
-  std::string file_path = "C:\\temp\\filename.jpeg";
+  const std::string file_path = "C:\\temp\\filename.jpeg";
 
   EXPECT_CALL(*result, ErrorInternal).Times(0);
   EXPECT_CALL(*result, SuccessInternal(Pointee(EncodableValue(file_path))));
@@ -331,14 +434,31 @@
   std::unique_ptr<MockMethodResult> result =
       std::make_unique<MockMethodResult>();
 
-  std::string error_text = "error_text";
+  const std::string error_text = "error_text";
 
   EXPECT_CALL(*result, SuccessInternal).Times(0);
   EXPECT_CALL(*result, ErrorInternal(Eq("camera_error"), Eq(error_text), _));
 
   camera->AddPendingResult(PendingResultType::kTakePicture, std::move(result));
 
-  camera->OnTakePictureFailed(error_text);
+  camera->OnTakePictureFailed(CameraResult::kError, error_text);
+}
+
+TEST(Camera, TakePictureReportsAccessDenied) {
+  std::unique_ptr<CameraImpl> camera =
+      std::make_unique<CameraImpl>(MOCK_DEVICE_ID);
+  std::unique_ptr<MockMethodResult> result =
+      std::make_unique<MockMethodResult>();
+
+  const std::string error_text = "error_text";
+
+  EXPECT_CALL(*result, SuccessInternal).Times(0);
+  EXPECT_CALL(*result,
+              ErrorInternal(Eq("CameraAccessDenied"), Eq(error_text), _));
+
+  camera->AddPendingResult(PendingResultType::kTakePicture, std::move(result));
+
+  camera->OnTakePictureFailed(CameraResult::kAccessDenied, error_text);
 }
 
 TEST(Camera, OnVideoRecordSucceededInvokesCameraChannelEvent) {
@@ -350,12 +470,12 @@
   std::unique_ptr<MockBinaryMessenger> binary_messenger =
       std::make_unique<MockBinaryMessenger>();
 
-  std::string file_path = "C:\\temp\\filename.mp4";
-  int64_t camera_id = 12345;
+  const std::string file_path = "C:\\temp\\filename.mp4";
+  const int64_t camera_id = 12345;
   std::string camera_channel =
       std::string("plugins.flutter.io/camera_windows/camera") +
       std::to_string(camera_id);
-  int64_t video_duration = 1000000;
+  const int64_t video_duration = 1000000;
 
   EXPECT_CALL(*capture_controller_factory, CreateCaptureController)
       .Times(1)
diff --git a/packages/camera/camera_windows/windows/test/capture_controller_test.cpp b/packages/camera/camera_windows/windows/test/capture_controller_test.cpp
index 776c150..4662d33 100644
--- a/packages/camera/camera_windows/windows/test/capture_controller_test.cpp
+++ b/packages/camera/camera_windows/windows/test/capture_controller_test.cpp
@@ -294,7 +294,52 @@
   EXPECT_CALL(*texture_registrar, UnregisterTexture).Times(0);
   EXPECT_CALL(*camera, OnCreateCaptureEngineSucceeded).Times(0);
   EXPECT_CALL(*camera,
-              OnCreateCaptureEngineFailed(Eq("Failed to create camera")))
+              OnCreateCaptureEngineFailed(Eq(CameraResult::kError),
+                                          Eq("Failed to create camera")))
+      .Times(1);
+
+  bool result = capture_controller->InitCaptureDevice(
+      texture_registrar.get(), MOCK_DEVICE_ID, true, ResolutionPreset::kAuto);
+
+  EXPECT_FALSE(result);
+  EXPECT_FALSE(engine->initialized_);
+
+  capture_controller = nullptr;
+  camera = nullptr;
+  texture_registrar = nullptr;
+  engine = nullptr;
+}
+
+TEST(CaptureController, InitCaptureEngineReportsAccessDenied) {
+  ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+  std::unique_ptr<MockCamera> camera =
+      std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+  std::unique_ptr<CaptureControllerImpl> capture_controller =
+      std::make_unique<CaptureControllerImpl>(camera.get());
+  std::unique_ptr<MockTextureRegistrar> texture_registrar =
+      std::make_unique<MockTextureRegistrar>();
+
+  ComPtr<MockMediaSource> video_source = new MockMediaSource();
+  ComPtr<MockMediaSource> audio_source = new MockMediaSource();
+
+  capture_controller->SetCaptureEngine(
+      reinterpret_cast<IMFCaptureEngine*>(engine.Get()));
+  capture_controller->SetVideoSource(
+      reinterpret_cast<IMFMediaSource*>(video_source.Get()));
+  capture_controller->SetAudioSource(
+      reinterpret_cast<IMFMediaSource*>(audio_source.Get()));
+
+  // Cause initialization to fail
+  EXPECT_CALL(*engine.Get(), Initialize)
+      .Times(1)
+      .WillOnce(Return(E_ACCESSDENIED));
+
+  EXPECT_CALL(*texture_registrar, RegisterTexture).Times(0);
+  EXPECT_CALL(*texture_registrar, UnregisterTexture).Times(0);
+  EXPECT_CALL(*camera, OnCreateCaptureEngineSucceeded).Times(0);
+  EXPECT_CALL(*camera,
+              OnCreateCaptureEngineFailed(Eq(CameraResult::kAccessDenied),
+                                          Eq("Failed to create camera")))
       .Times(1);
 
   bool result = capture_controller->InitCaptureDevice(
@@ -324,6 +369,7 @@
                             engine.Get(), camera.get(), mock_texture_id);
 
   EXPECT_CALL(*camera, OnCreateCaptureEngineFailed(
+                           Eq(CameraResult::kError),
                            Eq("Failed to initialize capture engine")))
       .Times(1);
   EXPECT_CALL(*camera, OnCreateCaptureEngineSucceeded).Times(0);
@@ -337,6 +383,35 @@
   engine = nullptr;
 }
 
+TEST(CaptureController, ReportsInitializedAccessDeniedEvent) {
+  ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+  std::unique_ptr<MockCamera> camera =
+      std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+  std::unique_ptr<CaptureControllerImpl> capture_controller =
+      std::make_unique<CaptureControllerImpl>(camera.get());
+  std::unique_ptr<MockTextureRegistrar> texture_registrar =
+      std::make_unique<MockTextureRegistrar>();
+
+  int64_t mock_texture_id = 1234;
+
+  MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+                            engine.Get(), camera.get(), mock_texture_id);
+
+  EXPECT_CALL(*camera, OnCreateCaptureEngineFailed(
+                           Eq(CameraResult::kAccessDenied),
+                           Eq("Failed to initialize capture engine")))
+      .Times(1);
+  EXPECT_CALL(*camera, OnCreateCaptureEngineSucceeded).Times(0);
+
+  // Send initialization failed event
+  engine->CreateFakeEvent(E_ACCESSDENIED, MF_CAPTURE_ENGINE_INITIALIZED);
+
+  capture_controller = nullptr;
+  camera = nullptr;
+  texture_registrar = nullptr;
+  engine = nullptr;
+}
+
 TEST(CaptureController, ReportsCaptureEngineErrorEvent) {
   ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
   std::unique_ptr<MockCamera> camera =
@@ -351,7 +426,8 @@
   MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
                             engine.Get(), camera.get(), mock_texture_id);
 
-  EXPECT_CALL(*(camera.get()), OnCaptureError(Eq("Unspecified error")))
+  EXPECT_CALL(*(camera.get()),
+              OnCaptureError(Eq(CameraResult::kError), Eq("Unspecified error")))
       .Times(1);
 
   // Send error event.
@@ -363,6 +439,33 @@
   engine = nullptr;
 }
 
+TEST(CaptureController, ReportsCaptureEngineAccessDeniedEvent) {
+  ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+  std::unique_ptr<MockCamera> camera =
+      std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+  std::unique_ptr<CaptureControllerImpl> capture_controller =
+      std::make_unique<CaptureControllerImpl>(camera.get());
+  std::unique_ptr<MockTextureRegistrar> texture_registrar =
+      std::make_unique<MockTextureRegistrar>();
+
+  int64_t mock_texture_id = 1234;
+
+  MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+                            engine.Get(), camera.get(), mock_texture_id);
+
+  EXPECT_CALL(*(camera.get()), OnCaptureError(Eq(CameraResult::kAccessDenied),
+                                              Eq("Access is denied.")))
+      .Times(1);
+
+  // Send error event.
+  engine->CreateFakeEvent(E_ACCESSDENIED, MF_CAPTURE_ENGINE_ERROR);
+
+  capture_controller = nullptr;
+  camera = nullptr;
+  texture_registrar = nullptr;
+  engine = nullptr;
+}
+
 TEST(CaptureController, StartPreviewStartsProcessingSamples) {
   ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
   std::unique_ptr<MockCamera> camera =
@@ -477,7 +580,8 @@
   EXPECT_CALL(*engine.Get(), StopPreview).Times(0);
   EXPECT_CALL(*camera, OnStartPreviewSucceeded).Times(0);
   EXPECT_CALL(*camera,
-              OnStartPreviewFailed(Eq("Failed to start video preview")))
+              OnStartPreviewFailed(Eq(CameraResult::kError),
+                                   Eq("Failed to start video preview")))
       .Times(1);
 
   capture_controller->StartPreview();
@@ -517,6 +621,45 @@
   engine = nullptr;
 }
 
+TEST(CaptureController, ReportsStartPreviewAccessDenied) {
+  ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+  std::unique_ptr<MockCamera> camera =
+      std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+  std::unique_ptr<CaptureControllerImpl> capture_controller =
+      std::make_unique<CaptureControllerImpl>(camera.get());
+  std::unique_ptr<MockTextureRegistrar> texture_registrar =
+      std::make_unique<MockTextureRegistrar>();
+
+  int64_t mock_texture_id = 1234;
+
+  // Initialize capture controller to be able to start preview
+  MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+                            engine.Get(), camera.get(), mock_texture_id);
+
+  ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
+  MockAvailableMediaTypes(engine.Get(), capture_source.Get(), 1, 1);
+
+  // Cause start preview to fail
+  EXPECT_CALL(*engine.Get(), GetSink(MF_CAPTURE_ENGINE_SINK_TYPE_PREVIEW, _))
+      .Times(1)
+      .WillOnce(Return(E_ACCESSDENIED));
+
+  EXPECT_CALL(*engine.Get(), StartPreview).Times(0);
+  EXPECT_CALL(*engine.Get(), StopPreview).Times(0);
+  EXPECT_CALL(*camera, OnStartPreviewSucceeded).Times(0);
+  EXPECT_CALL(*camera,
+              OnStartPreviewFailed(Eq(CameraResult::kAccessDenied),
+                                   Eq("Failed to start video preview")))
+      .Times(1);
+
+  capture_controller->StartPreview();
+
+  capture_controller = nullptr;
+  engine = nullptr;
+  camera = nullptr;
+  texture_registrar = nullptr;
+}
+
 TEST(CaptureController, StartRecordSuccess) {
   ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
   std::unique_ptr<MockCamera> camera =
@@ -584,7 +727,49 @@
   EXPECT_CALL(*engine.Get(), StopRecord).Times(0);
   EXPECT_CALL(*camera, OnStartRecordSucceeded).Times(0);
   EXPECT_CALL(*camera,
-              OnStartRecordFailed(Eq("Failed to start video recording")))
+              OnStartRecordFailed(Eq(CameraResult::kError),
+                                  Eq("Failed to start video recording")))
+      .Times(1);
+
+  capture_controller->StartRecord("mock_path", -1);
+
+  capture_controller = nullptr;
+  texture_registrar = nullptr;
+  engine = nullptr;
+  camera = nullptr;
+}
+
+TEST(CaptureController, ReportsStartRecordAccessDenied) {
+  ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+  std::unique_ptr<MockCamera> camera =
+      std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+  std::unique_ptr<CaptureControllerImpl> capture_controller =
+      std::make_unique<CaptureControllerImpl>(camera.get());
+  std::unique_ptr<MockTextureRegistrar> texture_registrar =
+      std::make_unique<MockTextureRegistrar>();
+
+  int64_t mock_texture_id = 1234;
+
+  // Initialize capture controller to be able to start preview
+  MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+                            engine.Get(), camera.get(), mock_texture_id);
+
+  ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
+
+  // Prepare fake media types
+  MockAvailableMediaTypes(engine.Get(), capture_source.Get(), 1, 1);
+
+  // Cause start record to fail
+  EXPECT_CALL(*engine.Get(), GetSink(MF_CAPTURE_ENGINE_SINK_TYPE_RECORD, _))
+      .Times(1)
+      .WillOnce(Return(E_ACCESSDENIED));
+
+  EXPECT_CALL(*engine.Get(), StartRecord).Times(0);
+  EXPECT_CALL(*engine.Get(), StopRecord).Times(0);
+  EXPECT_CALL(*camera, OnStartRecordSucceeded).Times(0);
+  EXPECT_CALL(*camera,
+              OnStartRecordFailed(Eq(CameraResult::kAccessDenied),
+                                  Eq("Failed to start video recording")))
       .Times(1);
 
   capture_controller->StartRecord("mock_path", -1);
@@ -644,7 +829,9 @@
 
   // Send a start record failed event
   EXPECT_CALL(*camera, OnStartRecordSucceeded).Times(0);
-  EXPECT_CALL(*camera, OnStartRecordFailed(Eq("Unspecified error"))).Times(1);
+  EXPECT_CALL(*camera, OnStartRecordFailed(Eq(CameraResult::kError),
+                                           Eq("Unspecified error")))
+      .Times(1);
 
   engine->CreateFakeEvent(E_FAIL, MF_CAPTURE_ENGINE_RECORD_STARTED);
 
@@ -658,6 +845,71 @@
   record_sink = nullptr;
 }
 
+TEST(CaptureController, ReportsStartRecordAccessDeniedEvent) {
+  ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+  std::unique_ptr<MockCamera> camera =
+      std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+  std::unique_ptr<CaptureControllerImpl> capture_controller =
+      std::make_unique<CaptureControllerImpl>(camera.get());
+  std::unique_ptr<MockTextureRegistrar> texture_registrar =
+      std::make_unique<MockTextureRegistrar>();
+
+  int64_t mock_texture_id = 1234;
+
+  // Initialize capture controller to be able to start preview
+  MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+                            engine.Get(), camera.get(), mock_texture_id);
+
+  ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
+
+  // Prepare fake media types
+  MockAvailableMediaTypes(engine.Get(), capture_source.Get(), 1, 1);
+
+  // Start record
+  ComPtr<MockCaptureRecordSink> record_sink = new MockCaptureRecordSink();
+  std::string mock_path_to_video = "mock_path_to_video";
+
+  EXPECT_CALL(*engine.Get(), StartRecord()).Times(1).WillOnce(Return(S_OK));
+
+  EXPECT_CALL(*engine.Get(), GetSink(MF_CAPTURE_ENGINE_SINK_TYPE_RECORD, _))
+      .Times(1)
+      .WillOnce([src_sink = record_sink](MF_CAPTURE_ENGINE_SINK_TYPE sink_type,
+                                         IMFCaptureSink** target_sink) {
+        *target_sink = src_sink.Get();
+        src_sink->AddRef();
+        return S_OK;
+      });
+
+  EXPECT_CALL(*record_sink.Get(), RemoveAllStreams)
+      .Times(1)
+      .WillOnce(Return(S_OK));
+  EXPECT_CALL(*record_sink.Get(), AddStream)
+      .Times(2)
+      .WillRepeatedly(Return(S_OK));
+  EXPECT_CALL(*record_sink.Get(), SetOutputFileName)
+      .Times(1)
+      .WillOnce(Return(S_OK));
+
+  // Send a start record failed event
+  capture_controller->StartRecord(mock_path_to_video, -1);
+
+  EXPECT_CALL(*camera, OnStartRecordSucceeded).Times(0);
+  EXPECT_CALL(*camera, OnStartRecordFailed(Eq(CameraResult::kAccessDenied),
+                                           Eq("Access is denied.")))
+      .Times(1);
+
+  engine->CreateFakeEvent(E_ACCESSDENIED, MF_CAPTURE_ENGINE_RECORD_STARTED);
+
+  // Destructor shouldn't attempt to stop the recording that failed to start.
+  EXPECT_CALL(*engine.Get(), StopRecord).Times(0);
+
+  capture_controller = nullptr;
+  texture_registrar = nullptr;
+  engine = nullptr;
+  camera = nullptr;
+  record_sink = nullptr;
+}
+
 TEST(CaptureController, StopRecordSuccess) {
   ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
   std::unique_ptr<MockCamera> camera =
@@ -734,7 +986,52 @@
       .WillOnce(Return(E_FAIL));
 
   EXPECT_CALL(*camera, OnStopRecordSucceeded).Times(0);
-  EXPECT_CALL(*camera, OnStopRecordFailed(Eq("Failed to stop video recording")))
+  EXPECT_CALL(*camera, OnStopRecordFailed(Eq(CameraResult::kError),
+                                          Eq("Failed to stop video recording")))
+      .Times(1);
+
+  capture_controller->StopRecord();
+
+  capture_controller = nullptr;
+  texture_registrar = nullptr;
+  engine = nullptr;
+  camera = nullptr;
+  record_sink = nullptr;
+}
+
+TEST(CaptureController, ReportsStopRecordAccessDenied) {
+  ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+  std::unique_ptr<MockCamera> camera =
+      std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+  std::unique_ptr<CaptureControllerImpl> capture_controller =
+      std::make_unique<CaptureControllerImpl>(camera.get());
+  std::unique_ptr<MockTextureRegistrar> texture_registrar =
+      std::make_unique<MockTextureRegistrar>();
+
+  int64_t mock_texture_id = 1234;
+
+  // Initialize capture controller to be able to start preview
+  MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+                            engine.Get(), camera.get(), mock_texture_id);
+
+  ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
+
+  // Prepare fake media types
+  MockAvailableMediaTypes(engine.Get(), capture_source.Get(), 1, 1);
+
+  // Start record
+  ComPtr<MockCaptureRecordSink> record_sink = new MockCaptureRecordSink();
+  MockRecordStart(capture_controller.get(), engine.Get(), record_sink.Get(),
+                  camera.get(), "mock_path_to_video");
+
+  // Cause stop record to fail
+  EXPECT_CALL(*(engine.Get()), StopRecord(true, false))
+      .Times(1)
+      .WillOnce(Return(E_ACCESSDENIED));
+
+  EXPECT_CALL(*camera, OnStopRecordSucceeded).Times(0);
+  EXPECT_CALL(*camera, OnStopRecordFailed(Eq(CameraResult::kAccessDenied),
+                                          Eq("Failed to stop video recording")))
       .Times(1);
 
   capture_controller->StopRecord();
@@ -774,7 +1071,9 @@
 
   // Send a stop record failure event
   EXPECT_CALL(*camera, OnStopRecordSucceeded).Times(0);
-  EXPECT_CALL(*camera, OnStopRecordFailed(Eq("Unspecified error"))).Times(1);
+  EXPECT_CALL(*camera, OnStopRecordFailed(Eq(CameraResult::kError),
+                                          Eq("Unspecified error")))
+      .Times(1);
 
   engine->CreateFakeEvent(E_FAIL, MF_CAPTURE_ENGINE_RECORD_STOPPED);
 
@@ -785,6 +1084,47 @@
   record_sink = nullptr;
 }
 
+TEST(CaptureController, ReportsStopRecordAccessDeniedEvent) {
+  ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+  std::unique_ptr<MockCamera> camera =
+      std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+  std::unique_ptr<CaptureControllerImpl> capture_controller =
+      std::make_unique<CaptureControllerImpl>(camera.get());
+  std::unique_ptr<MockTextureRegistrar> texture_registrar =
+      std::make_unique<MockTextureRegistrar>();
+
+  int64_t mock_texture_id = 1234;
+
+  // Initialize capture controller to be able to start preview
+  MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+                            engine.Get(), camera.get(), mock_texture_id);
+
+  ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
+
+  // Prepare fake media types
+  MockAvailableMediaTypes(engine.Get(), capture_source.Get(), 1, 1);
+
+  // Start record
+  ComPtr<MockCaptureRecordSink> record_sink = new MockCaptureRecordSink();
+  std::string mock_path_to_video = "mock_path_to_video";
+  MockRecordStart(capture_controller.get(), engine.Get(), record_sink.Get(),
+                  camera.get(), mock_path_to_video);
+
+  // Send a stop record failure event
+  EXPECT_CALL(*camera, OnStopRecordSucceeded).Times(0);
+  EXPECT_CALL(*camera, OnStopRecordFailed(Eq(CameraResult::kAccessDenied),
+                                          Eq("Access is denied.")))
+      .Times(1);
+
+  engine->CreateFakeEvent(E_ACCESSDENIED, MF_CAPTURE_ENGINE_RECORD_STOPPED);
+
+  capture_controller = nullptr;
+  texture_registrar = nullptr;
+  engine = nullptr;
+  camera = nullptr;
+  record_sink = nullptr;
+}
+
 TEST(CaptureController, TakePictureSuccess) {
   ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
   std::unique_ptr<MockCamera> camera =
@@ -856,7 +1196,52 @@
   EXPECT_CALL(*(engine.Get()), TakePhoto).Times(1).WillOnce(Return(E_FAIL));
 
   EXPECT_CALL(*camera, OnTakePictureSucceeded).Times(0);
-  EXPECT_CALL(*camera, OnTakePictureFailed(Eq("Failed to take photo")))
+  EXPECT_CALL(*camera, OnTakePictureFailed(Eq(CameraResult::kError),
+                                           Eq("Failed to take photo")))
+      .Times(1);
+
+  capture_controller->TakePicture("mock_path_to_photo");
+
+  capture_controller = nullptr;
+  texture_registrar = nullptr;
+  engine = nullptr;
+  camera = nullptr;
+  photo_sink = nullptr;
+}
+
+TEST(CaptureController, ReportsTakePictureAccessDenied) {
+  ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+  std::unique_ptr<MockCamera> camera =
+      std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+  std::unique_ptr<CaptureControllerImpl> capture_controller =
+      std::make_unique<CaptureControllerImpl>(camera.get());
+  std::unique_ptr<MockTextureRegistrar> texture_registrar =
+      std::make_unique<MockTextureRegistrar>();
+
+  int64_t mock_texture_id = 1234;
+
+  // Initialize capture controller to be able to take picture
+  MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+                            engine.Get(), camera.get(), mock_texture_id);
+
+  ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
+
+  // Prepare fake media types
+  MockAvailableMediaTypes(engine.Get(), capture_source.Get(), 1, 1);
+
+  ComPtr<MockCapturePhotoSink> photo_sink = new MockCapturePhotoSink();
+
+  // Initialize photo sink
+  MockPhotoSink(engine.Get(), photo_sink.Get());
+
+  // Cause take picture to fail.
+  EXPECT_CALL(*(engine.Get()), TakePhoto)
+      .Times(1)
+      .WillOnce(Return(E_ACCESSDENIED));
+
+  EXPECT_CALL(*camera, OnTakePictureSucceeded).Times(0);
+  EXPECT_CALL(*camera, OnTakePictureFailed(Eq(CameraResult::kAccessDenied),
+                                           Eq("Failed to take photo")))
       .Times(1);
 
   capture_controller->TakePicture("mock_path_to_photo");
@@ -900,7 +1285,9 @@
 
   // Send take picture failed event
   EXPECT_CALL(*camera, OnTakePictureSucceeded).Times(0);
-  EXPECT_CALL(*camera, OnTakePictureFailed(Eq("Unspecified error"))).Times(1);
+  EXPECT_CALL(*camera, OnTakePictureFailed(Eq(CameraResult::kError),
+                                           Eq("Unspecified error")))
+      .Times(1);
 
   engine->CreateFakeEvent(E_FAIL, MF_CAPTURE_ENGINE_PHOTO_TAKEN);
 
@@ -911,6 +1298,51 @@
   photo_sink = nullptr;
 }
 
+TEST(CaptureController, ReportsPhotoTakenAccessDeniedEvent) {
+  ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
+  std::unique_ptr<MockCamera> camera =
+      std::make_unique<MockCamera>(MOCK_DEVICE_ID);
+  std::unique_ptr<CaptureControllerImpl> capture_controller =
+      std::make_unique<CaptureControllerImpl>(camera.get());
+  std::unique_ptr<MockTextureRegistrar> texture_registrar =
+      std::make_unique<MockTextureRegistrar>();
+
+  int64_t mock_texture_id = 1234;
+
+  // Initialize capture controller to be able to take picture
+  MockInitCaptureController(capture_controller.get(), texture_registrar.get(),
+                            engine.Get(), camera.get(), mock_texture_id);
+
+  ComPtr<MockCaptureSource> capture_source = new MockCaptureSource();
+
+  // Prepare fake media types
+  MockAvailableMediaTypes(engine.Get(), capture_source.Get(), 1, 1);
+
+  ComPtr<MockCapturePhotoSink> photo_sink = new MockCapturePhotoSink();
+
+  // Initialize photo sink
+  MockPhotoSink(engine.Get(), photo_sink.Get());
+
+  // Request photo
+  std::string mock_path_to_photo = "mock_path_to_photo";
+  EXPECT_CALL(*(engine.Get()), TakePhoto()).Times(1).WillOnce(Return(S_OK));
+  capture_controller->TakePicture(mock_path_to_photo);
+
+  // Send take picture failed event
+  EXPECT_CALL(*camera, OnTakePictureSucceeded).Times(0);
+  EXPECT_CALL(*camera, OnTakePictureFailed(Eq(CameraResult::kAccessDenied),
+                                           Eq("Access is denied.")))
+      .Times(1);
+
+  engine->CreateFakeEvent(E_ACCESSDENIED, MF_CAPTURE_ENGINE_PHOTO_TAKEN);
+
+  capture_controller = nullptr;
+  texture_registrar = nullptr;
+  engine = nullptr;
+  camera = nullptr;
+  photo_sink = nullptr;
+}
+
 TEST(CaptureController, PauseResumePreviewSuccess) {
   ComPtr<MockCaptureEngine> engine = new MockCaptureEngine();
   std::unique_ptr<MockCamera> camera =
@@ -963,7 +1395,8 @@
                             engine.Get(), camera.get(), mock_texture_id);
 
   // Pause preview fails if not started
-  EXPECT_CALL(*camera, OnPausePreviewFailed(Eq("Preview not started")))
+  EXPECT_CALL(*camera, OnPausePreviewFailed(Eq(CameraResult::kError),
+                                            Eq("Preview not started")))
       .Times(1);
 
   capture_controller->PausePreview();
@@ -989,7 +1422,8 @@
                             engine.Get(), camera.get(), mock_texture_id);
 
   // Resume preview fails if not started.
-  EXPECT_CALL(*camera, OnResumePreviewFailed(Eq("Preview not started")))
+  EXPECT_CALL(*camera, OnResumePreviewFailed(Eq(CameraResult::kError),
+                                             Eq("Preview not started")))
       .Times(1);
 
   capture_controller->ResumePreview();
diff --git a/packages/camera/camera_windows/windows/test/mocks.h b/packages/camera/camera_windows/windows/test/mocks.h
index 53101f5..678b758 100644
--- a/packages/camera/camera_windows/windows/test/mocks.h
+++ b/packages/camera/camera_windows/windows/test/mocks.h
@@ -134,41 +134,43 @@
               (override));
   MOCK_METHOD(std::unique_ptr<flutter::MethodResult<>>, GetPendingResultByType,
               (PendingResultType type));
-  MOCK_METHOD(void, OnCreateCaptureEngineFailed, (const std::string& error),
-              (override));
+  MOCK_METHOD(void, OnCreateCaptureEngineFailed,
+              (CameraResult result, const std::string& error), (override));
 
   MOCK_METHOD(void, OnStartPreviewSucceeded, (int32_t width, int32_t height),
               (override));
-  MOCK_METHOD(void, OnStartPreviewFailed, (const std::string& error),
-              (override));
+  MOCK_METHOD(void, OnStartPreviewFailed,
+              (CameraResult result, const std::string& error), (override));
 
   MOCK_METHOD(void, OnResumePreviewSucceeded, (), (override));
-  MOCK_METHOD(void, OnResumePreviewFailed, (const std::string& error),
-              (override));
+  MOCK_METHOD(void, OnResumePreviewFailed,
+              (CameraResult result, const std::string& error), (override));
 
   MOCK_METHOD(void, OnPausePreviewSucceeded, (), (override));
-  MOCK_METHOD(void, OnPausePreviewFailed, (const std::string& error),
-              (override));
+  MOCK_METHOD(void, OnPausePreviewFailed,
+              (CameraResult result, const std::string& error), (override));
 
   MOCK_METHOD(void, OnStartRecordSucceeded, (), (override));
-  MOCK_METHOD(void, OnStartRecordFailed, (const std::string& error),
-              (override));
+  MOCK_METHOD(void, OnStartRecordFailed,
+              (CameraResult result, const std::string& error), (override));
 
   MOCK_METHOD(void, OnStopRecordSucceeded, (const std::string& file_path),
               (override));
-  MOCK_METHOD(void, OnStopRecordFailed, (const std::string& error), (override));
+  MOCK_METHOD(void, OnStopRecordFailed,
+              (CameraResult result, const std::string& error), (override));
 
   MOCK_METHOD(void, OnTakePictureSucceeded, (const std::string& file_path),
               (override));
-  MOCK_METHOD(void, OnTakePictureFailed, (const std::string& error),
-              (override));
+  MOCK_METHOD(void, OnTakePictureFailed,
+              (CameraResult result, const std::string& error), (override));
 
   MOCK_METHOD(void, OnVideoRecordSucceeded,
               (const std::string& file_path, int64_t video_duration),
               (override));
-  MOCK_METHOD(void, OnVideoRecordFailed, (const std::string& error),
-              (override));
-  MOCK_METHOD(void, OnCaptureError, (const std::string& error), (override));
+  MOCK_METHOD(void, OnVideoRecordFailed,
+              (CameraResult result, const std::string& error), (override));
+  MOCK_METHOD(void, OnCaptureError,
+              (CameraResult result, const std::string& error), (override));
 
   MOCK_METHOD(bool, HasDeviceId, (std::string & device_id), (const override));
   MOCK_METHOD(bool, HasCameraId, (int64_t camera_id), (const override));