Commit 2ed5f820 authored by imcheng's avatar imcheng Committed by Commit bot

Reland of: [Presentation API] Implement ondefaultsessionstart in PSImpl.

To fix PresentationServiceImplTest.DefaultSessionStartReset timeout
in  Android Tests (dbg).

TEST=git cl try + linux_android_dbg_ng
----

Added DefaultSessionStartContext for coordinating sending default
session back to PresentationDispatcher.

When ListenForDefaultSessionStart is called, DefaultSessionStartContext
will be installed on PresentationServiceImpl. When both the default
session and PresentationDispatcher's callback are available, the
callback will be invoked with the session.

On Reset(), if a callback is available, it will be invoked with null.
Changed PresentationDispatcher to not update Blink in that case.

Also, PSImpl now keeps track of the corresponding RFH's ID instead of
RFH* since most of the time we only need to use the ID.

Changed PresentationServiceDelegate's Add/RemoveObserver interface,
since the PresentationServiceDelegate need to be able to correlate
an Observer with a RFH. (at most 1 per RFH, as it stands today).

Added OnDefaultPresentationStarted to
PresentationServiceDelegate::Observer interface and implemented it
in PresentationServiceImpl.

Added tests in PresentationServiceImpl.

BUG=459001

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

Cr-Commit-Position: refs/heads/master@{#326859}
parent 5f663d8a
...@@ -23,23 +23,24 @@ PresentationServiceImpl::PresentationServiceImpl( ...@@ -23,23 +23,24 @@ PresentationServiceImpl::PresentationServiceImpl(
WebContents* web_contents, WebContents* web_contents,
PresentationServiceDelegate* delegate) PresentationServiceDelegate* delegate)
: WebContentsObserver(web_contents), : WebContentsObserver(web_contents),
render_frame_host_(render_frame_host),
delegate_(delegate), delegate_(delegate),
is_start_session_pending_(false), is_start_session_pending_(false),
next_request_session_id_(0), next_request_session_id_(0),
weak_factory_(this) { weak_factory_(this) {
DCHECK(render_frame_host_); DCHECK(render_frame_host);
DCHECK(web_contents); DCHECK(web_contents);
render_process_id_ = render_frame_host->GetProcess()->GetID();
render_frame_id_ = render_frame_host->GetRoutingID();
DVLOG(2) << "PresentationServiceImpl: " DVLOG(2) << "PresentationServiceImpl: "
<< render_frame_host_->GetProcess()->GetID() << ", " << render_process_id_ << ", " << render_frame_id_;
<< render_frame_host_->GetRoutingID();
if (delegate_) if (delegate_)
delegate_->AddObserver(this); delegate_->AddObserver(render_process_id_, render_frame_id_, this);
} }
PresentationServiceImpl::~PresentationServiceImpl() { PresentationServiceImpl::~PresentationServiceImpl() {
if (delegate_) if (delegate_)
delegate_->RemoveObserver(this); delegate_->RemoveObserver(render_process_id_, render_frame_id_);
FlushNewSessionCallbacks(); FlushNewSessionCallbacks();
} }
...@@ -83,9 +84,7 @@ PresentationServiceImpl::GetOrCreateAvailabilityContext( ...@@ -83,9 +84,7 @@ PresentationServiceImpl::GetOrCreateAvailabilityContext(
linked_ptr<ScreenAvailabilityContext> context( linked_ptr<ScreenAvailabilityContext> context(
new ScreenAvailabilityContext(presentation_url)); new ScreenAvailabilityContext(presentation_url));
if (!delegate_->AddScreenAvailabilityListener( if (!delegate_->AddScreenAvailabilityListener(
render_frame_host_->GetProcess()->GetID(), render_process_id_, render_frame_id_, context.get())) {
render_frame_host_->GetRoutingID(),
context.get())) {
DVLOG(1) << "AddScreenAvailabilityListener failed. Ignoring request."; DVLOG(1) << "AddScreenAvailabilityListener failed. Ignoring request.";
return nullptr; return nullptr;
} }
...@@ -125,9 +124,7 @@ void PresentationServiceImpl::RemoveScreenAvailabilityListener( ...@@ -125,9 +124,7 @@ void PresentationServiceImpl::RemoveScreenAvailabilityListener(
return; return;
delegate_->RemoveScreenAvailabilityListener( delegate_->RemoveScreenAvailabilityListener(
render_frame_host_->GetProcess()->GetID(), render_process_id_, render_frame_id_, it->second.get());
render_frame_host_->GetRoutingID(),
it->second.get());
// Resolve the context's pending callbacks before removing it. // Resolve the context's pending callbacks before removing it.
it->second->OnScreenAvailabilityChanged(false); it->second->OnScreenAvailabilityChanged(false);
availability_contexts_.erase(it); availability_contexts_.erase(it);
...@@ -135,7 +132,9 @@ void PresentationServiceImpl::RemoveScreenAvailabilityListener( ...@@ -135,7 +132,9 @@ void PresentationServiceImpl::RemoveScreenAvailabilityListener(
void PresentationServiceImpl::ListenForDefaultSessionStart( void PresentationServiceImpl::ListenForDefaultSessionStart(
const DefaultSessionMojoCallback& callback) { const DefaultSessionMojoCallback& callback) {
NOTIMPLEMENTED(); if (!default_session_start_context_.get())
default_session_start_context_.reset(new DefaultSessionStartContext);
default_session_start_context_->AddCallback(callback);
} }
void PresentationServiceImpl::StartSession( void PresentationServiceImpl::StartSession(
...@@ -169,8 +168,8 @@ void PresentationServiceImpl::JoinSession( ...@@ -169,8 +168,8 @@ void PresentationServiceImpl::JoinSession(
int request_session_id = RegisterNewSessionCallback(callback); int request_session_id = RegisterNewSessionCallback(callback);
delegate_->JoinSession( delegate_->JoinSession(
render_frame_host_->GetProcess()->GetID(), render_process_id_,
render_frame_host_->GetRoutingID(), render_frame_id_,
presentation_url, presentation_url,
presentation_id, presentation_id,
base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionSucceeded, base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionSucceeded,
...@@ -214,8 +213,8 @@ void PresentationServiceImpl::DoStartSession( ...@@ -214,8 +213,8 @@ void PresentationServiceImpl::DoStartSession(
int request_session_id = RegisterNewSessionCallback(callback); int request_session_id = RegisterNewSessionCallback(callback);
is_start_session_pending_ = true; is_start_session_pending_ = true;
delegate_->StartSession( delegate_->StartSession(
render_frame_host_->GetProcess()->GetID(), render_process_id_,
render_frame_host_->GetRoutingID(), render_frame_id_,
presentation_url, presentation_url,
presentation_id, presentation_id,
base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionSucceeded, base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionSucceeded,
...@@ -266,8 +265,8 @@ void PresentationServiceImpl::DoSetDefaultPresentationUrl( ...@@ -266,8 +265,8 @@ void PresentationServiceImpl::DoSetDefaultPresentationUrl(
const std::string& default_presentation_id) { const std::string& default_presentation_id) {
DCHECK(delegate_); DCHECK(delegate_);
delegate_->SetDefaultPresentationUrl( delegate_->SetDefaultPresentationUrl(
render_frame_host_->GetProcess()->GetID(), render_process_id_,
render_frame_host_->GetRoutingID(), render_frame_id_,
default_presentation_url, default_presentation_url,
default_presentation_id); default_presentation_id);
default_presentation_url_ = default_presentation_url; default_presentation_url_ = default_presentation_url;
...@@ -307,8 +306,8 @@ void PresentationServiceImpl::SetDefaultPresentationURL( ...@@ -307,8 +306,8 @@ void PresentationServiceImpl::SetDefaultPresentationURL(
// Remove listener for old default presentation URL. // Remove listener for old default presentation URL.
delegate_->RemoveScreenAvailabilityListener( delegate_->RemoveScreenAvailabilityListener(
render_frame_host_->GetProcess()->GetID(), render_process_id_,
render_frame_host_->GetRoutingID(), render_frame_id_,
old_it->second.get()); old_it->second.get());
availability_contexts_.erase(old_it); availability_contexts_.erase(old_it);
DoSetDefaultPresentationUrl(new_default_url, default_presentation_id); DoSetDefaultPresentationUrl(new_default_url, default_presentation_id);
...@@ -325,12 +324,21 @@ void PresentationServiceImpl::ListenForSessionStateChange( ...@@ -325,12 +324,21 @@ void PresentationServiceImpl::ListenForSessionStateChange(
NOTIMPLEMENTED(); NOTIMPLEMENTED();
} }
bool PresentationServiceImpl::FrameMatches(
content::RenderFrameHost* render_frame_host) const {
if (!render_frame_host)
return false;
return render_frame_host->GetProcess()->GetID() == render_process_id_ &&
render_frame_host->GetRoutingID() == render_frame_id_;
}
void PresentationServiceImpl::DidNavigateAnyFrame( void PresentationServiceImpl::DidNavigateAnyFrame(
content::RenderFrameHost* render_frame_host, content::RenderFrameHost* render_frame_host,
const content::LoadCommittedDetails& details, const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) { const content::FrameNavigateParams& params) {
DVLOG(2) << "PresentationServiceImpl::DidNavigateAnyFrame"; DVLOG(2) << "PresentationServiceImpl::DidNavigateAnyFrame";
if (render_frame_host_ != render_frame_host) if (!FrameMatches(render_frame_host))
return; return;
std::string prev_url_host = details.previous_url.host(); std::string prev_url_host = details.previous_url.host();
...@@ -355,29 +363,26 @@ void PresentationServiceImpl::DidNavigateAnyFrame( ...@@ -355,29 +363,26 @@ void PresentationServiceImpl::DidNavigateAnyFrame(
void PresentationServiceImpl::RenderFrameDeleted( void PresentationServiceImpl::RenderFrameDeleted(
content::RenderFrameHost* render_frame_host) { content::RenderFrameHost* render_frame_host) {
DVLOG(2) << "PresentationServiceImpl::RenderFrameDeleted"; DVLOG(2) << "PresentationServiceImpl::RenderFrameDeleted";
if (render_frame_host_ != render_frame_host) if (!FrameMatches(render_frame_host))
return; return;
// RenderFrameDeleted means |render_frame_host_| is going to be deleted soon. // RenderFrameDeleted means the associated RFH is going to be deleted soon.
// This object should also be deleted. // This object should also be deleted.
Reset(); Reset();
render_frame_host_ = nullptr;
delete this; delete this;
} }
void PresentationServiceImpl::Reset() { void PresentationServiceImpl::Reset() {
DVLOG(2) << "PresentationServiceImpl::Reset"; DVLOG(2) << "PresentationServiceImpl::Reset";
if (delegate_) { if (delegate_)
delegate_->Reset( delegate_->Reset(render_process_id_, render_frame_id_);
render_frame_host_->GetProcess()->GetID(),
render_frame_host_->GetRoutingID());
}
default_presentation_url_.clear(); default_presentation_url_.clear();
default_presentation_id_.clear(); default_presentation_id_.clear();
availability_contexts_.clear(); availability_contexts_.clear();
queued_start_session_requests_.clear(); queued_start_session_requests_.clear();
FlushNewSessionCallbacks(); FlushNewSessionCallbacks();
default_session_start_context_.reset();
} }
// static // static
...@@ -395,6 +400,12 @@ void PresentationServiceImpl::OnDelegateDestroyed() { ...@@ -395,6 +400,12 @@ void PresentationServiceImpl::OnDelegateDestroyed() {
Reset(); Reset();
} }
void PresentationServiceImpl::OnDefaultPresentationStarted(
const PresentationSessionInfo& session) {
if (default_session_start_context_.get())
default_session_start_context_->set_session(session);
}
PresentationServiceImpl::ScreenAvailabilityContext::ScreenAvailabilityContext( PresentationServiceImpl::ScreenAvailabilityContext::ScreenAvailabilityContext(
const std::string& presentation_url) const std::string& presentation_url)
: presentation_url_(presentation_url) { : presentation_url_(presentation_url) {
...@@ -478,5 +489,46 @@ PresentationServiceImpl::StartSessionRequest::PassCallback() { ...@@ -478,5 +489,46 @@ PresentationServiceImpl::StartSessionRequest::PassCallback() {
return callback; return callback;
} }
PresentationServiceImpl::DefaultSessionStartContext
::DefaultSessionStartContext() {
}
PresentationServiceImpl::DefaultSessionStartContext
::~DefaultSessionStartContext() {
Reset();
}
void PresentationServiceImpl::DefaultSessionStartContext::AddCallback(
const DefaultSessionMojoCallback& callback) {
if (session_.get()) {
DCHECK(callbacks_.empty());
callback.Run(presentation::PresentationSessionInfo::From(*session_));
session_.reset();
} else {
callbacks_.push_back(new DefaultSessionMojoCallback(callback));
}
}
void PresentationServiceImpl::DefaultSessionStartContext::set_session(
const PresentationSessionInfo& session) {
if (callbacks_.empty()) {
session_.reset(new PresentationSessionInfo(session));
} else {
DCHECK(!session_.get());
ScopedVector<DefaultSessionMojoCallback> callbacks;
callbacks.swap(callbacks_);
for (const auto& callback : callbacks)
callback->Run(presentation::PresentationSessionInfo::From(session));
}
}
void PresentationServiceImpl::DefaultSessionStartContext::Reset() {
ScopedVector<DefaultSessionMojoCallback> callbacks;
callbacks.swap(callbacks_);
for (const auto& callback : callbacks)
callback->Run(presentation::PresentationSessionInfoPtr());
session_.reset();
}
} // namespace content } // namespace content
...@@ -109,6 +109,27 @@ class CONTENT_EXPORT PresentationServiceImpl ...@@ -109,6 +109,27 @@ class CONTENT_EXPORT PresentationServiceImpl
scoped_ptr<bool> available_ptr_; scoped_ptr<bool> available_ptr_;
}; };
class CONTENT_EXPORT DefaultSessionStartContext {
public:
DefaultSessionStartContext();
~DefaultSessionStartContext();
// Adds a callback. May invoke the callback immediately if |session| using
// default presentation URL was already started.
void AddCallback(const DefaultSessionMojoCallback& callback);
// Sets the session info. Maybe invoke callbacks queued with AddCallback().
void set_session(const PresentationSessionInfo& session);
private:
// Flush all queued callbacks by invoking them with null
// PresentationSessionInfoPtr.
void Reset();
ScopedVector<DefaultSessionMojoCallback> callbacks_;
scoped_ptr<PresentationSessionInfo> session_;
};
// Context for a StartSession request. // Context for a StartSession request.
class CONTENT_EXPORT StartSessionRequest { class CONTENT_EXPORT StartSessionRequest {
public: public:
...@@ -146,6 +167,12 @@ class CONTENT_EXPORT PresentationServiceImpl ...@@ -146,6 +167,12 @@ class CONTENT_EXPORT PresentationServiceImpl
SetSameDefaultPresentationUrl); SetSameDefaultPresentationUrl);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ClearDefaultPresentationUrl); ClearDefaultPresentationUrl);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ListenForDefaultSessionStart);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
ListenForDefaultSessionStartAfterSet);
FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
DefaultSessionStartReset);
// |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.
...@@ -197,6 +224,8 @@ class CONTENT_EXPORT PresentationServiceImpl ...@@ -197,6 +224,8 @@ class CONTENT_EXPORT PresentationServiceImpl
// PresentationServiceDelegate::Observer // PresentationServiceDelegate::Observer
void OnDelegateDestroyed() override; void OnDelegateDestroyed() override;
void OnDefaultPresentationStarted(const PresentationSessionInfo& session)
override;
// Finds the callback from |pending_session_cbs_| using |request_session_id|. // Finds the callback from |pending_session_cbs_| using |request_session_id|.
// If it exists, invoke it with |session| and |error|, then erase it from // If it exists, invoke it with |session| and |error|, then erase it from
...@@ -256,7 +285,9 @@ class CONTENT_EXPORT PresentationServiceImpl ...@@ -256,7 +285,9 @@ class CONTENT_EXPORT PresentationServiceImpl
ScreenAvailabilityContext* GetOrCreateAvailabilityContext( ScreenAvailabilityContext* GetOrCreateAvailabilityContext(
const std::string& presentation_url); const std::string& presentation_url);
RenderFrameHost* render_frame_host_; // Returns true if this object is associated with |render_frame_host|.
bool FrameMatches(content::RenderFrameHost* render_frame_host) const;
PresentationServiceDelegate* delegate_; PresentationServiceDelegate* delegate_;
// Map from presentation URL to its ScreenAvailabilityContext state machine. // Map from presentation URL to its ScreenAvailabilityContext state machine.
...@@ -277,10 +308,16 @@ class CONTENT_EXPORT PresentationServiceImpl ...@@ -277,10 +308,16 @@ class CONTENT_EXPORT PresentationServiceImpl
int next_request_session_id_; int next_request_session_id_;
base::hash_map<int, linked_ptr<NewSessionMojoCallback>> pending_session_cbs_; base::hash_map<int, linked_ptr<NewSessionMojoCallback>> pending_session_cbs_;
scoped_ptr<DefaultSessionStartContext> default_session_start_context_;
// RAII binding of |this| to an Presentation interface request. // RAII binding of |this| to an Presentation interface request.
// The binding is removed when binding_ is cleared or goes out of scope. // The binding is removed when binding_ is cleared or goes out of scope.
scoped_ptr<mojo::Binding<presentation::PresentationService>> binding_; scoped_ptr<mojo::Binding<presentation::PresentationService>> binding_;
// ID of the RenderFrameHost this object is associated with.
int render_process_id_;
int render_frame_id_;
// NOTE: Weak pointers must be invalidated before all other member variables. // NOTE: Weak pointers must be invalidated before all other member variables.
base::WeakPtrFactory<PresentationServiceImpl> weak_factory_; base::WeakPtrFactory<PresentationServiceImpl> weak_factory_;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/test/test_timeouts.h"
#include "content/browser/presentation/presentation_service_impl.h" #include "content/browser/presentation/presentation_service_impl.h"
#include "content/public/browser/presentation_service_delegate.h" #include "content/public/browser/presentation_service_delegate.h"
#include "content/public/browser/presentation_session.h" #include "content/public/browser/presentation_session.h"
...@@ -23,12 +24,23 @@ using ::testing::SaveArg; ...@@ -23,12 +24,23 @@ using ::testing::SaveArg;
namespace content { namespace content {
namespace {
bool ArePresentationSessionsEqual(
const presentation::PresentationSessionInfo& expected,
const presentation::PresentationSessionInfo& actual) {
return expected.url == actual.url && expected.id == actual.id;
}
} // namespace
class MockPresentationServiceDelegate : public PresentationServiceDelegate { class MockPresentationServiceDelegate : public PresentationServiceDelegate {
public: public:
MOCK_METHOD1(AddObserver, MOCK_METHOD3(AddObserver,
void(PresentationServiceDelegate::Observer* observer)); void(int render_process_id,
MOCK_METHOD1(RemoveObserver, int render_frame_id,
void(PresentationServiceDelegate::Observer* observer)); PresentationServiceDelegate::Observer* observer));
MOCK_METHOD2(RemoveObserver,
void(int render_process_id, int render_frame_id));
MOCK_METHOD3(AddScreenAvailabilityListener, MOCK_METHOD3(AddScreenAvailabilityListener,
bool( bool(
int render_process_id, int render_process_id,
...@@ -69,13 +81,15 @@ class MockPresentationServiceDelegate : public PresentationServiceDelegate { ...@@ -69,13 +81,15 @@ class MockPresentationServiceDelegate : public PresentationServiceDelegate {
class PresentationServiceImplTest : public RenderViewHostImplTestHarness { class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
public: public:
PresentationServiceImplTest() : callback_count_(0) {} PresentationServiceImplTest()
: callback_count_(0), default_session_started_count_(0) {}
void SetUp() override { void SetUp() override {
RenderViewHostImplTestHarness::SetUp(); RenderViewHostImplTestHarness::SetUp();
auto request = mojo::GetProxy(&service_ptr_); auto request = mojo::GetProxy(&service_ptr_);
EXPECT_CALL(mock_delegate_, AddObserver(_)).Times(1);
EXPECT_CALL(mock_delegate_, AddObserver(_, _, _)).Times(1);
service_impl_.reset(new PresentationServiceImpl( service_impl_.reset(new PresentationServiceImpl(
contents()->GetMainFrame(), contents(), &mock_delegate_)); contents()->GetMainFrame(), contents(), &mock_delegate_));
service_impl_->Bind(request.Pass()); service_impl_->Bind(request.Pass());
...@@ -84,11 +98,9 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness { ...@@ -84,11 +98,9 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
void TearDown() override { void TearDown() override {
service_ptr_.reset(); service_ptr_.reset();
if (service_impl_.get()) { if (service_impl_.get()) {
EXPECT_CALL(mock_delegate_, RemoveObserver(Eq(service_impl_.get()))) EXPECT_CALL(mock_delegate_, RemoveObserver(_, _)).Times(1);
.Times(1);
service_impl_.reset(); service_impl_.reset();
} }
RenderViewHostImplTestHarness::TearDown(); RenderViewHostImplTestHarness::TearDown();
} }
...@@ -155,8 +167,7 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness { ...@@ -155,8 +167,7 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
} }
void ExpectReset() { void ExpectReset() {
EXPECT_CALL(mock_delegate_, Reset(_, _)) EXPECT_CALL(mock_delegate_, Reset(_, _)).Times(1);
.Times(1);
} }
void ExpectCleanState() { void ExpectCleanState() {
...@@ -164,6 +175,7 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness { ...@@ -164,6 +175,7 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
EXPECT_TRUE(service_impl_->default_presentation_url_.empty()); EXPECT_TRUE(service_impl_->default_presentation_url_.empty());
EXPECT_TRUE(service_impl_->default_presentation_id_.empty()); EXPECT_TRUE(service_impl_->default_presentation_id_.empty());
EXPECT_TRUE(service_impl_->queued_start_session_requests_.empty()); EXPECT_TRUE(service_impl_->queued_start_session_requests_.empty());
EXPECT_FALSE(service_impl_->default_session_start_context_.get());
} }
void ExpectNewSessionMojoCallbackSuccess( void ExpectNewSessionMojoCallbackSuccess(
...@@ -184,11 +196,31 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness { ...@@ -184,11 +196,31 @@ class PresentationServiceImplTest : public RenderViewHostImplTestHarness {
run_loop_quit_closure_.Run(); run_loop_quit_closure_.Run();
} }
void ExpectDefaultSessionStarted(
const presentation::PresentationSessionInfo& expected_session,
presentation::PresentationSessionInfoPtr actual_session) {
ASSERT_TRUE(!actual_session.is_null());
EXPECT_TRUE(ArePresentationSessionsEqual(
expected_session, *actual_session));
++default_session_started_count_;
if (!run_loop_quit_closure_.is_null())
run_loop_quit_closure_.Run();
}
void ExpectDefaultSessionNull(
presentation::PresentationSessionInfoPtr actual_session) {
EXPECT_TRUE(actual_session.is_null());
++default_session_started_count_;
if (!run_loop_quit_closure_.is_null())
run_loop_quit_closure_.Run();
}
MockPresentationServiceDelegate mock_delegate_; MockPresentationServiceDelegate mock_delegate_;
scoped_ptr<PresentationServiceImpl> service_impl_; scoped_ptr<PresentationServiceImpl> service_impl_;
mojo::InterfacePtr<presentation::PresentationService> service_ptr_; mojo::InterfacePtr<presentation::PresentationService> service_ptr_;
base::Closure run_loop_quit_closure_; base::Closure run_loop_quit_closure_;
int callback_count_; int callback_count_;
int default_session_started_count_;
}; };
TEST_F(PresentationServiceImplTest, ListenForScreenAvailability) { TEST_F(PresentationServiceImplTest, ListenForScreenAvailability) {
...@@ -294,7 +326,7 @@ TEST_F(PresentationServiceImplTest, ThisRenderFrameDeleted) { ...@@ -294,7 +326,7 @@ TEST_F(PresentationServiceImplTest, ThisRenderFrameDeleted) {
// Since the frame matched the service, |service_impl_| will be deleted. // Since the frame matched the service, |service_impl_| will be deleted.
PresentationServiceImpl* service = service_impl_.release(); PresentationServiceImpl* service = service_impl_.release();
EXPECT_CALL(mock_delegate_, RemoveObserver(Eq(service))).Times(1); EXPECT_CALL(mock_delegate_, RemoveObserver(_, _)).Times(1);
service->RenderFrameDeleted(contents()->GetMainFrame()); service->RenderFrameDeleted(contents()->GetMainFrame());
} }
...@@ -581,4 +613,59 @@ TEST_F(PresentationServiceImplTest, StartSessionInProgress) { ...@@ -581,4 +613,59 @@ TEST_F(PresentationServiceImplTest, StartSessionInProgress) {
SaveQuitClosureAndRunLoop(); SaveQuitClosureAndRunLoop();
} }
TEST_F(PresentationServiceImplTest, ListenForDefaultSessionStart) {
std::string presentation_url1("http://fooUrl1");
std::string presentation_id1("presentationId1");
presentation::PresentationSessionInfo expected_session;
expected_session.url = presentation_url1;
expected_session.id = presentation_id1;
service_ptr_->ListenForDefaultSessionStart(
base::Bind(&PresentationServiceImplTest::ExpectDefaultSessionStarted,
base::Unretained(this),
expected_session));
RunLoopFor(base::TimeDelta::FromMilliseconds(50));
service_impl_->OnDefaultPresentationStarted(
content::PresentationSessionInfo(presentation_url1, presentation_id1));
SaveQuitClosureAndRunLoop();
EXPECT_EQ(1, default_session_started_count_);
}
TEST_F(PresentationServiceImplTest, ListenForDefaultSessionStartAfterSet) {
// Note that the callback will only pick up presentation_url2/id2 since
// ListenForDefaultSessionStart wasn't called yet when the DPU was still
// presentation_url1.
std::string presentation_url1("http://fooUrl1");
std::string presentation_id1("presentationId1");
std::string presentation_url2("http://fooUrl2");
std::string presentation_id2("presentationId2");
service_impl_->OnDefaultPresentationStarted(
content::PresentationSessionInfo(presentation_url1, presentation_id1));
presentation::PresentationSessionInfo expected_session;
expected_session.url = presentation_url2;
expected_session.id = presentation_id2;
service_ptr_->ListenForDefaultSessionStart(
base::Bind(&PresentationServiceImplTest::ExpectDefaultSessionStarted,
base::Unretained(this),
expected_session));
RunLoopFor(base::TimeDelta::FromMilliseconds(50));
service_impl_->OnDefaultPresentationStarted(
content::PresentationSessionInfo(presentation_url2, presentation_id2));
SaveQuitClosureAndRunLoop();
EXPECT_EQ(1, default_session_started_count_);
}
TEST_F(PresentationServiceImplTest, DefaultSessionStartReset) {
service_ptr_->ListenForDefaultSessionStart(
base::Bind(&PresentationServiceImplTest::ExpectDefaultSessionNull,
base::Unretained(this)));
RunLoopFor(TestTimeouts::tiny_timeout());
ExpectReset();
service_impl_->Reset();
ExpectCleanState();
SaveQuitClosureAndRunLoop();
EXPECT_EQ(1, default_session_started_count_);
}
} // namespace content } // namespace content
...@@ -52,7 +52,7 @@ interface PresentationService { ...@@ -52,7 +52,7 @@ interface PresentationService {
// 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
......
...@@ -23,6 +23,13 @@ class CONTENT_EXPORT PresentationServiceDelegate { ...@@ -23,6 +23,13 @@ class CONTENT_EXPORT PresentationServiceDelegate {
// Called when the PresentationServiceDelegate is being destroyed. // Called when the PresentationServiceDelegate is being destroyed.
virtual void OnDelegateDestroyed() = 0; virtual void OnDelegateDestroyed() = 0;
// Called when the default presentation has been started outside of a
// Presentation API context (e.g., browser action). This will not be called
// if the session was created as a result of Presentation API's
// StartSession()/JoinSession().
virtual void OnDefaultPresentationStarted(
const PresentationSessionInfo& session) = 0;
protected: protected:
virtual ~Observer() {} virtual ~Observer() {}
}; };
...@@ -34,12 +41,19 @@ class CONTENT_EXPORT PresentationServiceDelegate { ...@@ -34,12 +41,19 @@ class CONTENT_EXPORT PresentationServiceDelegate {
virtual ~PresentationServiceDelegate() {} virtual ~PresentationServiceDelegate() {}
// Registers an observer with this class to listen for updates to this class. // Registers an observer associated with frame with |render_process_id|
// and |render_frame_id| with this class to listen for updates.
// This class does not own the observer. // This class does not own the observer.
// It is an error to add an observer if it has already been added before. // It is an error to add an observer if there is already an observer for that
virtual void AddObserver(Observer* observer) = 0; // frame.
// Unregisters an observer with this class. virtual void AddObserver(int render_process_id,
virtual void RemoveObserver(Observer* observer) = 0; int render_frame_id,
Observer* observer) = 0;
// Unregisters the observer associated with the frame with |render_process_id|
// and |render_frame_id|.
// The observer will no longer receive updates.
virtual void RemoveObserver(int render_process_id, int render_frame_id) = 0;
// Registers |listener| to continuously listen for // Registers |listener| to continuously listen for
// availability updates for a presentation URL, originated from the frame // availability updates for a presentation URL, originated from the frame
......
...@@ -172,9 +172,10 @@ void PresentationDispatcher::OnDefaultSessionStarted( ...@@ -172,9 +172,10 @@ void PresentationDispatcher::OnDefaultSessionStarted(
&PresentationDispatcher::OnDefaultSessionStarted, &PresentationDispatcher::OnDefaultSessionStarted,
base::Unretained(this))); base::Unretained(this)));
DCHECK(!session_info.is_null()); if (!session_info.is_null()) {
controller_->didStartDefaultSession( controller_->didStartDefaultSession(
new PresentationSessionClient(session_info.Pass())); new PresentationSessionClient(session_info.Pass()));
}
} }
void PresentationDispatcher::OnSessionCreated( void PresentationDispatcher::OnSessionCreated(
......
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