Commit 9ce5394b authored by imcheng's avatar imcheng Committed by Commit bot

[Presentation API] Convert screen availability API into Client style.

Introduced a PresentationServiceClient mojo interface implemented by
PresentationDispatcher. On connection to PresentationService,
PDispatcher will pass a proxy of itself to PSImpl.

Please note that screen availability updates are already throttled
from the browser's perspective.

When a screen availability update is available, it will be transmitted
back to PSDispatcher via the PresentationServiceClient interface.

In the future, I plan to use the same interface for other types of
observer-style APIs (e.g. default session start, session state change,
on message).

Also, simplified the ScreenAvailability API so it only operates on
the DPU (or 1-UA mode if absent). The current semantics to support
listening on arbitrarily presentation URLs + handling behavior for
DPU is very confusing. We should revisit the implementation when we
decide to support it.

This will also hopefully fix the bug where ScreenAvailability mojo
callbacks accumulate over time.

Also fix mojom indent.

BUG=485337

Review URL: https://codereview.chromium.org/1131053005

Cr-Commit-Position: refs/heads/master@{#329457}
parent e8b1380e
...@@ -138,58 +138,62 @@ void PresentationServiceImpl::OnConnectionError() { ...@@ -138,58 +138,62 @@ void PresentationServiceImpl::OnConnectionError() {
delete this; delete this;
} }
PresentationServiceImpl::ScreenAvailabilityContext* void PresentationServiceImpl::SetClient(
PresentationServiceImpl::GetOrCreateAvailabilityContext( presentation::PresentationServiceClientPtr client) {
const std::string& presentation_url) { DCHECK(!client_.get());
auto it = availability_contexts_.find(presentation_url); // TODO(imcheng): Set ErrorHandler to listen for errors.
if (it == availability_contexts_.end()) { client_ = client.Pass();
linked_ptr<ScreenAvailabilityContext> context(
new ScreenAvailabilityContext(presentation_url));
if (!delegate_->AddScreenAvailabilityListener(
render_process_id_, render_frame_id_, context.get())) {
DVLOG(1) << "AddScreenAvailabilityListener failed. Ignoring request.";
return nullptr;
}
it = availability_contexts_.insert(
std::make_pair(context->GetPresentationUrl(), context)).first;
}
return it->second.get();
} }
void PresentationServiceImpl::ListenForScreenAvailability( void PresentationServiceImpl::ListenForScreenAvailability() {
const mojo::String& presentation_url,
const ScreenAvailabilityMojoCallback& callback) {
DVLOG(2) << "ListenForScreenAvailability"; DVLOG(2) << "ListenForScreenAvailability";
if (!delegate_) { if (!delegate_)
callback.Run(presentation_url, false);
return; return;
}
ScreenAvailabilityContext* context = if (screen_availability_listener_.get() &&
GetOrCreateAvailabilityContext(presentation_url.get()); screen_availability_listener_->GetPresentationUrl() ==
if (!context) { default_presentation_url_) {
callback.Run(presentation_url, false);
return; return;
} }
context->CallbackReceived(callback);
ResetScreenAvailabilityListener(default_presentation_url_);
} }
void PresentationServiceImpl::RemoveScreenAvailabilityListener( void PresentationServiceImpl::ResetScreenAvailabilityListener(
const mojo::String& presentation_url) { const std::string& presentation_url) {
DVLOG(2) << "RemoveScreenAvailabilityListener"; DCHECK(delegate_);
if (!delegate_) DCHECK(!screen_availability_listener_.get() ||
return; presentation_url != default_presentation_url_);
// (1) Unregister old listener with delegate
StopListeningForScreenAvailability();
// (2) Replace old listener with new listener
screen_availability_listener_.reset(new ScreenAvailabilityListenerImpl(
presentation_url, this));
const std::string& presentation_url_str = presentation_url.get(); // (3) Register new listener with delegate
auto it = availability_contexts_.find(presentation_url_str); if (!delegate_->AddScreenAvailabilityListener(
if (it == availability_contexts_.end()) render_process_id_,
render_frame_id_,
screen_availability_listener_.get())) {
DVLOG(1) << "AddScreenAvailabilityListener failed. Ignoring request.";
screen_availability_listener_.reset();
}
}
void PresentationServiceImpl::StopListeningForScreenAvailability() {
DVLOG(2) << "StopListeningForScreenAvailability";
if (!delegate_)
return; return;
delegate_->RemoveScreenAvailabilityListener( if (screen_availability_listener_.get()) {
render_process_id_, render_frame_id_, it->second.get()); delegate_->RemoveScreenAvailabilityListener(
// Resolve the context's pending callbacks before removing it. render_process_id_,
it->second->OnScreenAvailabilityChanged(false); render_frame_id_,
availability_contexts_.erase(it); screen_availability_listener_.get());
screen_availability_listener_.reset();
}
} }
void PresentationServiceImpl::ListenForDefaultSessionStart( void PresentationServiceImpl::ListenForDefaultSessionStart(
...@@ -322,19 +326,6 @@ void PresentationServiceImpl::RunAndEraseNewSessionMojoCallback( ...@@ -322,19 +326,6 @@ void PresentationServiceImpl::RunAndEraseNewSessionMojoCallback(
pending_session_cbs_.erase(it); pending_session_cbs_.erase(it);
} }
void PresentationServiceImpl::DoSetDefaultPresentationUrl(
const std::string& default_presentation_url,
const std::string& default_presentation_id) {
DCHECK(delegate_);
delegate_->SetDefaultPresentationUrl(
render_process_id_,
render_frame_id_,
default_presentation_url,
default_presentation_id);
default_presentation_url_ = default_presentation_url;
default_presentation_id_ = default_presentation_id;
}
void PresentationServiceImpl::SetDefaultPresentationURL( void PresentationServiceImpl::SetDefaultPresentationURL(
const mojo::String& default_presentation_url, const mojo::String& default_presentation_url,
const mojo::String& default_presentation_id) { const mojo::String& default_presentation_id) {
...@@ -351,28 +342,19 @@ void PresentationServiceImpl::SetDefaultPresentationURL( ...@@ -351,28 +342,19 @@ void PresentationServiceImpl::SetDefaultPresentationURL(
return; return;
} }
auto old_it = availability_contexts_.find(old_default_url); if (old_default_url != new_default_url) {
// Haven't started listening yet. // If DPU changed, replace screen availability listeners if any.
if (old_it == availability_contexts_.end()) { if (screen_availability_listener_.get())
DoSetDefaultPresentationUrl(new_default_url, default_presentation_id); ResetScreenAvailabilityListener(new_default_url);
return;
} }
// Have already started listening. Create a listener for the new URL and delegate_->SetDefaultPresentationUrl(
// transfer the callbacks from the old listener, if any.
// This is done so that a listener added before default URL is changed
// will continue to work.
ScreenAvailabilityContext* context =
GetOrCreateAvailabilityContext(new_default_url);
old_it->second->PassPendingCallbacks(context);
// Remove listener for old default presentation URL.
delegate_->RemoveScreenAvailabilityListener(
render_process_id_, render_process_id_,
render_frame_id_, render_frame_id_,
old_it->second.get()); default_presentation_url,
availability_contexts_.erase(old_it); default_presentation_id);
DoSetDefaultPresentationUrl(new_default_url, default_presentation_id); default_presentation_url_ = default_presentation_url;
default_presentation_id_ = default_presentation_id;
} }
...@@ -507,7 +489,7 @@ void PresentationServiceImpl::Reset() { ...@@ -507,7 +489,7 @@ void PresentationServiceImpl::Reset() {
default_presentation_url_.clear(); default_presentation_url_.clear();
default_presentation_id_.clear(); default_presentation_id_.clear();
availability_contexts_.clear(); screen_availability_listener_.reset();
queued_start_session_requests_.clear(); queued_start_session_requests_.clear();
FlushNewSessionCallbacks(); FlushNewSessionCallbacks();
default_session_start_context_.reset(); default_session_start_context_.reset();
...@@ -545,65 +527,28 @@ void PresentationServiceImpl::OnDefaultPresentationStarted( ...@@ -545,65 +527,28 @@ void PresentationServiceImpl::OnDefaultPresentationStarted(
default_session_start_context_->set_session(session); default_session_start_context_->set_session(session);
} }
PresentationServiceImpl::ScreenAvailabilityContext::ScreenAvailabilityContext( PresentationServiceImpl::ScreenAvailabilityListenerImpl
const std::string& presentation_url) ::ScreenAvailabilityListenerImpl(
: presentation_url_(presentation_url) { const std::string& presentation_url,
} PresentationServiceImpl* service)
: presentation_url_(presentation_url),
PresentationServiceImpl::ScreenAvailabilityContext:: service_(service) {
~ScreenAvailabilityContext() { DCHECK(service_);
// Ensure that pending callbacks are flushed. DCHECK(service_->client_.get());
OnScreenAvailabilityChanged(false);
} }
void PresentationServiceImpl::ScreenAvailabilityContext::CallbackReceived( PresentationServiceImpl::ScreenAvailabilityListenerImpl::
const ScreenAvailabilityMojoCallback& callback) { ~ScreenAvailabilityListenerImpl() {
// NOTE: This will overwrite previously registered callback if any.
if (!available_ptr_) {
// No results yet, store callback for later invocation.
callbacks_.push_back(new ScreenAvailabilityMojoCallback(callback));
} else {
// Run callback now, reset result.
// There shouldn't be any callbacks stored in this scenario.
DCHECK(!HasPendingCallbacks());
callback.Run(presentation_url_, *available_ptr_);
available_ptr_.reset();
}
} }
std::string PresentationServiceImpl::ScreenAvailabilityContext std::string PresentationServiceImpl::ScreenAvailabilityListenerImpl
::GetPresentationUrl() const { ::GetPresentationUrl() const {
return presentation_url_; return presentation_url_;
} }
void PresentationServiceImpl::ScreenAvailabilityContext void PresentationServiceImpl::ScreenAvailabilityListenerImpl
::OnScreenAvailabilityChanged(bool available) { ::OnScreenAvailabilityChanged(bool available) {
if (!HasPendingCallbacks()) { service_->client_->OnScreenAvailabilityUpdated(available);
// No callback, stash the result for now.
available_ptr_.reset(new bool(available));
} else {
// Invoke callbacks and erase them.
// There shouldn't be any result stored in this scenario.
DCHECK(!available_ptr_);
ScopedVector<ScreenAvailabilityMojoCallback> callbacks;
callbacks.swap(callbacks_);
for (const auto& callback : callbacks)
callback->Run(presentation_url_, available);
}
}
void PresentationServiceImpl::ScreenAvailabilityContext
::PassPendingCallbacks(
PresentationServiceImpl::ScreenAvailabilityContext* other) {
std::vector<ScreenAvailabilityMojoCallback*> callbacks;
callbacks_.release(&callbacks);
std::copy(callbacks.begin(), callbacks.end(),
std::back_inserter(other->callbacks_));
}
bool PresentationServiceImpl::ScreenAvailabilityContext
::HasPendingCallbacks() const {
return !callbacks_.empty();
} }
PresentationServiceImpl::StartSessionRequest::StartSessionRequest( PresentationServiceImpl::StartSessionRequest::StartSessionRequest(
......
...@@ -55,8 +55,30 @@ class CONTENT_EXPORT PresentationServiceImpl ...@@ -55,8 +55,30 @@ class CONTENT_EXPORT PresentationServiceImpl
mojo::InterfaceRequest<presentation::PresentationService> request); mojo::InterfaceRequest<presentation::PresentationService> request);
private: private:
using ScreenAvailabilityMojoCallback = friend class PresentationServiceImplTest;
mojo::Callback<void(mojo::String, bool)>; FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, Reset);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, DidNavigateThisFrame);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
DidNavigateOtherFrame);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, ThisRenderFrameDeleted);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
OtherRenderFrameDeleted);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, DelegateFails);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
SetDefaultPresentationUrl);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
SetSameDefaultPresentationUrl);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ClearDefaultPresentationUrl);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ListenForDefaultSessionStart);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ListenForDefaultSessionStartAfterSet);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
DefaultSessionStartReset);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ReceiveSessionMessagesAfterReset);
using NewSessionMojoCallback = using NewSessionMojoCallback =
mojo::Callback<void(presentation::PresentationSessionInfoPtr, mojo::Callback<void(presentation::PresentationSessionInfoPtr,
presentation::PresentationErrorPtr)>; presentation::PresentationErrorPtr)>;
...@@ -69,48 +91,25 @@ class CONTENT_EXPORT PresentationServiceImpl ...@@ -69,48 +91,25 @@ class CONTENT_EXPORT PresentationServiceImpl
mojo::Callback<void(mojo::Array<presentation::SessionMessagePtr>)>; mojo::Callback<void(mojo::Array<presentation::SessionMessagePtr>)>;
using SendMessageMojoCallback = mojo::Callback<void(bool)>; using SendMessageMojoCallback = mojo::Callback<void(bool)>;
// A helper data class used by PresentationServiceImpl to do bookkeeping // Listener implementation owned by PresentationServiceImpl. An instance of
// of currently registered screen availability listeners. // this is created when an |onavailablechange| handler is added.
// An instance of this class is a simple state machine that waits for both // The instance receives screen availability results from the embedder and
// the available bit and the Mojo callback to become available. // propagates results back to PresentationServiceImpl.
// Once this happens, the Mojo callback will be invoked with the available class CONTENT_EXPORT ScreenAvailabilityListenerImpl
// bit, and the state machine will reset.
// The available bit is obtained from the embedder's media router.
// The callback is obtained from the renderer via PresentationServiceImpl's
// ListenForScreenAvailability().
class CONTENT_EXPORT ScreenAvailabilityContext
: public PresentationScreenAvailabilityListener { : public PresentationScreenAvailabilityListener {
public: public:
explicit ScreenAvailabilityContext( ScreenAvailabilityListenerImpl(
const std::string& presentation_url); const std::string& presentation_url,
~ScreenAvailabilityContext() override; PresentationServiceImpl* service);
~ScreenAvailabilityListenerImpl() override;
// If available bit exists, |callback| will be invoked with the bit and
// this state machine will reset.
// Otherwise |callback| is saved for later use.
// |callback|: Callback to the client of PresentationService
// (i.e. the renderer) that screen availability has changed, via Mojo.
void CallbackReceived(const ScreenAvailabilityMojoCallback& callback);
// PresentationScreenAvailabilityListener implementation. // PresentationScreenAvailabilityListener implementation.
std::string GetPresentationUrl() const override; std::string GetPresentationUrl() const override;
// If callback exists, it will be invoked with |available| and
// this state machine will reset.
// Otherwise |available| is saved for later use.
// |available|: New screen availability for the presentation URL.
void OnScreenAvailabilityChanged(bool available) override; void OnScreenAvailabilityChanged(bool available) override;
// Pass this context's queued callbacks to another context.
void PassPendingCallbacks(ScreenAvailabilityContext* other);
// Indicates if this context has any pending callbacks.
bool HasPendingCallbacks() const;
private: private:
std::string presentation_url_; const std::string presentation_url_;
ScopedVector<ScreenAvailabilityMojoCallback> callbacks_; PresentationServiceImpl* const service_;
scoped_ptr<bool> available_ptr_;
}; };
class CONTENT_EXPORT DefaultSessionStartContext { class CONTENT_EXPORT DefaultSessionStartContext {
...@@ -155,31 +154,6 @@ class CONTENT_EXPORT PresentationServiceImpl ...@@ -155,31 +154,6 @@ class CONTENT_EXPORT PresentationServiceImpl
NewSessionMojoCallback callback_; NewSessionMojoCallback callback_;
}; };
friend class PresentationServiceImplTest;
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, Reset);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
DidNavigateThisFrame);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
DidNavigateNotThisFrame);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ThisRenderFrameDeleted);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
NotThisRenderFrameDeleted);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
SetDefaultPresentationUrl);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
SetSameDefaultPresentationUrl);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ClearDefaultPresentationUrl);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ListenForDefaultSessionStart);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ListenForDefaultSessionStartAfterSet);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
DefaultSessionStartReset);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ReceiveSessionMessagesAfterReset);
// |render_frame_host|: The RFH this instance is associated with. // |render_frame_host|: The RFH this instance is associated with.
// |web_contents|: The WebContents to observe. // |web_contents|: The WebContents to observe.
// |delegate|: Where Presentation API requests are delegated to. Not owned // |delegate|: Where Presentation API requests are delegated to. Not owned
...@@ -193,11 +167,9 @@ class CONTENT_EXPORT PresentationServiceImpl ...@@ -193,11 +167,9 @@ class CONTENT_EXPORT PresentationServiceImpl
void SetDefaultPresentationURL( void SetDefaultPresentationURL(
const mojo::String& presentation_url, const mojo::String& presentation_url,
const mojo::String& presentation_id) override; const mojo::String& presentation_id) override;
void ListenForScreenAvailability( void SetClient(presentation::PresentationServiceClientPtr client) override;
const mojo::String& presentation_url, void ListenForScreenAvailability() override;
const ScreenAvailabilityMojoCallback& callback) override; void StopListeningForScreenAvailability() override;
void RemoveScreenAvailabilityListener(
const mojo::String& presentation_url) override;
void ListenForDefaultSessionStart( void ListenForDefaultSessionStart(
const DefaultSessionMojoCallback& callback) override; const DefaultSessionMojoCallback& callback) override;
void StartSession( void StartSession(
...@@ -246,11 +218,9 @@ class CONTENT_EXPORT PresentationServiceImpl ...@@ -246,11 +218,9 @@ class CONTENT_EXPORT PresentationServiceImpl
presentation::PresentationSessionInfoPtr session, presentation::PresentationSessionInfoPtr session,
presentation::PresentationErrorPtr error); presentation::PresentationErrorPtr error);
// Sets |default_presentation_url_| to |presentation_url| and informs the // Creates a new screen availability listener for |presentation_url| and
// delegate of new default presentation URL and ID. // registers it with |delegate_|. Replaces the existing listener if any.
void DoSetDefaultPresentationUrl( void ResetScreenAvailabilityListener(const std::string& presentation_url);
const std::string& presentation_url,
const std::string& presentation_id);
// Removes all listeners and resets default presentation URL on this instance // Removes all listeners and resets default presentation URL on this instance
// and informs the PresentationServiceDelegate of such. // and informs the PresentationServiceDelegate of such.
...@@ -299,23 +269,22 @@ class CONTENT_EXPORT PresentationServiceImpl ...@@ -299,23 +269,22 @@ class CONTENT_EXPORT PresentationServiceImpl
static void InvokeNewSessionMojoCallbackWithError( static void InvokeNewSessionMojoCallbackWithError(
const NewSessionMojoCallback& callback); const NewSessionMojoCallback& callback);
// Gets the ScreenAvailabilityContext for |presentation_url|, or creates one
// if it does not exist.
ScreenAvailabilityContext* GetOrCreateAvailabilityContext(
const std::string& presentation_url);
// Returns true if this object is associated with |render_frame_host|. // Returns true if this object is associated with |render_frame_host|.
bool FrameMatches(content::RenderFrameHost* render_frame_host) const; bool FrameMatches(content::RenderFrameHost* render_frame_host) const;
// Embedder-specific delegate to forward Presentation requests to.
// May be null if embedder does not support Presentation API.
PresentationServiceDelegate* delegate_; PresentationServiceDelegate* delegate_;
// Map from presentation URL to its ScreenAvailabilityContext state machine. // Proxy to the PresentationServiceClient to send results (e.g., screen
base::hash_map<std::string, linked_ptr<ScreenAvailabilityContext>> // availability) to.
availability_contexts_; presentation::PresentationServiceClientPtr client_;
std::string default_presentation_url_; std::string default_presentation_url_;
std::string default_presentation_id_; std::string default_presentation_id_;
scoped_ptr<ScreenAvailabilityListenerImpl> screen_availability_listener_;
// We only allow one StartSession request to be processed at a time. // We only allow one StartSession request to be processed at a time.
// StartSession requests are queued here. When a request has been processed, // StartSession requests are queued here. When a request has been processed,
// it is removed from head of the queue. // it is removed from head of the queue.
......
...@@ -5,108 +5,111 @@ ...@@ -5,108 +5,111 @@
module presentation; module presentation;
struct PresentationSessionInfo { struct PresentationSessionInfo {
string url; string url;
string id; string id;
}; };
enum PresentationSessionState { enum PresentationSessionState {
CONNECTED, CONNECTED,
DISCONNECTED DISCONNECTED
}; };
enum PresentationErrorType { enum PresentationErrorType {
NO_AVAILABLE_SCREENS, NO_AVAILABLE_SCREENS,
SESSION_REQUEST_CANCELLED, SESSION_REQUEST_CANCELLED,
NO_PRESENTATION_FOUND, NO_PRESENTATION_FOUND,
UNKNOWN, UNKNOWN,
}; };
struct PresentationError { struct PresentationError {
PresentationErrorType error_type; PresentationErrorType error_type;
string message; string message;
}; };
enum PresentationMessageType { enum PresentationMessageType {
TEXT, TEXT,
ARRAY_BUFFER, ARRAY_BUFFER,
}; };
struct SessionMessage { struct SessionMessage {
string presentation_url; string presentation_url;
string presentation_id; string presentation_id;
PresentationMessageType type; PresentationMessageType type;
string? message; string? message;
array<uint8>? data; array<uint8>? data;
}; };
interface PresentationService { interface PresentationService {
// Called when the frame sets or changes the default presentation URL or // Called when the frame sets or changes the default presentation URL or
// presentation ID. // presentation ID.
SetDefaultPresentationURL( SetDefaultPresentationURL(
string default_presentation_url, string default_presentation_url,
string? default_presentation_id); string? default_presentation_id);
// Returns the last screen availability state if it’s changed since the last // Sets the PresentationServiceClient.
// time the method was called. The client has to call this method again when SetClient(PresentationServiceClient client);
// handling the result (provided via Mojo callback) to get the next update
// about the availability status. // Starts listening for screen availability for the current default
// May start discovery of the presentation screens. The implementation might // presentation URL. Availability results will be returned to the client
// stop discovery once there are no active calls to // via PresentationServiceClient::OnScreenAvailabilityUpdated.
// ListenForScreenAvailability. |presentation_url| can be specified to help ListenForScreenAvailability();
// the implementation to filter out incompatible screens.
ListenForScreenAvailability(string? presentation_url) => // Stops listening for screen availability for the current default
(string? presentation_url, bool available); // default presentation URL. The client will stop receiving availability
// updates.
// Called when the frame no longer listens to the |availablechange| event. StopListeningForScreenAvailability();
RemoveScreenAvailabilityListener(string? presentation_url);
// Called when the renderer is ready to receive the browser initiated
// Called when the renderer is ready to receive the browser initiated // session. If the default session is started by the embedder before this
// session. If the default session is started by the embedder before this // call, the embedder may queue it and run the callback when the call is
// call, the embedder may queue it and run the callback when the call is // performed.
// performed. ListenForDefaultSessionStart()
ListenForDefaultSessionStart() => (PresentationSessionInfo? defaultSessionInfo);
=> (PresentationSessionInfo? defaultSessionInfo);
// Called when startSession() is called by the frame. The result callback
// Called when startSession() is called by the frame. The result callback // will return a non-null and valid PresentationSessionInfo if starting the
// will return a non-null and valid PresentationSessionInfo if starting the // session succeeded, or null with a PresentationError if starting the
// session succeeded, or null with a PresentationError if starting the // session failed.
// session failed. // The presentation id is always returned along with the initialized
// The presentation id is always returned along with the initialized // session on success.
// session on success. // If the UA identifies a matching session (same presentation url and id),
// If the UA identifies a matching session (same presentation url and id), // the user may choose this existing session and the page will join it
// the user may choose this existing session and the page will join it // rather than get a new one. An empty presentation id means that the
// rather than get a new one. An empty presentation id means that the // UA will generate the presentation id.
// UA will generate the presentation id. StartSession(string presentation_url, string? presentation_id)
StartSession(string presentation_url, string? presentation_id) => (PresentationSessionInfo? sessionInfo, PresentationError? error);
=> (PresentationSessionInfo? sessionInfo, PresentationError? error);
// Called when joinSession() is called by the frame. The result callback
// Called when joinSession() is called by the frame. The result callback // works the same as for the method above. JoinSession will join a known
// works the same as for the method above. JoinSession will join a known // session (i.e. when the page navigates or the user opens another tab)
// session (i.e. when the page navigates or the user opens another tab) // silently and without user action.
// silently and without user action. JoinSession(string presentation_url, string? presentation_id)
JoinSession(string presentation_url, string? presentation_id) => (PresentationSessionInfo? sessionInfo, PresentationError? error);
=> (PresentationSessionInfo? sessionInfo, PresentationError? error);
// Called when send() is called by the frame. The true in the
// Called when send() is called by the frame. The true in the // result callback notifies that the service is ready for next message.
// result callback notifies that the service is ready for next message. // The false in the result callback notifies the renderer to stop sending
// The false in the result callback notifies the renderer to stop sending // the send requests and invalidate all pending requests. This occurs
// the send requests and invalidate all pending requests. This occurs // for eg., when frame is deleted or navigated away.
// for eg., when frame is deleted or navigated away. SendSessionMessage(SessionMessage message_request) => (bool success);
SendSessionMessage(SessionMessage message_request) => (bool success);
// Called when closeSession() is called by the frame.
// Called when closeSession() is called by the frame. CloseSession(string presentation_url, string presentation_id);
CloseSession(string presentation_url, string presentation_id);
// Called when the frame is ready to process the next state change. Returns
// Called when the frame is ready to process the next state change. Returns // the last session state if it’s changed since the last time the callback
// the last session state if it’s changed since the last time the callback // was called. Might cause the event fired with the initial state change.
// was called. Might cause the event fired with the initial state change. ListenForSessionStateChange()
ListenForSessionStateChange() => (PresentationSessionInfo sessionInfo,
=> (PresentationSessionInfo sessionInfo, PresentationSessionState newState);
PresentationSessionState newState);
// Called when the frame is ready to process the next batch of messages.
// Called when the frame is ready to process the next batch of messages. // When the callback carries null messages, there is an error
// When the callback carries null messages, there is an error // at the presentation service side.
// at the presentation service side. ListenForSessionMessages()
ListenForSessionMessages() => (array<SessionMessage>? messages);
=> (array<SessionMessage>? messages); };
interface PresentationServiceClient {
OnScreenAvailabilityUpdated(bool available);
}; };
...@@ -60,7 +60,8 @@ namespace content { ...@@ -60,7 +60,8 @@ namespace content {
PresentationDispatcher::PresentationDispatcher(RenderFrame* render_frame) PresentationDispatcher::PresentationDispatcher(RenderFrame* render_frame)
: RenderFrameObserver(render_frame), : RenderFrameObserver(render_frame),
controller_(nullptr) { controller_(nullptr),
binding_(this) {
} }
PresentationDispatcher::~PresentationDispatcher() { PresentationDispatcher::~PresentationDispatcher() {
...@@ -80,21 +81,11 @@ void PresentationDispatcher::setController( ...@@ -80,21 +81,11 @@ void PresentationDispatcher::setController(
} }
void PresentationDispatcher::updateAvailableChangeWatched(bool watched) { void PresentationDispatcher::updateAvailableChangeWatched(bool watched) {
GURL presentation_url(GetPresentationURLFromFrame(render_frame()));
DoUpdateAvailableChangeWatched(presentation_url.spec(), watched);
}
void PresentationDispatcher::DoUpdateAvailableChangeWatched(
const std::string& presentation_url, bool watched) {
ConnectToPresentationServiceIfNeeded(); ConnectToPresentationServiceIfNeeded();
if (watched) { if (watched)
presentation_service_->ListenForScreenAvailability( presentation_service_->ListenForScreenAvailability();
presentation_url, else
base::Bind(&PresentationDispatcher::OnScreenAvailabilityChanged, presentation_service_->StopListeningForScreenAvailability();
base::Unretained(this)));
} else {
presentation_service_->RemoveScreenAvailabilityListener(presentation_url);
}
} }
void PresentationDispatcher::startSession( void PresentationDispatcher::startSession(
...@@ -270,16 +261,9 @@ void PresentationDispatcher::DidCommitProvisionalLoad( ...@@ -270,16 +261,9 @@ void PresentationDispatcher::DidCommitProvisionalLoad(
std::swap(message_request_queue_, empty); std::swap(message_request_queue_, empty);
} }
void PresentationDispatcher::OnScreenAvailabilityChanged( void PresentationDispatcher::OnScreenAvailabilityUpdated(bool available) {
const std::string& presentation_url, bool available) { if (controller_)
if (!controller_) controller_->didChangeAvailability(available);
return;
// Reset the callback to get the next event.
DoUpdateAvailableChangeWatched(presentation_url,
controller_->isAvailableChangeWatched());
controller_->didChangeAvailability(available);
} }
void PresentationDispatcher::OnDefaultSessionStarted( void PresentationDispatcher::OnDefaultSessionStarted(
...@@ -360,6 +344,10 @@ void PresentationDispatcher::ConnectToPresentationServiceIfNeeded() { ...@@ -360,6 +344,10 @@ void PresentationDispatcher::ConnectToPresentationServiceIfNeeded() {
render_frame()->GetServiceRegistry()->ConnectToRemoteService( render_frame()->GetServiceRegistry()->ConnectToRemoteService(
&presentation_service_); &presentation_service_);
presentation::PresentationServiceClientPtr client_ptr;
binding_.Bind(GetProxy(&client_ptr));
presentation_service_->SetClient(client_ptr.Pass());
// TODO(imcheng): Uncomment these once they are implemented on the browser // TODO(imcheng): Uncomment these once they are implemented on the browser
// side. (crbug.com/459006) // side. (crbug.com/459006)
/* /*
......
...@@ -22,7 +22,8 @@ namespace content { ...@@ -22,7 +22,8 @@ namespace content {
// Blink. It forwards the calls to the Mojo PresentationService. // Blink. It forwards the calls to the Mojo PresentationService.
class CONTENT_EXPORT PresentationDispatcher class CONTENT_EXPORT PresentationDispatcher
: public RenderFrameObserver, : public RenderFrameObserver,
public NON_EXPORTED_BASE(blink::WebPresentationClient) { public NON_EXPORTED_BASE(blink::WebPresentationClient),
public NON_EXPORTED_BASE(presentation::PresentationServiceClient) {
public: public:
explicit PresentationDispatcher(RenderFrame* render_frame); explicit PresentationDispatcher(RenderFrame* render_frame);
~PresentationDispatcher() override; ~PresentationDispatcher() override;
...@@ -59,9 +60,9 @@ class CONTENT_EXPORT PresentationDispatcher ...@@ -59,9 +60,9 @@ class CONTENT_EXPORT PresentationDispatcher
bool is_new_navigation, bool is_new_navigation,
bool is_same_page_navigation) override; bool is_same_page_navigation) override;
void OnScreenAvailabilityChanged( // presentation::PresentationServiceClient
const std::string& presentation_url, void OnScreenAvailabilityUpdated(bool available) override;
bool available);
void OnSessionCreated( void OnSessionCreated(
blink::WebPresentationSessionClientCallbacks* callback, blink::WebPresentationSessionClientCallbacks* callback,
presentation::PresentationSessionInfoPtr session_info, presentation::PresentationSessionInfoPtr session_info,
...@@ -73,25 +74,23 @@ class CONTENT_EXPORT PresentationDispatcher ...@@ -73,25 +74,23 @@ class CONTENT_EXPORT PresentationDispatcher
presentation::PresentationSessionState session_state); presentation::PresentationSessionState session_state);
void OnSessionMessagesReceived( void OnSessionMessagesReceived(
mojo::Array<presentation::SessionMessagePtr> messages); mojo::Array<presentation::SessionMessagePtr> messages);
void ConnectToPresentationServiceIfNeeded();
void DoUpdateAvailableChangeWatched(
const std::string& presentation_url,
bool watched);
void DoSendMessage(const presentation::SessionMessage& session_message); void DoSendMessage(const presentation::SessionMessage& session_message);
void HandleSendMessageRequests(bool success); void HandleSendMessageRequests(bool success);
void ConnectToPresentationServiceIfNeeded();
// Used as a weak reference. Can be null since lifetime is bound to the frame. // Used as a weak reference. Can be null since lifetime is bound to the frame.
blink::WebPresentationController* controller_; blink::WebPresentationController* controller_;
presentation::PresentationServicePtr presentation_service_; presentation::PresentationServicePtr presentation_service_;
mojo::Binding<presentation::PresentationServiceClient> binding_;
// Message requests are queued here and only one message at a time is sent // Message requests are queued here and only one message at a time is sent
// over mojo channel. // over mojo channel.
using MessageRequestQueue = using MessageRequestQueue =
std::queue<linked_ptr<presentation::SessionMessage>>; std::queue<linked_ptr<presentation::SessionMessage>>;
MessageRequestQueue message_request_queue_; MessageRequestQueue message_request_queue_;
DISALLOW_COPY_AND_ASSIGN(PresentationDispatcher);
}; };
} // namespace content } // namespace content
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment