diff --git a/runtime/browser/media/media_capture_devices_dispatcher.cc b/runtime/browser/media/media_capture_devices_dispatcher.cc index 21db72934b..15c8d714b6 100644 --- a/runtime/browser/media/media_capture_devices_dispatcher.cc +++ b/runtime/browser/media/media_capture_devices_dispatcher.cc @@ -5,9 +5,26 @@ #include "xwalk/runtime/browser/media/media_capture_devices_dispatcher.h" +#include "base/prefs/pref_service.h" +#include "base/strings/utf_string_conversions.h" +#include "components/content_settings/core/common/content_settings_types.h" +#include "components/user_prefs/user_prefs.h" #include "content/public/browser/media_capture_devices.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" #include "content/public/common/media_stream_request.h" +#include "grit/xwalk_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "xwalk/application/browser/application.h" +#include "xwalk/application/browser/application_service.h" +#include "xwalk/runtime/browser/xwalk_browser_context.h" +#include "xwalk/runtime/browser/xwalk_content_settings.h" +#include "xwalk/runtime/common/xwalk_system_locale.h" + +#if !defined(OS_ANDROID) +#include "xwalk/runtime/browser/ui/desktop/xwalk_permission_dialog_manager.h" +#endif using content::BrowserThread; using content::MediaCaptureDevices; @@ -33,46 +50,164 @@ const content::MediaStreamDevice* FindDefaultDeviceWithId( } // namespace +namespace xwalk { XWalkMediaCaptureDevicesDispatcher* XWalkMediaCaptureDevicesDispatcher::GetInstance() { return base::Singleton::get(); } +bool ContentTypeIsRequested(ContentSettingsType type, + const content::MediaStreamRequest& request) { + if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) + return request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE; + if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) + return request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE; + + return false; +} + +int GetDialogMessageText(const content::MediaStreamRequest& request) { + bool audio_requested = + request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE; + bool video_requested = + request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE; + if (audio_requested && video_requested) + return IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO; + if (video_requested) + return IDS_MEDIA_CAPTURE_VIDEO_ONLY; + + return IDS_MEDIA_CAPTURE_AUDIO_ONLY; +} + void XWalkMediaCaptureDevicesDispatcher::RunRequestMediaAccessPermission( content::WebContents* web_contents, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) { content::MediaStreamDevices devices; - // Based on chrome/browser/media/media_stream_devices_controller.cc. - bool microphone_requested = - (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE); - bool webcam_requested = - (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE); - if (microphone_requested || webcam_requested) { + if (ContentTypeIsRequested( + CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, request) || + ContentTypeIsRequested( + CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, request)) { switch (request.request_type) { case content::MEDIA_OPEN_DEVICE_PEPPER_ONLY: case content::MEDIA_DEVICE_ACCESS: case content::MEDIA_GENERATE_STREAM: - case content::MEDIA_ENUMERATE_DEVICES: + case content::MEDIA_ENUMERATE_DEVICES: { +#if defined (OS_ANDROID) // Get the exact audio and video devices if id is specified. // Or get the default devices when requested device id is empty. XWalkMediaCaptureDevicesDispatcher::GetInstance()->GetRequestedDevice( request.requested_audio_device_id, request.requested_video_device_id, - microphone_requested, - webcam_requested, + request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE, + request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE, &devices); break; +#else + RequestPermissionToUser(web_contents, request, callback); + break; +#endif + } } } +#if defined (OS_ANDROID) callback.Run(devices, devices.empty() ? content::MEDIA_DEVICE_NO_HARDWARE : content::MEDIA_DEVICE_OK, scoped_ptr()); +#endif } +#if !defined (OS_ANDROID) +void XWalkMediaCaptureDevicesDispatcher::RequestPermissionToUser( + content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + + if (request.security_origin.SchemeIs(url::kHttpScheme)) + callback.Run(content::MediaStreamDevices(), + content::MEDIA_DEVICE_PERMISSION_DENIED, + scoped_ptr()); + + XWalkPermissionDialogManager* permission_dialog_manager = + XWalkPermissionDialogManager::GetPermissionDialogManager(web_contents); + + XWalkBrowserContext* browser_context = + static_cast(web_contents->GetBrowserContext()); + + PrefService* pref_service = + user_prefs::UserPrefs::Get(browser_context); + + application::Application* app = + browser_context->application_service()->GetApplicationByRenderHostID( + web_contents->GetMainFrame()->GetProcess()->GetID()); + std::string app_name; + if (app) + app_name = app->data()->Name(); + + ContentSettingsType content_settings_type = + request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE + ? CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC + : CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA; + + base::string16 dialog_text = l10n_util::GetStringFUTF16( + GetDialogMessageText(request), + base::ASCIIToUTF16(app_name)); + + permission_dialog_manager->RequestPermission( + content_settings_type, + request.security_origin, + pref_service->GetString(kIntlAcceptLanguage), dialog_text, + base::Bind( + &XWalkMediaCaptureDevicesDispatcher::OnPermissionRequestFinished, + callback, request, web_contents)); +} + +void XWalkMediaCaptureDevicesDispatcher::OnPermissionRequestFinished( + const content::MediaResponseCallback& callback, + const content::MediaStreamRequest& request, + content::WebContents* web_contents, + bool success) { + content::MediaStreamDevices devices; + bool audio_requested = + request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE; + bool video_requested = + request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE; + // We always request the permission for the audio capture if both audio and + // video are requested (though the dialog clearly shows both), + // let's make sure we set the video as well in the settings. + if (audio_requested && video_requested) { + XWalkContentSettings::GetInstance()->SetPermission( + CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, + request.security_origin, + web_contents->GetLastCommittedURL().GetOrigin(), + success ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK); + } + if (success) { + // Get the exact audio and video devices if id is specified. + // Or get the default devices when requested device id is empty. + XWalkMediaCaptureDevicesDispatcher::GetInstance()->GetRequestedDevice( + request.requested_audio_device_id, + request.requested_video_device_id, + audio_requested, + video_requested, + &devices); + callback.Run(devices, + devices.empty() ? + content::MEDIA_DEVICE_NO_HARDWARE : + content::MEDIA_DEVICE_OK, + scoped_ptr()); + } else { + callback.Run(devices, + content::MEDIA_DEVICE_PERMISSION_DENIED, + scoped_ptr()); + } +} +#endif + XWalkMediaCaptureDevicesDispatcher::XWalkMediaCaptureDevicesDispatcher() {} XWalkMediaCaptureDevicesDispatcher::~XWalkMediaCaptureDevicesDispatcher() {} @@ -190,7 +325,6 @@ void XWalkMediaCaptureDevicesDispatcher::UpdateMediaReqStateOnUIThread( state)); } - void XWalkMediaCaptureDevicesDispatcher::SetTestAudioCaptureDevices( const MediaStreamDevices& devices) { test_audio_devices_ = devices; @@ -200,3 +334,5 @@ void XWalkMediaCaptureDevicesDispatcher::SetTestVideoCaptureDevices( const MediaStreamDevices& devices) { test_video_devices_ = devices; } + +} // namespace xwalk diff --git a/runtime/browser/media/media_capture_devices_dispatcher.h b/runtime/browser/media/media_capture_devices_dispatcher.h index 5675f0edc3..3338e8dab1 100644 --- a/runtime/browser/media/media_capture_devices_dispatcher.h +++ b/runtime/browser/media/media_capture_devices_dispatcher.h @@ -16,6 +16,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/media_stream_request.h" +namespace xwalk { // This singleton is used to receive updates about media events from the content // layer. Based on chrome/browser/media/media_capture_devices_dispatcher.[h|cc]. class XWalkMediaCaptureDevicesDispatcher : public content::MediaObserver { @@ -91,6 +92,17 @@ class XWalkMediaCaptureDevicesDispatcher : public content::MediaObserver { XWalkMediaCaptureDevicesDispatcher(); ~XWalkMediaCaptureDevicesDispatcher() override; +#if !defined (OS_ANDROID) + static void OnPermissionRequestFinished( + const content::MediaResponseCallback& callback, + const content::MediaStreamRequest& request, + content::WebContents* web_contents, + bool success); + static void RequestPermissionToUser( + content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback); +#endif // Called by the MediaObserver() functions, executed on UI thread. void NotifyAudioDevicesChangedOnUIThread(); void NotifyVideoDevicesChangedOnUIThread(); @@ -111,4 +123,6 @@ class XWalkMediaCaptureDevicesDispatcher : public content::MediaObserver { base::ObserverList observers_; }; +} // namespace xwalk + #endif // XWALK_RUNTIME_BROWSER_MEDIA_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_ diff --git a/runtime/browser/runtime.cc b/runtime/browser/runtime.cc index 522fac8fa4..dbcca48d9b 100644 --- a/runtime/browser/runtime.cc +++ b/runtime/browser/runtime.cc @@ -11,6 +11,8 @@ #include "base/message_loop/message_loop.h" #include "base/strings/utf_string_conversions.h" #include "components/app_modal/javascript_dialog_manager.h" +#include "components/content_settings/core/common/content_settings.h" +#include "components/content_settings/core/common/content_settings_types.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_service.h" @@ -30,6 +32,7 @@ #include "xwalk/runtime/browser/xwalk_autofill_manager.h" #include "xwalk/runtime/browser/xwalk_browser_context.h" #include "xwalk/runtime/browser/xwalk_content_browser_client.h" +#include "xwalk/runtime/browser/xwalk_content_settings.h" #include "xwalk/runtime/browser/xwalk_runner.h" #include "xwalk/runtime/common/xwalk_notification_types.h" #include "xwalk/runtime/common/xwalk_switches.h" @@ -340,10 +343,25 @@ bool Runtime::CheckMediaAccessPermission( const GURL& security_origin, content::MediaStreamType type) { // Requested by Pepper Flash plugin and mediaDevices.enumerateDevices(). - // FIXME(huningxin): current code grants the access by default. It should - // follow the generic permssions mechanism (XWALK-5475). Open XWALK-6083 to - // track it. - return true; +#if defined (OS_ANDROID) + return false; +#else + // This function may be called for a media request coming from + // from WebRTC/mediaDevices. These requests can't be made from HTTP. + if (security_origin.SchemeIs(url::kHttpScheme)) + return false; + + ContentSettingsType content_settings_type = + type == content::MEDIA_DEVICE_AUDIO_CAPTURE + ? CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC + : CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA; + ContentSetting content_setting = + XWalkContentSettings::GetInstance()->GetPermission( + content_settings_type, + security_origin, + web_contents_->GetLastCommittedURL().GetOrigin()); + return content_setting == CONTENT_SETTING_ALLOW; +#endif } void Runtime::LoadProgressChanged(content::WebContents* source, diff --git a/runtime/browser/runtime_geolocation_permission_context.cc b/runtime/browser/runtime_geolocation_permission_context.cc index b1079558d7..65be4ae3f7 100644 --- a/runtime/browser/runtime_geolocation_permission_context.cc +++ b/runtime/browser/runtime_geolocation_permission_context.cc @@ -107,12 +107,7 @@ RuntimeGeolocationPermissionContext::RequestGeolocationPermission( #else DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); XWalkPermissionDialogManager* permission_dialog_manager = - XWalkPermissionDialogManager::FromWebContents(web_contents); - if (!permission_dialog_manager) { - XWalkPermissionDialogManager::CreateForWebContents(web_contents); - permission_dialog_manager = - XWalkPermissionDialogManager::FromWebContents(web_contents); - } + XWalkPermissionDialogManager::GetPermissionDialogManager(web_contents); PrefService* pref_service = user_prefs::UserPrefs::Get(XWalkBrowserContext::GetDefault()); diff --git a/runtime/browser/ui/desktop/xwalk_permission_dialog_manager.cc b/runtime/browser/ui/desktop/xwalk_permission_dialog_manager.cc index 73c6a74af8..21f763f379 100644 --- a/runtime/browser/ui/desktop/xwalk_permission_dialog_manager.cc +++ b/runtime/browser/ui/desktop/xwalk_permission_dialog_manager.cc @@ -29,6 +29,19 @@ XWalkPermissionDialogManager::~XWalkPermissionDialogManager() { CancelPermissionRequest(); } +XWalkPermissionDialogManager* + XWalkPermissionDialogManager::GetPermissionDialogManager( + content::WebContents* web_contents) { + XWalkPermissionDialogManager* permission_dialog_manager = + XWalkPermissionDialogManager::FromWebContents(web_contents); + if (!permission_dialog_manager) { + XWalkPermissionDialogManager::CreateForWebContents(web_contents); + permission_dialog_manager = + XWalkPermissionDialogManager::FromWebContents(web_contents); + } + return permission_dialog_manager; +} + void XWalkPermissionDialogManager::WebContentsDestroyed() { CancelPermissionRequest(); web_contents_->RemoveUserData(UserDataKey()); @@ -60,10 +73,10 @@ void XWalkPermissionDialogManager::RequestPermission( default: { app_modal::AppModalDialogQueue::GetInstance()->AddDialog( new XWalkPermissionModalDialog( - web_contents_, - message_text, - base::Bind(&XWalkPermissionDialogManager::OnPermissionDialogClosed, - base::Unretained(this), type, origin_url, callback))); + web_contents_, + message_text, + base::Bind(&XWalkPermissionDialogManager::OnPermissionDialogClosed, + base::Unretained(this), type, origin_url, callback))); } } } diff --git a/runtime/browser/ui/desktop/xwalk_permission_dialog_manager.h b/runtime/browser/ui/desktop/xwalk_permission_dialog_manager.h index d94565ad97..41deebc517 100644 --- a/runtime/browser/ui/desktop/xwalk_permission_dialog_manager.h +++ b/runtime/browser/ui/desktop/xwalk_permission_dialog_manager.h @@ -21,6 +21,8 @@ class XWalkPermissionDialogManager : public content::WebContentsObserver, public content::WebContentsUserData { public: + static XWalkPermissionDialogManager* GetPermissionDialogManager( + content::WebContents* web_contents); void RequestPermission( ContentSettingsType type, const GURL& origin_url, diff --git a/runtime/browser/xwalk_browser_context.h b/runtime/browser/xwalk_browser_context.h index b14ccc9c26..188e86c940 100644 --- a/runtime/browser/xwalk_browser_context.h +++ b/runtime/browser/xwalk_browser_context.h @@ -108,6 +108,9 @@ class XWalkBrowserContext void UpdateAcceptLanguages(const std::string& accept_languages); void set_save_form_data(bool enable) { save_form_data_ = enable; } bool save_form_data() const { return save_form_data_; } + application::ApplicationService* application_service() const { + return application_service_; + } void set_application_service( application::ApplicationService* application_service) { application_service_ = application_service; diff --git a/runtime/resources/xwalk_resources.grd b/runtime/resources/xwalk_resources.grd index ad5711de6c..84e3a6c5ad 100644 --- a/runtime/resources/xwalk_resources.grd +++ b/runtime/resources/xwalk_resources.grd @@ -193,6 +193,21 @@ $1maps.google.com wants to use your computer's location. + + + $1html5rocks.com + wants to use your camera and microphone. + + + + $1html5rocks.com + wants to use your microphone. + + + + $1html5rocks.com + wants to use your camera. + Allow