Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / media / media_stream_devices_controller.cc
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/media/media_stream_devices_controller.h"
6
7 #include "base/metrics/histogram.h"
8 #include "base/prefs/scoped_user_pref_update.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/values.h"
11 #include "chrome/browser/content_settings/host_content_settings_map.h"
12 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
13 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
14 #include "chrome/browser/media/media_stream_capture_indicator.h"
15 #include "chrome/browser/media/media_stream_device_permissions.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/common/chrome_switches.h"
19 #include "chrome/common/pref_names.h"
20 #include "chrome/grit/generated_resources.h"
21 #include "components/content_settings/core/browser/content_settings_provider.h"
22 #include "components/content_settings/core/common/content_settings.h"
23 #include "components/content_settings/core/common/content_settings_pattern.h"
24 #include "components/pref_registry/pref_registry_syncable.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/render_widget_host_view.h"
27 #include "content/public/common/media_stream_request.h"
28 #include "extensions/common/constants.h"
29 #include "grit/theme_resources.h"
30 #include "ui/base/l10n/l10n_util.h"
31
32 using content::BrowserThread;
33
34 namespace {
35
36 bool HasAvailableDevicesForRequest(const content::MediaStreamRequest& request) {
37   const content::MediaStreamDevices* audio_devices =
38       request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE ?
39           &MediaCaptureDevicesDispatcher::GetInstance()
40               ->GetAudioCaptureDevices() :
41           NULL;
42
43   const content::MediaStreamDevices* video_devices =
44       request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE ?
45           &MediaCaptureDevicesDispatcher::GetInstance()
46               ->GetVideoCaptureDevices() :
47           NULL;
48
49   // Check if we're being asked for audio and/or video and that either of those
50   // lists is empty.  If they are, we do not have devices available for the
51   // request.
52   // TODO(tommi): It's kind of strange to have this here since if we fail this
53   // test, there'll be a UI shown that indicates to the user that access to
54   // non-existing audio/video devices has been denied.  The user won't have
55   // any way to change that but there will be a UI shown which indicates that
56   // access is blocked.
57   if ((audio_devices != NULL && audio_devices->empty()) ||
58       (video_devices != NULL && video_devices->empty())) {
59     return false;
60   }
61
62   // Note: we check requested_[audio|video]_device_id before dereferencing
63   // [audio|video]_devices.  If the requested device id is non-empty, then
64   // the corresponding device list must not be NULL.
65
66   if (!request.requested_audio_device_id.empty() &&
67       !audio_devices->FindById(request.requested_audio_device_id)) {
68     return false;
69   }
70
71   if (!request.requested_video_device_id.empty() &&
72       !video_devices->FindById(request.requested_video_device_id)) {
73     return false;
74   }
75
76   return true;
77 }
78
79 enum DevicePermissionActions {
80   kAllowHttps = 0,
81   kAllowHttp,
82   kDeny,
83   kCancel,
84   kPermissionActionsMax  // Must always be last!
85 };
86
87 }  // namespace
88
89 MediaStreamDevicesController::MediaStreamTypeSettings::MediaStreamTypeSettings(
90     Permission permission, const std::string& requested_device_id):
91     permission(permission), requested_device_id(requested_device_id) {}
92
93 MediaStreamDevicesController::MediaStreamTypeSettings::
94     MediaStreamTypeSettings(): permission(MEDIA_NONE) {}
95
96 MediaStreamDevicesController::MediaStreamTypeSettings::
97     ~MediaStreamTypeSettings() {}
98
99 MediaStreamDevicesController::MediaStreamDevicesController(
100     content::WebContents* web_contents,
101     const content::MediaStreamRequest& request,
102     const content::MediaResponseCallback& callback)
103     : web_contents_(web_contents),
104       request_(request),
105       callback_(callback) {
106   profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext());
107   content_settings_ = TabSpecificContentSettings::FromWebContents(web_contents);
108
109   // For MEDIA_OPEN_DEVICE requests (Pepper) we always request both webcam
110   // and microphone to avoid popping two infobars.
111   // We start with setting the requested media type to allowed or blocked
112   // depending on the policy. If not blocked by policy it may be blocked later
113   // in the two remaining filtering steps (by user setting or by user when
114   // clicking the infobar).
115   // TODO(grunell): It's not the nicest solution to let the MEDIA_OPEN_DEVICE
116   // case take a ride on the MEDIA_DEVICE_*_CAPTURE permission. Should be fixed.
117   if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
118       request.request_type == content::MEDIA_OPEN_DEVICE) {
119     if (GetDevicePolicy(profile_,
120                         request_.security_origin,
121                         prefs::kAudioCaptureAllowed,
122                         prefs::kAudioCaptureAllowedUrls) == ALWAYS_DENY) {
123       request_permissions_.insert(std::make_pair(
124           content::MEDIA_DEVICE_AUDIO_CAPTURE,
125           MediaStreamTypeSettings(MEDIA_BLOCKED_BY_POLICY,
126                                   request.requested_audio_device_id)));
127     } else {
128       request_permissions_.insert(std::make_pair(
129           content::MEDIA_DEVICE_AUDIO_CAPTURE,
130           MediaStreamTypeSettings(MEDIA_ALLOWED,
131                                   request.requested_audio_device_id)));
132     }
133   }
134   if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE ||
135       request.request_type == content::MEDIA_OPEN_DEVICE) {
136     if (GetDevicePolicy(profile_,
137                         request_.security_origin,
138                         prefs::kVideoCaptureAllowed,
139                         prefs::kVideoCaptureAllowedUrls) == ALWAYS_DENY) {
140       request_permissions_.insert(std::make_pair(
141           content::MEDIA_DEVICE_VIDEO_CAPTURE,
142           MediaStreamTypeSettings(MEDIA_BLOCKED_BY_POLICY,
143                                   request.requested_video_device_id)));
144     } else {
145       request_permissions_.insert(std::make_pair(
146           content::MEDIA_DEVICE_VIDEO_CAPTURE,
147           MediaStreamTypeSettings(MEDIA_ALLOWED,
148                                   request.requested_video_device_id)));
149     }
150   }
151 }
152
153 MediaStreamDevicesController::~MediaStreamDevicesController() {
154   if (!callback_.is_null()) {
155     callback_.Run(content::MediaStreamDevices(),
156                   content::MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN,
157                   scoped_ptr<content::MediaStreamUI>());
158   }
159 }
160
161 // static
162 void MediaStreamDevicesController::RegisterProfilePrefs(
163     user_prefs::PrefRegistrySyncable* prefs) {
164   prefs->RegisterBooleanPref(prefs::kVideoCaptureAllowed,
165                              true,
166                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
167   prefs->RegisterBooleanPref(prefs::kAudioCaptureAllowed,
168                              true,
169                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
170   prefs->RegisterListPref(prefs::kVideoCaptureAllowedUrls,
171                           user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
172   prefs->RegisterListPref(prefs::kAudioCaptureAllowedUrls,
173                           user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
174 }
175
176 // TODO(gbillock): rename? doesn't actually dismiss. More of a 'check profile
177 // and system for compatibility' thing.
178 bool MediaStreamDevicesController::DismissInfoBarAndTakeActionOnSettings() {
179   // Tab capture is allowed for extensions only and infobar is not shown for
180   // extensions.
181   if (request_.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE ||
182       request_.video_type == content::MEDIA_TAB_VIDEO_CAPTURE) {
183     Deny(false, content::MEDIA_DEVICE_INVALID_STATE);
184     return true;
185   }
186
187   // Deny the request if the security origin is empty, this happens with
188   // file access without |--allow-file-access-from-files| flag.
189   if (request_.security_origin.is_empty()) {
190     Deny(false, content::MEDIA_DEVICE_INVALID_SECURITY_ORIGIN);
191     return true;
192   }
193
194   // Deny the request if there is no device attached to the OS of the
195   // requested type. If both audio and video is requested, both types must be
196   // available.
197   if (!HasAvailableDevicesForRequest(request_)) {
198     Deny(false, content::MEDIA_DEVICE_NO_HARDWARE);
199     return true;
200   }
201
202   // Check if any allow exception has been made for this request.
203   if (IsRequestAllowedByDefault()) {
204     Accept(false);
205     return true;
206   }
207
208   // Filter any parts of the request that have been blocked by default and deny
209   // it if nothing is left to accept.
210   if (FilterBlockedByDefaultDevices() == 0) {
211     Deny(false, content::MEDIA_DEVICE_PERMISSION_DENIED);
212     return true;
213   }
214
215   // Check if the media default setting is set to block.
216   if (IsDefaultMediaAccessBlocked()) {
217     Deny(false, content::MEDIA_DEVICE_PERMISSION_DENIED);
218     return true;
219   }
220
221   // Show the infobar.
222   return false;
223 }
224
225 bool MediaStreamDevicesController::HasAudio() const {
226   return IsDeviceAudioCaptureRequestedAndAllowed();
227 }
228
229 bool MediaStreamDevicesController::HasVideo() const {
230   return IsDeviceVideoCaptureRequestedAndAllowed();
231 }
232
233 const std::string& MediaStreamDevicesController::GetSecurityOriginSpec() const {
234   return request_.security_origin.spec();
235 }
236
237 void MediaStreamDevicesController::Accept(bool update_content_setting) {
238   NotifyUIRequestAccepted();
239
240   // Get the default devices for the request.
241   content::MediaStreamDevices devices;
242   bool audio_allowed = IsDeviceAudioCaptureRequestedAndAllowed();
243   bool video_allowed = IsDeviceVideoCaptureRequestedAndAllowed();
244   if (audio_allowed || video_allowed) {
245     switch (request_.request_type) {
246       case content::MEDIA_OPEN_DEVICE: {
247         const content::MediaStreamDevice* device = NULL;
248         // For open device request, when requested device_id is empty, pick
249         // the first available of the given type. If requested device_id is
250         // not empty, return the desired device if it's available. Otherwise,
251         // return no device.
252         if (audio_allowed &&
253             request_.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE) {
254           if (!request_.requested_audio_device_id.empty()) {
255             device = MediaCaptureDevicesDispatcher::GetInstance()->
256                 GetRequestedAudioDevice(request_.requested_audio_device_id);
257           } else {
258             device = MediaCaptureDevicesDispatcher::GetInstance()->
259                 GetFirstAvailableAudioDevice();
260           }
261         } else if (video_allowed &&
262             request_.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) {
263           // Pepper API opens only one device at a time.
264           if (!request_.requested_video_device_id.empty()) {
265             device = MediaCaptureDevicesDispatcher::GetInstance()->
266                 GetRequestedVideoDevice(request_.requested_video_device_id);
267           } else {
268             device = MediaCaptureDevicesDispatcher::GetInstance()->
269                 GetFirstAvailableVideoDevice();
270           }
271         }
272         if (device)
273           devices.push_back(*device);
274         break;
275       }
276       case content::MEDIA_GENERATE_STREAM: {
277         bool get_default_audio_device = audio_allowed;
278         bool get_default_video_device = video_allowed;
279
280         // Get the exact audio or video device if an id is specified.
281         if (audio_allowed && !request_.requested_audio_device_id.empty()) {
282           const content::MediaStreamDevice* audio_device =
283               MediaCaptureDevicesDispatcher::GetInstance()->
284                   GetRequestedAudioDevice(request_.requested_audio_device_id);
285           if (audio_device) {
286             devices.push_back(*audio_device);
287             get_default_audio_device = false;
288           }
289         }
290         if (video_allowed && !request_.requested_video_device_id.empty()) {
291           const content::MediaStreamDevice* video_device =
292               MediaCaptureDevicesDispatcher::GetInstance()->
293                   GetRequestedVideoDevice(request_.requested_video_device_id);
294           if (video_device) {
295             devices.push_back(*video_device);
296             get_default_video_device = false;
297           }
298         }
299
300         // If either or both audio and video devices were requested but not
301         // specified by id, get the default devices.
302         if (get_default_audio_device || get_default_video_device) {
303           MediaCaptureDevicesDispatcher::GetInstance()->
304               GetDefaultDevicesForProfile(profile_,
305                                           get_default_audio_device,
306                                           get_default_video_device,
307                                           &devices);
308         }
309         break;
310       }
311       case content::MEDIA_DEVICE_ACCESS: {
312         // Get the default devices for the request.
313         MediaCaptureDevicesDispatcher::GetInstance()->
314             GetDefaultDevicesForProfile(profile_,
315                                         audio_allowed,
316                                         video_allowed,
317                                         &devices);
318         break;
319       }
320       case content::MEDIA_ENUMERATE_DEVICES: {
321         // Do nothing.
322         NOTREACHED();
323         break;
324       }
325     }  // switch
326
327     // TODO(raymes): We currently set the content permission for non-https
328     // websites for Pepper requests as well. This is temporary and should be
329     // removed.
330     if (update_content_setting) {
331       if ((IsSchemeSecure() && !devices.empty()) ||
332           request_.request_type == content::MEDIA_OPEN_DEVICE) {
333         SetPermission(true);
334       }
335     }
336
337     if (audio_allowed) {
338       profile_->GetHostContentSettingsMap()->UpdateLastUsageByPattern(
339           ContentSettingsPattern::FromURLNoWildcard(request_.security_origin),
340           ContentSettingsPattern::Wildcard(),
341           CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
342     }
343     if (video_allowed) {
344       profile_->GetHostContentSettingsMap()->UpdateLastUsageByPattern(
345           ContentSettingsPattern::FromURLNoWildcard(request_.security_origin),
346           ContentSettingsPattern::Wildcard(),
347           CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
348     }
349   }
350
351   scoped_ptr<content::MediaStreamUI> ui;
352   if (!devices.empty()) {
353     ui = MediaCaptureDevicesDispatcher::GetInstance()->
354         GetMediaStreamCaptureIndicator()->RegisterMediaStream(
355             web_contents_, devices);
356   }
357   content::MediaResponseCallback cb = callback_;
358   callback_.Reset();
359   cb.Run(devices,
360          devices.empty() ?
361              content::MEDIA_DEVICE_NO_HARDWARE : content::MEDIA_DEVICE_OK,
362          ui.Pass());
363 }
364
365 void MediaStreamDevicesController::Deny(
366     bool update_content_setting,
367     content::MediaStreamRequestResult result) {
368   DLOG(WARNING) << "MediaStreamDevicesController::Deny: " << result;
369   NotifyUIRequestDenied();
370
371   if (update_content_setting) {
372     CHECK_EQ(content::MEDIA_DEVICE_PERMISSION_DENIED, result);
373     SetPermission(false);
374   }
375
376   content::MediaResponseCallback cb = callback_;
377   callback_.Reset();
378   cb.Run(content::MediaStreamDevices(),
379          result,
380          scoped_ptr<content::MediaStreamUI>());
381 }
382
383 int MediaStreamDevicesController::GetIconID() const {
384   if (HasVideo())
385     return IDR_INFOBAR_MEDIA_STREAM_CAMERA;
386
387   return IDR_INFOBAR_MEDIA_STREAM_MIC;
388 }
389
390 base::string16 MediaStreamDevicesController::GetMessageText() const {
391   int message_id = IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO;
392   if (!HasAudio())
393     message_id = IDS_MEDIA_CAPTURE_VIDEO_ONLY;
394   else if (!HasVideo())
395     message_id = IDS_MEDIA_CAPTURE_AUDIO_ONLY;
396   return l10n_util::GetStringFUTF16(
397       message_id, base::UTF8ToUTF16(GetSecurityOriginSpec()));
398 }
399
400 base::string16 MediaStreamDevicesController::GetMessageTextFragment() const {
401   int message_id = IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO_PERMISSION_FRAGMENT;
402   if (!HasAudio())
403     message_id = IDS_MEDIA_CAPTURE_VIDEO_ONLY_PERMISSION_FRAGMENT;
404   else if (!HasVideo())
405     message_id = IDS_MEDIA_CAPTURE_AUDIO_ONLY_PERMISSION_FRAGMENT;
406   return l10n_util::GetStringUTF16(message_id);
407 }
408
409 bool MediaStreamDevicesController::HasUserGesture() const {
410   return request_.user_gesture;
411 }
412
413 GURL MediaStreamDevicesController::GetRequestingHostname() const {
414   return request_.security_origin;
415 }
416
417 void MediaStreamDevicesController::PermissionGranted() {
418   GURL origin(GetSecurityOriginSpec());
419   if (origin.SchemeIsSecure()) {
420     UMA_HISTOGRAM_ENUMERATION("Media.DevicePermissionActions",
421                               kAllowHttps, kPermissionActionsMax);
422   } else {
423     UMA_HISTOGRAM_ENUMERATION("Media.DevicePermissionActions",
424                               kAllowHttp, kPermissionActionsMax);
425   }
426   Accept(true);
427 }
428
429 void MediaStreamDevicesController::PermissionDenied() {
430   UMA_HISTOGRAM_ENUMERATION("Media.DevicePermissionActions",
431                             kDeny, kPermissionActionsMax);
432   Deny(true, content::MEDIA_DEVICE_PERMISSION_DENIED);
433 }
434
435 void MediaStreamDevicesController::Cancelled() {
436   UMA_HISTOGRAM_ENUMERATION("Media.DevicePermissionActions",
437                             kCancel, kPermissionActionsMax);
438   Deny(false, content::MEDIA_DEVICE_PERMISSION_DISMISSED);
439 }
440
441 void MediaStreamDevicesController::RequestFinished() {
442   delete this;
443 }
444
445 bool MediaStreamDevicesController::IsRequestAllowedByDefault() const {
446   // The request from internal objects like chrome://URLs is always allowed.
447   if (CheckAllowAllMediaStreamContentForOrigin(profile_,
448                                                request_.security_origin)) {
449     return true;
450   }
451
452   struct {
453     bool has_capability;
454     const char* policy_name;
455     const char* list_policy_name;
456     ContentSettingsType settings_type;
457   } device_checks[] = {
458     { IsDeviceAudioCaptureRequestedAndAllowed(), prefs::kAudioCaptureAllowed,
459       prefs::kAudioCaptureAllowedUrls, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC },
460     { IsDeviceVideoCaptureRequestedAndAllowed(), prefs::kVideoCaptureAllowed,
461       prefs::kVideoCaptureAllowedUrls,
462       CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA },
463   };
464
465   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(device_checks); ++i) {
466     if (!device_checks[i].has_capability)
467       continue;
468
469     MediaStreamDevicePolicy policy =
470         GetDevicePolicy(profile_,
471                         request_.security_origin,
472                         device_checks[i].policy_name,
473                         device_checks[i].list_policy_name);
474
475     if (policy == ALWAYS_DENY)
476       return false;
477
478     if (policy == POLICY_NOT_SET) {
479       // Only load content settings from secure origins unless it is a
480       // content::MEDIA_OPEN_DEVICE (Pepper) request.
481       if (!IsSchemeSecure() &&
482           request_.request_type != content::MEDIA_OPEN_DEVICE) {
483         return false;
484       }
485       if (profile_->GetHostContentSettingsMap()->GetContentSetting(
486               request_.security_origin, request_.security_origin,
487               device_checks[i].settings_type, NO_RESOURCE_IDENTIFIER) !=
488               CONTENT_SETTING_ALLOW) {
489         return false;
490       }
491     }
492     // If we get here, then either policy is set to ALWAYS_ALLOW or the content
493     // settings allow the request by default.
494   }
495
496   return true;
497 }
498
499 int MediaStreamDevicesController::FilterBlockedByDefaultDevices() {
500   int requested_devices = 0;
501
502   if (IsDeviceAudioCaptureRequestedAndAllowed()) {
503     if (profile_->GetHostContentSettingsMap()->GetContentSetting(
504         request_.security_origin,
505         request_.security_origin,
506         CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
507         NO_RESOURCE_IDENTIFIER) == CONTENT_SETTING_BLOCK) {
508       request_permissions_[content::MEDIA_DEVICE_AUDIO_CAPTURE].permission =
509           MEDIA_BLOCKED_BY_USER_SETTING;
510     } else {
511       ++requested_devices;
512     }
513   }
514
515   if (IsDeviceVideoCaptureRequestedAndAllowed()) {
516     if (profile_->GetHostContentSettingsMap()->GetContentSetting(
517         request_.security_origin,
518         request_.security_origin,
519         CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
520         NO_RESOURCE_IDENTIFIER) == CONTENT_SETTING_BLOCK) {
521       request_permissions_[content::MEDIA_DEVICE_VIDEO_CAPTURE].permission =
522           MEDIA_BLOCKED_BY_USER_SETTING;
523     } else {
524       ++requested_devices;
525     }
526   }
527
528   return requested_devices;
529 }
530
531 bool MediaStreamDevicesController::IsDefaultMediaAccessBlocked() const {
532   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
533   // TODO(markusheintz): Replace CONTENT_SETTINGS_TYPE_MEDIA_STREAM with the
534   // appropriate new CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC and
535   // CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA.
536   ContentSetting current_setting =
537       profile_->GetHostContentSettingsMap()->GetDefaultContentSetting(
538           CONTENT_SETTINGS_TYPE_MEDIASTREAM, NULL);
539   return (current_setting == CONTENT_SETTING_BLOCK);
540 }
541
542 bool MediaStreamDevicesController::IsSchemeSecure() const {
543   return request_.security_origin.SchemeIsSecure() ||
544       request_.security_origin.SchemeIs(extensions::kExtensionScheme);
545 }
546
547 void MediaStreamDevicesController::SetPermission(bool allowed) const {
548   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
549   ContentSettingsPattern primary_pattern =
550       ContentSettingsPattern::FromURLNoWildcard(request_.security_origin);
551   // Check the pattern is valid or not. When the request is from a file access,
552   // no exception will be made.
553   if (!primary_pattern.IsValid())
554     return;
555
556   ContentSetting content_setting = allowed ?
557       CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
558   if (request_permissions_.find(content::MEDIA_DEVICE_AUDIO_CAPTURE) !=
559       request_permissions_.end()) {
560     profile_->GetHostContentSettingsMap()->SetContentSetting(
561         primary_pattern,
562         ContentSettingsPattern::Wildcard(),
563         CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
564         std::string(),
565         content_setting);
566   }
567   if (request_permissions_.find(content::MEDIA_DEVICE_VIDEO_CAPTURE) !=
568       request_permissions_.end()) {
569     profile_->GetHostContentSettingsMap()->SetContentSetting(
570         primary_pattern,
571         ContentSettingsPattern::Wildcard(),
572         CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
573         std::string(),
574         content_setting);
575   }
576 }
577
578 void MediaStreamDevicesController::NotifyUIRequestAccepted() const {
579   if (!content_settings_)
580     return;
581
582   content_settings_->OnMediaStreamPermissionSet(request_.security_origin,
583                                                 request_permissions_);
584 }
585
586 void MediaStreamDevicesController::NotifyUIRequestDenied() {
587   if (!content_settings_)
588     return;
589
590   if (IsDeviceAudioCaptureRequestedAndAllowed()) {
591     request_permissions_[content::MEDIA_DEVICE_AUDIO_CAPTURE].permission =
592         MEDIA_BLOCKED_BY_USER;
593   }
594   if (IsDeviceVideoCaptureRequestedAndAllowed()) {
595     request_permissions_[content::MEDIA_DEVICE_VIDEO_CAPTURE].permission =
596         MEDIA_BLOCKED_BY_USER;
597   }
598
599   content_settings_->OnMediaStreamPermissionSet(request_.security_origin,
600                                                 request_permissions_);
601 }
602
603 bool MediaStreamDevicesController::IsDeviceAudioCaptureRequestedAndAllowed()
604     const {
605   MediaStreamTypeSettingsMap::const_iterator it =
606       request_permissions_.find(content::MEDIA_DEVICE_AUDIO_CAPTURE);
607   return (it != request_permissions_.end() && IsCaptureDeviceRequestAllowed() &&
608           it->second.permission == MEDIA_ALLOWED);
609 }
610
611 bool MediaStreamDevicesController::IsDeviceVideoCaptureRequestedAndAllowed()
612     const {
613   MediaStreamTypeSettingsMap::const_iterator it =
614       request_permissions_.find(content::MEDIA_DEVICE_VIDEO_CAPTURE);
615   return (it != request_permissions_.end() && IsCaptureDeviceRequestAllowed() &&
616           it->second.permission == MEDIA_ALLOWED);
617 }
618
619 bool MediaStreamDevicesController::IsCaptureDeviceRequestAllowed() const {
620 #if defined(OS_ANDROID)
621   // Don't approve device requests if the tab was hidden.
622   // TODO(qinmin): Add a test for this. http://crbug.com/396869.
623   return web_contents_->GetRenderWidgetHostView()->IsShowing();
624 #endif
625   return true;
626 }