Home | History | Annotate | Download | only in media
      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 }
    627