Commit 7adfa2d5 authored by btolsch's avatar btolsch Committed by Commit Bot

Add PresentationReceiverWindow for wired screen presentations

This change adds a class which shows a Presentation API receiver page in
a popup-style window that is started fullscreen on a specific wired
display.

It also changes the handling of one-off OTR profiles used by
presentations, which affects this class and offscreen tabs.  Previously,
offscreen tabs assumed ownership of their OTR profiles.  However, it was
possible for this to be violated by opening a DevTools window and
Browser would think that it could destroy the profile.  Additionally,
there was no handling of the original profile being destroyed, which
would leave dangling references in the OTR profile.  This has been
addressed by adding an IndependentOTRProfileManager class, which helps
both offscreen tabs and PresentationReceiverWindow manage the lifetime
of these one-off OTR profiles.

Bug: 777654, 786158, 664351, 727487
Change-Id: I64d032419d341affbdde4ee80b57d45c99648588
Reviewed-on: https://chromium-review.googlesource.com/742122
Commit-Queue: Brandon Tolsch <btolsch@chromium.org>
Reviewed-by: default avatarmark a. foltz <mfoltz@chromium.org>
Reviewed-by: default avatarDerek Cheng <imcheng@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarYuri Wiitala <miu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#524615}
parent 5a4c2abb
......@@ -19,6 +19,7 @@
#include "content/public/browser/browsing_data_remover.h"
class ArcAppTest;
class IndependentOTRProfileManagerTest;
class SessionControllerClientTest;
class Profile;
......@@ -191,6 +192,7 @@ class ProfileHelper
friend class ::ArcAppTest;
friend class ::SessionControllerClientTest;
friend class ::test::BrowserFinderChromeOSTest;
friend class ::IndependentOTRProfileManagerTest;
// Called when signin profile is cleared.
void OnSigninProfileCleared();
......
......@@ -5,23 +5,22 @@
#include "chrome/browser/extensions/api/tab_capture/offscreen_tab.h"
#include <algorithm>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h"
#include "chrome/browser/media/router/presentation_navigation_policy.h"
#include "chrome/browser/media/router/receiver_presentation_service_delegate_impl.h" // nogncheck
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/web_contents_sizer.h"
#include "content/public/browser/keyboard_event_processing_result.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/web_preferences.h"
#include "extensions/browser/extension_host.h"
#include "extensions/browser/process_manager.h"
#include "third_party/WebKit/public/web/WebPresentationReceiverFlags.h"
......@@ -41,10 +40,6 @@ const int kMaxOffscreenTabsPerExtension = 4;
const int kMaxSecondsToWaitForCapture = 60;
const int kPollIntervalInSeconds = 1;
typedef std::vector<content::BrowserContext*> BrowserContextList;
static base::LazyInstance<BrowserContextList>::Leaky g_offscreen_profiles =
LAZY_INSTANCE_INITIALIZER;
} // namespace
namespace extensions {
......@@ -64,13 +59,6 @@ OffscreenTabsOwner* OffscreenTabsOwner::Get(
return FromWebContents(extension_web_contents);
}
// static
bool OffscreenTabsOwner::IsOffscreenProfile(const Profile* profile) {
const BrowserContextList& offscreen_profiles = g_offscreen_profiles.Get();
return std::find(offscreen_profiles.begin(), offscreen_profiles.end(),
profile) != offscreen_profiles.end();
}
OffscreenTab* OffscreenTabsOwner::OpenNewTab(
const GURL& start_url,
const gfx::Size& initial_size,
......@@ -98,48 +86,23 @@ void OffscreenTabsOwner::DestroyTab(OffscreenTab* tab) {
}
}
// Navigation policy for presentations, where top-level navigations are not
// allowed.
class OffscreenTab::PresentationNavigationPolicy
: public OffscreenTab::NavigationPolicy {
public:
PresentationNavigationPolicy() : first_navigation_started_(false) {}
~PresentationNavigationPolicy() override = default;
private:
// OffscreenTab::NavigationPolicy overrides
bool DidStartNavigation(content::NavigationHandle* navigation_handle) final {
// We only care about top-level navigations that are cross-document.
if (!navigation_handle->IsInMainFrame() ||
navigation_handle->IsSameDocument()) {
return true;
}
// The initial navigation had already begun.
if (first_navigation_started_)
return false;
first_navigation_started_ = true;
return true;
}
bool first_navigation_started_;
};
OffscreenTab::OffscreenTab(OffscreenTabsOwner* owner)
: owner_(owner),
profile_(Profile::FromBrowserContext(
owner->extension_web_contents()->GetBrowserContext())
->CreateOffTheRecordProfile()),
otr_profile_registration_(
IndependentOTRProfileManager::GetInstance()
->CreateFromOriginalProfile(
Profile::FromBrowserContext(
owner->extension_web_contents()->GetBrowserContext()),
base::BindOnce(&OffscreenTab::DieIfOriginalProfileDestroyed,
base::Unretained(this)))),
capture_poll_timer_(false, false),
content_capture_was_detected_(false),
navigation_policy_(new NavigationPolicy) {
DCHECK(profile_);
g_offscreen_profiles.Get().push_back(profile_.get());
navigation_policy_(
std::make_unique<media_router::DefaultNavigationPolicy>()) {
DCHECK(otr_profile_registration_->profile());
}
OffscreenTab::~OffscreenTab() {
base::Erase(g_offscreen_profiles.Get(), profile_.get());
DVLOG(1) << "Destroying OffscreenTab for start_url=" << start_url_.spec();
}
......@@ -152,7 +115,7 @@ void OffscreenTab::Start(const GURL& start_url,
<< initial_size.ToString() << " for start_url=" << start_url_.spec();
// Create the WebContents to contain the off-screen tab's page.
WebContents::CreateParams params(profile_.get());
WebContents::CreateParams params(otr_profile_registration_->profile());
if (!optional_presentation_id.empty())
params.starting_sandbox_flags = blink::kPresentationReceiverSandboxFlags;
......@@ -182,17 +145,11 @@ void OffscreenTab::Start(const GURL& start_url,
media_router::ReceiverPresentationServiceDelegateImpl::CreateForWebContents(
offscreen_tab_web_contents_.get(), optional_presentation_id);
if (auto* render_view_host =
offscreen_tab_web_contents_->GetRenderViewHost()) {
auto web_prefs = render_view_host->GetWebkitPreferences();
web_prefs.presentation_receiver = true;
render_view_host->UpdateWebkitPreferences(web_prefs);
}
// Presentations are not allowed to perform top-level navigations after
// initial load. This is enforced through sandboxing flags, but we also
// enforce it here.
navigation_policy_.reset(new PresentationNavigationPolicy);
navigation_policy_ =
std::make_unique<media_router::PresentationNavigationPolicy>();
}
// Navigate to the initial URL.
......@@ -411,22 +368,13 @@ void OffscreenTab::DidShowFullscreenWidget() {
void OffscreenTab::DidStartNavigation(
content::NavigationHandle* navigation_handle) {
DCHECK(offscreen_tab_web_contents_.get());
if (!navigation_policy_->DidStartNavigation(navigation_handle)) {
if (!navigation_policy_->AllowNavigation(navigation_handle)) {
DVLOG(2) << "Closing because NavigationPolicy disallowed "
<< "StartNavigation to " << navigation_handle->GetURL().spec();
Close();
}
}
// Default navigation policy.
OffscreenTab::NavigationPolicy::NavigationPolicy() = default;
OffscreenTab::NavigationPolicy::~NavigationPolicy() = default;
bool OffscreenTab::NavigationPolicy::DidStartNavigation(
content::NavigationHandle* navigation_handle) {
return true;
}
void OffscreenTab::DieIfContentCaptureEnded() {
DCHECK(offscreen_tab_web_contents_.get());
......@@ -464,4 +412,9 @@ void OffscreenTab::DieIfContentCaptureEnded() {
base::Unretained(this)));
}
void OffscreenTab::DieIfOriginalProfileDestroyed(Profile* profile) {
DCHECK(profile == otr_profile_registration_->profile());
owner_->DestroyTab(this);
}
} // namespace extensions
......@@ -7,18 +7,22 @@
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
#include "base/macros.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/browser/media/router/independent_otr_profile_manager.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "ui/gfx/geometry/size.h"
class Profile;
namespace media_router {
class NavigationPolicy;
} // namespace media_router
namespace extensions {
......@@ -44,10 +48,6 @@ class OffscreenTabsOwner
// background page's WebContents. Never returns nullptr.
static OffscreenTabsOwner* Get(content::WebContents* extension_web_contents);
// Returns |true| if |profile| is associated with an offscreen tab, false
// otherwise.
static bool IsOffscreenProfile(const Profile* profile);
// Instantiate a new offscreen tab and navigate it to |start_url|. The new
// tab's main frame will start out with the given |initial_size| in DIP
// coordinates. If too many offscreen tabs are already running, nothing
......@@ -56,10 +56,9 @@ class OffscreenTabsOwner
// If |optional_presentation_id| is non-empty, the offscreen tab is registered
// for use by the Media Router (chrome/browser/media/router/...) as the
// receiving browsing context for the W3C Presentation API.
OffscreenTab* OpenNewTab(
const GURL& start_url,
const gfx::Size& initial_size,
const std::string& optional_presentation_id);
OffscreenTab* OpenNewTab(const GURL& start_url,
const gfx::Size& initial_size,
const std::string& optional_presentation_id);
protected:
friend class OffscreenTab;
......@@ -180,28 +179,16 @@ class OffscreenTab : protected content::WebContentsDelegate,
void DidStartNavigation(content::NavigationHandle* navigation_handle) final;
private:
bool in_fullscreen_mode() const {
return !non_fullscreen_size_.IsEmpty();
}
// Selected calls to the navigation methods in WebContentsObserver are
// delegated to this object to determine a navigation is allowed. If any
// call returns false, the offscreen tab is destroyed. The default policy
// allows all navigations.
class NavigationPolicy {
public:
NavigationPolicy();
virtual ~NavigationPolicy();
virtual bool DidStartNavigation(
content::NavigationHandle* navigation_handle);
};
class PresentationNavigationPolicy; // Forward declaration
bool in_fullscreen_mode() const { return !non_fullscreen_size_.IsEmpty(); }
// Called by |capture_poll_timer_| to automatically destroy this OffscreenTab
// when the capturer count returns to zero.
void DieIfContentCaptureEnded();
// Called if the profile that our OTR profile is based on is being destroyed
// and |this| therefore needs to be destroyed also.
void DieIfOriginalProfileDestroyed(Profile* profile);
OffscreenTabsOwner* const owner_;
// The initial navigation URL, which may or may not match the current URL if
......@@ -210,7 +197,8 @@ class OffscreenTab : protected content::WebContentsDelegate,
// A non-shared off-the-record profile based on the profile of the extension
// background page.
const std::unique_ptr<Profile> profile_;
const std::unique_ptr<IndependentOTRProfileManager::OTRProfileRegistration>
otr_profile_registration_;
// The WebContents containing the off-screen tab's page.
std::unique_ptr<content::WebContents> offscreen_tab_web_contents_;
......@@ -236,7 +224,7 @@ class OffscreenTab : protected content::WebContentsDelegate,
bool content_capture_was_detected_;
// Object consulted to determine which offscreen tab navigations are allowed.
std::unique_ptr<NavigationPolicy> navigation_policy_;
std::unique_ptr<media_router::NavigationPolicy> navigation_policy_;
DISALLOW_COPY_AND_ASSIGN(OffscreenTab);
};
......
......@@ -47,6 +47,8 @@ static_library("router") {
"media_sinks_observer.h",
"presentation_media_sinks_observer.cc",
"presentation_media_sinks_observer.h",
"presentation_navigation_policy.cc",
"presentation_navigation_policy.h",
"presentation_service_delegate_impl.cc",
"presentation_service_delegate_impl.h",
"presentation_service_delegate_observers.cc",
......@@ -85,6 +87,13 @@ static_library("router") {
"mojo/wired_display_media_route_provider.h",
]
}
if (!is_android) {
sources += [
"independent_otr_profile_manager.cc",
"independent_otr_profile_manager.h",
]
}
}
static_library("test_support") {
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/media/router/independent_otr_profile_manager.h"
#include <algorithm>
#include <utility>
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_source.h"
using content::BrowserThread;
IndependentOTRProfileManager::OTRProfileRegistration::
~OTRProfileRegistration() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
manager_->UnregisterProfile(profile_);
}
IndependentOTRProfileManager::OTRProfileRegistration::OTRProfileRegistration(
IndependentOTRProfileManager* manager,
Profile* profile)
: manager_(manager), profile_(profile) {
DCHECK(manager_);
DCHECK(profile);
DCHECK(profile->IsOffTheRecord());
}
// static
IndependentOTRProfileManager* IndependentOTRProfileManager::GetInstance() {
return base::Singleton<IndependentOTRProfileManager>::get();
}
std::unique_ptr<IndependentOTRProfileManager::OTRProfileRegistration>
IndependentOTRProfileManager::CreateFromOriginalProfile(
Profile* profile,
ProfileDestroyedCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(profile);
DCHECK(!profile->IsOffTheRecord());
DCHECK(!callback.is_null());
if (!HasDependentProfiles(profile)) {
registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
content::Source<Profile>(profile));
}
auto* otr_profile = profile->CreateOffTheRecordProfile();
auto entry = refcounts_map_.emplace(otr_profile, 1);
auto callback_entry =
callbacks_map_.emplace(otr_profile, std::move(callback));
DCHECK(entry.second);
DCHECK(callback_entry.second);
return base::WrapUnique(new OTRProfileRegistration(this, otr_profile));
}
void IndependentOTRProfileManager::OnBrowserAdded(Browser* browser) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto* profile = browser->profile();
auto entry = refcounts_map_.find(profile);
if (entry != refcounts_map_.end()) {
++entry->second;
}
}
void IndependentOTRProfileManager::OnBrowserRemoved(Browser* browser) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto* profile = browser->profile();
auto entry = refcounts_map_.find(profile);
if (entry == refcounts_map_.end()) {
return;
}
--entry->second;
if (entry->second == 0) {
// The is the last Browser that references |profile| _and_ the original
// registration that owned |profile| has already been destroyed. Since the
// owner of the registration is also responsible for the callback, there
// should be no callback at this point.
DCHECK(callbacks_map_.find(profile) == callbacks_map_.end());
// This will be called from within ~Browser so we can't delete its profile
// immediately in case it has a (possibly indirect) dependency on the
// profile.
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, entry->first);
auto* original_profile = entry->first->GetOriginalProfile();
refcounts_map_.erase(entry);
if (!HasDependentProfiles(original_profile)) {
registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
content::Source<Profile>(original_profile));
}
}
}
IndependentOTRProfileManager::IndependentOTRProfileManager() {
BrowserList::AddObserver(this);
}
IndependentOTRProfileManager::~IndependentOTRProfileManager() {
BrowserList::RemoveObserver(this);
// This should be destroyed after all Browser objects, so any remaining
// refcounts should be due to registrations, which each have a corresponding
// callback.
DCHECK(std::all_of(refcounts_map_.begin(), refcounts_map_.end(),
[](const std::pair<Profile*, int32_t>& entry) {
return entry.second == 1;
}));
DCHECK(refcounts_map_.size() == callbacks_map_.size());
}
bool IndependentOTRProfileManager::HasDependentProfiles(
Profile* profile) const {
return std::find_if(refcounts_map_.begin(), refcounts_map_.end(),
[profile](const std::pair<Profile*, int32_t>& entry) {
return entry.first->GetOriginalProfile() == profile;
}) != refcounts_map_.end();
}
void IndependentOTRProfileManager::UnregisterProfile(Profile* profile) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto entry = refcounts_map_.find(profile);
DCHECK(entry != refcounts_map_.end());
callbacks_map_.erase(profile);
--entry->second;
if (entry->second == 0) {
auto* original_profile = profile->GetOriginalProfile();
delete entry->first;
refcounts_map_.erase(entry);
if (!HasDependentProfiles(original_profile)) {
registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
content::Source<Profile>(original_profile));
}
}
}
void IndependentOTRProfileManager::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type);
for (auto it = callbacks_map_.begin(); it != callbacks_map_.end();) {
if (source != content::Source<Profile>(it->first->GetOriginalProfile())) {
++it;
continue;
}
// If the registration is destroyed from within this callback, we don't want
// to double-erase. If it isn't, we still need to erase the callback entry.
auto* profile = it->first;
auto callback = std::move(it->second);
it = callbacks_map_.erase(it);
std::move(callback).Run(profile);
}
}
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_MEDIA_ROUTER_INDEPENDENT_OTR_PROFILE_MANAGER_H_
#define CHROME_BROWSER_MEDIA_ROUTER_INDEPENDENT_OTR_PROFILE_MANAGER_H_
#include <cstdint>
#include <memory>
#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
class Profile;
// This class manages Profile instances that were created by
// Profile::CreateOffTheRecordProfile(). These instances are owned by this
// class, instead of the original Profile (as is normally the case), as the
// lifetime assumptions are different.
//
// Normally, the last Browser object using an OTR profile will delete that
// profile (via its original Profile) when the Browser is closed. Users of
// CreateOffTheRecordProfile can't let a Browser destroy an independently
// created OTR profile and must instead rely on this class.
//
// In particular, this functionality is used by extensions::OffscreenTab and
// PresentationReceiverWindowController (used by the Presentation API). In the
// case of offscreen tabs, there is no interaction with a Browser object outside
// of DevTools. The Presentation API reciever Windows don't necessarily have
// special lifetime requirements but they still can't use the same destruction
// path in ~Browser as the normal OTR profile. DevTools presents a similar
// problem for presentation API windows as well.
//
// Normally, the caller should own the registration and delete it if the
// original profile is destroyed. This will be signaled via the callback passed
// to CreateFromOriginalProfile if the registration is still alive when the
// original profile is being destroyed.
//
// All methods must be called on the UI thread.
class IndependentOTRProfileManager final
: public BrowserListObserver,
public content::NotificationObserver {
public:
class OTRProfileRegistration {
public:
~OTRProfileRegistration();
Profile* profile() const { return profile_; }
private:
friend class IndependentOTRProfileManager;
OTRProfileRegistration(IndependentOTRProfileManager* manager,
Profile* profile);
IndependentOTRProfileManager* const manager_;
Profile* const profile_;
DISALLOW_COPY_AND_ASSIGN(OTRProfileRegistration);
};
using ProfileDestroyedCallback = base::OnceCallback<void(Profile*)>;
static IndependentOTRProfileManager* GetInstance();
// Creates an OTR profile from |profile| and registers it with this object.
// |callback| will be called if |profile| is being destroyed. If |callback|
// is called, the registration this method returns should be destroyed.
std::unique_ptr<OTRProfileRegistration> CreateFromOriginalProfile(
Profile* profile,
ProfileDestroyedCallback callback);
private:
friend struct base::DefaultSingletonTraits<IndependentOTRProfileManager>;
IndependentOTRProfileManager();
~IndependentOTRProfileManager() final;
bool HasDependentProfiles(Profile* profile) const;
void UnregisterProfile(Profile* profile);
// chrome::BrowserListObserver overrides.
void OnBrowserAdded(Browser* browser) final;
void OnBrowserRemoved(Browser* browser) final;
// content::NotificationObserver overrides.
void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) final;
// Counts the number of Browser instances referencing an independent OTR
// profile plus 1 for the OTRProfileRegistration object that created it.
base::flat_map<Profile*, int32_t> refcounts_map_;
base::flat_map<Profile*, ProfileDestroyedCallback> callbacks_map_;
content::NotificationRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(IndependentOTRProfileManager);
};
#endif // CHROME_BROWSER_MEDIA_ROUTER_INDEPENDENT_OTR_PROFILE_MANAGER_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/media/router/presentation_navigation_policy.h"
#include "content/public/browser/navigation_handle.h"
namespace media_router {
NavigationPolicy::~NavigationPolicy() = default;
DefaultNavigationPolicy::DefaultNavigationPolicy() = default;
DefaultNavigationPolicy::~DefaultNavigationPolicy() = default;
bool DefaultNavigationPolicy::AllowNavigation(content::NavigationHandle*) {
return true;
}
PresentationNavigationPolicy::PresentationNavigationPolicy() = default;
PresentationNavigationPolicy::~PresentationNavigationPolicy() = default;
bool PresentationNavigationPolicy::AllowNavigation(
content::NavigationHandle* navigation_handle) {
// We only care about top-level navigations that are cross-document.
if (!navigation_handle->IsInMainFrame() ||
navigation_handle->IsSameDocument()) {
return true;
}
// The initial navigation had already begun.
if (first_navigation_started_) {
return false;
}
first_navigation_started_ = true;
return true;
}
} // namespace media_router
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_MEDIA_ROUTER_PRESENTATION_NAVIGATION_POLICY_H_
#define CHROME_BROWSER_MEDIA_ROUTER_PRESENTATION_NAVIGATION_POLICY_H_
namespace content {
class NavigationHandle;
} // namespace content
namespace media_router {
// Selected calls to the navigation methods in WebContentsObserver are
// delegated to this object to determine whether a navigation is allowed. If
// any call returns false, the presentation tab is destroyed.
class NavigationPolicy {
public:
virtual ~NavigationPolicy();
virtual bool AllowNavigation(
content::NavigationHandle* navigation_handle) = 0;
};
// This default policy allows all navigations.
class DefaultNavigationPolicy : public NavigationPolicy {
public:
DefaultNavigationPolicy();
~DefaultNavigationPolicy() override;
bool AllowNavigation(content::NavigationHandle* navigation_handle) override;
};
// Navigation policy for presentations, where top-level navigations are not
// allowed.
class PresentationNavigationPolicy : public NavigationPolicy {
public:
PresentationNavigationPolicy();
~PresentationNavigationPolicy() override;
bool AllowNavigation(content::NavigationHandle* navigation_handle) override;
private:
bool first_navigation_started_ = false;
};
} // namespace media_router
#endif // CHROME_BROWSER_MEDIA_ROUTER_PRESENTATION_NAVIGATION_POLICY_H_
......@@ -7,6 +7,9 @@
#include "base/memory/ptr_util.h"
#include "chrome/browser/media/router/local_presentation_manager.h"
#include "chrome/browser/media/router/local_presentation_manager_factory.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/web_preferences.h"
DEFINE_WEB_CONTENTS_USER_DATA_KEY(
media_router::ReceiverPresentationServiceDelegateImpl);
......@@ -28,6 +31,11 @@ void ReceiverPresentationServiceDelegateImpl::CreateForWebContents(
UserDataKey(),
base::WrapUnique(new ReceiverPresentationServiceDelegateImpl(
web_contents, presentation_id)));
auto* render_view_host = web_contents->GetRenderViewHost();
DCHECK(render_view_host);
auto web_prefs = render_view_host->GetWebkitPreferences();
web_prefs.presentation_receiver = true;
render_view_host->UpdateWebkitPreferences(web_prefs);
}
void ReceiverPresentationServiceDelegateImpl::AddObserver(
......
......@@ -805,6 +805,10 @@ split_static_library("ui") {
"layout_constants.h",
"location_bar/location_bar.cc",
"location_bar/location_bar.h",
"media_router/presentation_receiver_window.h",
"media_router/presentation_receiver_window_controller.cc",
"media_router/presentation_receiver_window_controller.h",
"media_router/presentation_receiver_window_delegate.h",
"native_window_tracker.h",
"omnibox/alternate_nav_infobar_delegate.cc",
"omnibox/alternate_nav_infobar_delegate.h",
......@@ -3041,6 +3045,11 @@ split_static_library("ui") {
"views/location_bar/star_view.h",
"views/location_bar/zoom_view.cc",
"views/location_bar/zoom_view.h",
"views/media_router/presentation_receiver_window_factory.cc",
"views/media_router/presentation_receiver_window_frame.cc",
"views/media_router/presentation_receiver_window_frame.h",
"views/media_router/presentation_receiver_window_view.cc",
"views/media_router/presentation_receiver_window_view.h",
"views/omnibox/omnibox_popup_contents_view.cc",
"views/omnibox/omnibox_popup_contents_view.h",
"views/omnibox/omnibox_result_view.cc",
......
......@@ -50,7 +50,6 @@
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/download/download_core_service.h"
#include "chrome/browser/download/download_core_service_factory.h"
#include "chrome/browser/extensions/api/tab_capture/offscreen_tab.h"
#include "chrome/browser/extensions/api/tabs/tabs_event_router.h"
#include "chrome/browser/extensions/api/tabs/tabs_windows_api.h"
#include "chrome/browser/extensions/browser_extension_window_controller.h"
......@@ -535,13 +534,14 @@ Browser::~Browser() {
// because the ProfileManager needs to be able to destroy all profiles when
// it is destroyed. See crbug.com/527035
//
// A profile used to render an offscreen tab should not be destroyed while
// that tab is still alive. The offscreen tab is not associated with a
// browser (similar to the user manager window case). See crbug.com/664351
// A profile created with Profile::CreateOffTheRecordProfile() should not be
// destroyed directly by Browser (e.g. for offscreen tabs,
// https://crbug.com/664351).
if (profile_->IsOffTheRecord() &&
profile_->GetOriginalProfile()->HasOffTheRecordProfile() &&
profile_->GetOriginalProfile()->GetOffTheRecordProfile() == profile_ &&
!BrowserList::IsIncognitoSessionActiveForProfile(profile_) &&
!profile_->GetOriginalProfile()->IsSystemProfile() &&
!extensions::OffscreenTabsOwner::IsOffscreenProfile(profile_)) {
!profile_->GetOriginalProfile()->IsSystemProfile()) {
if (profile_->IsGuestSession()) {
// ChromeOS handles guest data independently.
#if !defined(OS_CHROMEOS)
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_MEDIA_ROUTER_PRESENTATION_RECEIVER_WINDOW_H_
#define CHROME_BROWSER_UI_MEDIA_ROUTER_PRESENTATION_RECEIVER_WINDOW_H_
namespace gfx {
class Rect;
}
class PresentationReceiverWindowDelegate;
// This interface represents a window used to render a receiver page for the
// Presentation API. It should display a WebContents provided by its controller
// and a location bar. The window is not owned by the caller of Create (for
// Views, it is owned by the native widget and Views hierarchy). It will call
// WindowClosing on |delegate| before being destroyed.
class PresentationReceiverWindow {
public:
static PresentationReceiverWindow* Create(
PresentationReceiverWindowDelegate* delegate,
const gfx::Rect& bounds);
// Closes the window.
virtual void Close() = 0;
// Returns true if the window is active (i.e. has focus).
virtual bool IsWindowActive() const = 0;
// Returns true if the window is currently fullscreened.
virtual bool IsWindowFullscreen() const = 0;
// Returns the current bounds of the window.
virtual gfx::Rect GetWindowBounds() const = 0;
// Shows the window as inactive and transitions it to fullscreen.
virtual void ShowInactiveFullscreen() = 0;
// Updates the window title if it has changed.
virtual void UpdateWindowTitle() = 0;
// Updates the location bar if the location of the displayed WebContents has
// changed.
virtual void UpdateLocationBar() = 0;
protected:
~PresentationReceiverWindow() = default;
};
#endif // CHROME_BROWSER_UI_MEDIA_ROUTER_PRESENTATION_RECEIVER_WINDOW_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/media_router/presentation_receiver_window_controller.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "chrome/browser/media/router/receiver_presentation_service_delegate_impl.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/media_router/presentation_receiver_window.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/web_contents.h"
#include "third_party/WebKit/public/web/WebPresentationReceiverFlags.h"
#include "ui/views/widget/widget.h"
using content::WebContents;
namespace {
WebContents::CreateParams CreateWebContentsParams(Profile* profile) {
WebContents::CreateParams params(profile);
params.starting_sandbox_flags = blink::kPresentationReceiverSandboxFlags;
return params;
}
} // namespace
// static
std::unique_ptr<PresentationReceiverWindowController>
PresentationReceiverWindowController::CreateFromOriginalProfile(
Profile* profile,
const gfx::Rect& bounds,
base::OnceClosure termination_callback) {
DCHECK(profile);
DCHECK(!profile->IsOffTheRecord());
DCHECK(termination_callback);
return base::WrapUnique(new PresentationReceiverWindowController(
profile, bounds, std::move(termination_callback)));
}
PresentationReceiverWindowController::~PresentationReceiverWindowController() {
DCHECK(!web_contents_);
DCHECK(!window_);
}
void PresentationReceiverWindowController::Start(
const std::string& presentation_id,
const GURL& start_url) {
DCHECK(window_);
DCHECK(web_contents_);
media_router::ReceiverPresentationServiceDelegateImpl::CreateForWebContents(
web_contents_.get(), presentation_id);
content::NavigationController::LoadURLParams load_params(start_url);
load_params.should_replace_current_entry = true;
load_params.should_clear_history_list = true;
web_contents_->GetController().LoadURLWithParams(load_params);
window_->ShowInactiveFullscreen();
}
void PresentationReceiverWindowController::Terminate() {
if (web_contents_) {
web_contents_->ClosePage();
} else if (window_) {
window_->Close();
} else if (termination_callback_) {
std::move(termination_callback_).Run();
}
}
void PresentationReceiverWindowController::CloseWindowForTest() {
window_->Close();
}
bool PresentationReceiverWindowController::IsWindowActiveForTest() const {
return window_->IsWindowActive();
}
bool PresentationReceiverWindowController::IsWindowFullscreenForTest() const {
return window_->IsWindowFullscreen();
}
gfx::Rect PresentationReceiverWindowController::GetWindowBoundsForTest() const {
return window_->GetWindowBounds();
}
WebContents* PresentationReceiverWindowController::web_contents() const {
return web_contents_.get();
}
PresentationReceiverWindowController::PresentationReceiverWindowController(
Profile* profile,
const gfx::Rect& bounds,
base::OnceClosure termination_callback)
: otr_profile_registration_(
IndependentOTRProfileManager::GetInstance()
->CreateFromOriginalProfile(
profile,
base::BindOnce(&PresentationReceiverWindowController::
OriginalProfileDestroyed,
base::Unretained(this)))),
web_contents_(WebContents::Create(
CreateWebContentsParams(otr_profile_registration_->profile()))),
window_(PresentationReceiverWindow::Create(this, bounds)),
termination_callback_(std::move(termination_callback)) {
DCHECK(otr_profile_registration_->profile());
DCHECK(otr_profile_registration_->profile()->IsOffTheRecord());
content::WebContentsObserver::Observe(web_contents_.get());
web_contents_->SetDelegate(this);
}
void PresentationReceiverWindowController::WindowClosed() {
window_ = nullptr;
Terminate();
}
void PresentationReceiverWindowController::OriginalProfileDestroyed(
Profile* profile) {
DCHECK(profile == otr_profile_registration_->profile());
web_contents_.reset();
otr_profile_registration_.reset();
Terminate();
}
void PresentationReceiverWindowController::DidStartNavigation(
content::NavigationHandle* handle) {
if (!navigation_policy_.AllowNavigation(handle))
Terminate();
}
void PresentationReceiverWindowController::TitleWasSet(
content::NavigationEntry* entry) {
window_->UpdateWindowTitle();
}
void PresentationReceiverWindowController::NavigationStateChanged(
WebContents* source,
content::InvalidateTypes changed_flags) {
window_->UpdateLocationBar();
}
void PresentationReceiverWindowController::CloseContents(
content::WebContents* source) {
web_contents_.reset();
Terminate();
}
bool PresentationReceiverWindowController::ShouldSuppressDialogs(
content::WebContents* source) {
DCHECK_EQ(web_contents_.get(), source);
// Suppress all because there is no possible direct user interaction with
// dialogs.
// TODO(https://crbug.com/734191): This does not suppress window.print().
return true;
}
bool PresentationReceiverWindowController::ShouldFocusLocationBarByDefault(
content::WebContents* source) {
DCHECK_EQ(web_contents_.get(), source);
// Indicate the location bar should be focused instead of the page, even
// though there is no location bar in fullscreen (the presentation's default
// state). This will prevent the page from automatically receiving input
// focus, which is usually not intended.
return true;
}
bool PresentationReceiverWindowController::ShouldFocusPageAfterCrash() {
// Never focus the page after a crash.
return false;
}
void PresentationReceiverWindowController::CanDownload(
const GURL& url,
const std::string& request_method,
const base::Callback<void(bool)>& callback) {
// Local presentation pages are not allowed to download files.
callback.Run(false);
}
bool PresentationReceiverWindowController::ShouldCreateWebContents(
content::WebContents* web_contents,
content::RenderFrameHost* opener,
content::SiteInstance* source_site_instance,
int32_t route_id,
int32_t main_frame_route_id,
int32_t main_frame_widget_route_id,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
const std::string& frame_name,
const GURL& target_url,
const std::string& partition_id,
content::SessionStorageNamespace* session_storage_namespace) {
DCHECK_EQ(web_contents_.get(), web_contents);
// Disallow creating separate WebContentses. The WebContents implementation
// uses this to spawn new windows/tabs, which is also not allowed for
// local presentations.
return false;
}
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_MEDIA_ROUTER_PRESENTATION_RECEIVER_WINDOW_CONTROLLER_H_
#define CHROME_BROWSER_UI_MEDIA_ROUTER_PRESENTATION_RECEIVER_WINDOW_CONTROLLER_H_
#include <memory>
#include <string>
#include "base/callback.h"
#include "base/macros.h"
#include "chrome/browser/media/router/independent_otr_profile_manager.h"
#include "chrome/browser/media/router/presentation_navigation_policy.h"
#include "chrome/browser/ui/media_router/presentation_receiver_window_delegate.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
class GURL;
class PresentationReceiverWindow;
class Profile;
namespace content {
class WebContents;
}
namespace gfx {
class Rect;
}
// This class controls a window which is used to render a receiver page for the
// Presentation API. It handles creating the window to show the desired URL and
// showing it in fullscreen on the desired display. This class should not be
// destroyed until |termination_callback| has been called, which may be called
// before Terminate() is ever called.
class PresentationReceiverWindowController final
: public PresentationReceiverWindowDelegate,
public content::WebContentsObserver,
public content::WebContentsDelegate {
public:
static std::unique_ptr<PresentationReceiverWindowController>
CreateFromOriginalProfile(Profile* profile,
const gfx::Rect& bounds,
base::OnceClosure termination_callback);
~PresentationReceiverWindowController() final;
// Starts the presentation with the receiver page |start_url| and the
// presentation ID |presentation_id| for the purpose of messaging.
void Start(const std::string& presentation_id, const GURL& start_url);
// Closes the window and stops the presentation.
void Terminate();
// PresentationReceiverWindowDelegate overrides.
content::WebContents* web_contents() const final;
private:
friend class PresentationReceiverWindowControllerBrowserTest;
PresentationReceiverWindowController(Profile* profile,
const gfx::Rect& bounds,
base::OnceClosure termination_callback);
void OriginalProfileDestroyed(Profile* profile);
// These methods are intended to be used by tests.
void CloseWindowForTest();
bool IsWindowActiveForTest() const;
bool IsWindowFullscreenForTest() const;
gfx::Rect GetWindowBoundsForTest() const;
// PresentationReceiverWindowDelegate overrides.
void WindowClosed() final;
// content::WebContentsObserver overrides.
void DidStartNavigation(content::NavigationHandle* handle) final;
void TitleWasSet(content::NavigationEntry* entry) final;
// content::WebContentsDelegate overrides.
void NavigationStateChanged(content::WebContents* source,
content::InvalidateTypes changed_flags) final;
void CloseContents(content::WebContents* source) final;
bool ShouldSuppressDialogs(content::WebContents* source) final;
bool ShouldFocusLocationBarByDefault(content::WebContents* source) final;
bool ShouldFocusPageAfterCrash() final;
void CanDownload(const GURL& url,
const std::string& request_method,
const base::Callback<void(bool)>& callback) final;
bool ShouldCreateWebContents(
content::WebContents* web_contents,
content::RenderFrameHost* opener,
content::SiteInstance* source_site_instance,
int32_t route_id,
int32_t main_frame_route_id,
int32_t main_frame_widget_route_id,
content::mojom::WindowContainerType window_container_type,
const GURL& opener_url,
const std::string& frame_name,
const GURL& target_url,
const std::string& partition_id,
content::SessionStorageNamespace* session_storage_namespace) final;
// The profile used for the presentation.
std::unique_ptr<IndependentOTRProfileManager::OTRProfileRegistration>
otr_profile_registration_;
// WebContents for rendering the receiver page.
std::unique_ptr<content::WebContents> web_contents_;
// The actual UI window for displaying the receiver page.
PresentationReceiverWindow* window_;
base::OnceClosure termination_callback_;
media_router::PresentationNavigationPolicy navigation_policy_;
DISALLOW_COPY_AND_ASSIGN(PresentationReceiverWindowController);
};
#endif // CHROME_BROWSER_UI_MEDIA_ROUTER_PRESENTATION_RECEIVER_WINDOW_CONTROLLER_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_MEDIA_ROUTER_PRESENTATION_RECEIVER_WINDOW_DELEGATE_H_
#define CHROME_BROWSER_UI_MEDIA_ROUTER_PRESENTATION_RECEIVER_WINDOW_DELEGATE_H_
namespace content {
class WebContents;
}
// This interface allows communication between a PresentationReceiverWindow and
// its controller. The controller provides a WebContents instance for the
// window, and the window can tell the controller when it is closing.
class PresentationReceiverWindowDelegate {
public:
// WebContents instance provided by the delegate to be displayed in the
// window.
virtual content::WebContents* web_contents() const = 0;
// Notifies the delegate that the window is closed so it can perform any
// necessary cleanup.
virtual void WindowClosed() = 0;
protected:
~PresentationReceiverWindowDelegate() = default;
};
#endif // CHROME_BROWSER_UI_MEDIA_ROUTER_PRESENTATION_RECEIVER_WINDOW_DELEGATE_H_
......@@ -239,14 +239,17 @@ void LocationBarView::Init() {
add_icon(zoom_view_ = new ZoomView(delegate_));
add_icon(manage_passwords_icon_view_ =
new ManagePasswordsIconViews(command_updater()));
add_icon(save_credit_card_icon_view_ =
new autofill::SaveCardIconView(command_updater(), browser_));
if (browser_)
add_icon(save_credit_card_icon_view_ =
new autofill::SaveCardIconView(command_updater(), browser_));
add_icon(translate_icon_view_ = new TranslateIconView(command_updater()));
#if defined(OS_CHROMEOS)
add_icon(intent_picker_view_ = new IntentPickerView(browser_));
if (browser_)
add_icon(intent_picker_view_ = new IntentPickerView(browser_));
#endif
add_icon(find_bar_icon_ = new FindBarIcon());
add_icon(star_view_ = new StarView(command_updater(), browser_));
if (browser_)
add_icon(star_view_ = new StarView(command_updater(), browser_));
clear_all_button_ = views::CreateVectorImageButton(this);
clear_all_button_->SetTooltipText(
......@@ -449,10 +452,12 @@ gfx::Size LocationBarView::CalculatePreferredSize() const {
// Compute width of omnibox-trailing content.
int trailing_width = edge_thickness;
trailing_width += IncrementalMinimumWidth(star_view_) +
IncrementalMinimumWidth(translate_icon_view_) +
IncrementalMinimumWidth(save_credit_card_icon_view_) +
IncrementalMinimumWidth(manage_passwords_icon_view_) +
if (star_view_)
trailing_width += IncrementalMinimumWidth(star_view_);
trailing_width += IncrementalMinimumWidth(translate_icon_view_);
if (save_credit_card_icon_view_)
trailing_width += IncrementalMinimumWidth(save_credit_card_icon_view_);
trailing_width += IncrementalMinimumWidth(manage_passwords_icon_view_) +
IncrementalMinimumWidth(zoom_view_);
#if defined(OS_CHROMEOS)
if (intent_picker_view_)
......@@ -535,12 +540,15 @@ void LocationBarView::Layout() {
};
#if defined(OS_CHROMEOS)
add_trailing_decoration(intent_picker_view_);
if (intent_picker_view_)
add_trailing_decoration(intent_picker_view_);
#endif
add_trailing_decoration(star_view_);
if (star_view_)
add_trailing_decoration(star_view_);
add_trailing_decoration(find_bar_icon_);
add_trailing_decoration(translate_icon_view_);
add_trailing_decoration(save_credit_card_icon_view_);
if (save_credit_card_icon_view_)
add_trailing_decoration(save_credit_card_icon_view_);
add_trailing_decoration(manage_passwords_icon_view_);
add_trailing_decoration(zoom_view_);
for (ContentSettingViews::const_reverse_iterator i(
......@@ -768,7 +776,7 @@ bool LocationBarView::IsVirtualKeyboardVisible() {
bool LocationBarView::RefreshSaveCreditCardIconView() {
WebContents* web_contents = GetWebContents();
if (!web_contents)
if (!save_credit_card_icon_view_ || !web_contents)
return false;
const bool was_visible = save_credit_card_icon_view_->visible();
......
......@@ -153,14 +153,16 @@ class LocationBarView : public LocationBar,
void SetStarToggled(bool on);
#if defined(OS_CHROMEOS)
// The intent picker, should not always be visible.
// The intent picker, should not always be visible. It will be null when
// |browser_| is null.
IntentPickerView* intent_picker_view() { return intent_picker_view_; }
#endif // defined(OS_CHROMEOS)
// The star. It may not be visible.
// The star. It may not be visible. It will be null when |browser_| is null.
StarView* star_view() { return star_view_; }
// The save credit card icon. It may not be visible.
// The save credit card icon. It may not be visible. It will be null when
// |browser_| is null.
autofill::SaveCardIconView* save_credit_card_icon_view() {
return save_credit_card_icon_view_;
}
......@@ -402,21 +404,22 @@ class LocationBarView : public LocationBar,
// The manage passwords icon.
ManagePasswordsIconViews* manage_passwords_icon_view_ = nullptr;
// The save credit card icon.
// The save credit card icon. It will be null when |browser_| is null.
autofill::SaveCardIconView* save_credit_card_icon_view_ = nullptr;
// The icon for Translate.
TranslateIconView* translate_icon_view_ = nullptr;
#if defined(OS_CHROMEOS)
// The intent picker for accessing ARC's apps.
// The intent picker for accessing ARC's apps. It will be null when
// |browser_| is null.
IntentPickerView* intent_picker_view_ = nullptr;
#endif // defined(OS_CHROMEOS)
// The icon displayed when the find bar is visible.
FindBarIcon* find_bar_icon_ = nullptr;
// The star for bookmarking.
// The star for bookmarking. It will be null when |browser_| is null.
StarView* star_view_ = nullptr;
// An [x] that appears in touch mode (when the OSK is visible) and allows the
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/media_router/presentation_receiver_window.h"
#include <memory>
#include "base/logging.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/media_router/presentation_receiver_window_delegate.h"
#include "chrome/browser/ui/views/media_router/presentation_receiver_window_frame.h"
#include "chrome/browser/ui/views/media_router/presentation_receiver_window_view.h"
#include "content/public/browser/web_contents.h"
// static
PresentationReceiverWindow* PresentationReceiverWindow::Create(
PresentationReceiverWindowDelegate* delegate,
const gfx::Rect& bounds) {
DCHECK(delegate);
DCHECK(delegate->web_contents());
auto* frame = new PresentationReceiverWindowFrame(Profile::FromBrowserContext(
delegate->web_contents()->GetBrowserContext()));
auto view = std::make_unique<PresentationReceiverWindowView>(frame, delegate);
auto* view_raw = view.get();
frame->InitReceiverFrame(std::move(view), bounds);
view_raw->Init();
return view_raw;
}
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/media_router/presentation_receiver_window_frame.h"
#include "chrome/browser/themes/theme_service.h"
#include "ui/views/widget/widget_delegate.h"
PresentationReceiverWindowFrame::PresentationReceiverWindowFrame(
Profile* profile)
: profile_(profile) {}
PresentationReceiverWindowFrame::~PresentationReceiverWindowFrame() = default;
void PresentationReceiverWindowFrame::InitReceiverFrame(
std::unique_ptr<views::WidgetDelegateView> delegate,
const gfx::Rect& bounds) {
views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
params.bounds = bounds;
params.delegate = delegate.release();
Init(params);
}
const ui::ThemeProvider* PresentationReceiverWindowFrame::GetThemeProvider()
const {
return &ThemeService::GetThemeProviderForProfile(profile_);
}
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_PRESENTATION_RECEIVER_WINDOW_FRAME_H_
#define CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_PRESENTATION_RECEIVER_WINDOW_FRAME_H_
#include <memory>
#include "base/macros.h"
#include "ui/views/widget/widget.h"
namespace gfx {
class Rect;
}
namespace ui {
class ThemeProvider;
}
class Profile;
namespace views {
class WidgetDelegateView;
}
// This class implements the window portion of PresentationReceiverWindow. It
// is just a normal Widget that overrides GetThemeProvider to provide normal
// colors for the URL bar.
class PresentationReceiverWindowFrame final : public views::Widget {
public:
explicit PresentationReceiverWindowFrame(Profile* profile);
~PresentationReceiverWindowFrame() final;
void InitReceiverFrame(std::unique_ptr<views::WidgetDelegateView> delegate,
const gfx::Rect& bounds);
private:
const ui::ThemeProvider* GetThemeProvider() const final;
// The profile from which we get the theme.
Profile* const profile_;
DISALLOW_COPY_AND_ASSIGN(PresentationReceiverWindowFrame);
};
#endif // CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_PRESENTATION_RECEIVER_WINDOW_FRAME_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_PRESENTATION_RECEIVER_WINDOW_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_PRESENTATION_RECEIVER_WINDOW_VIEW_H_
#include <memory>
#include "base/macros.h"
#include "base/strings/string16.h"
#include "chrome/browser/command_updater_delegate.h"
#include "chrome/browser/command_updater_impl.h"
#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h"
#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
#include "chrome/browser/ui/media_router/presentation_receiver_window.h"
#include "chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.h"
#include "chrome/browser/ui/views/exclusive_access_bubble_views_context.h"
#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
#include "ui/views/widget/widget_delegate.h"
class ExclusiveAccessBubbleViews;
class PresentationReceiverWindowDelegate;
class PresentationReceiverWindowFrame;
class ToolbarModelImpl;
// This class implements the View portion of PresentationReceiverWindow. It
// contains a WebView for displaying the receiver page and a LocationBarView for
// displaying the URL.
class PresentationReceiverWindowView final
: public PresentationReceiverWindow,
public views::WidgetDelegateView,
public LocationBarView::Delegate,
public CommandUpdaterDelegate,
public ChromeToolbarModelDelegate,
public ExclusiveAccessContext,
public ExclusiveAccessBubbleViewsContext,
public ui::AcceleratorProvider {
public:
PresentationReceiverWindowView(PresentationReceiverWindowFrame* frame,
PresentationReceiverWindowDelegate* delegate);
~PresentationReceiverWindowView() final;
void Init();
private:
// PresentationReceiverWindow overrides.
void Close() final;
bool IsWindowActive() const final;
bool IsWindowFullscreen() const final;
gfx::Rect GetWindowBounds() const final;
void ShowInactiveFullscreen() final;
void UpdateWindowTitle() final;
void UpdateLocationBar() final;
// LocationBarView::Delegate overrides.
content::WebContents* GetWebContents() final;
ToolbarModel* GetToolbarModel() final;
const ToolbarModel* GetToolbarModel() const final;
ContentSettingBubbleModelDelegate* GetContentSettingBubbleModelDelegate()
final;
// CommandUpdaterDelegate overrides.
void ExecuteCommandWithDisposition(int id,
WindowOpenDisposition disposition) final;
// ChromeToolbarModelDelegate overrides.
content::WebContents* GetActiveWebContents() const final;
// views::WidgetDelegateView overrides.
bool CanResize() const final;
bool CanMaximize() const final;
bool CanMinimize() const final;
void DeleteDelegate() final;
base::string16 GetWindowTitle() const final;
// ui::AcceleratorTarget overrides.
bool AcceleratorPressed(const ui::Accelerator& accelerator) final;
// ExclusiveAccessContext overrides.
Profile* GetProfile() final;
bool IsFullscreen() const final;
void EnterFullscreen(const GURL& url,
ExclusiveAccessBubbleType bubble_type) final;
void ExitFullscreen() final;
void UpdateExclusiveAccessExitBubbleContent(
const GURL& url,
ExclusiveAccessBubbleType bubble_type,
ExclusiveAccessBubbleHideCallback bubble_first_hide_callback) final;
void OnExclusiveAccessUserInput() final;
content::WebContents* GetActiveWebContents() final;
void UnhideDownloadShelf() final;
void HideDownloadShelf() final;
// ExclusiveAccessBubbleViewsContext overrides.
ExclusiveAccessManager* GetExclusiveAccessManager() final;
views::Widget* GetBubbleAssociatedWidget() final;
ui::AcceleratorProvider* GetAcceleratorProvider() final;
gfx::NativeView GetBubbleParentView() const final;
gfx::Point GetCursorPointInParent() const final;
gfx::Rect GetClientAreaBoundsInScreen() const final;
bool IsImmersiveModeEnabled() const final;
gfx::Rect GetTopContainerBoundsInScreen() final;
void DestroyAnyExclusiveAccessBubble() final;
bool CanTriggerOnMouse() const final;
// ui::AcceleratorProvider overrides.
bool GetAcceleratorForCommandId(int command_id,
ui::Accelerator* accelerator) const final;
PresentationReceiverWindowFrame* const frame_;
PresentationReceiverWindowDelegate* const delegate_;
base::string16 title_;
const std::unique_ptr<ToolbarModelImpl> toolbar_model_;
CommandUpdaterImpl command_updater_;
LocationBarView* location_bar_view_ = nullptr;
ExclusiveAccessManager exclusive_access_manager_;
ui::Accelerator fullscreen_accelerator_;
std::unique_ptr<ExclusiveAccessBubbleViews> exclusive_access_bubble_;
DISALLOW_COPY_AND_ASSIGN(PresentationReceiverWindowView);
};
#endif // CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_PRESENTATION_RECEIVER_WINDOW_VIEW_H_
......@@ -535,6 +535,7 @@ test("browser_tests") {
"../browser/media/media_browsertest.h",
"../browser/media/media_engagement_autoplay_browsertest.cc",
"../browser/media/media_engagement_browsertest.cc",
"../browser/media/router/independent_otr_profile_manager_browsertest.cc",
"../browser/media/test_license_server.cc",
"../browser/media/test_license_server.h",
"../browser/media/test_license_server_config.h",
......@@ -1389,6 +1390,7 @@ test("browser_tests") {
# TODO(tapted): Move these to chrome_browser_tests_views_sources when the
# the corresponding files are moved in chrome_browser_ui.gypi (i.e. out of
# chrome_browser_ui_views_non_mac_sources). http://crbug.com/404979.
"../browser/ui/media_router/presentation_receiver_window_controller_browsertest.cc",
"../browser/ui/views/autofill/autofill_popup_base_view_browsertest.cc",
"../browser/ui/views/autofill/autofill_popup_view_views_browsertest.cc",
"../browser/ui/views/autofill/password_generation_popup_view_tester_views.cc",
......
<!DOCTYPE HTML>
<html>
<head>
<title>Media Router Integration Test - Receiver Page</title>
<script>
const addConnection = connection => {
connection.onconnect = () => {
connection.onmessage = event => {
if (event.data == 'close') {
connection.close();
} else {
connection.send('Pong: ' + event.data);
}
};
connection.send('ready');
};
};
navigator.presentation.receiver.connectionList
.then(list => {
list.onconnectionavailable = evt => {
addConnection(evt.connection);
};
list.connections.map(connection => {
addConnection(connection);
});
});
</script>
</head>
<body>
</body>
</html>
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