blob: 643389833b7fc860f1cae003971eff7edd770ff6 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2015 The Chromium Authors
avayvodbca35fad2015-01-29 20:20:572// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/browser/presentation/presentation_service_impl.h"
6
avib7348942015-12-25 20:57:107#include <stddef.h>
8#include <stdint.h>
Peter Boströmdd7e40ec2021-04-05 20:40:109
rockotad6b6cb2015-03-19 17:54:2010#include <algorithm>
Peter Boströmdd7e40ec2021-04-05 20:40:1011#include <memory>
dcheng36b6aec92015-12-26 06:16:3612#include <utility>
rockotad6b6cb2015-03-19 17:54:2013
Derek Cheng3eb973c2018-04-23 19:10:1714#include "base/command_line.h"
Avi Drissmanadac21992023-01-11 23:46:3915#include "base/functional/bind.h"
avayvodbca35fad2015-01-29 20:20:5716#include "base/logging.h"
Gabriel Charette9f60dd12020-03-06 20:48:0417#include "base/memory/ptr_util.h"
imcheng9f515d02015-02-10 20:09:2418#include "content/public/browser/content_browser_client.h"
jam5fdbb58d2017-02-06 22:09:5919#include "content/public/browser/navigation_handle.h"
Derek Cheng1071a232017-07-25 22:23:5620#include "content/public/browser/presentation_request.h"
imcheng9f515d02015-02-10 20:09:2421#include "content/public/browser/render_frame_host.h"
22#include "content/public/browser/render_process_host.h"
23#include "content/public/browser/web_contents.h"
24#include "content/public/common/content_client.h"
Derek Cheng3eb973c2018-04-23 19:10:1725#include "content/public/common/content_switches.h"
avayvodbca35fad2015-01-29 20:20:5726
mark a. foltze8ad3202018-04-23 22:50:2327using blink::mojom::PresentationConnectionState;
mark a. foltzd9d2a4512018-04-16 20:42:4528using blink::mojom::PresentationError;
29using blink::mojom::PresentationErrorPtr;
30using blink::mojom::PresentationErrorType;
mark a. foltze2084383c2018-05-11 19:21:5031using blink::mojom::PresentationInfo;
32using blink::mojom::PresentationInfoPtr;
mark a. foltzd9d2a4512018-04-16 20:42:4533using blink::mojom::ScreenAvailability;
34
imcheng27e2b56b2015-05-15 21:39:3035namespace content {
36
haibinluf7b39b782015-05-05 22:23:3937namespace {
38
mark a. foltze2084383c2018-05-11 19:21:5039static constexpr int kInvalidRequestId = -1;
40static constexpr size_t kMaxPresentationIdLength = 256;
imcheng27e2b56b2015-05-15 21:39:3041
mfoltz11fc4df82017-03-20 23:49:1842int GetNextRequestId() {
43 static int next_request_id = 0;
44 return ++next_request_id;
imcheng27e2b56b2015-05-15 21:39:3045}
46
mfoltz11fc4df82017-03-20 23:49:1847void InvokeNewPresentationCallbackWithError(
tzikcf7bcd652017-06-15 04:19:3048 PresentationServiceImpl::NewPresentationCallback callback) {
49 std::move(callback).Run(
btolsch8ca10fb22018-08-29 01:35:0950 /** PresentationConnectionResultPtr */ nullptr,
mark a. foltzd9d2a4512018-04-16 20:42:4551 PresentationError::New(
52 PresentationErrorType::PREVIOUS_START_IN_PROGRESS,
tzikcf7bcd652017-06-15 04:19:3053 "There is already an unsettled Promise from a previous call "
54 "to start."));
imcheng27e2b56b2015-05-15 21:39:3055}
haibinluf7b39b782015-05-05 22:23:3956
kmarshallf5367c642015-08-20 19:23:1357} // namespace
avayvodbca35fad2015-01-29 20:20:5758
imcheng9f515d02015-02-10 20:09:2459PresentationServiceImpl::PresentationServiceImpl(
60 RenderFrameHost* render_frame_host,
61 WebContents* web_contents,
zhaobinf3704f82017-01-12 07:19:3662 ControllerPresentationServiceDelegate* controller_delegate,
63 ReceiverPresentationServiceDelegate* receiver_delegate)
imcheng9f515d02015-02-10 20:09:2464 : WebContentsObserver(web_contents),
Derek Cheng1071a232017-07-25 22:23:5665 render_frame_host_(render_frame_host),
zhaobinf3704f82017-01-12 07:19:3666 controller_delegate_(controller_delegate),
67 receiver_delegate_(receiver_delegate),
mfoltz11fc4df82017-03-20 23:49:1868 start_presentation_request_id_(kInvalidRequestId),
Derek Cheng4de47c52017-10-10 01:05:5469 // TODO(imcheng): Consider using RenderFrameHost* directly instead of IDs.
Emily Andrewsd15fd762024-12-10 20:41:5470 render_process_id_(render_frame_host->GetProcess()->GetDeprecatedID()),
Derek Cheng4de47c52017-10-10 01:05:5471 render_frame_id_(render_frame_host->GetRoutingID()),
Claudio DeSouzaee45cae2021-11-24 20:30:2772 is_outermost_document_(!render_frame_host->GetParentOrOuterDocument()) {
Derek Cheng4de47c52017-10-10 01:05:5473 DCHECK(render_frame_host_);
imcheng9f515d02015-02-10 20:09:2474 DCHECK(web_contents);
Derek Cheng4de47c52017-10-10 01:05:5475 CHECK(render_frame_host_->IsRenderFrameLive());
zhaobindca98f632017-06-29 18:42:2876
77 DVLOG(2) << "PresentationServiceImpl: " << render_process_id_ << ", "
Claudio DeSouzaee45cae2021-11-24 20:30:2778 << render_frame_id_
79 << " is outermost document: " << is_outermost_document_;
zhaobinf3704f82017-01-12 07:19:3680
81 if (auto* delegate = GetPresentationServiceDelegate())
82 delegate->AddObserver(render_process_id_, render_frame_id_, this);
avayvodbca35fad2015-01-29 20:20:5783}
84
85PresentationServiceImpl::~PresentationServiceImpl() {
zhaobinf3704f82017-01-12 07:19:3686 DVLOG(2) << __FUNCTION__ << ": " << render_process_id_ << ", "
87 << render_frame_id_;
88
Derek Cheng4de47c52017-10-10 01:05:5489 // Call Reset() to inform the PresentationServiceDelegate to clean up.
90 Reset();
91
zhaobinf3704f82017-01-12 07:19:3692 if (auto* delegate = GetPresentationServiceDelegate())
93 delegate->RemoveObserver(render_process_id_, render_frame_id_);
avayvodbca35fad2015-01-29 20:20:5794}
95
96// static
Derek Cheng4de47c52017-10-10 01:05:5497std::unique_ptr<PresentationServiceImpl> PresentationServiceImpl::Create(
98 RenderFrameHost* render_frame_host) {
Emily Andrewsd15fd762024-12-10 20:41:5499 DVLOG(2) << __func__ << ": "
100 << render_frame_host->GetProcess()->GetDeprecatedID() << ", "
101 << render_frame_host->GetRoutingID();
imcheng9f515d02015-02-10 20:09:24102 WebContents* web_contents =
103 WebContents::FromRenderFrameHost(render_frame_host);
104 DCHECK(web_contents);
105
zhaobinf3704f82017-01-12 07:19:36106 auto* browser = GetContentClient()->browser();
107 auto* receiver_delegate =
108 browser->GetReceiverPresentationServiceDelegate(web_contents);
109
110 // In current implementation, web_contents can be controller or receiver
111 // but not both.
112 auto* controller_delegate =
113 receiver_delegate
114 ? nullptr
115 : browser->GetControllerPresentationServiceDelegate(web_contents);
116
Derek Cheng4de47c52017-10-10 01:05:54117 return base::WrapUnique(new PresentationServiceImpl(
118 render_frame_host, web_contents, controller_delegate, receiver_delegate));
imcheng16819b92015-04-03 08:52:45119}
120
121void PresentationServiceImpl::Bind(
Mario Sanchez Pradad960266d2019-08-26 15:11:53122 mojo::PendingReceiver<blink::mojom::PresentationService> receiver) {
Clovis PJ535cff6a2020-08-06 14:40:04123 presentation_service_receivers_.Add(this, std::move(receiver));
124 presentation_service_receivers_.set_disconnect_handler(base::BindRepeating(
Derek Cheng3eb973c2018-04-23 19:10:17125 &PresentationServiceImpl::OnConnectionError, base::Unretained(this)));
avayvodbca35fad2015-01-29 20:20:57126}
127
Derek Chengf8ffbec52017-12-06 19:43:04128void PresentationServiceImpl::SetController(
Mario Sanchez Prada2ae29e5a2019-08-26 14:42:23129 mojo::PendingRemote<blink::mojom::PresentationController>
130 presentation_controller_remote) {
131 if (presentation_controller_remote_) {
anshul.jain8fe6a652021-09-20 18:45:54132 presentation_service_receivers_.ReportBadMessage(
Derek Chengf8ffbec52017-12-06 19:43:04133 "There can only be one PresentationController at any given time.");
134 return;
135 }
Mario Sanchez Prada2ae29e5a2019-08-26 14:42:23136
137 presentation_controller_remote_.Bind(
138 std::move(presentation_controller_remote));
139 presentation_controller_remote_.set_disconnect_handler(base::BindOnce(
Derek Cheng1ad77242018-04-16 18:55:11140 &PresentationServiceImpl::OnConnectionError, base::Unretained(this)));
Derek Cheng4de47c52017-10-10 01:05:54141}
zhaobinf3704f82017-01-12 07:19:36142
Derek Cheng4de47c52017-10-10 01:05:54143void PresentationServiceImpl::SetReceiver(
Mario Sanchez Prada23a91b22019-08-26 14:45:33144 mojo::PendingRemote<blink::mojom::PresentationReceiver>
145 presentation_receiver_remote) {
Claudio DeSouzabfb1d3ee2021-12-09 01:16:20146 // Mojo interfaces for Presentation API are disabled during pre-rendering.
147 DCHECK_NE(render_frame_host_->GetLifecycleState(),
148 content::RenderFrameHost::LifecycleState::kPrerendering);
149
Kent Tamura21d1de62018-12-10 04:45:20150 // Presentation receiver virtual web tests (which have the flag set) has no
Derek Cheng3eb973c2018-04-23 19:10:17151 // ReceiverPresentationServiceDelegate implementation.
152 // TODO(imcheng): Refactor content_browser_client to return a no-op
153 // PresentationService instead.
154 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
155 switches::kForcePresentationReceiverForTesting)) {
156 return;
157 }
158
Claudio DeSouzaee45cae2021-11-24 20:30:27159 if (!receiver_delegate_ || !is_outermost_document_) {
anshul.jain8fe6a652021-09-20 18:45:54160 presentation_service_receivers_.ReportBadMessage(
Derek Cheng4de47c52017-10-10 01:05:54161 "SetReceiver can only be called from a "
Claudio DeSouzaee45cae2021-11-24 20:30:27162 "presentation receiver outermost document.");
Derek Cheng4de47c52017-10-10 01:05:54163 return;
zhaobinf3704f82017-01-12 07:19:36164 }
Derek Cheng4de47c52017-10-10 01:05:54165
Mario Sanchez Prada23a91b22019-08-26 14:45:33166 if (presentation_receiver_remote_) {
anshul.jain8fe6a652021-09-20 18:45:54167 presentation_service_receivers_.ReportBadMessage(
168 "SetReceiver can only be called once.");
Derek Cheng4de47c52017-10-10 01:05:54169 return;
170 }
171
Mario Sanchez Prada23a91b22019-08-26 14:45:33172 presentation_receiver_remote_.Bind(std::move(presentation_receiver_remote));
173 presentation_receiver_remote_.set_disconnect_handler(base::BindOnce(
Derek Cheng1ad77242018-04-16 18:55:11174 &PresentationServiceImpl::OnConnectionError, base::Unretained(this)));
Derek Cheng4de47c52017-10-10 01:05:54175 receiver_delegate_->RegisterReceiverConnectionAvailableCallback(
danakjf4b9e942019-11-29 15:43:04176 base::BindRepeating(
177 &PresentationServiceImpl::OnReceiverConnectionAvailable,
178 weak_factory_.GetWeakPtr()));
imcheng271b9ef2015-03-18 19:43:19179}
imcheng9f515d02015-02-10 20:09:24180
mfoltzfcad52622016-09-03 03:08:33181void PresentationServiceImpl::ListenForScreenAvailability(const GURL& url) {
mfoltz7a2c823b2016-10-08 01:35:24182 DVLOG(2) << "ListenForScreenAvailability " << url.spec();
imchengf23b8962017-07-10 23:01:56183 if (!controller_delegate_ || !url.is_valid()) {
Mario Sanchez Prada2ae29e5a2019-08-26 14:42:23184 if (presentation_controller_remote_) {
185 presentation_controller_remote_->OnScreenAvailabilityUpdated(
186 url, ScreenAvailability::UNAVAILABLE);
Derek Chengf8ffbec52017-12-06 19:43:04187 }
imcheng271b9ef2015-03-18 19:43:19188 return;
mlamouric6d5a452015-08-21 13:45:49189 }
imcheng271b9ef2015-03-18 19:43:19190
mfoltz7a2c823b2016-10-08 01:35:24191 if (screen_availability_listeners_.count(url))
imcheng9ce5394b2015-05-12 19:27:01192 return;
imcheng9ce5394b2015-05-12 19:27:01193
dcheng59716272016-04-09 05:19:08194 std::unique_ptr<ScreenAvailabilityListenerImpl> listener(
mfoltz7a2c823b2016-10-08 01:35:24195 new ScreenAvailabilityListenerImpl(url, this));
zhaobinf3704f82017-01-12 07:19:36196 if (controller_delegate_->AddScreenAvailabilityListener(
197 render_process_id_, render_frame_id_, listener.get())) {
mfoltz7a2c823b2016-10-08 01:35:24198 screen_availability_listeners_[url] = std::move(listener);
mfoltz3f30502f2015-08-11 16:13:38199 } else {
imcheng9ce5394b2015-05-12 19:27:01200 DVLOG(1) << "AddScreenAvailabilityListener failed. Ignoring request.";
imcheng9ce5394b2015-05-12 19:27:01201 }
202}
203
mfoltz3f30502f2015-08-11 16:13:38204void PresentationServiceImpl::StopListeningForScreenAvailability(
mfoltzfcad52622016-09-03 03:08:33205 const GURL& url) {
206 DVLOG(2) << "StopListeningForScreenAvailability " << url.spec();
zhaobinf3704f82017-01-12 07:19:36207 if (!controller_delegate_)
imcheng271b9ef2015-03-18 19:43:19208 return;
209
mfoltz7a2c823b2016-10-08 01:35:24210 auto listener_it = screen_availability_listeners_.find(url);
mfoltz3f30502f2015-08-11 16:13:38211 if (listener_it == screen_availability_listeners_.end())
212 return;
213
zhaobinf3704f82017-01-12 07:19:36214 controller_delegate_->RemoveScreenAvailabilityListener(
limasdf14d71e72015-11-17 17:38:04215 render_process_id_, render_frame_id_, listener_it->second.get());
mfoltz3f30502f2015-08-11 16:13:38216 screen_availability_listeners_.erase(listener_it);
avayvodbca35fad2015-01-29 20:20:57217}
218
mfoltz11fc4df82017-03-20 23:49:18219void PresentationServiceImpl::StartPresentation(
mfoltzfcad52622016-09-03 03:08:33220 const std::vector<GURL>& presentation_urls,
tzikcf7bcd652017-06-15 04:19:30221 NewPresentationCallback callback) {
mfoltz11fc4df82017-03-20 23:49:18222 DVLOG(2) << "StartPresentation";
imcheng271b9ef2015-03-18 19:43:19223
mfoltz11fc4df82017-03-20 23:49:18224 // There is a StartPresentation request in progress. To avoid queueing up
imchengacfb4532015-06-19 16:32:13225 // requests, the incoming request is rejected.
mfoltz11fc4df82017-03-20 23:49:18226 if (start_presentation_request_id_ != kInvalidRequestId) {
tzikcf7bcd652017-06-15 04:19:30227 InvokeNewPresentationCallbackWithError(std::move(callback));
imcheng27e2b56b2015-05-15 21:39:30228 return;
229 }
230
mark a. foltz930ea9462019-02-11 23:04:01231 if (!controller_delegate_) {
232 std::move(callback).Run(
233 /** PresentationConnectionResultPtr */ nullptr,
234 PresentationError::New(PresentationErrorType::NO_AVAILABLE_SCREENS,
235 "No screens found."));
236 return;
237 }
238
mfoltz11fc4df82017-03-20 23:49:18239 start_presentation_request_id_ = GetNextRequestId();
Peter Boströmdd7e40ec2021-04-05 20:40:10240 pending_start_presentation_cb_ =
241 std::make_unique<NewPresentationCallbackWrapper>(std::move(callback));
Derek Cheng1071a232017-07-25 22:23:56242 PresentationRequest request({render_process_id_, render_frame_id_},
243 presentation_urls,
244 render_frame_host_->GetLastCommittedOrigin());
mfoltz11fc4df82017-03-20 23:49:18245 controller_delegate_->StartPresentation(
Derek Cheng1071a232017-07-25 22:23:56246 request,
tzike2aca992017-09-05 08:50:54247 base::BindOnce(&PresentationServiceImpl::OnStartPresentationSucceeded,
248 weak_factory_.GetWeakPtr(),
249 start_presentation_request_id_),
250 base::BindOnce(&PresentationServiceImpl::OnStartPresentationError,
251 weak_factory_.GetWeakPtr(),
252 start_presentation_request_id_));
avayvodf0dd9742015-02-27 23:48:46253}
254
mfoltz11fc4df82017-03-20 23:49:18255void PresentationServiceImpl::ReconnectPresentation(
mfoltzfcad52622016-09-03 03:08:33256 const std::vector<GURL>& presentation_urls,
Derek Cheng71ede792017-07-27 07:58:16257 const std::string& presentation_id,
tzikcf7bcd652017-06-15 04:19:30258 NewPresentationCallback callback) {
mfoltz11fc4df82017-03-20 23:49:18259 DVLOG(2) << "ReconnectPresentation";
zhaobinf3704f82017-01-12 07:19:36260 if (!controller_delegate_) {
tzikcf7bcd652017-06-15 04:19:30261 std::move(callback).Run(
btolsch8ca10fb22018-08-29 01:35:09262 /** PresentationConnectionResultPtr */ nullptr,
mark a. foltzd9d2a4512018-04-16 20:42:45263 PresentationError::New(PresentationErrorType::NO_PRESENTATION_FOUND,
264 "Error joining route: No matching route"));
imcheng271b9ef2015-03-18 19:43:19265 return;
rockotad6b6cb2015-03-19 17:54:20266 }
imcheng271b9ef2015-03-18 19:43:19267
tzikcf7bcd652017-06-15 04:19:30268 int request_id = RegisterReconnectPresentationCallback(&callback);
mfoltz11fc4df82017-03-20 23:49:18269 if (request_id == kInvalidRequestId) {
tzikcf7bcd652017-06-15 04:19:30270 InvokeNewPresentationCallbackWithError(std::move(callback));
imcheng27e2b56b2015-05-15 21:39:30271 return;
272 }
Derek Cheng1071a232017-07-25 22:23:56273
274 PresentationRequest request({render_process_id_, render_frame_id_},
275 presentation_urls,
276 render_frame_host_->GetLastCommittedOrigin());
mfoltz11fc4df82017-03-20 23:49:18277 controller_delegate_->ReconnectPresentation(
Derek Cheng71ede792017-07-27 07:58:16278 request, presentation_id,
tzike2aca992017-09-05 08:50:54279 base::BindOnce(&PresentationServiceImpl::OnReconnectPresentationSucceeded,
280 weak_factory_.GetWeakPtr(), request_id),
281 base::BindOnce(&PresentationServiceImpl::OnReconnectPresentationError,
282 weak_factory_.GetWeakPtr(), request_id));
imcheng271b9ef2015-03-18 19:43:19283}
284
mfoltz11fc4df82017-03-20 23:49:18285int PresentationServiceImpl::RegisterReconnectPresentationCallback(
tzikcf7bcd652017-06-15 04:19:30286 NewPresentationCallback* callback) {
mfoltz11fc4df82017-03-20 23:49:18287 if (pending_reconnect_presentation_cbs_.size() >= kMaxQueuedRequests)
288 return kInvalidRequestId;
imcheng31fe0da92015-03-26 02:08:50289
mfoltz11fc4df82017-03-20 23:49:18290 int request_id = GetNextRequestId();
Avi Drissman6e6f6912018-12-04 17:43:52291 pending_reconnect_presentation_cbs_[request_id] =
292 std::make_unique<NewPresentationCallbackWrapper>(std::move(*callback));
tzikcf7bcd652017-06-15 04:19:30293 DCHECK_NE(kInvalidRequestId, request_id);
imcheng27e2b56b2015-05-15 21:39:30294 return request_id;
rockot5d5dbf0d2015-04-14 18:31:15295}
296
imcheng1ebdd162017-01-26 22:01:52297void PresentationServiceImpl::ListenForConnectionStateChange(
mfoltz11fc4df82017-03-20 23:49:18298 const PresentationInfo& connection) {
imcheng1ebdd162017-01-26 22:01:52299 // NOTE: Blink will automatically transition the connection's state to
300 // 'connected'.
zhaobinf3704f82017-01-12 07:19:36301 if (controller_delegate_) {
302 controller_delegate_->ListenForConnectionStateChange(
imchengf3e5a012015-11-20 04:08:37303 render_process_id_, render_frame_id_, connection,
danakjf4b9e942019-11-29 15:43:04304 base::BindRepeating(&PresentationServiceImpl::OnConnectionStateChanged,
305 weak_factory_.GetWeakPtr(), connection));
imchengf3e5a012015-11-20 04:08:37306 }
307}
308
mfoltz11fc4df82017-03-20 23:49:18309void PresentationServiceImpl::OnStartPresentationSucceeded(
310 int request_id,
btolsch8ca10fb22018-08-29 01:35:09311 blink::mojom::PresentationConnectionResultPtr result) {
mfoltz11fc4df82017-03-20 23:49:18312 if (request_id != start_presentation_request_id_)
imchengf3e5a012015-11-20 04:08:37313 return;
314
btolsch8ca10fb22018-08-29 01:35:09315 auto presentation_info = *result->presentation_info;
316 DCHECK(pending_start_presentation_cb_.get());
mark a. foltze2084383c2018-05-11 19:21:50317 DCHECK(presentation_info.id.length() <= kMaxPresentationIdLength);
btolsch8ca10fb22018-08-29 01:35:09318 pending_start_presentation_cb_->Run(std::move(result),
319 /** PresentationErrorPtr */ nullptr);
mfoltz11fc4df82017-03-20 23:49:18320 ListenForConnectionStateChange(presentation_info);
321 pending_start_presentation_cb_.reset();
322 start_presentation_request_id_ = kInvalidRequestId;
imcheng27e2b56b2015-05-15 21:39:30323}
324
mfoltz11fc4df82017-03-20 23:49:18325void PresentationServiceImpl::OnStartPresentationError(
326 int request_id,
mark a. foltzd9d2a4512018-04-16 20:42:45327 const blink::mojom::PresentationError& error) {
mfoltz11fc4df82017-03-20 23:49:18328 if (request_id != start_presentation_request_id_)
imchengf3e5a012015-11-20 04:08:37329 return;
330
mfoltz11fc4df82017-03-20 23:49:18331 CHECK(pending_start_presentation_cb_.get());
btolsch8ca10fb22018-08-29 01:35:09332 pending_start_presentation_cb_->Run(
333 /** PresentationConnectionResultPtr */ nullptr,
334 PresentationError::New(error));
mfoltz11fc4df82017-03-20 23:49:18335 pending_start_presentation_cb_.reset();
336 start_presentation_request_id_ = kInvalidRequestId;
imcheng27e2b56b2015-05-15 21:39:30337}
338
mfoltz11fc4df82017-03-20 23:49:18339void PresentationServiceImpl::OnReconnectPresentationSucceeded(
340 int request_id,
btolsch8ca10fb22018-08-29 01:35:09341 blink::mojom::PresentationConnectionResultPtr result) {
342 auto presentation_info = *result->presentation_info;
mfoltz11fc4df82017-03-20 23:49:18343 if (RunAndEraseReconnectPresentationMojoCallback(
btolsch8ca10fb22018-08-29 01:35:09344 request_id, std::move(result), /** PresentationErrorPtr */ nullptr)) {
mfoltz11fc4df82017-03-20 23:49:18345 ListenForConnectionStateChange(presentation_info);
imchengf3e5a012015-11-20 04:08:37346 }
imcheng271b9ef2015-03-18 19:43:19347}
348
mfoltz11fc4df82017-03-20 23:49:18349void PresentationServiceImpl::OnReconnectPresentationError(
350 int request_id,
mark a. foltzd9d2a4512018-04-16 20:42:45351 const blink::mojom::PresentationError& error) {
mark a. foltze2084383c2018-05-11 19:21:50352 RunAndEraseReconnectPresentationMojoCallback(
btolsch8ca10fb22018-08-29 01:35:09353 request_id, blink::mojom::PresentationConnectionResultPtr(),
354 PresentationError::New(error));
imcheng271b9ef2015-03-18 19:43:19355}
356
mfoltz11fc4df82017-03-20 23:49:18357bool PresentationServiceImpl::RunAndEraseReconnectPresentationMojoCallback(
358 int request_id,
btolsch8ca10fb22018-08-29 01:35:09359 blink::mojom::PresentationConnectionResultPtr result,
360 blink::mojom::PresentationErrorPtr error) {
mfoltz11fc4df82017-03-20 23:49:18361 auto it = pending_reconnect_presentation_cbs_.find(request_id);
362 if (it == pending_reconnect_presentation_cbs_.end())
imchengf3e5a012015-11-20 04:08:37363 return false;
imcheng31fe0da92015-03-26 02:08:50364
365 DCHECK(it->second.get());
btolsch8ca10fb22018-08-29 01:35:09366 it->second->Run(std::move(result), std::move(error));
mfoltz11fc4df82017-03-20 23:49:18367 pending_reconnect_presentation_cbs_.erase(it);
imchengf3e5a012015-11-20 04:08:37368 return true;
imcheng31fe0da92015-03-26 02:08:50369}
370
mfoltzfcad52622016-09-03 03:08:33371void PresentationServiceImpl::SetDefaultPresentationUrls(
372 const std::vector<GURL>& presentation_urls) {
373 DVLOG(2) << "SetDefaultPresentationUrls";
Claudio DeSouzaee45cae2021-11-24 20:30:27374 if (!controller_delegate_ || !is_outermost_document_)
imcheng271b9ef2015-03-18 19:43:19375 return;
376
mfoltz7a2c823b2016-10-08 01:35:24377 if (default_presentation_urls_ == presentation_urls)
imcheng271b9ef2015-03-18 19:43:19378 return;
imchengfa43aae02015-11-11 17:28:44379
mfoltz7a2c823b2016-10-08 01:35:24380 default_presentation_urls_ = presentation_urls;
Derek Cheng1071a232017-07-25 22:23:56381 PresentationRequest request({render_process_id_, render_frame_id_},
382 presentation_urls,
383 render_frame_host_->GetLastCommittedOrigin());
zhaobinf3704f82017-01-12 07:19:36384 controller_delegate_->SetDefaultPresentationUrls(
danakjf4b9e942019-11-29 15:43:04385 request, base::BindRepeating(
386 &PresentationServiceImpl::OnDefaultPresentationStarted,
387 weak_factory_.GetWeakPtr()));
avayvodf0dd9742015-02-27 23:48:46388}
389
mfoltzd0c3de12015-12-12 04:43:08390void PresentationServiceImpl::CloseConnection(
mfoltzfcad52622016-09-03 03:08:33391 const GURL& presentation_url,
tapted8f125bdd2016-08-01 04:51:09392 const std::string& presentation_id) {
mfoltzd0c3de12015-12-12 04:43:08393 DVLOG(2) << "CloseConnection " << presentation_id;
zhaobinf3704f82017-01-12 07:19:36394 if (controller_delegate_)
395 controller_delegate_->CloseConnection(render_process_id_, render_frame_id_,
396 presentation_id);
haibinluce6beec2015-03-19 02:50:51397}
398
mfoltzfcad52622016-09-03 03:08:33399void PresentationServiceImpl::Terminate(const GURL& presentation_url,
tapted8f125bdd2016-08-01 04:51:09400 const std::string& presentation_id) {
mfoltzd0c3de12015-12-12 04:43:08401 DVLOG(2) << "Terminate " << presentation_id;
zhaobinf3704f82017-01-12 07:19:36402 if (controller_delegate_)
403 controller_delegate_->Terminate(render_process_id_, render_frame_id_,
404 presentation_id);
mlamouric65a70d72015-11-27 16:28:59405}
406
Rakina Zata Amnic7bc82632019-12-09 05:21:22407void PresentationServiceImpl::SetControllerDelegateForTesting(
408 ControllerPresentationServiceDelegate* controller_delegate) {
409 controller_delegate_ = controller_delegate;
410}
411
imchengf3e5a012015-11-20 04:08:37412void PresentationServiceImpl::OnConnectionStateChanged(
mfoltz11fc4df82017-03-20 23:49:18413 const PresentationInfo& connection,
imchenged10e962016-02-23 06:34:44414 const PresentationConnectionStateChangeInfo& info) {
zhaobinbadd5952016-11-09 18:25:50415 DVLOG(2) << "PresentationServiceImpl::OnConnectionStateChanged "
mark a. foltze2084383c2018-05-11 19:21:50416 << "[presentation_id]: " << connection.id
zhaobinbadd5952016-11-09 18:25:50417 << " [state]: " << info.state;
Mario Sanchez Prada2ae29e5a2019-08-26 14:42:23418 if (!presentation_controller_remote_)
Derek Chengf8ffbec52017-12-06 19:43:04419 return;
420
mark a. foltze8ad3202018-04-23 22:50:23421 if (info.state == PresentationConnectionState::CLOSED) {
Mario Sanchez Prada2ae29e5a2019-08-26 14:42:23422 presentation_controller_remote_->OnConnectionClosed(
423 PresentationInfo::New(connection), info.close_reason, info.message);
imchenged10e962016-02-23 06:34:44424 } else {
Mario Sanchez Prada2ae29e5a2019-08-26 14:42:23425 presentation_controller_remote_->OnConnectionStateChanged(
426 PresentationInfo::New(connection), info.state);
imchenged10e962016-02-23 06:34:44427 }
avayvoda3731aa2015-03-25 15:01:53428}
429
imcheng2ed5f8202015-04-24 19:41:17430bool PresentationServiceImpl::FrameMatches(
431 content::RenderFrameHost* render_frame_host) const {
432 if (!render_frame_host)
433 return false;
434
Emily Andrewsd15fd762024-12-10 20:41:54435 return render_frame_host->GetProcess()->GetDeprecatedID() ==
436 render_process_id_ &&
imcheng2ed5f8202015-04-24 19:41:17437 render_frame_host->GetRoutingID() == render_frame_id_;
438}
439
Derek Cheng1ad77242018-04-16 18:55:11440void PresentationServiceImpl::OnConnectionError() {
441 Reset();
442}
443
zhaobinf3704f82017-01-12 07:19:36444PresentationServiceDelegate*
445PresentationServiceImpl::GetPresentationServiceDelegate() {
446 return receiver_delegate_
447 ? static_cast<PresentationServiceDelegate*>(receiver_delegate_)
448 : static_cast<PresentationServiceDelegate*>(controller_delegate_);
449}
450
zhaobinf3704f82017-01-12 07:19:36451void PresentationServiceImpl::OnReceiverConnectionAvailable(
Wei4 Wange1c8c002023-04-24 23:30:25452 blink::mojom::PresentationConnectionResultPtr result) {
zhaobinf3704f82017-01-12 07:19:36453 DVLOG(2) << "PresentationServiceImpl::OnReceiverConnectionAvailable";
454
Mario Sanchez Prada23a91b22019-08-26 14:45:33455 presentation_receiver_remote_->OnReceiverConnectionAvailable(
Wei4 Wange1c8c002023-04-24 23:30:25456 std::move(result));
zhaobinf3704f82017-01-12 07:19:36457}
458
jam5fdbb58d2017-02-06 22:09:59459void PresentationServiceImpl::DidFinishNavigation(
460 NavigationHandle* navigation_handle) {
Rakina Zata Amnic7bc82632019-12-09 05:21:22461 // Since the PresentationServiceImpl is tied to the lifetime of a
462 // RenderFrameHost, we should reset the connections when a navigation
463 // finished but we're still using the same RenderFrameHost.
464 // We don't need to do anything when the navigation didn't actually commit,
Takashi Toyoshima13633852021-06-08 02:37:06465 // won't use the same RenderFrameHost, is restoring a RenderFrameHost from
466 // the back-forward cache, or is activating a prerendered page.
imcheng271b9ef2015-03-18 19:43:19467 DVLOG(2) << "PresentationServiceImpl::DidNavigateAnyFrame";
jam5fdbb58d2017-02-06 22:09:59468 if (!navigation_handle->HasCommitted() ||
Rakina Zata Amnic7bc82632019-12-09 05:21:22469 !FrameMatches(navigation_handle->GetRenderFrameHost()) ||
Takashi Toyoshima13633852021-06-08 02:37:06470 navigation_handle->IsServedFromBackForwardCache() ||
471 navigation_handle->IsPrerenderedPageActivation()) {
imcheng9f515d02015-02-10 20:09:24472 return;
jam5fdbb58d2017-02-06 22:09:59473 }
imcheng9f515d02015-02-10 20:09:24474
eugenebuta11672fb2017-03-07 17:13:51475 // If a frame navigation is same-document (e.g. navigating to a fragment in
imcheng9f515d02015-02-10 20:09:24476 // same page) then we do not unregister listeners.
imcheng271b9ef2015-03-18 19:43:19477 DVLOG(2) << "DidNavigateAnyFrame: "
eugenebuta11672fb2017-03-07 17:13:51478 << ", is_same_document: " << navigation_handle->IsSameDocument();
479 if (navigation_handle->IsSameDocument())
imcheng9f515d02015-02-10 20:09:24480 return;
481
imcheng271b9ef2015-03-18 19:43:19482 // Reset if the frame actually navigated.
483 Reset();
imcheng9f515d02015-02-10 20:09:24484}
485
imcheng271b9ef2015-03-18 19:43:19486void PresentationServiceImpl::Reset() {
487 DVLOG(2) << "PresentationServiceImpl::Reset";
zhaobindca98f632017-06-29 18:42:28488 if (controller_delegate_)
489 controller_delegate_->Reset(render_process_id_, render_frame_id_);
490
Claudio DeSouzaee45cae2021-11-24 20:30:27491 if (receiver_delegate_ && is_outermost_document_)
zhaobindca98f632017-06-29 18:42:28492 receiver_delegate_->Reset(render_process_id_, render_frame_id_);
imcheng9f515d02015-02-10 20:09:24493
mfoltzfcad52622016-09-03 03:08:33494 default_presentation_urls_.clear();
imcheng27e2b56b2015-05-15 21:39:30495
mfoltz3f30502f2015-08-11 16:13:38496 screen_availability_listeners_.clear();
imcheng27e2b56b2015-05-15 21:39:30497
mfoltz11fc4df82017-03-20 23:49:18498 start_presentation_request_id_ = kInvalidRequestId;
499 pending_start_presentation_cb_.reset();
imcheng27e2b56b2015-05-15 21:39:30500
mfoltz11fc4df82017-03-20 23:49:18501 pending_reconnect_presentation_cbs_.clear();
Derek Chengf8ffbec52017-12-06 19:43:04502
Clovis PJ535cff6a2020-08-06 14:40:04503 presentation_service_receivers_.Clear();
Mario Sanchez Prada2ae29e5a2019-08-26 14:42:23504 presentation_controller_remote_.reset();
Mario Sanchez Prada23a91b22019-08-26 14:45:33505 presentation_receiver_remote_.reset();
imcheng31fe0da92015-03-26 02:08:50506}
507
imcheng9f515d02015-02-10 20:09:24508void PresentationServiceImpl::OnDelegateDestroyed() {
imcheng271b9ef2015-03-18 19:43:19509 DVLOG(2) << "PresentationServiceImpl::OnDelegateDestroyed";
zhaobinf3704f82017-01-12 07:19:36510 controller_delegate_ = nullptr;
511 receiver_delegate_ = nullptr;
imcheng271b9ef2015-03-18 19:43:19512 Reset();
imcheng9f515d02015-02-10 20:09:24513}
514
imcheng2ed5f8202015-04-24 19:41:17515void PresentationServiceImpl::OnDefaultPresentationStarted(
btolsch8ca10fb22018-08-29 01:35:09516 blink::mojom::PresentationConnectionResultPtr result) {
517 auto presentation_info = *result->presentation_info;
Mario Sanchez Prada2ae29e5a2019-08-26 14:42:23518 if (presentation_controller_remote_) {
519 presentation_controller_remote_->OnDefaultPresentationStarted(
520 std::move(result));
521 }
Derek Chengf8ffbec52017-12-06 19:43:04522
btolsch8ca10fb22018-08-29 01:35:09523 // TODO(btolsch): Remove the state-change API in favor of direct
524 // PresentationConnection state use.
525 ListenForConnectionStateChange(presentation_info);
imcheng2ed5f8202015-04-24 19:41:17526}
527
mfoltz7a2c823b2016-10-08 01:35:24528PresentationServiceImpl::ScreenAvailabilityListenerImpl::
529 ScreenAvailabilityListenerImpl(const GURL& availability_url,
530 PresentationServiceImpl* service)
531 : availability_url_(availability_url), service_(service) {
imchengf23b8962017-07-10 23:01:56532 DCHECK(availability_url_.is_valid());
imcheng9ce5394b2015-05-12 19:27:01533 DCHECK(service_);
imcheng9f515d02015-02-10 20:09:24534}
535
imcheng9ce5394b2015-05-12 19:27:01536PresentationServiceImpl::ScreenAvailabilityListenerImpl::
imchengf23b8962017-07-10 23:01:56537 ~ScreenAvailabilityListenerImpl() = default;
imcheng9f515d02015-02-10 20:09:24538
mfoltz7a2c823b2016-10-08 01:35:24539GURL PresentationServiceImpl::ScreenAvailabilityListenerImpl::
Lucas Furukawa Gadani4b4eed02019-06-04 23:12:04540 GetAvailabilityUrl() {
mfoltz3f30502f2015-08-11 16:13:38541 return availability_url_;
imcheng9f515d02015-02-10 20:09:24542}
543
Anton Vayvode3c39862017-06-20 20:53:32544void PresentationServiceImpl::ScreenAvailabilityListenerImpl::
545 OnScreenAvailabilityChanged(blink::mojom::ScreenAvailability availability) {
Mario Sanchez Prada2ae29e5a2019-08-26 14:42:23546 if (service_->presentation_controller_remote_) {
547 service_->presentation_controller_remote_->OnScreenAvailabilityUpdated(
548 availability_url_, availability);
Derek Chengf8ffbec52017-12-06 19:43:04549 }
imcheng271b9ef2015-03-18 19:43:19550}
551
mfoltz11fc4df82017-03-20 23:49:18552PresentationServiceImpl::NewPresentationCallbackWrapper::
tzikcf7bcd652017-06-15 04:19:30553 NewPresentationCallbackWrapper(NewPresentationCallback callback)
554 : callback_(std::move(callback)) {}
imcheng27e2b56b2015-05-15 21:39:30555
mfoltz11fc4df82017-03-20 23:49:18556PresentationServiceImpl::NewPresentationCallbackWrapper::
557 ~NewPresentationCallbackWrapper() {
Derek Cheng5f697032017-08-01 21:56:07558 if (!callback_.is_null()) {
559 std::move(callback_).Run(
btolsch8ca10fb22018-08-29 01:35:09560 /** PresentationConnectionResultPtr */ nullptr,
mark a. foltzd9d2a4512018-04-16 20:42:45561 PresentationError::New(
562 PresentationErrorType::PRESENTATION_REQUEST_CANCELLED,
563 "The frame is navigating or being destroyed."));
Derek Cheng5f697032017-08-01 21:56:07564 }
imcheng27e2b56b2015-05-15 21:39:30565}
566
mfoltz11fc4df82017-03-20 23:49:18567void PresentationServiceImpl::NewPresentationCallbackWrapper::Run(
btolsch8ca10fb22018-08-29 01:35:09568 blink::mojom::PresentationConnectionResultPtr result,
569 blink::mojom::PresentationErrorPtr error) {
imcheng27e2b56b2015-05-15 21:39:30570 DCHECK(!callback_.is_null());
btolsch8ca10fb22018-08-29 01:35:09571 std::move(callback_).Run(std::move(result), std::move(error));
imcheng27e2b56b2015-05-15 21:39:30572}
573
avayvodbca35fad2015-01-29 20:20:57574} // namespace content