Upstream version 9.37.195.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/command_line.h"
8 #include "base/metrics/histogram.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/prefs/scoped_user_pref_update.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "chrome/browser/content_settings/content_settings_provider.h"
14 #include "chrome/browser/content_settings/host_content_settings_map.h"
15 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
16 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
17 #include "chrome/browser/media/media_stream_capture_indicator.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/content_settings.h"
22 #include "chrome/common/content_settings_pattern.h"
23 #include "chrome/common/pref_names.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/generated_resources.h"
30 #include "grit/theme_resources.h"
31 #include "ui/base/l10n/l10n_util.h"
32
33 #if defined(OS_CHROMEOS)
34 #include "chrome/browser/chromeos/login/users/user_manager.h"
35 #endif
36
37 using content::BrowserThread;
38
39 namespace {
40
41 bool HasAvailableDevicesForRequest(const content::MediaStreamRequest& request) {
42   const content::MediaStreamDevices* audio_devices =
43       request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE ?
44           &MediaCaptureDevicesDispatcher::GetInstance()
45               ->GetAudioCaptureDevices() :
46           NULL;
47
48   const content::MediaStreamDevices* video_devices =
49       request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE ?
50           &MediaCaptureDevicesDispatcher::GetInstance()
51               ->GetVideoCaptureDevices() :
52           NULL;
53
54   // Check if we're being asked for audio and/or video and that either of those
55   // lists is empty.  If they are, we do not have devices available for the
56   // request.
57   // TODO(tommi): It's kind of strange to have this here since if we fail this
58   // test, there'll be a UI shown that indicates to the user that access to
59   // non-existing audio/video devices has been denied.  The user won't have
60   // any way to change that but there will be a UI shown which indicates that
61   // access is blocked.
62   if ((audio_devices != NULL && audio_devices->empty()) ||
63       (video_devices != NULL && video_devices->empty())) {
64     return false;
65   }
66
67   // Note: we check requested_[audio|video]_device_id before dereferencing
68   // [audio|video]_devices.  If the requested device id is non-empty, then
69   // the corresponding device list must not be NULL.
70
71   if (!request.requested_audio_device_id.empty() &&
72       !audio_devices->FindById(request.requested_audio_device_id)) {
73     return false;
74   }
75
76   if (!request.requested_video_device_id.empty() &&
77       !video_devices->FindById(request.requested_video_device_id)) {
78     return false;
79   }
80
81   return true;
82 }
83
84 bool IsInKioskMode() {
85   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode))
86     return true;
87
88 #if defined(OS_CHROMEOS)
89   const chromeos::UserManager* user_manager = chromeos::UserManager::Get();
90   return user_manager && user_manager->IsLoggedInAsKioskApp();
91 #else
92   return false;
93 #endif
94 }
95
96 enum DevicePermissionActions {
97   kAllowHttps = 0,
98   kAllowHttp,
99   kDeny,
100   kCancel,
101   kPermissionActionsMax  // Must always be last!
102 };
103
104 }  // namespace
105
106 MediaStreamDevicesController::MediaStreamTypeSettings::MediaStreamTypeSettings(
107     Permission permission, const std::string& requested_device_id):
108     permission(permission), requested_device_id(requested_device_id) {}
109
110 MediaStreamDevicesController::MediaStreamTypeSettings::
111     MediaStreamTypeSettings(): permission(MEDIA_NONE) {}
112
113 MediaStreamDevicesController::MediaStreamTypeSettings::
114     ~MediaStreamTypeSettings() {}
115
116 MediaStreamDevicesController::MediaStreamDevicesController(
117     content::WebContents* web_contents,
118     const content::MediaStreamRequest& request,
119     const content::MediaResponseCallback& callback)
120     : web_contents_(web_contents),
121       request_(request),
122       callback_(callback) {
123   profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext());
124   content_settings_ = TabSpecificContentSettings::FromWebContents(web_contents);
125
126   // For MEDIA_OPEN_DEVICE requests (Pepper) we always request both webcam
127   // and microphone to avoid popping two infobars.
128   // We start with setting the requested media type to allowed or blocked
129   // depending on the policy. If not blocked by policy it may be blocked later
130   // in the two remaining filtering steps (by user setting or by user when
131   // clicking the infobar).
132   // TODO(grunell): It's not the nicest solution to let the MEDIA_OPEN_DEVICE
133   // case take a ride on the MEDIA_DEVICE_*_CAPTURE permission. Should be fixed.
134   if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
135       request.request_type == content::MEDIA_OPEN_DEVICE) {
136     if (GetDevicePolicy(prefs::kAudioCaptureAllowed,
137                         prefs::kAudioCaptureAllowedUrls) == ALWAYS_DENY) {
138       request_permissions_.insert(std::make_pair(
139           content::MEDIA_DEVICE_AUDIO_CAPTURE,
140           MediaStreamTypeSettings(MEDIA_BLOCKED_BY_POLICY,
141                                   request.requested_audio_device_id)));
142     } else {
143       request_permissions_.insert(std::make_pair(
144           content::MEDIA_DEVICE_AUDIO_CAPTURE,
145           MediaStreamTypeSettings(MEDIA_ALLOWED,
146                                   request.requested_audio_device_id)));
147     }
148   }
149   if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE ||
150       request.request_type == content::MEDIA_OPEN_DEVICE) {
151     if (GetDevicePolicy(prefs::kVideoCaptureAllowed,
152                         prefs::kVideoCaptureAllowedUrls) == ALWAYS_DENY) {
153       request_permissions_.insert(std::make_pair(
154           content::MEDIA_DEVICE_VIDEO_CAPTURE,
155           MediaStreamTypeSettings(MEDIA_BLOCKED_BY_POLICY,
156                                   request.requested_video_device_id)));
157     } else {
158       request_permissions_.insert(std::make_pair(
159           content::MEDIA_DEVICE_VIDEO_CAPTURE,
160           MediaStreamTypeSettings(MEDIA_ALLOWED,
161                                   request.requested_video_device_id)));
162     }
163   }
164 }
165
166 MediaStreamDevicesController::~MediaStreamDevicesController() {
167   if (!callback_.is_null()) {
168     callback_.Run(content::MediaStreamDevices(),
169                   content::MEDIA_DEVICE_INVALID_STATE,
170                   scoped_ptr<content::MediaStreamUI>());
171   }
172 }
173
174 // static
175 void MediaStreamDevicesController::RegisterProfilePrefs(
176     user_prefs::PrefRegistrySyncable* prefs) {
177   prefs->RegisterBooleanPref(prefs::kVideoCaptureAllowed,
178                              true,
179                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
180   prefs->RegisterBooleanPref(prefs::kAudioCaptureAllowed,
181                              true,
182                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
183   prefs->RegisterListPref(prefs::kVideoCaptureAllowedUrls,
184                           user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
185   prefs->RegisterListPref(prefs::kAudioCaptureAllowedUrls,
186                           user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
187 }
188
189 // TODO(gbillock): rename? doesn't actually dismiss. More of a 'check profile
190 // and system for compatibility' thing.
191 bool MediaStreamDevicesController::DismissInfoBarAndTakeActionOnSettings() {
192   // Tab capture is allowed for extensions only and infobar is not shown for
193   // extensions.
194   if (request_.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE ||
195       request_.video_type == content::MEDIA_TAB_VIDEO_CAPTURE) {
196     Deny(false, content::MEDIA_DEVICE_INVALID_STATE);
197     return true;
198   }
199
200   // Deny the request if the security origin is empty, this happens with
201   // file access without |--allow-file-access-from-files| flag.
202   if (request_.security_origin.is_empty()) {
203     Deny(false, content::MEDIA_DEVICE_INVALID_SECURITY_ORIGIN);
204     return true;
205   }
206
207   // Deny the request if there is no device attached to the OS of the
208   // requested type. If both audio and video is requested, both types must be
209   // available.
210   if (!HasAvailableDevicesForRequest(request_)) {
211     Deny(false, content::MEDIA_DEVICE_NO_HARDWARE);
212     return true;
213   }
214
215   // Check if any allow exception has been made for this request.
216   if (IsRequestAllowedByDefault()) {
217     Accept(false);
218     return true;
219   }
220
221   // Filter any parts of the request that have been blocked by default and deny
222   // it if nothing is left to accept.
223   if (FilterBlockedByDefaultDevices() == 0) {
224     Deny(false, content::MEDIA_DEVICE_PERMISSION_DENIED);
225     return true;
226   }
227
228   // Check if the media default setting is set to block.
229   if (IsDefaultMediaAccessBlocked()) {
230     Deny(false, content::MEDIA_DEVICE_PERMISSION_DENIED);
231     return true;
232   }
233
234   // Show the infobar.
235   return false;
236 }
237
238 bool MediaStreamDevicesController::HasAudio() const {
239   return IsDeviceAudioCaptureRequestedAndAllowed();
240 }
241
242 bool MediaStreamDevicesController::HasVideo() const {
243   return IsDeviceVideoCaptureRequestedAndAllowed();
244 }
245
246 const std::string& MediaStreamDevicesController::GetSecurityOriginSpec() const {
247   return request_.security_origin.spec();
248 }
249
250 void MediaStreamDevicesController::Accept(bool update_content_setting) {
251   NotifyUIRequestAccepted();
252
253   // Get the default devices for the request.
254   content::MediaStreamDevices devices;
255   bool audio_allowed = IsDeviceAudioCaptureRequestedAndAllowed();
256   bool video_allowed = IsDeviceVideoCaptureRequestedAndAllowed();
257   if (audio_allowed || video_allowed) {
258     switch (request_.request_type) {
259       case content::MEDIA_OPEN_DEVICE: {
260         const content::MediaStreamDevice* device = NULL;
261         // For open device request, when requested device_id is empty, pick
262         // the first available of the given type. If requested device_id is
263         // not empty, return the desired device if it's available. Otherwise,
264         // return no device.
265         if (audio_allowed &&
266             request_.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE) {
267           if (!request_.requested_audio_device_id.empty()) {
268             device = MediaCaptureDevicesDispatcher::GetInstance()->
269                 GetRequestedAudioDevice(request_.requested_audio_device_id);
270           } else {
271             device = MediaCaptureDevicesDispatcher::GetInstance()->
272                 GetFirstAvailableAudioDevice();
273           }
274         } else if (video_allowed &&
275             request_.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) {
276           // Pepper API opens only one device at a time.
277           if (!request_.requested_video_device_id.empty()) {
278             device = MediaCaptureDevicesDispatcher::GetInstance()->
279                 GetRequestedVideoDevice(request_.requested_video_device_id);
280           } else {
281             device = MediaCaptureDevicesDispatcher::GetInstance()->
282                 GetFirstAvailableVideoDevice();
283           }
284         }
285         if (device)
286           devices.push_back(*device);
287         break;
288       }
289       case content::MEDIA_GENERATE_STREAM: {
290         bool get_default_audio_device = audio_allowed;
291         bool get_default_video_device = video_allowed;
292
293         // Get the exact audio or video device if an id is specified.
294         if (audio_allowed && !request_.requested_audio_device_id.empty()) {
295           const content::MediaStreamDevice* audio_device =
296               MediaCaptureDevicesDispatcher::GetInstance()->
297                   GetRequestedAudioDevice(request_.requested_audio_device_id);
298           if (audio_device) {
299             devices.push_back(*audio_device);
300             get_default_audio_device = false;
301           }
302         }
303         if (video_allowed && !request_.requested_video_device_id.empty()) {
304           const content::MediaStreamDevice* video_device =
305               MediaCaptureDevicesDispatcher::GetInstance()->
306                   GetRequestedVideoDevice(request_.requested_video_device_id);
307           if (video_device) {
308             devices.push_back(*video_device);
309             get_default_video_device = false;
310           }
311         }
312
313         // If either or both audio and video devices were requested but not
314         // specified by id, get the default devices.
315         if (get_default_audio_device || get_default_video_device) {
316           MediaCaptureDevicesDispatcher::GetInstance()->
317               GetDefaultDevicesForProfile(profile_,
318                                           get_default_audio_device,
319                                           get_default_video_device,
320                                           &devices);
321         }
322         break;
323       }
324       case content::MEDIA_DEVICE_ACCESS: {
325         // Get the default devices for the request.
326         MediaCaptureDevicesDispatcher::GetInstance()->
327             GetDefaultDevicesForProfile(profile_,
328                                         audio_allowed,
329                                         video_allowed,
330                                         &devices);
331         break;
332       }
333       case content::MEDIA_ENUMERATE_DEVICES: {
334         // Do nothing.
335         NOTREACHED();
336         break;
337       }
338     }  // switch
339
340     // TODO(raymes): We currently set the content permission for non-https
341     // websites for Pepper requests as well. This is temporary and should be
342     // removed.
343     if (update_content_setting) {
344       if ((IsSchemeSecure() && !devices.empty()) ||
345           request_.request_type == content::MEDIA_OPEN_DEVICE) {
346         SetPermission(true);
347       }
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 MediaStreamDevicesController::DevicePolicy
446 MediaStreamDevicesController::GetDevicePolicy(
447     const char* policy_name,
448     const char* whitelist_policy_name) const {
449   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
450
451   // If the security origin policy matches a value in the whitelist, allow it.
452   // Otherwise, check the |policy_name| master switch for the default behavior.
453
454   PrefService* prefs = profile_->GetPrefs();
455
456   // TODO(tommi): Remove the kiosk mode check when the whitelist below
457   // is visible in the media exceptions UI.
458   // See discussion here: https://codereview.chromium.org/15738004/
459   if (IsInKioskMode()) {
460     const base::ListValue* list = prefs->GetList(whitelist_policy_name);
461     std::string value;
462     for (size_t i = 0; i < list->GetSize(); ++i) {
463       if (list->GetString(i, &value)) {
464         ContentSettingsPattern pattern =
465             ContentSettingsPattern::FromString(value);
466         if (pattern == ContentSettingsPattern::Wildcard()) {
467           DLOG(WARNING) << "Ignoring wildcard URL pattern: " << value;
468           continue;
469         }
470         DLOG_IF(ERROR, !pattern.IsValid()) << "Invalid URL pattern: " << value;
471         if (pattern.IsValid() && pattern.Matches(request_.security_origin))
472           return ALWAYS_ALLOW;
473       }
474     }
475   }
476
477   // If a match was not found, check if audio capture is otherwise disallowed
478   // or if the user should be prompted.  Setting the policy value to "true"
479   // is equal to not setting it at all, so from hereon out, we will return
480   // either POLICY_NOT_SET (prompt) or ALWAYS_DENY (no prompt, no access).
481   if (!prefs->GetBoolean(policy_name))
482     return ALWAYS_DENY;
483
484   return POLICY_NOT_SET;
485 }
486
487 bool MediaStreamDevicesController::IsRequestAllowedByDefault() const {
488   // The request from internal objects like chrome://URLs is always allowed.
489   if (ShouldAlwaysAllowOrigin())
490     return true;
491
492   struct {
493     bool has_capability;
494     const char* policy_name;
495     const char* list_policy_name;
496     ContentSettingsType settings_type;
497   } device_checks[] = {
498     { IsDeviceAudioCaptureRequestedAndAllowed(), prefs::kAudioCaptureAllowed,
499       prefs::kAudioCaptureAllowedUrls, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC },
500     { IsDeviceVideoCaptureRequestedAndAllowed(), prefs::kVideoCaptureAllowed,
501       prefs::kVideoCaptureAllowedUrls,
502       CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA },
503   };
504
505   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(device_checks); ++i) {
506     if (!device_checks[i].has_capability)
507       continue;
508
509     DevicePolicy policy = GetDevicePolicy(device_checks[i].policy_name,
510                                           device_checks[i].list_policy_name);
511
512     if (policy == ALWAYS_DENY)
513       return false;
514
515     if (policy == POLICY_NOT_SET) {
516       // Only load content settings from secure origins unless it is a
517       // content::MEDIA_OPEN_DEVICE (Pepper) request.
518       if (!IsSchemeSecure() &&
519           request_.request_type != content::MEDIA_OPEN_DEVICE) {
520         return false;
521       }
522       if (profile_->GetHostContentSettingsMap()->GetContentSetting(
523               request_.security_origin, request_.security_origin,
524               device_checks[i].settings_type, NO_RESOURCE_IDENTIFIER) !=
525               CONTENT_SETTING_ALLOW) {
526         return false;
527       }
528     }
529     // If we get here, then either policy is set to ALWAYS_ALLOW or the content
530     // settings allow the request by default.
531   }
532
533   return true;
534 }
535
536 int MediaStreamDevicesController::FilterBlockedByDefaultDevices() {
537   int requested_devices = 0;
538
539   if (IsDeviceAudioCaptureRequestedAndAllowed()) {
540     if (profile_->GetHostContentSettingsMap()->GetContentSetting(
541         request_.security_origin,
542         request_.security_origin,
543         CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
544         NO_RESOURCE_IDENTIFIER) == CONTENT_SETTING_BLOCK) {
545       request_permissions_[content::MEDIA_DEVICE_AUDIO_CAPTURE].permission =
546           MEDIA_BLOCKED_BY_USER_SETTING;
547     } else {
548       ++requested_devices;
549     }
550   }
551
552   if (IsDeviceVideoCaptureRequestedAndAllowed()) {
553     if (profile_->GetHostContentSettingsMap()->GetContentSetting(
554         request_.security_origin,
555         request_.security_origin,
556         CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
557         NO_RESOURCE_IDENTIFIER) == CONTENT_SETTING_BLOCK) {
558       request_permissions_[content::MEDIA_DEVICE_VIDEO_CAPTURE].permission =
559           MEDIA_BLOCKED_BY_USER_SETTING;
560     } else {
561       ++requested_devices;
562     }
563   }
564
565   return requested_devices;
566 }
567
568 bool MediaStreamDevicesController::IsDefaultMediaAccessBlocked() const {
569   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
570   // TODO(markusheintz): Replace CONTENT_SETTINGS_TYPE_MEDIA_STREAM with the
571   // appropriate new CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC and
572   // CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA.
573   ContentSetting current_setting =
574       profile_->GetHostContentSettingsMap()->GetDefaultContentSetting(
575           CONTENT_SETTINGS_TYPE_MEDIASTREAM, NULL);
576   return (current_setting == CONTENT_SETTING_BLOCK);
577 }
578
579 bool MediaStreamDevicesController::IsSchemeSecure() const {
580   return request_.security_origin.SchemeIsSecure() ||
581       request_.security_origin.SchemeIs(extensions::kExtensionScheme);
582 }
583
584 bool MediaStreamDevicesController::ShouldAlwaysAllowOrigin() const {
585   // TODO(markusheintz): Replace CONTENT_SETTINGS_TYPE_MEDIA_STREAM with the
586   // appropriate new CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC and
587   // CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA.
588   return profile_->GetHostContentSettingsMap()->ShouldAllowAllContent(
589       request_.security_origin, request_.security_origin,
590       CONTENT_SETTINGS_TYPE_MEDIASTREAM);
591 }
592
593 void MediaStreamDevicesController::SetPermission(bool allowed) const {
594   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
595   ContentSettingsPattern primary_pattern =
596       ContentSettingsPattern::FromURLNoWildcard(request_.security_origin);
597   // Check the pattern is valid or not. When the request is from a file access,
598   // no exception will be made.
599   if (!primary_pattern.IsValid())
600     return;
601
602   ContentSetting content_setting = allowed ?
603       CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
604   if (request_permissions_.find(content::MEDIA_DEVICE_AUDIO_CAPTURE) !=
605       request_permissions_.end()) {
606     profile_->GetHostContentSettingsMap()->SetContentSetting(
607         primary_pattern,
608         ContentSettingsPattern::Wildcard(),
609         CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
610         std::string(),
611         content_setting);
612   }
613   if (request_permissions_.find(content::MEDIA_DEVICE_VIDEO_CAPTURE) !=
614       request_permissions_.end()) {
615     profile_->GetHostContentSettingsMap()->SetContentSetting(
616         primary_pattern,
617         ContentSettingsPattern::Wildcard(),
618         CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
619         std::string(),
620         content_setting);
621   }
622 }
623
624 void MediaStreamDevicesController::NotifyUIRequestAccepted() const {
625   if (!content_settings_)
626     return;
627
628   content_settings_->OnMediaStreamPermissionSet(request_.security_origin,
629                                                 request_permissions_);
630 }
631
632 void MediaStreamDevicesController::NotifyUIRequestDenied() {
633   if (!content_settings_)
634     return;
635
636   if (IsDeviceAudioCaptureRequestedAndAllowed()) {
637     request_permissions_[content::MEDIA_DEVICE_AUDIO_CAPTURE].permission =
638         MEDIA_BLOCKED_BY_USER;
639   }
640   if (IsDeviceVideoCaptureRequestedAndAllowed()) {
641     request_permissions_[content::MEDIA_DEVICE_VIDEO_CAPTURE].permission =
642         MEDIA_BLOCKED_BY_USER;
643   }
644
645   content_settings_->OnMediaStreamPermissionSet(request_.security_origin,
646                                                 request_permissions_);
647 }
648
649 bool MediaStreamDevicesController::IsDeviceAudioCaptureRequestedAndAllowed()
650     const {
651   MediaStreamTypeSettingsMap::const_iterator it =
652       request_permissions_.find(content::MEDIA_DEVICE_AUDIO_CAPTURE);
653   return (it != request_permissions_.end() && IsCaptureDeviceRequestAllowed() &&
654           it->second.permission == MEDIA_ALLOWED);
655 }
656
657 bool MediaStreamDevicesController::IsDeviceVideoCaptureRequestedAndAllowed()
658     const {
659   MediaStreamTypeSettingsMap::const_iterator it =
660       request_permissions_.find(content::MEDIA_DEVICE_VIDEO_CAPTURE);
661   return (it != request_permissions_.end() && IsCaptureDeviceRequestAllowed() &&
662           it->second.permission == MEDIA_ALLOWED);
663 }
664
665 bool MediaStreamDevicesController::IsCaptureDeviceRequestAllowed() const {
666 #if defined(OS_ANDROID)
667   // Don't approve device requests if the tab was hidden.
668   // TODO(qinmin): Add a test for this. http://crbug.com/396869.
669   return web_contents_->GetRenderWidgetHostView()->IsShowing();
670 #endif
671   return true;
672 }