Commit 2dd298b5 authored by Takumi Fujimoto's avatar Takumi Fujimoto Committed by Commit Bot

[Local Screen Casting] Hide the sink for the controlling window's display

We will observe which display the Media Router dialog's initiator web contents are on, and hide the local screen sink for that display from the sink list. This is to prevent the user from launching a presentation window that covers the controlling window.

It would be nicer if the WiredDisplayMRP were responsible for determining which sinks should be disabled. Unfortunately, there is no clean way for MRUI to notify WiredDisplayMRP which display the dialog is on. So it is done in MRUI instead.

Also doing some cleanups in MRUI (base::MakeUnique to std::make_unique, base::Callback to base::RepeatingCallback).

Bug: 800433
Change-Id: I0ec74758c485b89eee4f4417b7358922aa4f32a1
Reviewed-on: https://chromium-review.googlesource.com/830972
Commit-Queue: Takumi Fujimoto <takumif@chromium.org>
Reviewed-by: default avatarDerek Cheng <imcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#533814}
parent e1efa651
......@@ -27,11 +27,6 @@ namespace media_router {
namespace {
std::string GetSinkIdForDisplay(const Display& display) {
return WiredDisplayMediaRouteProvider::kSinkPrefix +
std::to_string(display.id());
}
bool IsPresentationSource(const std::string& media_source) {
const GURL source_url(media_source);
return source_url.is_valid() && source_url.SchemeIsHTTPOrHTTPS() &&
......@@ -41,7 +36,8 @@ bool IsPresentationSource(const std::string& media_source) {
MediaSinkInternal CreateSinkForDisplay(const Display& display,
int display_index) {
const std::string sink_id = GetSinkIdForDisplay(display);
const std::string sink_id =
WiredDisplayMediaRouteProvider::GetSinkIdForDisplay(display);
const std::string sink_name =
l10n_util::GetStringFUTF8(IDS_MEDIA_ROUTER_WIRED_DISPLAY_SINK_NAME,
base::FormatNumber(display_index));
......@@ -74,7 +70,10 @@ const MediaRouteProviderId WiredDisplayMediaRouteProvider::kProviderId =
MediaRouteProviderId::WIRED_DISPLAY;
// static
const char WiredDisplayMediaRouteProvider::kSinkPrefix[] = "wired_display_";
std::string WiredDisplayMediaRouteProvider::GetSinkIdForDisplay(
const Display& display) {
return "wired_display_" + std::to_string(display.id());
}
WiredDisplayMediaRouteProvider::WiredDisplayMediaRouteProvider(
mojom::MediaRouteProviderRequest request,
......@@ -421,8 +420,8 @@ base::Optional<Display> WiredDisplayMediaRouteProvider::GetDisplayBySinkId(
const std::string& sink_id) const {
std::vector<Display> displays = GetAllDisplays();
auto it = std::find_if(displays.begin(), displays.end(),
[&sink_id](const Display& d) {
return GetSinkIdForDisplay(d) == sink_id;
[&sink_id](const Display& display) {
return GetSinkIdForDisplay(display) == sink_id;
});
return it == displays.end() ? base::nullopt
: base::make_optional<Display>(std::move(*it));
......
......@@ -34,8 +34,8 @@ class WiredDisplayMediaRouteProvider : public mojom::MediaRouteProvider,
public display::DisplayObserver {
public:
static const MediaRouteProviderId kProviderId;
// Sink ID is generated by prefixing display ID with |kSinkPrefix|.
static const char kSinkPrefix[];
static std::string GetSinkIdForDisplay(const display::Display& display);
WiredDisplayMediaRouteProvider(mojom::MediaRouteProviderRequest request,
mojom::MediaRouterPtr media_router,
......
......@@ -39,8 +39,7 @@ class MockCallback {
};
std::string GetSinkId(const Display& display) {
return WiredDisplayMediaRouteProvider::kSinkPrefix +
std::to_string(display.id());
return WiredDisplayMediaRouteProvider::GetSinkIdForDisplay(display);
}
class MockPresentationReceiver : public WiredDisplayPresentationReceiver {
......
......@@ -1612,6 +1612,7 @@ split_static_library("ui") {
"webui/media_router/media_sink_with_cast_modes.h",
"webui/media_router/query_result_manager.cc",
"webui/media_router/query_result_manager.h",
"webui/media_router/web_contents_display_observer.h",
"webui/ntp/app_icon_webui_handler.cc",
"webui/ntp/app_icon_webui_handler.h",
"webui/ntp/app_launcher_handler.cc",
......@@ -3120,6 +3121,8 @@ split_static_library("ui") {
"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/media_router/web_contents_display_observer_view.cc",
"views/media_router/web_contents_display_observer_view.h",
"views/omnibox/omnibox_popup_contents_view.cc",
"views/omnibox/omnibox_popup_contents_view.h",
"views/omnibox/omnibox_result_view.cc",
......
// Copyright 2018 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 <memory>
#include <utility>
#include "chrome/browser/ui/views/media_router/web_contents_display_observer_view.h"
#include "chrome/browser/ui/browser_list.h"
#include "content/public/browser/web_contents.h"
#include "ui/display/screen.h"
#include "ui/views/widget/widget.h"
namespace media_router {
// static
std::unique_ptr<WebContentsDisplayObserver> WebContentsDisplayObserver::Create(
content::WebContents* web_contents,
base::RepeatingClosure callback) {
return std::make_unique<WebContentsDisplayObserverView>(web_contents,
std::move(callback));
}
WebContentsDisplayObserverView::WebContentsDisplayObserverView(
content::WebContents* web_contents,
base::RepeatingClosure callback)
: web_contents_(web_contents),
widget_(views::Widget::GetWidgetForNativeWindow(
web_contents->GetTopLevelNativeWindow())),
callback_(std::move(callback)) {
// |widget_| may be null in tests.
if (widget_) {
display_ = GetDisplayNearestWidget();
widget_->AddObserver(this);
}
BrowserList::GetInstance()->AddObserver(this);
}
WebContentsDisplayObserverView::~WebContentsDisplayObserverView() {
if (widget_)
widget_->RemoveObserver(this);
BrowserList::GetInstance()->RemoveObserver(this);
}
void WebContentsDisplayObserverView::OnBrowserSetLastActive(Browser* browser) {
// This gets called when a browser tab detaches from a window or gets merged
// into another window. We update the widget to observe, if necessary.
views::Widget* new_widget = views::Widget::GetWidgetForNativeWindow(
web_contents_->GetTopLevelNativeWindow());
if (new_widget != widget_) {
if (widget_)
widget_->RemoveObserver(this);
widget_ = new_widget;
if (widget_) {
widget_->AddObserver(this);
CheckForDisplayChange();
}
}
}
void WebContentsDisplayObserverView::OnWidgetClosing(views::Widget* widget) {
widget_ = nullptr;
}
void WebContentsDisplayObserverView::OnWidgetBoundsChanged(
views::Widget* widget,
const gfx::Rect& new_bounds) {
CheckForDisplayChange();
}
const display::Display& WebContentsDisplayObserverView::GetCurrentDisplay()
const {
return display_;
}
void WebContentsDisplayObserverView::CheckForDisplayChange() {
display::Display new_display = GetDisplayNearestWidget();
if (new_display.id() == display_.id())
return;
display_ = new_display;
callback_.Run();
}
display::Display WebContentsDisplayObserverView::GetDisplayNearestWidget()
const {
return display::Screen::GetScreen()->GetDisplayNearestWindow(
widget_->GetNativeWindow());
}
} // namespace media_router
// Copyright 2018 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_WEB_CONTENTS_DISPLAY_OBSERVER_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_WEB_CONTENTS_DISPLAY_OBSERVER_VIEW_H_
#include "base/callback.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "chrome/browser/ui/webui/media_router/web_contents_display_observer.h"
#include "ui/display/display.h"
#include "ui/views/widget/widget_observer.h"
namespace media_router {
class WebContentsDisplayObserverView : public WebContentsDisplayObserver,
public BrowserListObserver,
public views::WidgetObserver {
public:
WebContentsDisplayObserverView(content::WebContents* web_contents,
base::RepeatingClosure callback);
~WebContentsDisplayObserverView() override;
// BrowserListObserver overrides:
void OnBrowserSetLastActive(Browser* browser) override;
// views::WidgetObserver overrides:
void OnWidgetClosing(views::Widget* widget) override;
void OnWidgetBoundsChanged(views::Widget* widget,
const gfx::Rect& new_bounds) override;
// WebContentsDisplayObserver overrides:
const display::Display& GetCurrentDisplay() const override;
private:
// Calls |callback_| if the WebContents is no longer on |display_|.
void CheckForDisplayChange();
// Returns the display that is the closest to |wdiget_|.
virtual display::Display GetDisplayNearestWidget() const;
content::WebContents* const web_contents_;
// The widget containing |web_contents_|.
views::Widget* widget_;
// The display that |web_contents_| is on.
display::Display display_;
// Called when the display that |web_contents_| is on changes.
base::RepeatingClosure callback_;
};
} // namespace media_router
#endif // CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_WEB_CONTENTS_DISPLAY_OBSERVER_VIEW_H_
// Copyright 2018 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 <memory>
#include <utility>
#include "chrome/browser/ui/views/media_router/web_contents_display_observer_view.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/display.h"
#include "ui/gfx/geometry/rect.h"
namespace media_router {
class MockCallback {
public:
MOCK_METHOD0(OnDisplayChanged, void());
};
class TestWebContentsDisplayObserverView
: public WebContentsDisplayObserverView {
public:
TestWebContentsDisplayObserverView(content::WebContents* web_contents,
base::RepeatingCallback<void()> callback,
const display::Display& test_display)
: WebContentsDisplayObserverView(web_contents, std::move(callback)),
test_display_(test_display) {}
void set_test_display(const display::Display& test_display) {
test_display_ = test_display;
}
private:
display::Display GetDisplayNearestWidget() const override {
return test_display_;
}
display::Display test_display_;
};
class WebContentsDisplayObserverViewTest
: public ChromeRenderViewHostTestHarness {
public:
WebContentsDisplayObserverViewTest()
: ChromeRenderViewHostTestHarness(), display1_(101), display2_(102) {}
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
display_observer_ = std::make_unique<TestWebContentsDisplayObserverView>(
CreateTestWebContents(),
base::BindRepeating(&MockCallback::OnDisplayChanged,
base::Unretained(&callback_)),
display1_);
}
void TearDown() override {
display_observer_.reset();
ChromeRenderViewHostTestHarness::TearDown();
}
protected:
std::unique_ptr<TestWebContentsDisplayObserverView> display_observer_;
MockCallback callback_;
const display::Display display1_;
const display::Display display2_;
};
TEST_F(WebContentsDisplayObserverViewTest, NotifyWhenDisplayChanges) {
// Bounds change without display change should not trigger the callback.
display_observer_->OnWidgetBoundsChanged(nullptr, gfx::Rect(0, 0, 500, 500));
// If the widget is in a different display after moving, the callback should
// be called.
display_observer_->set_test_display(display2_);
EXPECT_CALL(callback_, OnDisplayChanged());
display_observer_->OnWidgetBoundsChanged(nullptr,
gfx::Rect(1920, 0, 500, 500));
EXPECT_EQ(display2_.id(), display_observer_->GetCurrentDisplay().id());
}
} // namespace media_router
......@@ -61,6 +61,11 @@
#include "ui/web_dialogs/web_dialog_delegate.h"
#include "url/origin.h"
#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
#include "chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.h"
#include "ui/display/display.h"
#endif
namespace media_router {
namespace {
......@@ -397,9 +402,10 @@ void MediaRouterUI::InitWithDefaultMediaSource(
OnDefaultPresentationChanged(delegate->GetDefaultPresentationRequest());
} else {
// Register for MediaRoute updates without a media source.
routes_observer_.reset(new UIMediaRoutesObserver(
routes_observer_ = std::make_unique<UIMediaRoutesObserver>(
router_, MediaSource::Id(),
base::Bind(&MediaRouterUI::OnRoutesUpdated, base::Unretained(this))));
base::BindRepeating(&MediaRouterUI::OnRoutesUpdated,
base::Unretained(this)));
}
}
......@@ -446,7 +452,7 @@ void MediaRouterUI::InitCommon(content::WebContents* initiator) {
collator_.reset();
}
query_result_manager_.reset(new QueryResultManager(router_));
query_result_manager_ = std::make_unique<QueryResultManager>(router_);
query_result_manager_->AddObserver(this);
// Use a placeholder URL as origin for mirroring.
......@@ -476,6 +482,11 @@ void MediaRouterUI::InitCommon(content::WebContents* initiator) {
// Get the current list of media routes, so that the WebUI will have routes
// information at initialization.
OnRoutesUpdated(router_->GetCurrentRoutes(), std::vector<MediaRoute::Id>());
#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
display_observer_ = WebContentsDisplayObserver::Create(
initiator_,
base::BindRepeating(&MediaRouterUI::UpdateSinks, base::Unretained(this)));
#endif
}
void MediaRouterUI::InitForTest(
......@@ -517,9 +528,10 @@ void MediaRouterUI::OnDefaultPresentationChanged(
// observer API for this case.
const MediaSource source_for_route_observer =
GetSourceForRouteObserver(sources);
routes_observer_.reset(new UIMediaRoutesObserver(
routes_observer_ = std::make_unique<UIMediaRoutesObserver>(
router_, source_for_route_observer.id(),
base::Bind(&MediaRouterUI::OnRoutesUpdated, base::Unretained(this))));
base::BindRepeating(&MediaRouterUI::OnRoutesUpdated,
base::Unretained(this)));
UpdateCastModes();
}
......@@ -534,9 +546,10 @@ void MediaRouterUI::OnDefaultPresentationRemoved() {
forced_cast_mode_ = base::nullopt;
// Register for MediaRoute updates without a media source.
routes_observer_.reset(new UIMediaRoutesObserver(
routes_observer_ = std::make_unique<UIMediaRoutesObserver>(
router_, MediaSource::Id(),
base::Bind(&MediaRouterUI::OnRoutesUpdated, base::Unretained(this))));
base::BindRepeating(&MediaRouterUI::OnRoutesUpdated,
base::Unretained(this)));
UpdateCastModes();
}
......@@ -581,7 +594,8 @@ void MediaRouterUI::UIInitialized() {
ui_initialized_ = true;
// Register for Issue updates.
issues_observer_.reset(new UIIssuesObserver(GetIssueManager(), this));
issues_observer_ =
std::make_unique<UIIssuesObserver>(GetIssueManager(), this);
issues_observer_->Init();
}
......@@ -792,9 +806,10 @@ void MediaRouterUI::SearchSinksAndCreateRoute(
// The CreateRoute() part of the function is accomplished in the callback
// OnSearchSinkResponseReceived().
router_->SearchSinks(sink_id, source_id, search_criteria, domain,
base::Bind(&MediaRouterUI::OnSearchSinkResponseReceived,
weak_factory_.GetWeakPtr(), cast_mode));
router_->SearchSinks(
sink_id, source_id, search_criteria, domain,
base::BindRepeating(&MediaRouterUI::OnSearchSinkResponseReceived,
weak_factory_.GetWeakPtr(), cast_mode));
}
bool MediaRouterUI::UserSelectedTabMirroringForCurrentOrigin() const {
......@@ -842,7 +857,7 @@ void MediaRouterUI::OnResultsUpdated(
});
if (ui_initialized_)
handler_->UpdateSinks(sinks_);
UpdateSinks();
}
void MediaRouterUI::SetIssue(const Issue& issue) {
......@@ -994,6 +1009,30 @@ GURL MediaRouterUI::GetFrameURL() const {
: GURL();
}
std::vector<MediaSinkWithCastModes> MediaRouterUI::GetEnabledSinks() const {
#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
if (!display_observer_)
return sinks_;
// Filter out the wired display sink for the display that the dialog is on.
// This is not the best place to do this because MRUI should not perform a
// provider-specific behavior, but we currently do not have a way to
// communicate dialog-specific information to/from the
// WiredDisplayMediaRouteProvider.
std::vector<MediaSinkWithCastModes> enabled_sinks;
const std::string display_sink_id =
WiredDisplayMediaRouteProvider::GetSinkIdForDisplay(
display_observer_->GetCurrentDisplay());
for (const MediaSinkWithCastModes& sink : sinks_) {
if (sink.sink.id() != display_sink_id)
enabled_sinks.push_back(sink);
}
return enabled_sinks;
#else
return sinks_;
#endif
}
std::string MediaRouterUI::GetPresentationRequestSourceName() const {
GURL gurl = GetFrameURL();
return gurl.SchemeIs(extensions::kExtensionScheme)
......@@ -1082,4 +1121,8 @@ IssueManager* MediaRouterUI::GetIssueManager() {
return router_->GetIssueManager();
}
void MediaRouterUI::UpdateSinks() {
handler_->UpdateSinks(GetEnabledSinks());
}
} // namespace media_router
......@@ -8,12 +8,15 @@
#include <memory>
#include <set>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
#include "chrome/browser/media/router/media_router_dialog_controller.h"
#include "chrome/browser/media/router/mojo/media_route_controller.h"
#include "chrome/browser/media/router/presentation/presentation_service_delegate_impl.h"
......@@ -26,8 +29,13 @@
#include "chrome/common/media_router/media_source.h"
#include "content/public/browser/web_ui_data_source.h"
#include "third_party/icu/source/common/unicode/uversion.h"
#include "ui/base/ui_features.h"
#include "url/gurl.h"
#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
#include "chrome/browser/ui/webui/media_router/web_contents_display_observer.h"
#endif
namespace content {
struct PresentationRequest;
class WebContents;
......@@ -145,13 +153,15 @@ class MediaRouterUI
// mode is MediaCastMode::DESKTOP_MIRROR.
virtual void RecordCastModeSelection(MediaCastMode cast_mode);
// Returns a subset of |sinks_| that should be listed in the dialog.
std::vector<MediaSinkWithCastModes> GetEnabledSinks() const;
// Returns the hostname of the PresentationRequest's parent frame URL.
std::string GetPresentationRequestSourceName() const;
std::string GetTruncatedPresentationRequestSourceName() const;
bool HasPendingRouteRequest() const {
return current_route_request_id_ != -1;
}
const std::vector<MediaSinkWithCastModes>& sinks() const { return sinks_; }
const std::vector<MediaRoute>& routes() const { return routes_; }
const std::vector<MediaRoute::Id>& joinable_route_ids() const {
return joinable_route_ids_;
......@@ -193,6 +203,13 @@ class MediaRouterUI
void InitForTest(std::unique_ptr<MediaRouterFileDialog> file_dialog);
#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
void set_display_observer_for_test(
std::unique_ptr<WebContentsDisplayObserver> display_observer) {
display_observer_ = std::move(display_observer);
}
#endif
private:
friend class MediaRouterUITest;
......@@ -216,6 +233,8 @@ class MediaRouterUI
FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest, SendMediaCommands);
FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest, SendMediaStatusUpdate);
FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest, SendInitialMediaStatusUpdate);
FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest,
UpdateSinksWhenDialogMovesToAnotherDisplay);
class UIIssuesObserver;
class WebContentsFullscreenOnLoadedObserver;
......@@ -223,8 +242,8 @@ class MediaRouterUI
class UIMediaRoutesObserver : public MediaRoutesObserver {
public:
using RoutesUpdatedCallback =
base::Callback<void(const std::vector<MediaRoute>&,
const std::vector<MediaRoute::Id>&)>;
base::RepeatingCallback<void(const std::vector<MediaRoute>&,
const std::vector<MediaRoute::Id>&)>;
UIMediaRoutesObserver(MediaRouter* router,
const MediaSource::Id& source_id,
const RoutesUpdatedCallback& callback);
......@@ -381,6 +400,9 @@ class MediaRouterUI
// Returns the IssueManager associated with |router_|.
IssueManager* GetIssueManager();
// Sends the current list of enabled sinks to |handler_|.
void UpdateSinks();
// Owned by the |web_ui| passed in the ctor, and guaranteed to be deleted
// only after it has deleted |this|.
MediaRouterWebUIMessageHandler* handler_ = nullptr;
......@@ -449,6 +471,11 @@ class MediaRouterUI
// If set, a cast mode that is required to be shown first.
base::Optional<MediaCastMode> forced_cast_mode_;
#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
// Keeps track of which display the dialog WebContents is on.
std::unique_ptr<WebContentsDisplayObserver> display_observer_;
#endif
// NOTE: Weak pointers must be invalidated before all other member variables.
// Therefore |weak_factory_| must be placed at the end.
base::WeakPtrFactory<MediaRouterUI> weak_factory_;
......
......@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "chrome/browser/media/router/media_router_factory.h"
#include "chrome/browser/media/router/test/media_router_mojo_test.h"
#include "chrome/browser/media/router/test/mock_media_router.h"
......@@ -31,6 +32,12 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
#include "chrome/browser/media/router/providers/wired_display/wired_display_media_route_provider.h"
#include "chrome/browser/ui/webui/media_router/web_contents_display_observer.h"
#include "ui/display/display.h"
#endif
using content::WebContents;
using testing::_;
using testing::AnyNumber;
......@@ -53,6 +60,8 @@ class MockMediaRouterWebUIMessageHandler
: MediaRouterWebUIMessageHandler(media_router_ui) {}
~MockMediaRouterWebUIMessageHandler() override {}
MOCK_METHOD1(UpdateSinks,
void(const std::vector<MediaSinkWithCastModes>& sinks));
MOCK_METHOD1(UpdateIssue, void(const Issue& issue));
MOCK_METHOD1(UpdateMediaRouteStatus, void(const MediaStatus& status));
MOCK_METHOD3(UpdateCastModes,
......@@ -71,6 +80,24 @@ class MockMediaRouterFileDialog : public MediaRouterFileDialog {
MOCK_METHOD1(OpenFileDialog, void(Browser* browser));
};
#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
class TestWebContentsDisplayObserver : public WebContentsDisplayObserver {
public:
explicit TestWebContentsDisplayObserver(const display::Display& display)
: display_(display) {}
~TestWebContentsDisplayObserver() override {}
const display::Display& GetCurrentDisplay() const override {
return display_;
}
void set_display(const display::Display& display) { display_ = display; }
private:
display::Display display_;
};
#endif // !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
class PresentationRequestCallbacks {
public:
PresentationRequestCallbacks() {}
......@@ -794,4 +821,67 @@ TEST_F(MediaRouterUITest, SetsForcedCastModeWithPresentationURLs) {
media_router_ui_.reset();
}
#if !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
// A wired display sink should not be on the sinks list when the dialog is on
// that display, to prevent showing a fullscreen presentation window over the
// controlling window.
TEST_F(MediaRouterUITest, UpdateSinksWhenDialogMovesToAnotherDisplay) {
const display::Display display1(1000001);
const display::Display display2(1000002);
const std::string display_sink_id1 =
WiredDisplayMediaRouteProvider::GetSinkIdForDisplay(display1);
const std::string display_sink_id2 =
WiredDisplayMediaRouteProvider::GetSinkIdForDisplay(display2);
CreateMediaRouterUI(profile());
auto display_observer_unique =
std::make_unique<TestWebContentsDisplayObserver>(display1);
TestWebContentsDisplayObserver* display_observer =
display_observer_unique.get();
media_router_ui_->set_display_observer_for_test(
std::move(display_observer_unique));
std::vector<MediaSinkWithCastModes> sinks;
MediaSinkWithCastModes display_sink1(
MediaSink(display_sink_id1, "sink", SinkIconType::GENERIC));
sinks.push_back(display_sink1);
MediaSinkWithCastModes display_sink2(
MediaSink(display_sink_id2, "sink", SinkIconType::GENERIC));
sinks.push_back(display_sink2);
MediaSinkWithCastModes sink3(MediaSink("id3", "sink", SinkIconType::GENERIC));
sinks.push_back(sink3);
media_router_ui_->OnResultsUpdated(sinks);
// Initially |display_sink1| should not be on the sinks list because we are on
// |display1|.
EXPECT_CALL(*message_handler_, UpdateSinks(_))
.WillOnce(Invoke([&display_sink_id1](
const std::vector<MediaSinkWithCastModes>& sinks) {
EXPECT_EQ(2u, sinks.size());
EXPECT_TRUE(std::find_if(sinks.begin(), sinks.end(),
[&display_sink_id1](
const MediaSinkWithCastModes& sink) {
return sink.sink.id() == display_sink_id1;
}) == sinks.end());
}));
media_router_ui_->UpdateSinks();
// Change the display to |display2|. Now |display_sink2| should be removed
// from the list of sinks.
EXPECT_CALL(*message_handler_, UpdateSinks(_))
.WillOnce(Invoke([&display_sink_id2](
const std::vector<MediaSinkWithCastModes>& sinks) {
EXPECT_EQ(2u, sinks.size());
EXPECT_TRUE(std::find_if(sinks.begin(), sinks.end(),
[&display_sink_id2](
const MediaSinkWithCastModes& sink) {
return sink.sink.id() == display_sink_id2;
}) == sinks.end());
}));
display_observer->set_display(display2);
media_router_ui_->UpdateSinks();
}
#endif // !defined(OS_MACOSX) || BUILDFLAG(MAC_VIEWS_BROWSER)
} // namespace media_router
......@@ -4,7 +4,9 @@
#include "chrome/browser/ui/webui/media_router/media_router_webui_message_handler.h"
#include <algorithm>
#include <memory>
#include <set>
#include <string>
#include <utility>
......@@ -506,7 +508,8 @@ void MediaRouterWebUIMessageHandler::OnRequestInitialData(
base::StringPrintf(kHelpPageUrlPrefix, 3249268));
std::unique_ptr<base::DictionaryValue> sinks_and_identity(
SinksAndIdentityToValue(media_router_ui_->sinks(), GetAccountInfo()));
SinksAndIdentityToValue(media_router_ui_->GetEnabledSinks(),
GetAccountInfo()));
initial_data.Set("sinksAndIdentity", std::move(sinks_and_identity));
std::unique_ptr<base::ListValue> routes(RoutesToValue(
......
......@@ -5,6 +5,8 @@
#ifndef CHROME_BROWSER_UI_WEBUI_MEDIA_ROUTER_MEDIA_ROUTER_WEBUI_MESSAGE_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_MEDIA_ROUTER_MEDIA_ROUTER_WEBUI_MESSAGE_HANDLER_H_
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
......@@ -41,7 +43,7 @@ class MediaRouterWebUIMessageHandler : public content::WebUIMessageHandler {
~MediaRouterWebUIMessageHandler() override;
// Methods to update the status displayed by the dialog.
void UpdateSinks(const std::vector<MediaSinkWithCastModes>& sinks);
virtual void UpdateSinks(const std::vector<MediaSinkWithCastModes>& sinks);
void UpdateRoutes(const std::vector<MediaRoute>& routes,
const std::vector<MediaRoute::Id>& joinable_route_ids,
const std::unordered_map<MediaRoute::Id, MediaCastMode>&
......
// Copyright 2018 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_WEBUI_MEDIA_ROUTER_WEB_CONTENTS_DISPLAY_OBSERVER_H_
#define CHROME_BROWSER_UI_WEBUI_MEDIA_ROUTER_WEB_CONTENTS_DISPLAY_OBSERVER_H_
#include <memory>
#include "base/callback.h"
namespace content {
class WebContents;
}
namespace display {
class Display;
}
namespace media_router {
// Keeps track of the display that a WebContents is on.
class WebContentsDisplayObserver {
public:
// |web_contents|: WebContents to observe.
// |callback|: Gets called whenever |web_contents| moves to another display.
static std::unique_ptr<WebContentsDisplayObserver> Create(
content::WebContents* web_contents,
base::RepeatingClosure callback);
virtual ~WebContentsDisplayObserver() = default;
virtual const display::Display& GetCurrentDisplay() const = 0;
};
} // namespace media_router
#endif // CHROME_BROWSER_UI_WEBUI_MEDIA_ROUTER_WEB_CONTENTS_DISPLAY_OBSERVER_H_
......@@ -4173,6 +4173,7 @@ test("unit_tests") {
"../browser/ui/views/frame/test_with_browser_view.h",
"../browser/ui/views/frame/web_contents_close_handler_unittest.cc",
"../browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc",
"../browser/ui/views/media_router/web_contents_display_observer_view_unittest.cc",
"../browser/ui/views/omnibox/omnibox_result_view_unittest.cc",
"../browser/ui/views/omnibox/omnibox_view_views_unittest.cc",
"../browser/ui/views/status_icons/status_tray_win_unittest.cc",
......
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