summaryrefslogtreecommitdiff
path: root/chromium/ui/views/mus
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui/views/mus')
-rw-r--r--chromium/ui/views/mus/BUILD.gn9
-rw-r--r--chromium/ui/views/mus/DEPS2
-rw-r--r--chromium/ui/views/mus/aura_init.cc2
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus.cc35
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus.h6
-rw-r--r--chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc1
-rw-r--r--chromium/ui/views/mus/drag_interactive_uitest.cc24
-rw-r--r--chromium/ui/views/mus/mus_client.cc15
-rw-r--r--chromium/ui/views/mus/mus_client.h10
-rw-r--r--chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc1
-rw-r--r--chromium/ui/views/mus/remote_view/BUILD.gn66
-rw-r--r--chromium/ui/views/mus/remote_view/README.md55
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_host.cc76
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_host.h60
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc151
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_provider.cc154
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_provider.h98
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_provider_test_api.cc18
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_provider_test_api.h29
-rw-r--r--chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc169
-rw-r--r--chromium/ui/views/mus/views_mus_test_suite.cc14
21 files changed, 933 insertions, 62 deletions
diff --git a/chromium/ui/views/mus/BUILD.gn b/chromium/ui/views/mus/BUILD.gn
index a8e4c997153..dfe239c16d5 100644
--- a/chromium/ui/views/mus/BUILD.gn
+++ b/chromium/ui/views/mus/BUILD.gn
@@ -80,9 +80,9 @@ jumbo_component("mus") {
]
if (is_linux && !is_android) {
- deps += [ "//components/font_service/public/cpp" ]
+ deps += [ "//components/services/font/public/cpp" ]
data_deps = [
- "//components/font_service",
+ "//components/services/font:font_service",
]
}
}
@@ -122,7 +122,7 @@ jumbo_static_library("test_support") {
":mus",
"//base",
"//base/test:test_support",
- "//mojo/edk/system",
+ "//mojo/edk",
"//services/catalog:lib",
"//services/service_manager/background:lib",
"//services/service_manager/public/cpp",
@@ -192,6 +192,7 @@ test("views_mus_unittests") {
"//ui/views",
"//ui/views:test_support_internal",
"//ui/views:views_unittests_sources",
+ "//ui/views/mus/remote_view:tests",
"//ui/wm",
"//url",
]
@@ -244,7 +245,7 @@ test("views_mus_interactive_ui_tests") {
":mus",
":test_support",
"//base",
- "//mojo/edk/system",
+ "//mojo/edk",
"//testing/gmock",
"//testing/gtest",
"//ui/aura",
diff --git a/chromium/ui/views/mus/DEPS b/chromium/ui/views/mus/DEPS
index 4d8a1fd285a..21ea014c764 100644
--- a/chromium/ui/views/mus/DEPS
+++ b/chromium/ui/views/mus/DEPS
@@ -1,7 +1,7 @@
include_rules = [
"+cc",
"-cc/blink",
- "+components/font_service/public",
+ "+components/services/font/public",
"+components/gpu",
"+mojo/cc",
"+mojo/common",
diff --git a/chromium/ui/views/mus/aura_init.cc b/chromium/ui/views/mus/aura_init.cc
index 7631ab57b0e..ea6490d4ec3 100644
--- a/chromium/ui/views/mus/aura_init.cc
+++ b/chromium/ui/views/mus/aura_init.cc
@@ -25,7 +25,7 @@
#include "ui/views/views_delegate.h"
#if defined(OS_LINUX)
-#include "components/font_service/public/cpp/font_loader.h"
+#include "components/services/font/public/cpp/font_loader.h"
#include "ui/gfx/platform_font_linux.h"
#endif
diff --git a/chromium/ui/views/mus/desktop_window_tree_host_mus.cc b/chromium/ui/views/mus/desktop_window_tree_host_mus.cc
index b24db3fc938..c417e738573 100644
--- a/chromium/ui/views/mus/desktop_window_tree_host_mus.cc
+++ b/chromium/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -4,7 +4,6 @@
#include "ui/views/mus/desktop_window_tree_host_mus.h"
-#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "ui/aura/client/aura_constants.h"
@@ -211,7 +210,7 @@ DesktopWindowTreeHostMus::DesktopWindowTreeHostMus(
MusClient::Get()->AddObserver(this);
MusClient::Get()->window_tree_client()->focus_synchronizer()->AddObserver(
this);
- desktop_native_widget_aura_->content_window()->AddObserver(this);
+ content_window()->AddObserver(this);
// DesktopNativeWidgetAura registers the association between |content_window_|
// and Widget, but code may also want to go from the root (window()) to the
// Widget. This call enables that.
@@ -226,7 +225,7 @@ DesktopWindowTreeHostMus::~DesktopWindowTreeHostMus() {
// the cursor-client needs to be unset on the root-window before
// |cursor_manager_| is destroyed.
aura::client::SetCursorClient(window(), nullptr);
- desktop_native_widget_aura_->content_window()->RemoveObserver(this);
+ content_window()->RemoveObserver(this);
MusClient::Get()->RemoveObserver(this);
MusClient::Get()->window_tree_client()->focus_synchronizer()->RemoveObserver(
this);
@@ -293,8 +292,7 @@ bool DesktopWindowTreeHostMus::ShouldSendClientAreaToServer() const {
return type == WIP::TYPE_WINDOW || type == WIP::TYPE_PANEL;
}
-void DesktopWindowTreeHostMus::Init(aura::Window* content_window,
- const Widget::InitParams& params) {
+void DesktopWindowTreeHostMus::Init(const Widget::InitParams& params) {
// |TYPE_WINDOW| and |TYPE_PANEL| are forced to transparent as otherwise the
// window is opaque and the client decorations drawn by the window manager
// would not be seen.
@@ -302,7 +300,7 @@ void DesktopWindowTreeHostMus::Init(aura::Window* content_window,
params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW ||
params.type == Widget::InitParams::TYPE_WINDOW ||
params.type == Widget::InitParams::TYPE_PANEL;
- content_window->SetTransparent(transparent);
+ content_window()->SetTransparent(transparent);
window()->SetTransparent(transparent);
window()->SetProperty(aura::client::kShowStateKey, params.show_state);
@@ -325,18 +323,14 @@ void DesktopWindowTreeHostMus::Init(aura::Window* content_window,
params.parent->GetHost()->window(), window());
}
- if (!params.accept_events) {
+ if (!params.accept_events)
window()->SetEventTargetingPolicy(ui::mojom::EventTargetingPolicy::NONE);
- } else {
- aura::WindowPortMus::Get(content_window)->SetCanAcceptDrops(true);
- }
+ else
+ aura::WindowPortMus::Get(content_window())->SetCanAcceptDrops(true);
}
void DesktopWindowTreeHostMus::OnNativeWidgetCreated(
const Widget::InitParams& params) {
- window()->SetName(params.name);
- desktop_native_widget_aura_->content_window()->SetName(
- "DesktopNativeWidgetAura - content window");
if (params.parent && params.parent->GetHost()) {
parent_ = static_cast<DesktopWindowTreeHostMus*>(params.parent->GetHost());
parent_->children_.insert(this);
@@ -396,8 +390,8 @@ void DesktopWindowTreeHostMus::Close() {
// Close doesn't delete this immediately, as 'this' may still be on the stack
// resulting in possible crashes when the stack unwindes.
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&DesktopWindowTreeHostMus::CloseNow,
- close_widget_factory_.GetWeakPtr()));
+ FROM_HERE, base::BindOnce(&DesktopWindowTreeHostMus::CloseNow,
+ close_widget_factory_.GetWeakPtr()));
}
void DesktopWindowTreeHostMus::CloseNow() {
@@ -495,10 +489,9 @@ void DesktopWindowTreeHostMus::CenterWindow(const gfx::Size& size) {
gfx::Rect bounds_to_center_in = GetWorkAreaBoundsInScreen();
// If there is a transient parent and it fits |size|, then center over it.
- aura::Window* content_window = desktop_native_widget_aura_->content_window();
- if (wm::GetTransientParent(content_window)) {
+ if (wm::GetTransientParent(content_window())) {
gfx::Rect transient_parent_bounds =
- wm::GetTransientParent(content_window)->GetBoundsInScreen();
+ wm::GetTransientParent(content_window())->GetBoundsInScreen();
if (transient_parent_bounds.height() >= size.height() &&
transient_parent_bounds.width() >= size.width()) {
bounds_to_center_in = transient_parent_bounds;
@@ -792,7 +785,7 @@ void DesktopWindowTreeHostMus::OnActiveFocusClientChanged(
void DesktopWindowTreeHostMus::OnWindowPropertyChanged(aura::Window* window,
const void* key,
intptr_t old) {
- DCHECK_EQ(window, desktop_native_widget_aura_->content_window());
+ DCHECK_EQ(window, content_window());
DCHECK(!window->GetRootWindow() || this->window() == window->GetRootWindow());
if (!this->window())
return;
@@ -851,4 +844,8 @@ void DesktopWindowTreeHostMus::SetBoundsInPixels(
}
}
+aura::Window* DesktopWindowTreeHostMus::content_window() {
+ return desktop_native_widget_aura_->content_window();
+}
+
} // namespace views
diff --git a/chromium/ui/views/mus/desktop_window_tree_host_mus.h b/chromium/ui/views/mus/desktop_window_tree_host_mus.h
index 2884d650d58..e1dca1c6735 100644
--- a/chromium/ui/views/mus/desktop_window_tree_host_mus.h
+++ b/chromium/ui/views/mus/desktop_window_tree_host_mus.h
@@ -61,8 +61,7 @@ class VIEWS_MUS_EXPORT DesktopWindowTreeHostMus
bool ShouldSendClientAreaToServer() const;
// DesktopWindowTreeHost:
- void Init(aura::Window* content_window,
- const Widget::InitParams& params) override;
+ void Init(const Widget::InitParams& params) override;
void OnNativeWidgetCreated(const Widget::InitParams& params) override;
void OnActiveWindowChanged(bool active) override;
void OnWidgetInitDone() override;
@@ -143,6 +142,9 @@ class VIEWS_MUS_EXPORT DesktopWindowTreeHostMus
void HideImpl() override;
void SetBoundsInPixels(const gfx::Rect& bounds_in_pixels) override;
+ // Accessor for DesktopNativeWidgetAura::content_window().
+ aura::Window* content_window();
+
internal::NativeWidgetDelegate* native_widget_delegate_;
DesktopNativeWidgetAura* desktop_native_widget_aura_;
diff --git a/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc b/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
index 34a105de7de..50851a87bfa 100644
--- a/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
+++ b/chromium/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
@@ -7,7 +7,6 @@
#include "base/debug/stack_trace.h"
#include "base/run_loop.h"
-#include "base/memory/ptr_util.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/client/transient_window_client.h"
diff --git a/chromium/ui/views/mus/drag_interactive_uitest.cc b/chromium/ui/views/mus/drag_interactive_uitest.cc
index 08bab8b2ae7..50bb37c5d49 100644
--- a/chromium/ui/views/mus/drag_interactive_uitest.cc
+++ b/chromium/ui/views/mus/drag_interactive_uitest.cc
@@ -124,11 +124,11 @@ void DragTest_Part2(int64_t display_id,
if (!result)
quit_closure.Run();
- ui::mojom::RemoteEventDispatcher* dispatcher =
- MusClient::Get()->GetTestingEventDispater();
- dispatcher->DispatchEvent(
+ ui::mojom::EventInjector* event_injector =
+ MusClient::Get()->GetTestingEventInjector();
+ event_injector->InjectEvent(
display_id, CreateMouseUpEvent(30, 30),
- base::Bind(&DragTest_Part3, display_id, quit_closure));
+ base::BindOnce(&DragTest_Part3, display_id, quit_closure));
}
void DragTest_Part1(int64_t display_id,
@@ -138,11 +138,11 @@ void DragTest_Part1(int64_t display_id,
if (!result)
quit_closure.Run();
- ui::mojom::RemoteEventDispatcher* dispatcher =
- MusClient::Get()->GetTestingEventDispater();
- dispatcher->DispatchEvent(
+ ui::mojom::EventInjector* event_injector =
+ MusClient::Get()->GetTestingEventInjector();
+ event_injector->InjectEvent(
display_id, CreateMouseMoveEvent(30, 30),
- base::Bind(&DragTest_Part2, display_id, quit_closure));
+ base::BindOnce(&DragTest_Part2, display_id, quit_closure));
}
TEST_F(DragTestInteractive, DragTest) {
@@ -175,11 +175,11 @@ TEST_F(DragTestInteractive, DragTest) {
{
base::RunLoop run_loop;
- ui::mojom::RemoteEventDispatcher* dispatcher =
- MusClient::Get()->GetTestingEventDispater();
- dispatcher->DispatchEvent(
+ ui::mojom::EventInjector* event_injector =
+ MusClient::Get()->GetTestingEventInjector();
+ event_injector->InjectEvent(
display_id, CreateMouseDownEvent(10, 10),
- base::Bind(&DragTest_Part1, display_id, run_loop.QuitClosure()));
+ base::BindOnce(&DragTest_Part1, display_id, run_loop.QuitClosure()));
run_loop.Run();
}
diff --git a/chromium/ui/views/mus/mus_client.cc b/chromium/ui/views/mus/mus_client.cc
index 9399f8228d7..1e049056dfb 100644
--- a/chromium/ui/views/mus/mus_client.cc
+++ b/chromium/ui/views/mus/mus_client.cc
@@ -104,15 +104,12 @@ MusClient::MusClient(service_manager::Connector* connector,
if (testing_state == MusClientTestingState::CREATE_TESTING_STATE) {
connector->BindInterface(ui::mojom::kServiceName, &server_test_ptr_);
- connector->BindInterface(ui::mojom::kServiceName,
- &remote_event_dispatcher_ptr_);
+ connector->BindInterface(ui::mojom::kServiceName, &event_injector_);
}
- window_tree_client_ = std::make_unique<aura::WindowTreeClient>(
- connector, this, nullptr /* window_manager_delegate */,
- nullptr /* window_tree_client_request */, std::move(io_task_runner));
+ window_tree_client_ = aura::WindowTreeClient::CreateForWindowTreeFactory(
+ connector, this, true, std::move(io_task_runner));
aura::Env::GetInstance()->SetWindowTreeClient(window_tree_client_.get());
- window_tree_client_->ConnectViaWindowTreeFactory();
pointer_watcher_event_router_ =
std::make_unique<PointerWatcherEventRouter>(window_tree_client_.get());
@@ -291,9 +288,9 @@ ui::mojom::WindowServerTest* MusClient::GetTestingInterface() const {
return server_test_ptr_.get();
}
-ui::mojom::RemoteEventDispatcher* MusClient::GetTestingEventDispater() const {
- CHECK(remote_event_dispatcher_ptr_);
- return remote_event_dispatcher_ptr_.get();
+ui::mojom::EventInjector* MusClient::GetTestingEventInjector() const {
+ CHECK(event_injector_);
+ return event_injector_.get();
}
std::unique_ptr<DesktopWindowTreeHost> MusClient::CreateDesktopWindowTreeHost(
diff --git a/chromium/ui/views/mus/mus_client.h b/chromium/ui/views/mus/mus_client.h
index 666f75eb533..0543e03247a 100644
--- a/chromium/ui/views/mus/mus_client.h
+++ b/chromium/ui/views/mus/mus_client.h
@@ -13,7 +13,7 @@
#include "base/macros.h"
#include "services/service_manager/public/cpp/identity.h"
-#include "services/ui/public/interfaces/remote_event_dispatcher.mojom.h"
+#include "services/ui/public/interfaces/event_injector.mojom.h"
#include "services/ui/public/interfaces/window_server_test.mojom.h"
#include "ui/aura/client/capture_client.h"
#include "ui/aura/mus/window_tree_client_delegate.h"
@@ -127,9 +127,9 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
// with MusClientTestingState::CREATE_TESTING_STATE.
ui::mojom::WindowServerTest* GetTestingInterface() const;
- // Returns an interface to dispatch events in the mus server. Only available
- // when created with MusClientTestingState::CREATE_TESTING_STATE.
- ui::mojom::RemoteEventDispatcher* GetTestingEventDispater() const;
+ // Returns an interface to inject events into the Window Service. Only
+ // available when created with MusClientTestingState::CREATE_TESTING_STATE.
+ ui::mojom::EventInjector* GetTestingEventInjector() const;
private:
friend class AuraInit;
@@ -182,7 +182,7 @@ class VIEWS_MUS_EXPORT MusClient : public aura::WindowTreeClientDelegate,
std::unique_ptr<PointerWatcherEventRouter> pointer_watcher_event_router_;
ui::mojom::WindowServerTestPtr server_test_ptr_;
- ui::mojom::RemoteEventDispatcherPtr remote_event_dispatcher_ptr_;
+ ui::mojom::EventInjectorPtr event_injector_;
DISALLOW_COPY_AND_ASSIGN(MusClient);
};
diff --git a/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc b/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc
index bdccaff4aa8..7634fff74bc 100644
--- a/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc
+++ b/chromium/ui/views/mus/pointer_watcher_event_router_unittest.cc
@@ -6,7 +6,6 @@
#include <memory>
-#include "base/memory/ptr_util.h"
#include "base/test/scoped_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/test/mus/window_tree_client_private.h"
diff --git a/chromium/ui/views/mus/remote_view/BUILD.gn b/chromium/ui/views/mus/remote_view/BUILD.gn
new file mode 100644
index 00000000000..a5232997d72
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/BUILD.gn
@@ -0,0 +1,66 @@
+# 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.
+
+source_set("remote_view_host") {
+ sources = [
+ "remote_view_host.cc",
+ "remote_view_host.h",
+ ]
+
+ deps = [
+ "//base",
+ "//ui/aura",
+ "//ui/views",
+ ]
+}
+
+source_set("remote_view_provider") {
+ sources = [
+ "remote_view_provider.cc",
+ "remote_view_provider.h",
+ ]
+
+ deps = [
+ "//base",
+ "//ui/aura",
+ "//ui/views",
+ "//ui/views/mus",
+ ]
+}
+
+source_set("test_support") {
+ testonly = true
+
+ sources = [
+ "remote_view_provider_test_api.cc",
+ "remote_view_provider_test_api.h",
+ ]
+
+ deps = [
+ ":remote_view_provider",
+ "//base",
+ ]
+}
+
+source_set("tests") {
+ testonly = true
+
+ sources = [
+ "remote_view_host_unittest.cc",
+ "remote_view_provider_unittest.cc",
+ ]
+
+ deps = [
+ ":remote_view_host",
+ ":remote_view_provider",
+ ":test_support",
+ "//base",
+ "//testing/gtest",
+ "//ui/aura",
+ "//ui/aura:test_support",
+ "//ui/base",
+ "//ui/views",
+ "//ui/views/mus",
+ ]
+}
diff --git a/chromium/ui/views/mus/remote_view/README.md b/chromium/ui/views/mus/remote_view/README.md
new file mode 100644
index 00000000000..391437e842e
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/README.md
@@ -0,0 +1,55 @@
+This directory contains helper classes to embed a `Window`.
+
+## `RemoteViewProvider`
+
+`RemoteViewProvider` wraps the work needed to provide a `Window` to another
+(remote) client. Typical usage is to create an instance of it with the window to
+provide to the remote client.
+
+e.g.
+```
+ ...
+
+ // Step 1: Prepares for embedding after |window_for_remote_client_| is ready.
+ void StartEmbed() {
+ remote_view_provider_ =
+ std::make_unique<views::RemoteViewProvider>(window_for_remote_client_);
+ remote_view_client->GetEmbedToken(base::BindOnce(
+ &EmbeddedClient::OnGotEmbedToken, base::Unretained(this)));
+ }
+
+ void OnGotEmbedToken(const base::UnguessableToken& token) {
+ // Step 2: Pass |token| to the embedder.
+ }
+
+ // A Window to to provide to the remote client.
+ aura::Window* window_for_remote_client_;
+
+ // Helper to prepare |window_for_remote_client_| for embedding.
+ std::unique_ptr<views::RemoteViewProvider> remote_view_provider_;
+
+ ...
+```
+
+## `RemoteViewHost`
+
+`RemoteViewHost` wraps the work on the embedder side and is a `NativeViewHost`
+that embeds the window from the `RemoteViewProvider`. `RemoveViewHost` is a
+`View` that you add to your existing `View` hierarchy.
+
+e.g.
+```
+ class EmbedderView : public views::View {
+ public:
+ ...
+ // Creates a RemoteViewHost using |token| from the embedded client.
+ void AddEmbeddedView(const base::UnguessableToken& token) {
+ // Ownership will be passed to the view hierarchy in AddChildView.
+ views::RemoteViewHost* remote_view_host = new RemoteViewHost();
+ remote_view_host->EmbedUsingToken(token, base::DoNothing());
+ AddChildView(remote_view_host);
+ }
+ ...
+ };
+```
+
diff --git a/chromium/ui/views/mus/remote_view/remote_view_host.cc b/chromium/ui/views/mus/remote_view/remote_view_host.cc
new file mode 100644
index 00000000000..c5f9e577de0
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/remote_view_host.cc
@@ -0,0 +1,76 @@
+// 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 "ui/views/mus/remote_view/remote_view_host.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/env.h"
+#include "ui/aura/mus/window_port_mus.h"
+
+namespace views {
+
+RemoteViewHost::RemoteViewHost() = default;
+RemoteViewHost::~RemoteViewHost() = default;
+
+void RemoteViewHost::EmbedUsingToken(const base::UnguessableToken& embed_token,
+ int embed_flags,
+ EmbedCallback callback) {
+ // Only works with mus.
+ DCHECK_EQ(aura::Env::Mode::MUS, aura::Env::GetInstanceDontCreate()->mode());
+
+ embed_token_ = embed_token;
+ embed_flags_ = embed_flags;
+ embed_callback_ = std::move(callback);
+
+ if (GetWidget())
+ CreateEmbeddingRoot();
+}
+
+void RemoteViewHost::CreateEmbeddingRoot() {
+ // Should not be attached to anything.
+ DCHECK(!native_view());
+
+ // There is a pending embed request.
+ DCHECK(!embed_token_.is_empty());
+
+ embedding_root_ = std::make_unique<aura::Window>(nullptr);
+ embedding_root_->set_owned_by_parent(false);
+
+ embedding_root_->SetName("RemoteViewHostWindow");
+ embedding_root_->SetProperty(aura::client::kEmbedType,
+ aura::client::WindowEmbedType::EMBED_IN_OWNER);
+ embedding_root_->SetType(aura::client::WINDOW_TYPE_CONTROL);
+ embedding_root_->Init(ui::LAYER_NOT_DRAWN);
+
+ // Must happen before EmbedUsingToken call for window server to figure out
+ // the relevant display.
+ Attach(embedding_root_.get());
+
+ aura::WindowPortMus::Get(embedding_root_.get())
+ ->EmbedUsingToken(embed_token_, embed_flags_,
+ base::BindOnce(&RemoteViewHost::OnEmbedResult,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void RemoteViewHost::OnEmbedResult(bool success) {
+ LOG_IF(ERROR, !success) << "Failed to embed, token=" << embed_token_;
+
+ if (!success && embedding_root_)
+ embedding_root_.reset();
+
+ if (embed_callback_)
+ std::move(embed_callback_).Run(success);
+}
+
+void RemoteViewHost::AddedToWidget() {
+ if (!native_view() && !embed_token_.is_empty())
+ CreateEmbeddingRoot();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/mus/remote_view/remote_view_host.h b/chromium/ui/views/mus/remote_view/remote_view_host.h
new file mode 100644
index 00000000000..44b1552f325
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/remote_view_host.h
@@ -0,0 +1,60 @@
+// 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 UI_VIEWS_MUS_REMOTE_VIEW_REMOTE_VIEW_HOST_H_
+#define UI_VIEWS_MUS_REMOTE_VIEW_REMOTE_VIEW_HOST_H_
+
+#include <memory>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/unguessable_token.h"
+#include "ui/aura/window.h"
+#include "ui/views/controls/native/native_view_host.h"
+
+namespace views {
+
+// A view at the embedder side to embed an aura::Window from another window
+// tree. Note this only works with mus.
+class RemoteViewHost : public views::NativeViewHost {
+ public:
+ RemoteViewHost();
+ ~RemoteViewHost() override;
+
+ // Embeds the remote contents after this view is added to a widget.
+ // |embed_token| is the token obtained from the WindowTree embed API
+ // (ScheduleEmbed/ForExistingClient). |embed_flags| are the embedding flags
+ // (see window_tree_constants.mojom). |callback| is an optional callback
+ // invoked with the embed result.
+ // Note that |callback| should not be used to add the view to a widget because
+ // the actual embedding only happens after the view is added.
+ using EmbedCallback = base::OnceCallback<void(bool success)>;
+ void EmbedUsingToken(const base::UnguessableToken& embed_token,
+ int embed_flags,
+ EmbedCallback callback);
+
+ private:
+ // Creates the embedding aura::Window and attach to it.
+ void CreateEmbeddingRoot();
+
+ // Invoked after the embed operation.
+ void OnEmbedResult(bool success);
+
+ // views::NativeViewHost:
+ void AddedToWidget() override;
+
+ base::UnguessableToken embed_token_;
+ int embed_flags_ = 0;
+ EmbedCallback embed_callback_;
+
+ std::unique_ptr<aura::Window> embedding_root_;
+ base::WeakPtrFactory<RemoteViewHost> weak_ptr_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteViewHost);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_MUS_REMOTE_VIEW_REMOTE_VIEW_HOST_H_
diff --git a/chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc b/chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc
new file mode 100644
index 00000000000..611c00151cd
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/remote_view_host_unittest.cc
@@ -0,0 +1,151 @@
+// 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 "ui/views/mus/remote_view/remote_view_host.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/unguessable_token.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/mus/test_window_tree.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+
+namespace views {
+
+namespace {
+
+// Embeds using |token| and waits for it. Returns true if embed succeeds.
+bool Embed(RemoteViewHost* host, const base::UnguessableToken& token) {
+ base::RunLoop run_loop;
+ bool embed_result = false;
+ host->EmbedUsingToken(
+ token, 0u /* no flags */,
+ base::BindOnce(
+ [](base::RunLoop* run_loop, bool* result, bool success) {
+ *result = success;
+ run_loop->Quit();
+ },
+ &run_loop, &embed_result));
+ run_loop.Run();
+ return embed_result;
+}
+
+} // namespace
+
+class RemoteViewHostTest : public aura::test::AuraTestBase {
+ public:
+ RemoteViewHostTest() = default;
+ ~RemoteViewHostTest() override = default;
+
+ // aura::test::AuraTestBase
+ void SetUp() override {
+ EnableMusWithTestWindowTree();
+ AuraTestBase::SetUp();
+ }
+
+ // Creates a widget to host |contents|.
+ std::unique_ptr<views::Widget> CreateTestWidget(views::View* contents) {
+ std::unique_ptr<views::Widget> widget = std::make_unique<views::Widget>();
+ views::Widget::InitParams params;
+ params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.bounds = gfx::Rect(0, 0, 100, 100);
+ params.context = root_window();
+ widget->Init(params);
+ widget->SetContentsView(contents);
+
+ return widget;
+ }
+
+ // Helper callback invoked during embed to simulate adding to widget during
+ // embed operation.
+ void CreateTestWidgetWhileEmbeddingHelper(
+ base::RunLoop* run_loop,
+ views::View* contents,
+ std::unique_ptr<views::Widget>* widget,
+ bool success) {
+ ASSERT_TRUE(success);
+ *widget = CreateTestWidget(contents);
+ run_loop->Quit();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RemoteViewHostTest);
+};
+
+// Tests that the embed operation fails with an unknown token and RemoteViewHost
+// will not be attached.
+TEST_F(RemoteViewHostTest, BadEmbed) {
+ const base::UnguessableToken unknown_token = base::UnguessableToken::Create();
+
+ // Ownership will be passed to |widget| later.
+ RemoteViewHost* host = new RemoteViewHost();
+ std::unique_ptr<views::Widget> widget = CreateTestWidget(host);
+ EXPECT_FALSE(host->native_view());
+
+ // Embed fails with unknown token.
+ EXPECT_FALSE(Embed(host, unknown_token));
+
+ // |host| is not attached after adding to a widget.
+ EXPECT_FALSE(host->native_view());
+}
+
+// Tests when RemoveViewHost is added to a widget before embedding.
+TEST_F(RemoteViewHostTest, AddToWidgetBeforeEmbed) {
+ const base::UnguessableToken token = base::UnguessableToken::Create();
+ window_tree()->AddScheduledEmbedToken(token);
+
+ // Ownership will be passed to |widget| later.
+ RemoteViewHost* host = new RemoteViewHost();
+
+ // |host| is not attached because embed operation is not performed.
+ EXPECT_FALSE(host->native_view());
+ std::unique_ptr<views::Widget> widget = CreateTestWidget(host);
+ EXPECT_FALSE(host->native_view());
+
+ // Embed succeeds.
+ EXPECT_TRUE(Embed(host, token));
+
+ // |host| is now attached to the embedding window.
+ EXPECT_TRUE(host->native_view());
+}
+
+// Tests when RemoveViewHost is added to a widget after embedding.
+TEST_F(RemoteViewHostTest, AddToWidgetAfterEmbed) {
+ const base::UnguessableToken token = base::UnguessableToken::Create();
+ window_tree()->AddScheduledEmbedToken(token);
+
+ // Ownership will be passed to |widget| later.
+ RemoteViewHost* host = new RemoteViewHost();
+
+ // Request embedding but it will be deferred until added to a widget.
+ base::RunLoop run_loop;
+ bool embed_result = false;
+ host->EmbedUsingToken(
+ token, 0u /* no flags */,
+ base::BindOnce(
+ [](base::RunLoop* run_loop, bool* result, bool success) {
+ *result = success;
+ run_loop->Quit();
+ },
+ &run_loop, &embed_result));
+
+ // |host| is not attached before adding to a widget.
+ EXPECT_FALSE(host->native_view());
+
+ // Add to a widget and wait for embed to finish.
+ std::unique_ptr<views::Widget> widget = CreateTestWidget(host);
+ run_loop.Run();
+
+ // |host| is attached after added to a widget.
+ EXPECT_TRUE(host->native_view());
+}
+
+} // namespace views
diff --git a/chromium/ui/views/mus/remote_view/remote_view_provider.cc b/chromium/ui/views/mus/remote_view/remote_view_provider.cc
new file mode 100644
index 00000000000..12286cd26af
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/remote_view_provider.cc
@@ -0,0 +1,154 @@
+// 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 "ui/views/mus/remote_view/remote_view_provider.h"
+
+#include <utility>
+
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "base/scoped_observer.h"
+#include "ui/aura/mus/embed_root.h"
+#include "ui/aura/mus/window_tree_client.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_observer.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/views/mus/mus_client.h"
+
+namespace views {
+
+// static
+aura::WindowTreeClient* RemoteViewProvider::window_tree_client_for_test =
+ nullptr;
+
+// Observes a window and invokes a callback when the window is destroyed.
+class RemoteViewProvider::EmbeddedWindowObserver : public aura::WindowObserver {
+ public:
+ EmbeddedWindowObserver(aura::Window* window, base::OnceClosure on_destroyed)
+ : window_observer_(this), on_destroyed_(std::move(on_destroyed)) {
+ window_observer_.Add(window);
+ }
+ ~EmbeddedWindowObserver() override = default;
+
+ // aura::WindowObserver:
+ void OnWindowDestroyed(aura::Window* window) override {
+ DCHECK(!on_destroyed_.is_null());
+
+ window_observer_.RemoveAll();
+ base::ResetAndReturn(&on_destroyed_).Run();
+ }
+
+ private:
+ ScopedObserver<aura::Window, EmbeddedWindowObserver> window_observer_;
+ base::OnceClosure on_destroyed_;
+
+ DISALLOW_COPY_AND_ASSIGN(EmbeddedWindowObserver);
+};
+
+// Observes a window and invokes a callback when the window size changes.
+class RemoteViewProvider::EmbeddingWindowObserver
+ : public aura::WindowObserver {
+ public:
+ using SizeChangedCallback = base::RepeatingCallback<void(const gfx::Size&)>;
+ EmbeddingWindowObserver(aura::Window* window,
+ const SizeChangedCallback& callback)
+ : window_observer_(this), on_size_changed_(callback) {
+ window_observer_.Add(window);
+ }
+ ~EmbeddingWindowObserver() override = default;
+
+ // aura::WindowObserver:
+ void OnWindowBoundsChanged(aura::Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ ui::PropertyChangeReason reason) override {
+ on_size_changed_.Run(new_bounds.size());
+ }
+ void OnWindowDestroyed(aura::Window* window) override {
+ window_observer_.RemoveAll();
+ }
+
+ private:
+ ScopedObserver<aura::Window, EmbeddingWindowObserver> window_observer_;
+ SizeChangedCallback on_size_changed_;
+
+ DISALLOW_COPY_AND_ASSIGN(EmbeddingWindowObserver);
+};
+
+RemoteViewProvider::RemoteViewProvider(aura::Window* embedded)
+ : embedded_(embedded) {
+ DCHECK(embedded_);
+ embedded_window_observer_ = std::make_unique<EmbeddedWindowObserver>(
+ embedded_, base::BindOnce(&RemoteViewProvider::OnEmbeddedWindowDestroyed,
+ base::Unretained(this)));
+}
+
+RemoteViewProvider::~RemoteViewProvider() = default;
+
+void RemoteViewProvider::GetEmbedToken(GetEmbedTokenCallback callback) {
+ DCHECK(embedded_);
+
+ if (embed_root_) {
+ std::move(callback).Run(embed_root_->token());
+ return;
+ }
+
+ DCHECK(get_embed_token_callback_.is_null());
+ get_embed_token_callback_ = std::move(callback);
+
+ aura::WindowTreeClient* window_tree_client = window_tree_client_for_test;
+ if (!window_tree_client) {
+ DCHECK(views::MusClient::Exists());
+ window_tree_client = views::MusClient::Get()->window_tree_client();
+ }
+
+ embed_root_ = window_tree_client->CreateEmbedRoot(this);
+}
+
+void RemoteViewProvider::SetCallbacks(const OnEmbedCallback& on_embed,
+ const OnUnembedCallback& on_unembed) {
+ on_embed_callback_ = on_embed;
+ on_unembed_callback_ = on_unembed;
+}
+
+void RemoteViewProvider::OnEmbeddedWindowDestroyed() {
+ embedded_ = nullptr;
+}
+
+void RemoteViewProvider::OnEmbeddingWindowResized(const gfx::Size& size) {
+ // |embedded_| is owned by external code. Bail if it is destroyed while being
+ // embedded.
+ if (!embedded_)
+ return;
+ embedded_->SetBounds(gfx::Rect(size));
+}
+
+void RemoteViewProvider::OnEmbedTokenAvailable(
+ const base::UnguessableToken& token) {
+ if (get_embed_token_callback_)
+ std::move(get_embed_token_callback_).Run(token);
+}
+
+void RemoteViewProvider::OnEmbed(aura::Window* window) {
+ DCHECK(embedded_);
+
+ embedding_window_observer_ = std::make_unique<EmbeddingWindowObserver>(
+ window, base::BindRepeating(&RemoteViewProvider::OnEmbeddingWindowResized,
+ base::Unretained(this)));
+ OnEmbeddingWindowResized(window->bounds().size());
+ window->AddChild(embedded_);
+
+ if (on_embed_callback_)
+ on_embed_callback_.Run(window);
+}
+
+void RemoteViewProvider::OnUnembed() {
+ embedding_window_observer_.reset();
+ embed_root_.reset();
+
+ if (on_unembed_callback_)
+ on_unembed_callback_.Run();
+}
+
+} // namespace views
diff --git a/chromium/ui/views/mus/remote_view/remote_view_provider.h b/chromium/ui/views/mus/remote_view/remote_view_provider.h
new file mode 100644
index 00000000000..9717d5f8a76
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/remote_view_provider.h
@@ -0,0 +1,98 @@
+// 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 UI_VIEWS_MUS_REMOTE_VIEW_REMOTE_VIEW_PROVIDER_H_
+#define UI_VIEWS_MUS_REMOTE_VIEW_REMOTE_VIEW_PROVIDER_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/unguessable_token.h"
+#include "ui/aura/mus/embed_root_delegate.h"
+
+namespace aura {
+class EmbedRoot;
+class Window;
+class WindowTreeClient;
+} // namespace aura
+
+namespace gfx {
+class Size;
+}
+
+namespace views {
+
+namespace test {
+class RemoteViewProviderTestApi;
+}
+
+// Creates an EmbedRoot for an embedded aura::Window on the client side and
+// updates the embedded window size when the embedder changes size. For example,
+// allows app list in ash to embed web-based "answer cards" that are rendered
+// by the browser. Note this works only with mus.
+class RemoteViewProvider : public aura::EmbedRootDelegate {
+ public:
+ explicit RemoteViewProvider(aura::Window* embedded);
+ ~RemoteViewProvider() override;
+
+ static void SetWindowTreeClientForTest(aura::WindowTreeClient* tree_client);
+
+ // Gets the embed token. An embed token is obtained from one of WindowTree's
+ // schedule embed calls (ScheduleEmbed or ScheduleEmbedForExistingClient). An
+ // embedder calls EmbedUsingToken using the token to embed desired contents.
+ // The embed token here is from an aura::EmbedRoot that uses
+ // ScheduleEmbedForExistingClient for embedding part of an existing
+ // WindowTreeClient. |callback| is invoked when the token is available.
+ using GetEmbedTokenCallback =
+ base::OnceCallback<void(const base::UnguessableToken& token)>;
+ void GetEmbedToken(GetEmbedTokenCallback callback);
+
+ // Optional callbacks to be invoked when embed or unembed happens.
+ using OnEmbedCallback = base::RepeatingCallback<void(aura::Window* embedder)>;
+ using OnUnembedCallback = base::RepeatingClosure;
+ void SetCallbacks(const OnEmbedCallback& on_embed,
+ const OnUnembedCallback& on_unembed);
+
+ private:
+ friend class test::RemoteViewProviderTestApi;
+
+ class EmbeddedWindowObserver;
+ class EmbeddingWindowObserver;
+
+ // Invoked when |embedded_| is destroyed.
+ void OnEmbeddedWindowDestroyed();
+
+ // Invoked when embedder changes size.
+ void OnEmbeddingWindowResized(const gfx::Size& size);
+
+ // aura::EmbedRootDelegate:
+ void OnEmbedTokenAvailable(const base::UnguessableToken& token) override;
+ void OnEmbed(aura::Window* window) override;
+ void OnUnembed() override;
+
+ // An aura::Window to be embedded. Not owned.
+ aura::Window* embedded_;
+
+ std::unique_ptr<aura::EmbedRoot> embed_root_;
+ GetEmbedTokenCallback get_embed_token_callback_;
+ OnEmbedCallback on_embed_callback_;
+ OnUnembedCallback on_unembed_callback_;
+
+ // An aura::WindowTreeClient for test. Use RemoteViewProviderTestApi to set
+ // it.
+ static aura::WindowTreeClient* window_tree_client_for_test;
+
+ // Observes the |embedded_| and clears it when it is gone.
+ std::unique_ptr<EmbeddedWindowObserver> embedded_window_observer_;
+
+ // Observes the embeddding window provided by embedder.
+ std::unique_ptr<EmbeddingWindowObserver> embedding_window_observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteViewProvider);
+};
+
+} // namespace views
+
+#endif // UI_VIEWS_MUS_REMOTE_VIEW_REMOTE_VIEW_PROVIDER_H_
diff --git a/chromium/ui/views/mus/remote_view/remote_view_provider_test_api.cc b/chromium/ui/views/mus/remote_view/remote_view_provider_test_api.cc
new file mode 100644
index 00000000000..c3668ba2114
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/remote_view_provider_test_api.cc
@@ -0,0 +1,18 @@
+// 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 "ui/views/mus/remote_view/remote_view_provider_test_api.h"
+
+#include "ui/views/mus/remote_view/remote_view_provider.h"
+
+namespace views {
+namespace test {
+
+void RemoteViewProviderTestApi::SetWindowTreeClient(
+ aura::WindowTreeClient* window_tree_client) {
+ RemoteViewProvider::window_tree_client_for_test = window_tree_client;
+}
+
+} // namespace test
+} // namespace views
diff --git a/chromium/ui/views/mus/remote_view/remote_view_provider_test_api.h b/chromium/ui/views/mus/remote_view/remote_view_provider_test_api.h
new file mode 100644
index 00000000000..49212fa6762
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/remote_view_provider_test_api.h
@@ -0,0 +1,29 @@
+// 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 UI_VIEWS_MUS_REMOTE_VIEW_REMOTE_VIEW_PROVIDER_TEST_API_H_
+#define UI_VIEWS_MUS_REMOTE_VIEW_REMOTE_VIEW_PROVIDER_TEST_API_H_
+
+#include "base/macros.h"
+
+namespace aura {
+class WindowTreeClient;
+}
+
+namespace views {
+namespace test {
+
+class RemoteViewProviderTestApi {
+ public:
+ // Sets an aura::WindowTreeClient to use with RemoteViewProvider.
+ static void SetWindowTreeClient(aura::WindowTreeClient* window_tree_client);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RemoteViewProviderTestApi);
+};
+
+} // namespace test
+} // namespace views
+
+#endif // UI_VIEWS_MUS_REMOTE_VIEW_REMOTE_VIEW_PROVIDER_TEST_API_H_
diff --git a/chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc b/chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc
new file mode 100644
index 00000000000..f87a3202ebc
--- /dev/null
+++ b/chromium/ui/views/mus/remote_view/remote_view_provider_unittest.cc
@@ -0,0 +1,169 @@
+// 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 "ui/views/mus/remote_view/remote_view_provider.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/unguessable_token.h"
+#include "ui/aura/mus/window_mus.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/mus/test_window_tree.h"
+#include "ui/aura/window.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/views/mus/remote_view/remote_view_provider_test_api.h"
+
+namespace views {
+
+class RemoteViewProviderTest : public aura::test::AuraTestBase {
+ public:
+ RemoteViewProviderTest() = default;
+ ~RemoteViewProviderTest() override = default;
+
+ // aura::test::AuraTestBase
+ void SetUp() override {
+ EnableMusWithTestWindowTree();
+ AuraTestBase::SetUp();
+
+ test::RemoteViewProviderTestApi::SetWindowTreeClient(
+ window_tree_client_impl());
+
+ embedded_ = std::make_unique<aura::Window>(nullptr);
+ embedded_->set_owned_by_parent(false);
+ embedded_->Init(ui::LAYER_NOT_DRAWN);
+ embedded_->SetBounds(gfx::Rect(100, 50));
+
+ provider_ = std::make_unique<RemoteViewProvider>(embedded_.get());
+ }
+
+ void TearDown() override {
+ // EmbedRoot in |provider_| must be released before WindowTreeClient.
+ provider_.reset();
+
+ AuraTestBase::TearDown();
+ }
+
+ // Gets the embed token and waits for it.
+ base::UnguessableToken GetEmbedToken() {
+ base::RunLoop run_loop;
+ base::UnguessableToken token;
+ provider_->GetEmbedToken(base::BindOnce(
+ [](base::RunLoop* run_loop, base::UnguessableToken* out_token,
+ const base::UnguessableToken& token) {
+ *out_token = token;
+ run_loop->Quit();
+ },
+ &run_loop, &token));
+ run_loop.Run();
+ return token;
+ }
+
+ // Simulates EmbedUsingToken call on embedder side and waits for
+ // WindowTreeClient to create a local embedder window.
+ aura::Window* SimulateEmbedUsingTokenAndGetEmbedder(
+ const base::UnguessableToken& token) {
+ base::RunLoop run_loop;
+ aura::Window* embedder = nullptr;
+ provider_->SetCallbacks(
+ base::BindRepeating(
+ [](base::RunLoop* run_loop, aura::Window** out_embedder,
+ aura::Window* embedder) {
+ *out_embedder = embedder;
+ run_loop->Quit();
+ },
+ &run_loop, &embedder),
+ base::DoNothing() /* OnUnembedCallback */);
+ window_tree()->AddEmbedRootForToken(token);
+ run_loop.Run();
+ return embedder;
+ }
+
+ // Helper to simulate embed.
+ aura::Window* SimulateEmbed() {
+ base::UnguessableToken token = GetEmbedToken();
+ if (token.is_empty()) {
+ ADD_FAILURE() << "Failed to get embed token.";
+ return nullptr;
+ }
+
+ return SimulateEmbedUsingTokenAndGetEmbedder(token);
+ }
+
+ // Simulates the embedder window close.
+ void SimulateEmbedderClose(aura::Window* embedder) {
+ base::RunLoop run_loop;
+ provider_->SetCallbacks(
+ base::DoNothing() /* OnEmbedCallback */,
+ base::BindRepeating([](base::RunLoop* run_loop) { run_loop->Quit(); },
+ &run_loop));
+
+ const ui::Id embedder_window_id =
+ aura::WindowMus::Get(embedder)->server_id();
+ window_tree()->RemoveEmbedderWindow(embedder_window_id);
+ run_loop.Run();
+ }
+
+ protected:
+ std::unique_ptr<aura::Window> embedded_;
+ std::unique_ptr<RemoteViewProvider> provider_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RemoteViewProviderTest);
+};
+
+// Tests the basics on the embedded client.
+TEST_F(RemoteViewProviderTest, Embed) {
+ aura::Window* embedder = SimulateEmbed();
+ ASSERT_TRUE(embedder);
+
+ // |embedded_| has the same non-empty size with |embedder| after embed.
+ EXPECT_EQ(embedded_->bounds().size(), embedder->bounds().size());
+ EXPECT_FALSE(embedded_->bounds().IsEmpty());
+ EXPECT_FALSE(embedder->bounds().IsEmpty());
+
+ // |embedded_| resizes with |embedder|.
+ const gfx::Rect new_bounds(embedder->bounds().width() + 100,
+ embedder->bounds().height() + 50);
+ embedder->SetBounds(new_bounds);
+ EXPECT_EQ(embedded_->bounds().size(), embedder->bounds().size());
+ EXPECT_FALSE(embedded_->bounds().IsEmpty());
+ EXPECT_FALSE(embedder->bounds().IsEmpty());
+}
+
+// Tests when |embedded_| is released first.
+TEST_F(RemoteViewProviderTest, EmbeddedReleasedFirst) {
+ SimulateEmbed();
+ embedded_.reset();
+}
+
+// Tests when |provider_| is released first.
+TEST_F(RemoteViewProviderTest, ClientReleasedFirst) {
+ SimulateEmbed();
+ provider_.reset();
+}
+
+// Tests when embedder goes away first.
+TEST_F(RemoteViewProviderTest, EmbedderReleasedFirst) {
+ aura::Window* embedder = SimulateEmbed();
+ ASSERT_TRUE(embedder);
+
+ SimulateEmbedderClose(embedder);
+}
+
+// Tests that the client can embed again.
+TEST_F(RemoteViewProviderTest, EmbedAgain) {
+ aura::Window* embedder = SimulateEmbed();
+ ASSERT_TRUE(embedder);
+
+ SimulateEmbedderClose(embedder);
+
+ aura::Window* new_embedder = SimulateEmbed();
+ ASSERT_TRUE(new_embedder);
+ EXPECT_NE(new_embedder, embedder);
+}
+
+} // namespace views
diff --git a/chromium/ui/views/mus/views_mus_test_suite.cc b/chromium/ui/views/mus/views_mus_test_suite.cc
index 0008b8eeaf4..3b2cfcd1c39 100644
--- a/chromium/ui/views/mus/views_mus_test_suite.cc
+++ b/chromium/ui/views/mus/views_mus_test_suite.cc
@@ -10,7 +10,6 @@
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
-#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
@@ -86,8 +85,8 @@ class ServiceManagerConnection {
base::Thread::Options options;
thread_.StartWithOptions(options);
thread_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&ServiceManagerConnection::SetUpConnections,
- base::Unretained(this), &wait));
+ FROM_HERE, base::BindOnce(&ServiceManagerConnection::SetUpConnections,
+ base::Unretained(this), &wait));
wait.Wait();
}
@@ -95,8 +94,9 @@ class ServiceManagerConnection {
base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
thread_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&ServiceManagerConnection::TearDownConnections,
- base::Unretained(this), &wait));
+ FROM_HERE,
+ base::BindOnce(&ServiceManagerConnection::TearDownConnections,
+ base::Unretained(this), &wait));
wait.Wait();
}
@@ -111,8 +111,8 @@ class ServiceManagerConnection {
base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
thread_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&ServiceManagerConnection::CloneConnector,
- base::Unretained(this), &wait));
+ FROM_HERE, base::BindOnce(&ServiceManagerConnection::CloneConnector,
+ base::Unretained(this), &wait));
wait.Wait();
DCHECK(service_manager_connector_);
return service_manager_connector_.get();