| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" | 5 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "content/browser/frame_host/render_frame_host_delegate.h" | 8 #include "content/browser/frame_host/render_frame_host_delegate.h" |
| 9 #include "content/browser/frame_host/render_frame_host_impl.h" | 9 #include "content/browser/frame_host/render_frame_host_impl.h" |
| 10 #include "content/public/browser/browser_thread.h" | 10 #include "content/public/browser/browser_thread.h" |
| 11 #include "content/public/common/content_switches.h" | 11 #include "content/public/common/content_switches.h" |
| 12 #include "media/video/capture/fake_video_capture_device.h" | 12 #include "media/video/capture/fake_video_capture_device.h" |
| 13 | 13 |
| 14 namespace content { | 14 namespace content { |
| 15 | 15 |
| 16 class MediaStreamUIProxy::Core { | 16 class MediaStreamUIProxy::Core { |
| 17 public: | 17 public: |
| 18 explicit Core(const base::WeakPtr<MediaStreamUIProxy>& proxy, | 18 explicit Core(const base::WeakPtr<MediaStreamUIProxy>& proxy, |
| 19 RenderFrameHostDelegate* test_render_delegate); | 19 RenderFrameHostDelegate* test_render_delegate); |
| 20 ~Core(); | 20 ~Core(); |
| 21 | 21 |
| 22 void RequestAccess(const MediaStreamRequest& request); | 22 void RequestAccess(const MediaStreamRequest& request); |
| 23 bool CheckAccess(const GURL& security_origin, |
| 24 MediaStreamType type, |
| 25 int process_id, |
| 26 int frame_id); |
| 23 void OnStarted(gfx::NativeViewId* window_id); | 27 void OnStarted(gfx::NativeViewId* window_id); |
| 24 | 28 |
| 25 private: | 29 private: |
| 26 void ProcessAccessRequestResponse(const MediaStreamDevices& devices, | 30 void ProcessAccessRequestResponse(const MediaStreamDevices& devices, |
| 27 content::MediaStreamRequestResult result, | 31 content::MediaStreamRequestResult result, |
| 28 scoped_ptr<MediaStreamUI> stream_ui); | 32 scoped_ptr<MediaStreamUI> stream_ui); |
| 29 void ProcessStopRequestFromUI(); | 33 void ProcessStopRequestFromUI(); |
| 34 RenderFrameHostDelegate* GetRenderFrameHostDelegate(int render_process_id, |
| 35 int render_frame_id); |
| 30 | 36 |
| 31 base::WeakPtr<MediaStreamUIProxy> proxy_; | 37 base::WeakPtr<MediaStreamUIProxy> proxy_; |
| 32 scoped_ptr<MediaStreamUI> ui_; | 38 scoped_ptr<MediaStreamUI> ui_; |
| 33 | 39 |
| 34 RenderFrameHostDelegate* const test_render_delegate_; | 40 RenderFrameHostDelegate* const test_render_delegate_; |
| 35 | 41 |
| 36 // WeakPtr<> is used to RequestMediaAccessPermission() because there is no way | 42 // WeakPtr<> is used to RequestMediaAccessPermission() because there is no way |
| 37 // cancel media requests. | 43 // cancel media requests. |
| 38 base::WeakPtrFactory<Core> weak_factory_; | 44 base::WeakPtrFactory<Core> weak_factory_; |
| 39 | 45 |
| 40 DISALLOW_COPY_AND_ASSIGN(Core); | 46 DISALLOW_COPY_AND_ASSIGN(Core); |
| 41 }; | 47 }; |
| 42 | 48 |
| 43 MediaStreamUIProxy::Core::Core(const base::WeakPtr<MediaStreamUIProxy>& proxy, | 49 MediaStreamUIProxy::Core::Core(const base::WeakPtr<MediaStreamUIProxy>& proxy, |
| 44 RenderFrameHostDelegate* test_render_delegate) | 50 RenderFrameHostDelegate* test_render_delegate) |
| 45 : proxy_(proxy), | 51 : proxy_(proxy), |
| 46 test_render_delegate_(test_render_delegate), | 52 test_render_delegate_(test_render_delegate), |
| 47 weak_factory_(this) { | 53 weak_factory_(this) { |
| 48 } | 54 } |
| 49 | 55 |
| 50 MediaStreamUIProxy::Core::~Core() { | 56 MediaStreamUIProxy::Core::~Core() { |
| 51 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 57 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 52 } | 58 } |
| 53 | 59 |
| 54 void MediaStreamUIProxy::Core::RequestAccess( | 60 void MediaStreamUIProxy::Core::RequestAccess( |
| 55 const MediaStreamRequest& request) { | 61 const MediaStreamRequest& request) { |
| 56 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 62 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 57 | 63 |
| 58 RenderFrameHostDelegate* render_delegate; | 64 RenderFrameHostDelegate* render_delegate = GetRenderFrameHostDelegate( |
| 59 if (test_render_delegate_) { | 65 request.render_process_id, request.render_frame_id); |
| 60 render_delegate = test_render_delegate_; | |
| 61 } else { | |
| 62 RenderFrameHostImpl* const host = RenderFrameHostImpl::FromID( | |
| 63 request.render_process_id, request.render_frame_id); | |
| 64 render_delegate = host ? host->delegate() : NULL; | |
| 65 } | |
| 66 | 66 |
| 67 // Tab may have gone away, or has no delegate from which to request access. | 67 // Tab may have gone away, or has no delegate from which to request access. |
| 68 if (!render_delegate) { | 68 if (!render_delegate) { |
| 69 ProcessAccessRequestResponse( | 69 ProcessAccessRequestResponse( |
| 70 MediaStreamDevices(), | 70 MediaStreamDevices(), |
| 71 MEDIA_DEVICE_INVALID_STATE, | 71 MEDIA_DEVICE_INVALID_STATE, |
| 72 scoped_ptr<MediaStreamUI>()); | 72 scoped_ptr<MediaStreamUI>()); |
| 73 return; | 73 return; |
| 74 } | 74 } |
| 75 | 75 |
| 76 render_delegate->RequestMediaAccessPermission( | 76 render_delegate->RequestMediaAccessPermission( |
| 77 request, base::Bind(&Core::ProcessAccessRequestResponse, | 77 request, base::Bind(&Core::ProcessAccessRequestResponse, |
| 78 weak_factory_.GetWeakPtr())); | 78 weak_factory_.GetWeakPtr())); |
| 79 } | 79 } |
| 80 | 80 |
| 81 bool MediaStreamUIProxy::Core::CheckAccess(const GURL& security_origin, |
| 82 MediaStreamType type, |
| 83 int render_process_id, |
| 84 int render_frame_id) { |
| 85 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 86 |
| 87 RenderFrameHostDelegate* render_delegate = |
| 88 GetRenderFrameHostDelegate(render_process_id, render_frame_id); |
| 89 if (!render_delegate) |
| 90 return false; |
| 91 |
| 92 return render_delegate->CheckMediaAccessPermission(security_origin, type); |
| 93 } |
| 94 |
| 81 void MediaStreamUIProxy::Core::OnStarted(gfx::NativeViewId* window_id) { | 95 void MediaStreamUIProxy::Core::OnStarted(gfx::NativeViewId* window_id) { |
| 82 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 96 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 83 if (ui_) { | 97 if (ui_) { |
| 84 *window_id = ui_->OnStarted( | 98 *window_id = ui_->OnStarted( |
| 85 base::Bind(&Core::ProcessStopRequestFromUI, base::Unretained(this))); | 99 base::Bind(&Core::ProcessStopRequestFromUI, base::Unretained(this))); |
| 86 } | 100 } |
| 87 } | 101 } |
| 88 | 102 |
| 89 void MediaStreamUIProxy::Core::ProcessAccessRequestResponse( | 103 void MediaStreamUIProxy::Core::ProcessAccessRequestResponse( |
| 90 const MediaStreamDevices& devices, | 104 const MediaStreamDevices& devices, |
| 91 content::MediaStreamRequestResult result, | 105 content::MediaStreamRequestResult result, |
| 92 scoped_ptr<MediaStreamUI> stream_ui) { | 106 scoped_ptr<MediaStreamUI> stream_ui) { |
| 93 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 107 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 94 | 108 |
| 95 ui_ = stream_ui.Pass(); | 109 ui_ = stream_ui.Pass(); |
| 96 BrowserThread::PostTask( | 110 BrowserThread::PostTask( |
| 97 BrowserThread::IO, FROM_HERE, | 111 BrowserThread::IO, FROM_HERE, |
| 98 base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse, | 112 base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse, |
| 99 proxy_, devices, result)); | 113 proxy_, devices, result)); |
| 100 } | 114 } |
| 101 | 115 |
| 102 void MediaStreamUIProxy::Core::ProcessStopRequestFromUI() { | 116 void MediaStreamUIProxy::Core::ProcessStopRequestFromUI() { |
| 103 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 117 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 104 | 118 |
| 105 BrowserThread::PostTask( | 119 BrowserThread::PostTask( |
| 106 BrowserThread::IO, FROM_HERE, | 120 BrowserThread::IO, FROM_HERE, |
| 107 base::Bind(&MediaStreamUIProxy::ProcessStopRequestFromUI, proxy_)); | 121 base::Bind(&MediaStreamUIProxy::ProcessStopRequestFromUI, proxy_)); |
| 108 } | 122 } |
| 109 | 123 |
| 124 RenderFrameHostDelegate* MediaStreamUIProxy::Core::GetRenderFrameHostDelegate( |
| 125 int render_process_id, |
| 126 int render_frame_id) { |
| 127 if (test_render_delegate_) |
| 128 return test_render_delegate_; |
| 129 RenderFrameHostImpl* host = |
| 130 RenderFrameHostImpl::FromID(render_process_id, render_frame_id); |
| 131 return host ? host->delegate() : NULL; |
| 132 } |
| 133 |
| 110 // static | 134 // static |
| 111 scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::Create() { | 135 scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::Create() { |
| 112 return scoped_ptr<MediaStreamUIProxy>(new MediaStreamUIProxy(NULL)); | 136 return scoped_ptr<MediaStreamUIProxy>(new MediaStreamUIProxy(NULL)); |
| 113 } | 137 } |
| 114 | 138 |
| 115 // static | 139 // static |
| 116 scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::CreateForTests( | 140 scoped_ptr<MediaStreamUIProxy> MediaStreamUIProxy::CreateForTests( |
| 117 RenderFrameHostDelegate* render_delegate) { | 141 RenderFrameHostDelegate* render_delegate) { |
| 118 return scoped_ptr<MediaStreamUIProxy>( | 142 return scoped_ptr<MediaStreamUIProxy>( |
| 119 new MediaStreamUIProxy(render_delegate)); | 143 new MediaStreamUIProxy(render_delegate)); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 134 const MediaStreamRequest& request, | 158 const MediaStreamRequest& request, |
| 135 const ResponseCallback& response_callback) { | 159 const ResponseCallback& response_callback) { |
| 136 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 160 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 137 | 161 |
| 138 response_callback_ = response_callback; | 162 response_callback_ = response_callback; |
| 139 BrowserThread::PostTask( | 163 BrowserThread::PostTask( |
| 140 BrowserThread::UI, FROM_HERE, | 164 BrowserThread::UI, FROM_HERE, |
| 141 base::Bind(&Core::RequestAccess, base::Unretained(core_.get()), request)); | 165 base::Bind(&Core::RequestAccess, base::Unretained(core_.get()), request)); |
| 142 } | 166 } |
| 143 | 167 |
| 168 void MediaStreamUIProxy::CheckAccess( |
| 169 const GURL& security_origin, |
| 170 MediaStreamType type, |
| 171 int render_process_id, |
| 172 int render_frame_id, |
| 173 const base::Callback<void(bool)>& callback) { |
| 174 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 175 |
| 176 BrowserThread::PostTaskAndReplyWithResult( |
| 177 BrowserThread::UI, |
| 178 FROM_HERE, |
| 179 base::Bind(&Core::CheckAccess, |
| 180 base::Unretained(core_.get()), |
| 181 security_origin, |
| 182 type, |
| 183 render_process_id, |
| 184 render_frame_id), |
| 185 base::Bind(&MediaStreamUIProxy::OnCheckedAccess, |
| 186 weak_factory_.GetWeakPtr(), |
| 187 callback)); |
| 188 } |
| 189 |
| 144 void MediaStreamUIProxy::OnStarted(const base::Closure& stop_callback, | 190 void MediaStreamUIProxy::OnStarted(const base::Closure& stop_callback, |
| 145 const WindowIdCallback& window_id_callback) { | 191 const WindowIdCallback& window_id_callback) { |
| 146 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 192 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 147 | 193 |
| 148 stop_callback_ = stop_callback; | 194 stop_callback_ = stop_callback; |
| 149 | 195 |
| 150 // Owned by the PostTaskAndReply callback. | 196 // Owned by the PostTaskAndReply callback. |
| 151 gfx::NativeViewId* window_id = new gfx::NativeViewId(0); | 197 gfx::NativeViewId* window_id = new gfx::NativeViewId(0); |
| 152 | 198 |
| 153 BrowserThread::PostTaskAndReply( | 199 BrowserThread::PostTaskAndReply( |
| 154 BrowserThread::UI, | 200 BrowserThread::UI, |
| 155 FROM_HERE, | 201 FROM_HERE, |
| 156 base::Bind(&Core::OnStarted, base::Unretained(core_.get()), window_id), | 202 base::Bind(&Core::OnStarted, base::Unretained(core_.get()), window_id), |
| 157 base::Bind(&MediaStreamUIProxy::OnWindowId, | 203 base::Bind(&MediaStreamUIProxy::OnWindowId, |
| 158 weak_factory_.GetWeakPtr(), | 204 weak_factory_.GetWeakPtr(), |
| 159 window_id_callback, | 205 window_id_callback, |
| 160 base::Owned(window_id))); | 206 base::Owned(window_id))); |
| 161 } | 207 } |
| 162 | 208 |
| 163 void MediaStreamUIProxy::OnWindowId(const WindowIdCallback& window_id_callback, | |
| 164 gfx::NativeViewId* window_id) { | |
| 165 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 166 if (!window_id_callback.is_null()) | |
| 167 window_id_callback.Run(*window_id); | |
| 168 } | |
| 169 | |
| 170 void MediaStreamUIProxy::ProcessAccessRequestResponse( | 209 void MediaStreamUIProxy::ProcessAccessRequestResponse( |
| 171 const MediaStreamDevices& devices, | 210 const MediaStreamDevices& devices, |
| 172 content::MediaStreamRequestResult result) { | 211 content::MediaStreamRequestResult result) { |
| 173 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 212 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 174 DCHECK(!response_callback_.is_null()); | 213 DCHECK(!response_callback_.is_null()); |
| 175 | 214 |
| 176 ResponseCallback cb = response_callback_; | 215 ResponseCallback cb = response_callback_; |
| 177 response_callback_.Reset(); | 216 response_callback_.Reset(); |
| 178 cb.Run(devices, result); | 217 cb.Run(devices, result); |
| 179 } | 218 } |
| 180 | 219 |
| 181 void MediaStreamUIProxy::ProcessStopRequestFromUI() { | 220 void MediaStreamUIProxy::ProcessStopRequestFromUI() { |
| 182 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 221 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 183 DCHECK(!stop_callback_.is_null()); | 222 DCHECK(!stop_callback_.is_null()); |
| 184 | 223 |
| 185 base::Closure cb = stop_callback_; | 224 base::Closure cb = stop_callback_; |
| 186 stop_callback_.Reset(); | 225 stop_callback_.Reset(); |
| 187 cb.Run(); | 226 cb.Run(); |
| 188 } | 227 } |
| 189 | 228 |
| 229 void MediaStreamUIProxy::OnWindowId(const WindowIdCallback& window_id_callback, |
| 230 gfx::NativeViewId* window_id) { |
| 231 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 232 if (!window_id_callback.is_null()) |
| 233 window_id_callback.Run(*window_id); |
| 234 } |
| 235 |
| 236 void MediaStreamUIProxy::OnCheckedAccess( |
| 237 const base::Callback<void(bool)>& callback, |
| 238 bool have_access) { |
| 239 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 240 if (!callback.is_null()) |
| 241 callback.Run(have_access); |
| 242 } |
| 243 |
| 190 FakeMediaStreamUIProxy::FakeMediaStreamUIProxy() | 244 FakeMediaStreamUIProxy::FakeMediaStreamUIProxy() |
| 191 : MediaStreamUIProxy(NULL) { | 245 : MediaStreamUIProxy(NULL), |
| 246 mic_access_(true), |
| 247 camera_access_(true) { |
| 192 } | 248 } |
| 193 | 249 |
| 194 FakeMediaStreamUIProxy::~FakeMediaStreamUIProxy() {} | 250 FakeMediaStreamUIProxy::~FakeMediaStreamUIProxy() {} |
| 195 | 251 |
| 196 void FakeMediaStreamUIProxy::SetAvailableDevices( | 252 void FakeMediaStreamUIProxy::SetAvailableDevices( |
| 197 const MediaStreamDevices& devices) { | 253 const MediaStreamDevices& devices) { |
| 198 devices_ = devices; | 254 devices_ = devices; |
| 199 } | 255 } |
| 200 | 256 |
| 257 void FakeMediaStreamUIProxy::SetMicAccess(bool access) { |
| 258 mic_access_ = access; |
| 259 } |
| 260 |
| 261 void FakeMediaStreamUIProxy::SetCameraAccess(bool access) { |
| 262 camera_access_ = access; |
| 263 } |
| 264 |
| 201 void FakeMediaStreamUIProxy::RequestAccess( | 265 void FakeMediaStreamUIProxy::RequestAccess( |
| 202 const MediaStreamRequest& request, | 266 const MediaStreamRequest& request, |
| 203 const ResponseCallback& response_callback) { | 267 const ResponseCallback& response_callback) { |
| 204 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 268 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 205 | 269 |
| 206 response_callback_ = response_callback; | 270 response_callback_ = response_callback; |
| 207 | 271 |
| 208 if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 272 if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| 209 switches::kUseFakeUIForMediaStream) == "deny") { | 273 switches::kUseFakeUIForMediaStream) == "deny") { |
| 210 // Immediately deny the request. | 274 // Immediately deny the request. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 235 } else if (!accepted_video && | 299 } else if (!accepted_video && |
| 236 IsVideoMediaType(request.video_type) && | 300 IsVideoMediaType(request.video_type) && |
| 237 IsVideoMediaType(it->type) && | 301 IsVideoMediaType(it->type) && |
| 238 (request.requested_video_device_id.empty() || | 302 (request.requested_video_device_id.empty() || |
| 239 request.requested_video_device_id == it->id)) { | 303 request.requested_video_device_id == it->id)) { |
| 240 devices_to_use.push_back(*it); | 304 devices_to_use.push_back(*it); |
| 241 accepted_video = true; | 305 accepted_video = true; |
| 242 } | 306 } |
| 243 } | 307 } |
| 244 | 308 |
| 245 // Fail the request if a device exist for the requested type. | 309 // Fail the request if a device doesn't exist for the requested type. |
| 246 if ((request.audio_type != MEDIA_NO_SERVICE && !accepted_audio) || | 310 if ((request.audio_type != MEDIA_NO_SERVICE && !accepted_audio) || |
| 247 (request.video_type != MEDIA_NO_SERVICE && !accepted_video)) { | 311 (request.video_type != MEDIA_NO_SERVICE && !accepted_video)) { |
| 248 devices_to_use.clear(); | 312 devices_to_use.clear(); |
| 249 } | 313 } |
| 250 | 314 |
| 251 BrowserThread::PostTask( | 315 BrowserThread::PostTask( |
| 252 BrowserThread::IO, FROM_HERE, | 316 BrowserThread::IO, FROM_HERE, |
| 253 base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse, | 317 base::Bind(&MediaStreamUIProxy::ProcessAccessRequestResponse, |
| 254 weak_factory_.GetWeakPtr(), | 318 weak_factory_.GetWeakPtr(), |
| 255 devices_to_use, | 319 devices_to_use, |
| 256 devices_to_use.empty() ? | 320 devices_to_use.empty() ? |
| 257 MEDIA_DEVICE_NO_HARDWARE : | 321 MEDIA_DEVICE_NO_HARDWARE : |
| 258 MEDIA_DEVICE_OK)); | 322 MEDIA_DEVICE_OK)); |
| 259 } | 323 } |
| 260 | 324 |
| 325 void FakeMediaStreamUIProxy::CheckAccess( |
| 326 const GURL& security_origin, |
| 327 MediaStreamType type, |
| 328 int render_process_id, |
| 329 int render_frame_id, |
| 330 const base::Callback<void(bool)>& callback) { |
| 331 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 332 DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE || |
| 333 type == MEDIA_DEVICE_VIDEO_CAPTURE); |
| 334 |
| 335 bool have_access = false; |
| 336 if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| 337 switches::kUseFakeUIForMediaStream) != "deny") { |
| 338 have_access = |
| 339 type == MEDIA_DEVICE_AUDIO_CAPTURE ? mic_access_ : camera_access_; |
| 340 } |
| 341 |
| 342 BrowserThread::PostTask( |
| 343 BrowserThread::IO, |
| 344 FROM_HERE, |
| 345 base::Bind(&MediaStreamUIProxy::OnCheckedAccess, |
| 346 weak_factory_.GetWeakPtr(), |
| 347 callback, |
| 348 have_access)); |
| 349 return; |
| 350 } |
| 351 |
| 261 void FakeMediaStreamUIProxy::OnStarted( | 352 void FakeMediaStreamUIProxy::OnStarted( |
| 262 const base::Closure& stop_callback, | 353 const base::Closure& stop_callback, |
| 263 const WindowIdCallback& window_id_callback) {} | 354 const WindowIdCallback& window_id_callback) {} |
| 264 | 355 |
| 265 } // namespace content | 356 } // namespace content |
| OLD | NEW |