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

Side by Side Diff: chrome/browser/media/permission_bubble_media_access_handler.cc

Issue 1095393004: Refactor: Make MediaCaptureDevicesDispatcher have pluggable handlers. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix tryjob error. Created 5 years, 6 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
(Empty)
1 // Copyright 2015 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/permission_bubble_media_access_handler.h"
6
7 #include "base/metrics/field_trial.h"
8 #include "chrome/browser/media/media_stream_device_permissions.h"
9 #include "chrome/browser/media/media_stream_infobar_delegate.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
12 #include "chrome/common/pref_names.h"
13 #include "components/content_settings/core/browser/host_content_settings_map.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/browser/notification_types.h"
17 #include "content/public/browser/web_contents.h"
18
19 using content::BrowserThread;
20
21 namespace {
22
23 // A finch experiment to enable the permission bubble for media requests only.
24 bool MediaStreamPermissionBubbleExperimentEnabled() {
25 const std::string group =
26 base::FieldTrialList::FindFullName("MediaStreamPermissionBubble");
27 if (group == "enabled")
28 return true;
29
30 return false;
31 }
32
33 } // namespace
34
35 struct PermissionBubbleMediaAccessHandler::PendingAccessRequest {
36 PendingAccessRequest(const content::MediaStreamRequest& request,
37 const content::MediaResponseCallback& callback)
38 : request(request), callback(callback) {}
39 ~PendingAccessRequest() {}
40
41 // TODO(gbillock): make the MediaStreamDevicesController owned by
42 // this object when we're using bubbles.
43 content::MediaStreamRequest request;
44 content::MediaResponseCallback callback;
45 };
46
47 PermissionBubbleMediaAccessHandler::PermissionBubbleMediaAccessHandler() {
48 // PermissionBubbleMediaAccessHandler should be created on UI thread.
49 // Otherwise, it will not receive
50 // content::NOTIFICATION_WEB_CONTENTS_DESTROYED, and that will result in
51 // possible use after free.
52 DCHECK_CURRENTLY_ON(BrowserThread::UI);
53 notifications_registrar_.Add(this,
54 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
55 content::NotificationService::AllSources());
56 }
57
58 PermissionBubbleMediaAccessHandler::~PermissionBubbleMediaAccessHandler() {
59 }
60
61 bool PermissionBubbleMediaAccessHandler::SupportsStreamType(
62 const content::MediaStreamType type,
63 const extensions::Extension* extension) {
64 return type == content::MEDIA_DEVICE_VIDEO_CAPTURE ||
65 type == content::MEDIA_DEVICE_AUDIO_CAPTURE;
66 }
67
68 bool PermissionBubbleMediaAccessHandler::CheckMediaAccessPermission(
69 content::WebContents* web_contents,
70 const GURL& security_origin,
71 content::MediaStreamType type,
72 const extensions::Extension* extension) {
73 Profile* profile =
74 Profile::FromBrowserContext(web_contents->GetBrowserContext());
75
76 ContentSettingsType content_settings_type =
77 type == content::MEDIA_DEVICE_AUDIO_CAPTURE
78 ? CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC
79 : CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA;
80
81 if (CheckAllowAllMediaStreamContentForOrigin(profile, security_origin,
82 content_settings_type)) {
83 return true;
84 }
85
86 const char* policy_name = type == content::MEDIA_DEVICE_AUDIO_CAPTURE
87 ? prefs::kAudioCaptureAllowed
88 : prefs::kVideoCaptureAllowed;
89 const char* list_policy_name = type == content::MEDIA_DEVICE_AUDIO_CAPTURE
90 ? prefs::kAudioCaptureAllowedUrls
91 : prefs::kVideoCaptureAllowedUrls;
92 if (GetDevicePolicy(profile, security_origin, policy_name,
93 list_policy_name) == ALWAYS_ALLOW) {
94 return true;
95 }
96
97 // There's no secondary URL for these content types, hence duplicating
98 // |security_origin|.
99 if (profile->GetHostContentSettingsMap()->GetContentSetting(
100 security_origin, security_origin, content_settings_type,
101 content_settings::ResourceIdentifier()) == CONTENT_SETTING_ALLOW) {
102 return true;
103 }
104
105 return false;
106 }
107
108 void PermissionBubbleMediaAccessHandler::HandleRequest(
109 content::WebContents* web_contents,
110 const content::MediaStreamRequest& request,
111 const content::MediaResponseCallback& callback,
112 const extensions::Extension* extension) {
113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
114
115 RequestsQueue& queue = pending_requests_[web_contents];
116 queue.push_back(PendingAccessRequest(request, callback));
117
118 // If this is the only request then show the infobar.
119 if (queue.size() == 1)
120 ProcessQueuedAccessRequest(web_contents);
121 }
122
123 void PermissionBubbleMediaAccessHandler::ProcessQueuedAccessRequest(
124 content::WebContents* web_contents) {
125 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
126
127 std::map<content::WebContents*, RequestsQueue>::iterator it =
128 pending_requests_.find(web_contents);
129
130 if (it == pending_requests_.end() || it->second.empty()) {
131 // Don't do anything if the tab was closed.
132 return;
133 }
134
135 DCHECK(!it->second.empty());
136
137 if (PermissionBubbleManager::Enabled() ||
138 MediaStreamPermissionBubbleExperimentEnabled()) {
139 scoped_ptr<MediaStreamDevicesController> controller(
140 new MediaStreamDevicesController(
141 web_contents, it->second.front().request,
142 base::Bind(
143 &PermissionBubbleMediaAccessHandler::OnAccessRequestResponse,
144 base::Unretained(this), web_contents)));
145 if (controller->DismissInfoBarAndTakeActionOnSettings())
146 return;
147 PermissionBubbleManager* bubble_manager =
148 PermissionBubbleManager::FromWebContents(web_contents);
149 if (bubble_manager)
150 bubble_manager->AddRequest(controller.release());
151 return;
152 }
153
154 // TODO(gbillock): delete this block and the MediaStreamInfoBarDelegate
155 // when we've transitioned to bubbles. (crbug/337458)
156 MediaStreamInfoBarDelegate::Create(
157 web_contents, it->second.front().request,
158 base::Bind(&PermissionBubbleMediaAccessHandler::OnAccessRequestResponse,
159 base::Unretained(this), web_contents));
160 }
161
162 void PermissionBubbleMediaAccessHandler::UpdateMediaRequestState(
163 int render_process_id,
164 int render_frame_id,
165 int page_request_id,
166 content::MediaStreamType stream_type,
167 content::MediaRequestState state) {
168 DCHECK_CURRENTLY_ON(BrowserThread::UI);
169 if (state != content::MEDIA_REQUEST_STATE_CLOSING)
170 return;
171
172 bool found = false;
173 for (RequestsQueues::iterator rqs_it = pending_requests_.begin();
174 rqs_it != pending_requests_.end(); ++rqs_it) {
175 RequestsQueue& queue = rqs_it->second;
176 for (RequestsQueue::iterator it = queue.begin(); it != queue.end(); ++it) {
177 if (it->request.render_process_id == render_process_id &&
178 it->request.render_frame_id == render_frame_id &&
179 it->request.page_request_id == page_request_id) {
180 queue.erase(it);
181 found = true;
182 break;
183 }
184 }
185 if (found)
186 break;
187 }
188 }
189
190 void PermissionBubbleMediaAccessHandler::OnAccessRequestResponse(
191 content::WebContents* web_contents,
192 const content::MediaStreamDevices& devices,
193 content::MediaStreamRequestResult result,
194 scoped_ptr<content::MediaStreamUI> ui) {
195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
196
197 std::map<content::WebContents*, RequestsQueue>::iterator it =
198 pending_requests_.find(web_contents);
199 if (it == pending_requests_.end()) {
200 // WebContents has been destroyed. Don't need to do anything.
201 return;
202 }
203
204 RequestsQueue& queue(it->second);
205 if (queue.empty())
206 return;
207
208 content::MediaResponseCallback callback = queue.front().callback;
209 queue.pop_front();
210
211 if (!queue.empty()) {
212 // Post a task to process next queued request. It has to be done
213 // asynchronously to make sure that calling infobar is not destroyed until
214 // after this function returns.
215 BrowserThread::PostTask(
216 BrowserThread::UI, FROM_HERE,
217 base::Bind(
218 &PermissionBubbleMediaAccessHandler::ProcessQueuedAccessRequest,
219 base::Unretained(this), web_contents));
220 }
221
222 callback.Run(devices, result, ui.Pass());
223 }
224
225 void PermissionBubbleMediaAccessHandler::Observe(
226 int type,
227 const content::NotificationSource& source,
228 const content::NotificationDetails& details) {
229 DCHECK_CURRENTLY_ON(BrowserThread::UI);
230 if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) {
231 content::WebContents* web_contents =
232 content::Source<content::WebContents>(source).ptr();
233 pending_requests_.erase(web_contents);
234 }
235 }
OLDNEW
« no previous file with comments | « chrome/browser/media/permission_bubble_media_access_handler.h ('k') | chrome/browser/media/tab_capture_access_handler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698