1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/bind.h" 6#include "base/memory/scoped_vector.h" 7#include "mojo/application_manager/application_manager.h" 8#include "mojo/public/cpp/application/application_delegate.h" 9#include "mojo/public/cpp/application/application_impl.h" 10#include "mojo/public/cpp/application/service_provider_impl.h" 11#include "mojo/public/interfaces/application/service_provider.mojom.h" 12#include "mojo/services/public/cpp/view_manager/types.h" 13#include "mojo/services/public/cpp/view_manager/view.h" 14#include "mojo/services/public/cpp/view_manager/view_manager.h" 15#include "mojo/services/public/cpp/view_manager/view_manager_client_factory.h" 16#include "mojo/services/public/cpp/view_manager/view_manager_delegate.h" 17#include "mojo/services/public/interfaces/view_manager/view_manager.mojom.h" 18#include "mojo/services/public/interfaces/window_manager/window_manager.mojom.h" 19#include "mojo/shell/shell_test_helper.h" 20#include "testing/gtest/include/gtest/gtest.h" 21 22namespace mojo { 23namespace { 24 25const char kTestServiceURL[] = "mojo:test_url"; 26 27void EmptyResultCallback(bool result) {} 28 29// Callback from Embed(). |result| is the result of the Embed() call and 30// |run_loop| the nested RunLoop. 31void ResultCallback(bool* result_cache, base::RunLoop* run_loop, bool result) { 32 *result_cache = result; 33 run_loop->Quit(); 34} 35 36// Responsible for establishing the initial ViewManagerService connection. 37// Blocks until result is determined. 38bool InitEmbed(ViewManagerInitService* view_manager_init, 39 const std::string& url) { 40 bool result = false; 41 base::RunLoop run_loop; 42 ServiceProviderPtr sp; 43 BindToProxy(new ServiceProviderImpl, &sp); 44 view_manager_init->Embed(url, sp.Pass(), 45 base::Bind(&ResultCallback, &result, &run_loop)); 46 run_loop.Run(); 47 return result; 48} 49 50class TestWindowManagerClient : public WindowManagerClient { 51 public: 52 typedef base::Callback<void(Id, Id)> 53 TwoNodeCallback; 54 55 explicit TestWindowManagerClient(base::RunLoop* run_loop) 56 : run_loop_(run_loop) {} 57 virtual ~TestWindowManagerClient() {} 58 59 void set_focus_changed_callback(const TwoNodeCallback& callback) { 60 focus_changed_callback_ = callback; 61 } 62 void set_active_window_changed_callback(const TwoNodeCallback& callback) { 63 active_window_changed_callback_ = callback; 64 } 65 66 private: 67 // Overridden from WindowManagerClient: 68 virtual void OnWindowManagerReady() MOJO_OVERRIDE { 69 run_loop_->Quit(); 70 } 71 virtual void OnCaptureChanged( 72 Id old_capture_node_id, 73 Id new_capture_node_id) MOJO_OVERRIDE { 74 } 75 virtual void OnFocusChanged( 76 Id old_focused_node_id, 77 Id new_focused_node_id) MOJO_OVERRIDE { 78 if (!focus_changed_callback_.is_null()) 79 focus_changed_callback_.Run(old_focused_node_id, new_focused_node_id); 80 } 81 virtual void OnActiveWindowChanged( 82 Id old_active_window, 83 Id new_active_window) MOJO_OVERRIDE { 84 if (!active_window_changed_callback_.is_null()) 85 active_window_changed_callback_.Run(old_active_window, new_active_window); 86 } 87 88 base::RunLoop* run_loop_; 89 TwoNodeCallback focus_changed_callback_; 90 TwoNodeCallback active_window_changed_callback_; 91 92 DISALLOW_COPY_AND_ASSIGN(TestWindowManagerClient); 93}; 94 95class TestApplicationLoader : public ApplicationLoader, 96 public ApplicationDelegate, 97 public ViewManagerDelegate { 98 public: 99 typedef base::Callback<void(View*)> RootAddedCallback; 100 101 explicit TestApplicationLoader(const RootAddedCallback& root_added_callback) 102 : root_added_callback_(root_added_callback) {} 103 virtual ~TestApplicationLoader() {} 104 105 private: 106 // Overridden from ApplicationLoader: 107 virtual void Load(ApplicationManager* application_manager, 108 const GURL& url, 109 scoped_refptr<LoadCallbacks> callbacks) MOJO_OVERRIDE { 110 ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication(); 111 if (!shell_handle.is_valid()) 112 return; 113 scoped_ptr<ApplicationImpl> app( 114 new ApplicationImpl(this, shell_handle.Pass())); 115 apps_.push_back(app.release()); 116 } 117 virtual void OnApplicationError(ApplicationManager* application_manager, 118 const GURL& url) MOJO_OVERRIDE {} 119 120 // Overridden from ApplicationDelegate: 121 virtual void Initialize(ApplicationImpl* app) MOJO_OVERRIDE { 122 view_manager_client_factory_.reset( 123 new ViewManagerClientFactory(app->shell(), this)); 124 } 125 126 virtual bool ConfigureIncomingConnection( 127 ApplicationConnection* connection) MOJO_OVERRIDE { 128 connection->AddService(view_manager_client_factory_.get()); 129 return true; 130 } 131 132 // Overridden from ViewManagerDelegate: 133 virtual void OnEmbed( 134 ViewManager* view_manager, 135 View* root, 136 ServiceProviderImpl* exported_services, 137 scoped_ptr<ServiceProvider> imported_services) MOJO_OVERRIDE { 138 root_added_callback_.Run(root); 139 } 140 virtual void OnViewManagerDisconnected( 141 ViewManager* view_manager) MOJO_OVERRIDE { 142 } 143 144 RootAddedCallback root_added_callback_; 145 146 ScopedVector<ApplicationImpl> apps_; 147 scoped_ptr<ViewManagerClientFactory> view_manager_client_factory_; 148 149 DISALLOW_COPY_AND_ASSIGN(TestApplicationLoader); 150}; 151 152} // namespace 153 154class WindowManagerApiTest : public testing::Test { 155 public: 156 WindowManagerApiTest() {} 157 virtual ~WindowManagerApiTest() {} 158 159 protected: 160 typedef std::pair<Id, Id> TwoIds; 161 162 Id WaitForEmbed() { 163 Id id; 164 base::RunLoop run_loop; 165 root_added_callback_ = base::Bind(&WindowManagerApiTest::OnEmbed, 166 base::Unretained(this), &id, &run_loop); 167 run_loop.Run(); 168 return id; 169 } 170 171 TwoIds WaitForFocusChange() { 172 TwoIds old_and_new; 173 base::RunLoop run_loop; 174 window_manager_client()->set_focus_changed_callback( 175 base::Bind(&WindowManagerApiTest::OnFocusChanged, 176 base::Unretained(this), &old_and_new, &run_loop)); 177 run_loop.Run(); 178 return old_and_new; 179 } 180 181 TwoIds WaitForActiveWindowChange() { 182 TwoIds old_and_new; 183 base::RunLoop run_loop; 184 window_manager_client()->set_active_window_changed_callback( 185 base::Bind(&WindowManagerApiTest::OnActiveWindowChanged, 186 base::Unretained(this), &old_and_new, &run_loop)); 187 run_loop.Run(); 188 return old_and_new; 189 } 190 191 Id OpenWindow() { 192 return OpenWindowWithURL(kTestServiceURL); 193 } 194 195 Id OpenWindowWithURL(const std::string& url) { 196 InitEmbed(view_manager_init_.get(), url); 197 return WaitForEmbed(); 198 } 199 200 TestWindowManagerClient* window_manager_client() { 201 return window_manager_client_.get(); 202 } 203 204 WindowManagerServicePtr window_manager_; 205 206 private: 207 // Overridden from testing::Test: 208 virtual void SetUp() MOJO_OVERRIDE { 209 test_helper_.Init(); 210 test_helper_.SetLoaderForURL( 211 scoped_ptr<ApplicationLoader>(new TestApplicationLoader(base::Bind( 212 &WindowManagerApiTest::OnRootAdded, base::Unretained(this)))), 213 GURL(kTestServiceURL)); 214 test_helper_.application_manager()->ConnectToService( 215 GURL("mojo:mojo_view_manager"), &view_manager_init_); 216 ASSERT_TRUE(InitEmbed(view_manager_init_.get(), 217 "mojo:mojo_core_window_manager")); 218 ConnectToWindowManager(); 219 } 220 virtual void TearDown() MOJO_OVERRIDE {} 221 222 void ConnectToWindowManager() { 223 test_helper_.application_manager()->ConnectToService( 224 GURL("mojo:mojo_core_window_manager"), &window_manager_); 225 base::RunLoop connect_loop; 226 window_manager_client_.reset(new TestWindowManagerClient(&connect_loop)); 227 window_manager_.set_client(window_manager_client()); 228 connect_loop.Run(); 229 } 230 231 void OnRootAdded(View* root) { 232 if (!root_added_callback_.is_null()) 233 root_added_callback_.Run(root); 234 } 235 236 void OnEmbed(Id* root_id, 237 base::RunLoop* loop, 238 View* root) { 239 *root_id = root->id(); 240 loop->Quit(); 241 } 242 243 void OnFocusChanged(TwoIds* old_and_new, 244 base::RunLoop* run_loop, 245 Id old_focused_node_id, 246 Id new_focused_node_id) { 247 DCHECK(old_and_new); 248 old_and_new->first = old_focused_node_id; 249 old_and_new->second = new_focused_node_id; 250 run_loop->Quit(); 251 } 252 253 void OnActiveWindowChanged(TwoIds* old_and_new, 254 base::RunLoop* run_loop, 255 Id old_focused_node_id, 256 Id new_focused_node_id) { 257 DCHECK(old_and_new); 258 old_and_new->first = old_focused_node_id; 259 old_and_new->second = new_focused_node_id; 260 run_loop->Quit(); 261 } 262 263 shell::ShellTestHelper test_helper_; 264 ViewManagerInitServicePtr view_manager_init_; 265 scoped_ptr<TestWindowManagerClient> window_manager_client_; 266 TestApplicationLoader::RootAddedCallback root_added_callback_; 267 268 DISALLOW_COPY_AND_ASSIGN(WindowManagerApiTest); 269}; 270 271TEST_F(WindowManagerApiTest, FocusAndActivateWindow) { 272 Id first_window = OpenWindow(); 273 window_manager_->FocusWindow(first_window, 274 base::Bind(&EmptyResultCallback)); 275 TwoIds ids = WaitForFocusChange(); 276 EXPECT_TRUE(ids.first == 0); 277 EXPECT_EQ(ids.second, first_window); 278 279 Id second_window = OpenWindow(); 280 window_manager_->ActivateWindow(second_window, 281 base::Bind(&EmptyResultCallback)); 282 ids = WaitForActiveWindowChange(); 283 EXPECT_EQ(ids.first, first_window); 284 EXPECT_EQ(ids.second, second_window); 285} 286 287} // namespace mojo 288