Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(188)

Side by Side Diff: chrome/browser/media/webrtc/media_stream_devices_controller.cc

Issue 2816933002: Grouped requests
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/media/webrtc/media_stream_devices_controller.h" 5 #include "chrome/browser/media/webrtc/media_stream_devices_controller.h"
6 6
7 #include <map> 7 #include <map>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/callback_helpers.h" 10 #include "base/callback_helpers.h"
11 #include "base/command_line.h"
11 #include "base/memory/ptr_util.h" 12 #include "base/memory/ptr_util.h"
12 #include "base/metrics/histogram_macros.h" 13 #include "base/metrics/histogram_macros.h"
13 #include "base/strings/utf_string_conversions.h" 14 #include "base/strings/utf_string_conversions.h"
14 #include "base/values.h" 15 #include "base/values.h"
15 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" 16 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
16 #include "chrome/browser/content_settings/tab_specific_content_settings.h" 17 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
17 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" 18 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
18 #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h" 19 #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h"
19 #include "chrome/browser/media/webrtc/media_stream_device_permissions.h" 20 #include "chrome/browser/media/webrtc/media_stream_device_permissions.h"
20 #include "chrome/browser/permissions/permission_manager.h" 21 #include "chrome/browser/permissions/permission_manager.h"
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 76
76 return false; 77 return false;
77 } 78 }
78 79
79 using PermissionActionCallback = 80 using PermissionActionCallback =
80 base::Callback<void(ContentSettingsType, 81 base::Callback<void(ContentSettingsType,
81 PermissionRequestGestureType, 82 PermissionRequestGestureType,
82 const GURL&, 83 const GURL&,
83 Profile*)>; 84 Profile*)>;
84 85
85 void RecordSinglePermissionAction(const content::MediaStreamRequest& request, 86
86 ContentSettingsType content_type, 87 // Calls |action_function| for each permission requested by |request|.
87 Profile* profile, 88 void RecordPermissionAction(bool is_asking_for_audio,
88 PermissionActionCallback callback) { 89 bool is_asking_for_video,
89 if (ContentTypeIsRequested(content_type, request)) { 90 const GURL& security_origin,
90 // TODO(stefanocs): Pass the actual |gesture_type| once this file has been 91 Profile* profile,
91 // refactored into PermissionContext. 92 PermissionActionCallback callback) {
92 callback.Run(content_type, PermissionRequestGestureType::UNKNOWN, 93 // TODO(stefanocs): Pass the actual |gesture_type| once this file has been
93 request.security_origin, profile); 94 // refactored into PermissionContext.
95 if (is_asking_for_audio) {
96 callback.Run(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
97 PermissionRequestGestureType::UNKNOWN, security_origin,
98 profile);
99 }
100
101 if (is_asking_for_video) {
102 callback.Run(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
103 PermissionRequestGestureType::UNKNOWN, security_origin,
104 profile);
94 } 105 }
95 } 106 }
96 107
97 // Calls |action_function| for each permission requested by |request|.
98 void RecordPermissionAction(const content::MediaStreamRequest& request,
99 Profile* profile,
100 PermissionActionCallback callback) {
101 RecordSinglePermissionAction(request, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
102 profile, callback);
103 RecordSinglePermissionAction(
104 request, CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, profile, callback);
105 }
106
107 #if defined(OS_ANDROID)
108 // Callback for the permission update infobar when the site and Chrome
109 // permissions are mismatched on Android.
110 void OnPermissionConflictResolved(
111 std::unique_ptr<MediaStreamDevicesController> controller,
112 bool allowed) {
113 if (allowed)
114 controller->PermissionGranted();
115 else
116 controller->ForcePermissionDeniedTemporarily();
117 }
118
119 #endif // defined(OS_ANDROID)
120
121 // This helper class helps to measure the number of media stream requests that 108 // This helper class helps to measure the number of media stream requests that
122 // occur. It ensures that only one request will be recorded per navigation, per 109 // occur. It ensures that only one request will be recorded per navigation, per
123 // frame. TODO(raymes): Remove this when https://crbug.com/526324 is fixed. 110 // frame. TODO(raymes): Remove this when https://crbug.com/526324 is fixed.
124 class MediaPermissionRequestLogger : content::WebContentsObserver { 111 class MediaPermissionRequestLogger : content::WebContentsObserver {
125 // Map of <render process id, render frame id> -> 112 // Map of <render process id, render frame id> ->
126 // MediaPermissionRequestLogger. 113 // MediaPermissionRequestLogger.
127 using RequestMap = std::map<std::pair<int, int>, 114 using RequestMap = std::map<std::pair<int, int>,
128 std::unique_ptr<MediaPermissionRequestLogger>>; 115 std::unique_ptr<MediaPermissionRequestLogger>>;
129 116
130 public: 117 public:
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 // device id is non-empty, then the corresponding device list must not be 186 // device id is non-empty, then the corresponding device list must not be
200 // NULL. 187 // NULL.
201 if (!device_id.empty() && !devices->FindById(device_id)) 188 if (!device_id.empty() && !devices->FindById(device_id))
202 return false; 189 return false;
203 190
204 return true; 191 return true;
205 } 192 }
206 193
207 } // namespace 194 } // namespace
208 195
209 // Stores whether a permission has been requested or blocked during the course 196 namespace internal {
210 // of a permission request, as well as the denial reason
211 class MediaStreamDevicesController::MediaPermissionStatus {
212 public:
213 explicit MediaPermissionStatus(const content::MediaStreamRequest& request)
214 : audio_requested_(
215 ContentTypeIsRequested(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
216 request)),
217 video_requested_(
218 ContentTypeIsRequested(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
219 request)) {}
220 197
221 ~MediaPermissionStatus() {} 198 MediaStreamPermissionRequest::MediaStreamPermissionRequest(
199 Profile* profile,
200 bool is_asking_for_audio,
201 bool is_asking_for_video,
202 GURL security_origin,
203 base::Callback<void(ContentSetting, bool)> prompt_answered_callback)
204 : profile_(profile),
205 is_asking_for_audio_(is_asking_for_audio),
206 is_asking_for_video_(is_asking_for_video),
207 security_origin_(security_origin),
208 prompt_answered_callback_(prompt_answered_callback) {}
222 209
223 bool audio_requested() const { return audio_requested_; } 210 MediaStreamPermissionRequest::~MediaStreamPermissionRequest() {
224 bool video_requested() const { return video_requested_; } 211 RecordPermissionAction(is_asking_for_audio_, is_asking_for_video_,
212 security_origin_, profile_,
213 base::Bind(PermissionUmaUtil::PermissionIgnored));
214 }
225 215
226 bool audio_blocked() const { return audio_blocked_; } 216 bool MediaStreamPermissionRequest::IsAskingForAudio() const {
227 bool video_blocked() const { return video_blocked_; } 217 return is_asking_for_audio_;
218 }
228 219
229 content::MediaStreamRequestResult denial_reason() const { 220 bool MediaStreamPermissionRequest::IsAskingForVideo() const {
230 return denial_reason_; 221 return is_asking_for_video_;
231 } 222 }
232 223
233 void SetAudioBlocked(content::MediaStreamRequestResult denial_reason) { 224 base::string16 MediaStreamPermissionRequest::GetMessageText() const {
234 DCHECK(audio_requested_); 225 int message_id = IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO;
235 audio_blocked_ = true; 226 if (!IsAskingForAudio())
236 denial_reason_ = denial_reason; 227 message_id = IDS_MEDIA_CAPTURE_VIDEO_ONLY;
237 } 228 else if (!IsAskingForVideo())
229 message_id = IDS_MEDIA_CAPTURE_AUDIO_ONLY;
230 return l10n_util::GetStringFUTF16(
231 message_id,
232 url_formatter::FormatUrlForSecurityDisplay(
233 GetOrigin(), url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC));
234 }
238 235
239 void SetVideoBlocked(content::MediaStreamRequestResult denial_reason) { 236 PermissionRequest::IconId MediaStreamPermissionRequest::GetIconId() const {
240 DCHECK(video_requested_); 237 #if defined(OS_ANDROID)
241 video_blocked_ = true; 238 return IsAskingForVideo() ? IDR_INFOBAR_MEDIA_STREAM_CAMERA
242 denial_reason_ = denial_reason; 239 : IDR_INFOBAR_MEDIA_STREAM_MIC;
243 } 240 #else
241 return IsAskingForVideo() ? ui::kVideocamIcon : ui::kMicrophoneIcon;
242 #endif
243 }
244 244
245 private: 245 base::string16 MediaStreamPermissionRequest::GetMessageTextFragment() const {
246 bool audio_requested_ = false; 246 int message_id = IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO_PERMISSION_FRAGMENT;
247 bool video_requested_ = false; 247 if (!IsAskingForAudio())
248 bool audio_blocked_ = false; 248 message_id = IDS_MEDIA_CAPTURE_VIDEO_ONLY_PERMISSION_FRAGMENT;
249 bool video_blocked_ = false; 249 else if (!IsAskingForVideo())
250 message_id = IDS_MEDIA_CAPTURE_AUDIO_ONLY_PERMISSION_FRAGMENT;
251 return l10n_util::GetStringUTF16(message_id);
252 }
250 253
251 content::MediaStreamRequestResult denial_reason_ = content::MEDIA_DEVICE_OK; 254 GURL MediaStreamPermissionRequest::GetOrigin() const {
252 }; 255 return security_origin_;
256 }
257
258 void MediaStreamPermissionRequest::PermissionGranted() {
259 RecordPermissionAction(is_asking_for_audio_, is_asking_for_video_,
260 security_origin_, profile_,
261 base::Bind(PermissionUmaUtil::PermissionGranted));
262 prompt_answered_callback_.Run(CONTENT_SETTING_ALLOW, persist());
263 }
264
265 void MediaStreamPermissionRequest::PermissionDenied() {
266 RecordPermissionAction(is_asking_for_audio_, is_asking_for_video_,
267 security_origin_, profile_,
268 base::Bind(PermissionUmaUtil::PermissionDenied));
269 prompt_answered_callback_.Run(CONTENT_SETTING_BLOCK, persist());
270 }
271
272 bool MediaStreamPermissionRequest::ShouldShowPersistenceToggle() const {
273 return PermissionUtil::ShouldShowPersistenceToggle();
274 }
275
276 void MediaStreamPermissionRequest::Cancelled() {
277 RecordPermissionAction(is_asking_for_audio_, is_asking_for_video_,
278 security_origin_, profile_,
279 base::Bind(PermissionUmaUtil::PermissionDismissed));
280 prompt_answered_callback_.Run(CONTENT_SETTING_ASK, persist());
281 }
282
283 void MediaStreamPermissionRequest::RequestFinished() {
284 delete this;
285 }
286
287 PermissionRequestType MediaStreamPermissionRequest::GetPermissionRequestType()
288 const {
289 return PermissionRequestType::MEDIA_STREAM;
290 }
291
292 } // namespace internal
253 293
254 // Implementation of PermissionPromptDelegate which actually shows a permission 294 // Implementation of PermissionPromptDelegate which actually shows a permission
255 // prompt. 295 // prompt.
256 class MediaStreamDevicesController::PermissionPromptDelegateImpl 296 class MediaStreamDevicesController::PermissionPromptDelegateImpl
257 : public internal::PermissionPromptDelegate { 297 : public internal::PermissionPromptDelegate {
258 public: 298 public:
259 void ShowPrompt( 299 void ShowPrompt(bool user_gesture,
260 bool user_gesture, 300 content::WebContents* web_contents,
261 content::WebContents* web_contents, 301 std::unique_ptr<internal::MediaStreamPermissionRequest>
262 std::unique_ptr<MediaStreamDevicesController> controller) override { 302 request) override {
263 #if defined(OS_ANDROID) 303 #if defined(OS_ANDROID)
264 PermissionUmaUtil::RecordPermissionPromptShown( 304 PermissionUmaUtil::RecordPermissionPromptShown(
265 controller->GetPermissionRequestType(), 305 request->GetPermissionRequestType(),
266 PermissionUtil::GetGestureType(user_gesture)); 306 PermissionUtil::GetGestureType(user_gesture));
267 if (PermissionDialogDelegate::ShouldShowDialog(user_gesture)) { 307 if (PermissionDialogDelegate::ShouldShowDialog(user_gesture)) {
268 PermissionDialogDelegate::CreateMediaStreamDialog( 308 PermissionDialogDelegate::CreateMediaStreamDialog(
269 web_contents, user_gesture, std::move(controller)); 309 web_contents, user_gesture, std::move(request));
270 } else { 310 } else {
271 MediaStreamInfoBarDelegateAndroid::Create(web_contents, user_gesture, 311 MediaStreamInfoBarDelegateAndroid::Create(web_contents, user_gesture,
272 std::move(controller)); 312 std::move(request));
273 } 313 }
274 #else 314 #else
275 PermissionRequestManager* permission_request_manager = 315 PermissionRequestManager* permission_request_manager =
276 PermissionRequestManager::FromWebContents(web_contents); 316 PermissionRequestManager::FromWebContents(web_contents);
277 if (permission_request_manager) 317 if (permission_request_manager)
278 permission_request_manager->AddRequest(controller.release()); 318 permission_request_manager->AddRequest(request.release());
279 #endif 319 #endif
280 } 320 }
281 }; 321 };
282 322
283 // static 323 // static
284 void MediaStreamDevicesController::RequestPermissions( 324 void MediaStreamDevicesController::RequestPermissions(
285 const content::MediaStreamRequest& request, 325 const content::MediaStreamRequest& request,
286 const content::MediaResponseCallback& callback) { 326 const content::MediaResponseCallback& callback) {
287 PermissionPromptDelegateImpl delegate; 327 PermissionPromptDelegateImpl delegate;
288 RequestPermissionsWithDelegate(request, callback, &delegate); 328 RequestPermissionsWithDelegate(request, callback, &delegate);
289 } 329 }
290 330
291 // static 331 // static
292 void MediaStreamDevicesController::RegisterProfilePrefs( 332 void MediaStreamDevicesController::RegisterProfilePrefs(
293 user_prefs::PrefRegistrySyncable* prefs) { 333 user_prefs::PrefRegistrySyncable* prefs) {
294 prefs->RegisterBooleanPref(prefs::kVideoCaptureAllowed, true); 334 prefs->RegisterBooleanPref(prefs::kVideoCaptureAllowed, true);
295 prefs->RegisterBooleanPref(prefs::kAudioCaptureAllowed, true); 335 prefs->RegisterBooleanPref(prefs::kAudioCaptureAllowed, true);
296 prefs->RegisterListPref(prefs::kVideoCaptureAllowedUrls); 336 prefs->RegisterListPref(prefs::kVideoCaptureAllowedUrls);
297 prefs->RegisterListPref(prefs::kAudioCaptureAllowedUrls); 337 prefs->RegisterListPref(prefs::kAudioCaptureAllowedUrls);
298 } 338 }
299 339
300 MediaStreamDevicesController::~MediaStreamDevicesController() { 340 MediaStreamDevicesController::~MediaStreamDevicesController() {
301 if (!callback_.is_null()) { 341 if (!callback_.is_null()) {
302 RecordPermissionAction(request_, profile_,
303 base::Bind(PermissionUmaUtil::PermissionIgnored));
304 callback_.Run(content::MediaStreamDevices(), 342 callback_.Run(content::MediaStreamDevices(),
305 content::MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN, 343 content::MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN,
306 std::unique_ptr<content::MediaStreamUI>()); 344 std::unique_ptr<content::MediaStreamUI>());
307 } 345 }
308 } 346 }
309 347
310 bool MediaStreamDevicesController::IsAskingForAudio() const { 348 bool MediaStreamDevicesController::IsAskingForAudio() const {
311 return old_audio_setting_ == CONTENT_SETTING_ASK; 349 return audio_setting_ == CONTENT_SETTING_ASK;
312 } 350 }
313 351
314 bool MediaStreamDevicesController::IsAskingForVideo() const { 352 bool MediaStreamDevicesController::IsAskingForVideo() const {
315 return old_video_setting_ == CONTENT_SETTING_ASK; 353 return video_setting_ == CONTENT_SETTING_ASK;
316 } 354 }
317 355
318 base::string16 MediaStreamDevicesController::GetMessageText() const { 356 void MediaStreamDevicesController::PromptAnswered(ContentSetting setting,
319 int message_id = IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO; 357 bool persist) {
320 if (!IsAskingForAudio()) 358 if (setting != CONTENT_SETTING_ALLOW)
321 message_id = IDS_MEDIA_CAPTURE_VIDEO_ONLY; 359 denial_reason_ = content::MEDIA_DEVICE_PERMISSION_DENIED;
322 else if (!IsAskingForVideo()) 360
323 message_id = IDS_MEDIA_CAPTURE_AUDIO_ONLY; 361 HostContentSettingsMap* host_content_settings_map =
324 return l10n_util::GetStringFUTF16( 362 HostContentSettingsMapFactory::GetForProfile(profile_);
325 message_id, 363 if (audio_setting_ == CONTENT_SETTING_ASK) {
326 url_formatter::FormatUrlForSecurityDisplay( 364 if (persist) {
327 GetOrigin(), url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC)); 365 host_content_settings_map->SetContentSettingDefaultScope(
366 request_.security_origin, GURL(),
367 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, std::string(), setting);
368 }
369 audio_setting_ = setting;
370 }
371
372 if (video_setting_ == CONTENT_SETTING_ASK) {
373 if (persist) {
374 host_content_settings_map->SetContentSettingDefaultScope(
375 request_.security_origin, GURL(),
376 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string(), setting);
377 }
378 video_setting_ = setting;
379 }
380
381 RunCallback();
328 } 382 }
329 383
330 void MediaStreamDevicesController::ForcePermissionDeniedTemporarily() { 384 void MediaStreamDevicesController::PromptAnsweredGroupedRequest(
331 set_persist(false); 385 const std::vector<ContentSetting>& response) {
332 // TODO(tsergeant): Determine whether it is appropriate to record permission 386 if (audio_setting_ == CONTENT_SETTING_ASK)
333 // action metrics here, as this is a different sort of user action. 387 audio_setting_ = response.front();
334 RunCallback(CONTENT_SETTING_BLOCK, 388
335 CONTENT_SETTING_BLOCK, 389 if (video_setting_ == CONTENT_SETTING_ASK)
336 content::MEDIA_DEVICE_PERMISSION_DENIED); 390 video_setting_ = response.back();
337 set_persist(true); 391
392 if (audio_setting_ != CONTENT_SETTING_ALLOW &&
393 video_setting_ != CONTENT_SETTING_ALLOW)
394 denial_reason_ = content::MEDIA_DEVICE_PERMISSION_DENIED;
395
396 RunCallback();
338 } 397 }
339 398
340 PermissionRequest::IconId MediaStreamDevicesController::GetIconId() const { 399 void MediaStreamDevicesController::AndroidOSPromptAnswered(bool allowed) {
341 #if defined(OS_ANDROID) 400 if (!allowed) {
342 return IsAskingForVideo() ? IDR_INFOBAR_MEDIA_STREAM_CAMERA 401 denial_reason_ = content::MEDIA_DEVICE_PERMISSION_DENIED;
343 : IDR_INFOBAR_MEDIA_STREAM_MIC; 402 if (audio_setting_ == CONTENT_SETTING_ALLOW)
344 #else 403 audio_setting_ = CONTENT_SETTING_BLOCK;
345 return IsAskingForVideo() ? ui::kVideocamIcon : ui::kMicrophoneIcon; 404 if (video_setting_ == CONTENT_SETTING_ALLOW)
346 #endif 405 video_setting_ = CONTENT_SETTING_BLOCK;
406 }
407
408 RunCallback();
347 } 409 }
348 410
349 base::string16 MediaStreamDevicesController::GetMessageTextFragment() const { 411 void MediaStreamDevicesController::RequestFinishedNoPrompt() {
350 int message_id = IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO_PERMISSION_FRAGMENT; 412 RunCallback();
351 if (!IsAskingForAudio())
352 message_id = IDS_MEDIA_CAPTURE_VIDEO_ONLY_PERMISSION_FRAGMENT;
353 else if (!IsAskingForVideo())
354 message_id = IDS_MEDIA_CAPTURE_AUDIO_ONLY_PERMISSION_FRAGMENT;
355 return l10n_util::GetStringUTF16(message_id);
356 }
357
358 GURL MediaStreamDevicesController::GetOrigin() const {
359 return request_.security_origin;
360 }
361
362 void MediaStreamDevicesController::PermissionGranted() {
363 RecordPermissionAction(request_, profile_,
364 base::Bind(PermissionUmaUtil::PermissionGranted));
365 RunCallback(GetNewSetting(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
366 old_audio_setting_, CONTENT_SETTING_ALLOW),
367 GetNewSetting(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
368 old_video_setting_, CONTENT_SETTING_ALLOW),
369 content::MEDIA_DEVICE_PERMISSION_DENIED);
370 }
371
372 void MediaStreamDevicesController::PermissionDenied() {
373 RecordPermissionAction(request_, profile_,
374 base::Bind(PermissionUmaUtil::PermissionDenied));
375 RunCallback(GetNewSetting(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
376 old_audio_setting_, CONTENT_SETTING_BLOCK),
377 GetNewSetting(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
378 old_video_setting_, CONTENT_SETTING_BLOCK),
379 content::MEDIA_DEVICE_PERMISSION_DENIED);
380 }
381
382 bool MediaStreamDevicesController::ShouldShowPersistenceToggle() const {
383 return PermissionUtil::ShouldShowPersistenceToggle();
384 }
385
386 void MediaStreamDevicesController::Cancelled() {
387 RecordPermissionAction(request_, profile_,
388 base::Bind(PermissionUmaUtil::PermissionDismissed));
389 RunCallback(old_audio_setting_, old_video_setting_,
390 content::MEDIA_DEVICE_PERMISSION_DISMISSED);
391 }
392
393 void MediaStreamDevicesController::RequestFinished() {
394 delete this;
395 }
396
397 PermissionRequestType MediaStreamDevicesController::GetPermissionRequestType()
398 const {
399 return PermissionRequestType::MEDIA_STREAM;
400 } 413 }
401 414
402 // static 415 // static
403 void MediaStreamDevicesController::RequestPermissionsWithDelegate( 416 void MediaStreamDevicesController::RequestPermissionsWithDelegate(
404 const content::MediaStreamRequest& request, 417 const content::MediaStreamRequest& request,
405 const content::MediaResponseCallback& callback, 418 const content::MediaResponseCallback& callback,
406 internal::PermissionPromptDelegate* delegate) { 419 internal::PermissionPromptDelegate* delegate) {
420 content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
421 request.render_process_id, request.render_frame_id);
407 content::WebContents* web_contents = 422 content::WebContents* web_contents =
408 content::WebContents::FromRenderFrameHost( 423 content::WebContents::FromRenderFrameHost(rfh);
409 content::RenderFrameHost::FromID(request.render_process_id,
410 request.render_frame_id));
411 if (request.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY) { 424 if (request.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY) {
412 MediaPermissionRequestLogger::LogRequest( 425 MediaPermissionRequestLogger::LogRequest(
413 web_contents, request.render_process_id, request.render_frame_id, 426 web_contents, request.render_process_id, request.render_frame_id,
414 content::IsOriginSecure(request.security_origin)); 427 content::IsOriginSecure(request.security_origin));
415 } 428 }
416 429
417 MediaPermissionStatus initial_permission(request); 430 std::unique_ptr<MediaStreamDevicesController> controller(
418 if (initial_permission.audio_requested() && 431 new MediaStreamDevicesController(web_contents, request, callback));
419 !HasAvailableDevices(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
420 request.requested_audio_device_id)) {
421 initial_permission.SetAudioBlocked(content::MEDIA_DEVICE_NO_HARDWARE);
422 }
423 432
424 if (initial_permission.video_requested() && 433 #if defined(OS_ANDROID)
425 !HasAvailableDevices(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
426 request.requested_video_device_id)) {
427 initial_permission.SetVideoBlocked(content::MEDIA_DEVICE_NO_HARDWARE);
428 }
429
430 std::unique_ptr<MediaStreamDevicesController> controller(
431 new MediaStreamDevicesController(web_contents, request, callback,
432 initial_permission));
433 if (!controller->IsAskingForAudio() && !controller->IsAskingForVideo()) { 434 if (!controller->IsAskingForAudio() && !controller->IsAskingForVideo()) {
434 #if defined(OS_ANDROID)
435 // If either audio or video was previously allowed and Chrome no longer has 435 // If either audio or video was previously allowed and Chrome no longer has
436 // the necessary permissions, show a infobar to attempt to address this 436 // the necessary permissions, show a infobar to attempt to address this
437 // mismatch. 437 // mismatch.
438 std::vector<ContentSettingsType> content_settings_types; 438 std::vector<ContentSettingsType> content_settings_types;
439 if (controller->IsAllowedForAudio()) 439 if (controller->IsAllowedForAudio())
440 content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC); 440 content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
441 441
442 if (controller->IsAllowedForVideo()) { 442 if (controller->IsAllowedForVideo()) {
443 content_settings_types.push_back( 443 content_settings_types.push_back(
444 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA); 444 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
445 } 445 }
446 if (!content_settings_types.empty() && 446 if (!content_settings_types.empty() &&
447 PermissionUpdateInfoBarDelegate::ShouldShowPermissionInfobar( 447 PermissionUpdateInfoBarDelegate::ShouldShowPermissionInfobar(
448 web_contents, content_settings_types)) { 448 web_contents, content_settings_types)) {
449 PermissionUpdateInfoBarDelegate::Create( 449 PermissionUpdateInfoBarDelegate::Create(
450 web_contents, content_settings_types, 450 web_contents, content_settings_types,
451 base::Bind(&OnPermissionConflictResolved, base::Passed(&controller))); 451 base::Bind(&AndroidOSPromptAnswered, base::Passed(&controller)));
452 return;
452 } 453 }
454 }
453 #endif 455 #endif
454 return; 456
457 Profile* profile =
458 Profile::FromBrowserContext(web_contents->GetBrowserContext());
459 if (!controller->IsAskingForAudio() && !controller->IsAskingForVideo()) {
460 controller->RequestFinishedNoPrompt();
461 } else {
462 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
463 switches::kEnableGroupedMediaPermissionPrompts)) {
464 std::vector<ContentSettingsType> content_settings_types;
465
466 if (controller->IsAskingForAudio())
467 content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
468 if (controller->IsAskingForVideo()) {
469 content_settings_types.push_back(
470 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
471 }
472
473 LOG(ERROR) << content_settings_types.size();
474
475 PermissionManager::Get(profile)->RequestPermissions(
476 content_settings_types, rfh, request.security_origin,
477 request.user_gesture,
478 base::Bind(
479 &MediaStreamDevicesController::PromptAnsweredGroupedRequest,
480 base::Passed(&controller)));
481 } else {
482 delegate->ShowPrompt(
483 request.user_gesture, web_contents,
484 base::MakeUnique<internal::MediaStreamPermissionRequest>(
485 profile, controller->IsAskingForAudio(),
486 controller->IsAskingForVideo(), request.security_origin,
487 base::Bind(&MediaStreamDevicesController::PromptAnswered,
488 base::Passed(&controller))));
489 }
455 } 490 }
456
457 delegate->ShowPrompt(request.user_gesture, web_contents,
458 std::move(controller));
459 } 491 }
460 492
461 MediaStreamDevicesController::MediaStreamDevicesController( 493 MediaStreamDevicesController::MediaStreamDevicesController(
462 content::WebContents* web_contents, 494 content::WebContents* web_contents,
463 const content::MediaStreamRequest& request, 495 const content::MediaStreamRequest& request,
464 const content::MediaResponseCallback& callback, 496 const content::MediaResponseCallback& callback)
465 const MediaPermissionStatus& initial_permission)
466 : web_contents_(web_contents), request_(request), callback_(callback) { 497 : web_contents_(web_contents), request_(request), callback_(callback) {
467 profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext()); 498 profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext());
468 content_settings_ = TabSpecificContentSettings::FromWebContents(web_contents); 499 content_settings_ = TabSpecificContentSettings::FromWebContents(web_contents);
469 500
470 content::MediaStreamRequestResult denial_reason = 501 denial_reason_ = content::MEDIA_DEVICE_OK;
471 initial_permission.denial_reason(); 502 audio_setting_ = GetContentSetting(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
472 old_audio_setting_ = 503 request, &denial_reason_);
473 GetContentSetting(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, request, 504 video_setting_ = GetContentSetting(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
474 initial_permission.audio_requested(), 505 request, &denial_reason_);
475 initial_permission.audio_blocked(), &denial_reason);
476 old_video_setting_ =
477 GetContentSetting(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, request,
478 initial_permission.video_requested(),
479 initial_permission.video_blocked(), &denial_reason);
480
481 // If either setting is ask, we show the infobar.
482 if (old_audio_setting_ == CONTENT_SETTING_ASK ||
483 old_video_setting_ == CONTENT_SETTING_ASK) {
484 return;
485 }
486
487 #if defined(OS_ANDROID)
488 std::vector<ContentSettingsType> content_settings_types;
489 if (IsAllowedForAudio())
490 content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
491
492 if (IsAllowedForVideo()) {
493 content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
494 }
495
496 // If the site had been previously granted the access to audio or video but
497 // Chrome is now missing the necessary permission, we need to show an infobar
498 // to resolve the difference.
499 if (!content_settings_types.empty() &&
500 PermissionUpdateInfoBarDelegate::ShouldShowPermissionInfobar(
501 web_contents, content_settings_types)) {
502 return;
503 }
504 #endif
505
506 // Otherwise we can run the callback immediately.
507 RunCallback(old_audio_setting_, old_video_setting_, denial_reason);
508 } 506 }
509 507
510 bool MediaStreamDevicesController::IsAllowedForAudio() const { 508 bool MediaStreamDevicesController::IsAllowedForAudio() const {
511 return old_audio_setting_ == CONTENT_SETTING_ALLOW; 509 return audio_setting_ == CONTENT_SETTING_ALLOW;
512 } 510 }
513 511
514 bool MediaStreamDevicesController::IsAllowedForVideo() const { 512 bool MediaStreamDevicesController::IsAllowedForVideo() const {
515 return old_video_setting_ == CONTENT_SETTING_ALLOW; 513 return video_setting_ == CONTENT_SETTING_ALLOW;
516 } 514 }
517 515
518 content::MediaStreamDevices MediaStreamDevicesController::GetDevices( 516 content::MediaStreamDevices MediaStreamDevicesController::GetDevices(
519 ContentSetting audio_setting, 517 ContentSetting audio_setting,
520 ContentSetting video_setting) { 518 ContentSetting video_setting) {
521 bool audio_allowed = audio_setting == CONTENT_SETTING_ALLOW; 519 bool audio_allowed = audio_setting == CONTENT_SETTING_ALLOW;
522 bool video_allowed = video_setting == CONTENT_SETTING_ALLOW; 520 bool video_allowed = video_setting == CONTENT_SETTING_ALLOW;
523 521
524 if (!audio_allowed && !video_allowed) 522 if (!audio_allowed && !video_allowed)
525 return content::MediaStreamDevices(); 523 return content::MediaStreamDevices();
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
597 // Get the default devices for the request. 595 // Get the default devices for the request.
598 MediaCaptureDevicesDispatcher::GetInstance()->GetDefaultDevicesForProfile( 596 MediaCaptureDevicesDispatcher::GetInstance()->GetDefaultDevicesForProfile(
599 profile_, audio_allowed, video_allowed, &devices); 597 profile_, audio_allowed, video_allowed, &devices);
600 break; 598 break;
601 } 599 }
602 } // switch 600 } // switch
603 601
604 return devices; 602 return devices;
605 } 603 }
606 604
607 void MediaStreamDevicesController::RunCallback( 605 void MediaStreamDevicesController::RunCallback() {
608 ContentSetting audio_setting,
609 ContentSetting video_setting,
610 content::MediaStreamRequestResult denial_reason) {
611 CHECK(!callback_.is_null()); 606 CHECK(!callback_.is_null());
612 607
613 // If the kill switch is on we don't update the tab context or persist the 608 // If the kill switch is on we don't update the tab context.
614 // setting. 609 if (denial_reason_ != content::MEDIA_DEVICE_KILL_SWITCH_ON)
615 if (denial_reason != content::MEDIA_DEVICE_KILL_SWITCH_ON) { 610 UpdateTabSpecificContentSettings(audio_setting_, video_setting_);
616 if (persist())
617 StorePermission(audio_setting, video_setting);
618 UpdateTabSpecificContentSettings(audio_setting, video_setting);
619 }
620 611
621 content::MediaStreamDevices devices = 612 content::MediaStreamDevices devices =
622 GetDevices(audio_setting, video_setting); 613 GetDevices(audio_setting_, video_setting_);
623 614
624 // If either audio or video are allowed then the callback should report 615 // If either audio or video are allowed then the callback should report
625 // success, otherwise we report |denial_reason|. 616 // success, otherwise we report |denial_reason_|.
626 content::MediaStreamRequestResult request_result = content::MEDIA_DEVICE_OK; 617 if (audio_setting_ != CONTENT_SETTING_ALLOW &&
627 if (audio_setting != CONTENT_SETTING_ALLOW && 618 video_setting_ != CONTENT_SETTING_ALLOW) {
628 video_setting != CONTENT_SETTING_ALLOW) { 619 DCHECK_NE(content::MEDIA_DEVICE_OK, denial_reason_);
629 DCHECK_NE(content::MEDIA_DEVICE_OK, denial_reason);
630 request_result = denial_reason;
631 } else if (devices.empty()) { 620 } else if (devices.empty()) {
632 // Even if one of the content settings was allowed, if there are no devices 621 // Even if one of the content settings was allowed, if there are no devices
633 // at this point we still report a failure. 622 // at this point we still report a failure.
634 request_result = content::MEDIA_DEVICE_NO_HARDWARE; 623 denial_reason_ = content::MEDIA_DEVICE_NO_HARDWARE;
635 } 624 }
636 625
637 std::unique_ptr<content::MediaStreamUI> ui; 626 std::unique_ptr<content::MediaStreamUI> ui;
638 if (!devices.empty()) { 627 if (!devices.empty()) {
639 ui = MediaCaptureDevicesDispatcher::GetInstance() 628 ui = MediaCaptureDevicesDispatcher::GetInstance()
640 ->GetMediaStreamCaptureIndicator() 629 ->GetMediaStreamCaptureIndicator()
641 ->RegisterMediaStream(web_contents_, devices); 630 ->RegisterMediaStream(web_contents_, devices);
642 } 631 }
643 base::ResetAndReturn(&callback_).Run(devices, request_result, std::move(ui)); 632 base::ResetAndReturn(&callback_).Run(devices, denial_reason_, std::move(ui));
644 }
645
646 void MediaStreamDevicesController::StorePermission(
647 ContentSetting new_audio_setting,
648 ContentSetting new_video_setting) const {
649 DCHECK_CURRENTLY_ON(BrowserThread::UI);
650 DCHECK(content::IsOriginSecure(request_.security_origin) ||
651 request_.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY);
652
653 if (IsAskingForAudio() && new_audio_setting != CONTENT_SETTING_ASK) {
654 HostContentSettingsMapFactory::GetForProfile(profile_)
655 ->SetContentSettingDefaultScope(request_.security_origin, GURL(),
656 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
657 std::string(), new_audio_setting);
658 }
659 if (IsAskingForVideo() && new_video_setting != CONTENT_SETTING_ASK) {
660 HostContentSettingsMapFactory::GetForProfile(profile_)
661 ->SetContentSettingDefaultScope(
662 request_.security_origin, GURL(),
663 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string(),
664 new_video_setting);
665 }
666 } 633 }
667 634
668 void MediaStreamDevicesController::UpdateTabSpecificContentSettings( 635 void MediaStreamDevicesController::UpdateTabSpecificContentSettings(
669 ContentSetting audio_setting, 636 ContentSetting audio_setting,
670 ContentSetting video_setting) const { 637 ContentSetting video_setting) const {
671 if (!content_settings_) 638 if (!content_settings_)
672 return; 639 return;
673 640
674 TabSpecificContentSettings::MicrophoneCameraState microphone_camera_state = 641 TabSpecificContentSettings::MicrophoneCameraState microphone_camera_state =
675 TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED; 642 TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
707 } 674 }
708 675
709 content_settings_->OnMediaStreamPermissionSet( 676 content_settings_->OnMediaStreamPermissionSet(
710 request_.security_origin, microphone_camera_state, selected_audio_device, 677 request_.security_origin, microphone_camera_state, selected_audio_device,
711 selected_video_device, requested_audio_device, requested_video_device); 678 selected_video_device, requested_audio_device, requested_video_device);
712 } 679 }
713 680
714 ContentSetting MediaStreamDevicesController::GetContentSetting( 681 ContentSetting MediaStreamDevicesController::GetContentSetting(
715 ContentSettingsType content_type, 682 ContentSettingsType content_type,
716 const content::MediaStreamRequest& request, 683 const content::MediaStreamRequest& request,
717 bool was_requested,
718 bool was_initially_blocked,
719 content::MediaStreamRequestResult* denial_reason) const { 684 content::MediaStreamRequestResult* denial_reason) const {
720 DCHECK(content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC || 685 DCHECK(content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC ||
721 content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA); 686 content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
722 DCHECK(!request_.security_origin.is_empty()); 687 DCHECK(!request_.security_origin.is_empty());
723 DCHECK(content::IsOriginSecure(request_.security_origin) || 688 DCHECK(content::IsOriginSecure(request_.security_origin) ||
724 request_.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY); 689 request_.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY);
725 if (!was_requested) { 690 if (!ContentTypeIsRequested(content_type, request)) {
726 // No denial reason set as it will have been previously set. 691 // No denial reason set as it will have been previously set.
727 return CONTENT_SETTING_DEFAULT; 692 return CONTENT_SETTING_DEFAULT;
728 } 693 }
729 694
730 if (was_initially_blocked) { 695 std::string device_id;
731 // No denial reason set as it will have been previously set. 696 if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)
697 device_id = request.requested_audio_device_id;
698 else
699 device_id = request.requested_video_device_id;
700 if (!HasAvailableDevices(content_type, device_id)) {
701 *denial_reason = content::MEDIA_DEVICE_NO_HARDWARE;
732 return CONTENT_SETTING_BLOCK; 702 return CONTENT_SETTING_BLOCK;
733 } 703 }
734 704
735 if (!IsUserAcceptAllowed(content_type)) { 705 if (!IsUserAcceptAllowed(content_type)) {
736 *denial_reason = content::MEDIA_DEVICE_PERMISSION_DENIED; 706 *denial_reason = content::MEDIA_DEVICE_PERMISSION_DENIED;
737 return CONTENT_SETTING_BLOCK; 707 return CONTENT_SETTING_BLOCK;
738 } 708 }
739 709
740 PermissionResult result = 710 PermissionResult result =
741 PermissionManager::Get(profile_)->GetPermissionStatus( 711 PermissionManager::Get(profile_)->GetPermissionStatus(
742 content_type, request.security_origin, 712 content_type, request.security_origin,
743 web_contents_->GetLastCommittedURL().GetOrigin()); 713 web_contents_->GetLastCommittedURL().GetOrigin());
744 if (result.content_setting == CONTENT_SETTING_BLOCK) { 714 if (result.content_setting == CONTENT_SETTING_BLOCK) {
745 *denial_reason = (result.source == PermissionStatusSource::KILL_SWITCH) 715 *denial_reason = (result.source == PermissionStatusSource::KILL_SWITCH)
746 ? content::MEDIA_DEVICE_KILL_SWITCH_ON 716 ? content::MEDIA_DEVICE_KILL_SWITCH_ON
747 : content::MEDIA_DEVICE_PERMISSION_DENIED; 717 : content::MEDIA_DEVICE_PERMISSION_DENIED;
748 } 718 }
749 719
750 return result.content_setting; 720 return result.content_setting;
751 } 721 }
752 722
753 ContentSetting MediaStreamDevicesController::GetNewSetting(
754 ContentSettingsType content_type,
755 ContentSetting old_setting,
756 ContentSetting user_decision) const {
757 DCHECK(user_decision == CONTENT_SETTING_ALLOW ||
758 user_decision == CONTENT_SETTING_BLOCK);
759 ContentSetting result = old_setting;
760 if (old_setting == CONTENT_SETTING_ASK)
761 result = user_decision;
762 return result;
763 }
764
765 bool MediaStreamDevicesController::IsUserAcceptAllowed( 723 bool MediaStreamDevicesController::IsUserAcceptAllowed(
766 ContentSettingsType content_type) const { 724 ContentSettingsType content_type) const {
767 #if defined(OS_ANDROID) 725 #if defined(OS_ANDROID)
768 content::ContentViewCore* cvc = 726 content::ContentViewCore* cvc =
769 content::ContentViewCore::FromWebContents(web_contents_); 727 content::ContentViewCore::FromWebContents(web_contents_);
770 if (!cvc) 728 if (!cvc)
771 return false; 729 return false;
772 730
773 ui::WindowAndroid* window_android = cvc->GetWindowAndroid(); 731 ui::WindowAndroid* window_android = cvc->GetWindowAndroid();
774 if (!window_android) 732 if (!window_android)
775 return false; 733 return false;
776 734
777 std::vector<std::string> android_permissions; 735 std::vector<std::string> android_permissions;
778 PrefServiceBridge::GetAndroidPermissionsForContentSetting( 736 PrefServiceBridge::GetAndroidPermissionsForContentSetting(
779 content_type, &android_permissions); 737 content_type, &android_permissions);
780 for (const auto& android_permission : android_permissions) { 738 for (const auto& android_permission : android_permissions) {
781 if (!window_android->HasPermission(android_permission) && 739 if (!window_android->HasPermission(android_permission) &&
782 !window_android->CanRequestPermission(android_permission)) { 740 !window_android->CanRequestPermission(android_permission)) {
783 return false; 741 return false;
784 } 742 }
785 } 743 }
786 744
787 // Don't approve device requests if the tab was hidden. 745 // Don't approve device requests if the tab was hidden.
788 // TODO(qinmin): Add a test for this. http://crbug.com/396869. 746 // TODO(qinmin): Add a test for this. http://crbug.com/396869.
789 // TODO(raymes): Shouldn't this apply to all permissions not just audio/video? 747 // TODO(raymes): Shouldn't this apply to all permissions not just audio/video?
790 return web_contents_->GetRenderWidgetHostView()->IsShowing(); 748 return web_contents_->GetRenderWidgetHostView()->IsShowing();
791 #endif 749 #endif
792 return true; 750 return true;
793 } 751 }
OLDNEW
« no previous file with comments | « chrome/browser/media/webrtc/media_stream_devices_controller.h ('k') | chrome/browser/permissions/permission_request.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698