diff options
Diffstat (limited to 'chromium/ui/views/mus')
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(); |