[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));