OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "chrome/browser/ui/views/ash/launcher/browser_launcher_item_controller.
h" | |
6 | |
7 #include <map> | |
8 #include <string> | |
9 | |
10 #include "ash/launcher/launcher_model.h" | |
11 #include "base/memory/scoped_ptr.h" | |
12 #include "chrome/browser/ui/tab_contents/tab_contents.h" | |
13 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
14 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h" | |
15 #include "chrome/browser/ui/views/ash/launcher/chrome_launcher_controller.h" | |
16 #include "chrome/test/base/chrome_render_view_host_test_harness.h" | |
17 #include "chrome/test/base/testing_profile.h" | |
18 #include "content/public/test/test_browser_thread.h" | |
19 #include "testing/gtest/include/gtest/gtest.h" | |
20 #include "third_party/skia/include/core/SkBitmap.h" | |
21 #include "ui/aura/client/aura_constants.h" | |
22 #include "ui/aura/client/activation_delegate.h" | |
23 #include "ui/aura/root_window.h" | |
24 #include "ui/aura/test/test_activation_client.h" | |
25 #include "ui/aura/test/test_window_delegate.h" | |
26 #include "ui/aura/window.h" | |
27 #include "ui/aura/window_delegate.h" | |
28 #include "ui/base/event.h" | |
29 | |
30 namespace { | |
31 | |
32 // Test implementation of AppTabHelper | |
33 class AppTabHelperImpl : public ChromeLauncherController::AppTabHelper { | |
34 public: | |
35 AppTabHelperImpl() {} | |
36 virtual ~AppTabHelperImpl() {} | |
37 | |
38 // Sets the id for the specified tab. The id is removed if Remove() is | |
39 // invoked. | |
40 void SetAppID(TabContents* tab, const std::string& id) { | |
41 tab_id_map_[tab] = id; | |
42 } | |
43 | |
44 // Returns true if there is an id registered for |tab|. | |
45 bool HasAppID(TabContents* tab) const { | |
46 return tab_id_map_.find(tab) != tab_id_map_.end(); | |
47 } | |
48 | |
49 // AppTabHelper implementation: | |
50 virtual std::string GetAppID(TabContents* tab) OVERRIDE { | |
51 return tab_id_map_.find(tab) != tab_id_map_.end() ? tab_id_map_[tab] : | |
52 std::string(); | |
53 } | |
54 | |
55 virtual bool IsValidID(const std::string& id) OVERRIDE { | |
56 for (TabToStringMap::const_iterator i = tab_id_map_.begin(); | |
57 i != tab_id_map_.end(); ++i) { | |
58 if (i->second == id) | |
59 return true; | |
60 } | |
61 return false; | |
62 } | |
63 | |
64 private: | |
65 typedef std::map<TabContents*, std::string> TabToStringMap; | |
66 | |
67 TabToStringMap tab_id_map_; | |
68 | |
69 DISALLOW_COPY_AND_ASSIGN(AppTabHelperImpl); | |
70 }; | |
71 | |
72 // Test implementation of AppIconLoader. | |
73 class AppIconLoaderImpl : public ChromeLauncherController::AppIconLoader { | |
74 public: | |
75 AppIconLoaderImpl() : fetch_count_(0) {} | |
76 virtual ~AppIconLoaderImpl() {} | |
77 | |
78 // Returns the number of times FetchImage() has been invoked and resets the | |
79 // count to 0. | |
80 int GetAndClearFetchCount() { | |
81 int value = fetch_count_; | |
82 fetch_count_ = 0; | |
83 return value; | |
84 } | |
85 | |
86 // AppIconLoader implementation: | |
87 virtual void FetchImage(const std::string& id) OVERRIDE { | |
88 fetch_count_++; | |
89 } | |
90 | |
91 private: | |
92 int fetch_count_; | |
93 | |
94 DISALLOW_COPY_AND_ASSIGN(AppIconLoaderImpl); | |
95 }; | |
96 | |
97 } // namespace | |
98 | |
99 class BrowserLauncherItemControllerTest : | |
100 public ChromeRenderViewHostTestHarness { | |
101 public: | |
102 BrowserLauncherItemControllerTest() | |
103 : browser_thread_(content::BrowserThread::UI, &message_loop_) { | |
104 } | |
105 | |
106 virtual void SetUp() OVERRIDE { | |
107 ChromeRenderViewHostTestHarness::SetUp(); | |
108 | |
109 activation_client_.reset( | |
110 new aura::test::TestActivationClient(root_window())); | |
111 launcher_model_.reset(new ash::LauncherModel); | |
112 launcher_delegate_.reset( | |
113 new ChromeLauncherController(profile(), launcher_model_.get())); | |
114 app_tab_helper_ = new AppTabHelperImpl; | |
115 app_icon_loader_ = new AppIconLoaderImpl; | |
116 launcher_delegate_->SetAppTabHelperForTest(app_tab_helper_); | |
117 launcher_delegate_->SetAppIconLoaderForTest(app_icon_loader_); | |
118 launcher_delegate_->Init(); | |
119 } | |
120 | |
121 virtual void TearDown() OVERRIDE { | |
122 launcher_delegate_.reset(); | |
123 ChromeRenderViewHostTestHarness::TearDown(); | |
124 } | |
125 | |
126 protected: | |
127 // Contains all the objects needed to create a BrowserLauncherItemController. | |
128 struct State : public aura::client::ActivationDelegate { | |
129 public: | |
130 State(BrowserLauncherItemControllerTest* test, | |
131 const std::string& app_id, | |
132 BrowserLauncherItemController::Type launcher_type) | |
133 : launcher_test(test), | |
134 window(NULL), | |
135 tab_strip(&tab_strip_delegate, test->profile()), | |
136 updater(&window, | |
137 &tab_strip, | |
138 test->launcher_delegate_.get(), | |
139 launcher_type, | |
140 app_id) { | |
141 window.Init(ui::LAYER_NOT_DRAWN); | |
142 launcher_test->root_window()->AddChild(&window); | |
143 launcher_test->activation_client_->ActivateWindow(&window); | |
144 aura::client::SetActivationDelegate(&window, this); | |
145 updater.Init(); | |
146 } | |
147 | |
148 ash::LauncherItem GetUpdaterItem() { | |
149 ash::LauncherID launcher_id = | |
150 BrowserLauncherItemController::TestApi(&updater).item_id(); | |
151 int index = launcher_test->launcher_model_->ItemIndexByID(launcher_id); | |
152 return launcher_test->launcher_model_->items()[index]; | |
153 } | |
154 | |
155 // aura::client::ActivationDelegate overrides. | |
156 virtual bool ShouldActivate(const ui::Event* event) OVERRIDE { | |
157 return true; | |
158 } | |
159 virtual void OnActivated() OVERRIDE { | |
160 updater.BrowserActivationStateChanged(); | |
161 } | |
162 virtual void OnLostActive() OVERRIDE { | |
163 updater.BrowserActivationStateChanged(); | |
164 } | |
165 | |
166 BrowserLauncherItemControllerTest* launcher_test; | |
167 aura::Window window; | |
168 TestTabStripModelDelegate tab_strip_delegate; | |
169 TabStripModel tab_strip; | |
170 BrowserLauncherItemController updater; | |
171 | |
172 private: | |
173 DISALLOW_COPY_AND_ASSIGN(State); | |
174 }; | |
175 | |
176 const std::string& GetAppID(ash::LauncherID id) const { | |
177 return launcher_delegate_->id_to_item_map_[id].app_id; | |
178 } | |
179 | |
180 void ResetAppTabHelper() { | |
181 launcher_delegate_->SetAppTabHelperForTest(app_tab_helper_); | |
182 } | |
183 | |
184 void ResetAppIconLoader() { | |
185 launcher_delegate_->SetAppIconLoaderForTest(app_icon_loader_); | |
186 } | |
187 | |
188 void UnpinAppsWithID(const std::string& app_id) { | |
189 launcher_delegate_->UnpinAppsWithID(app_id); | |
190 } | |
191 | |
192 const ash::LauncherItem& GetItem(BrowserLauncherItemController* updater) { | |
193 int index = launcher_model_->ItemIndexByID( | |
194 BrowserLauncherItemController::TestApi(updater).item_id()); | |
195 return launcher_model_->items()[index]; | |
196 } | |
197 | |
198 scoped_ptr<ash::LauncherModel> launcher_model_; | |
199 scoped_ptr<ChromeLauncherController> launcher_delegate_; | |
200 | |
201 // Owned by BrowserLauncherItemController. | |
202 AppTabHelperImpl* app_tab_helper_; | |
203 AppIconLoaderImpl* app_icon_loader_; | |
204 | |
205 scoped_ptr<aura::test::TestActivationClient> activation_client_; | |
206 | |
207 private: | |
208 content::TestBrowserThread browser_thread_; | |
209 std::vector<State*> states; | |
210 | |
211 DISALLOW_COPY_AND_ASSIGN(BrowserLauncherItemControllerTest); | |
212 }; | |
213 | |
214 // Verifies a new launcher item is added for TYPE_TABBED. | |
215 TEST_F(BrowserLauncherItemControllerTest, TabbedSetup) { | |
216 size_t initial_size = launcher_model_->items().size(); | |
217 { | |
218 TabContents tab_contents(CreateTestWebContents()); | |
219 State state(this, std::string(), | |
220 BrowserLauncherItemController::TYPE_TABBED); | |
221 | |
222 // There should be one more item. | |
223 ASSERT_EQ(initial_size + 1, launcher_model_->items().size()); | |
224 // New item should be added at the end. | |
225 EXPECT_EQ(ash::TYPE_TABBED, state.GetUpdaterItem().type); | |
226 } | |
227 | |
228 // Deleting the BrowserLauncherItemController should have removed the item. | |
229 ASSERT_EQ(initial_size, launcher_model_->items().size()); | |
230 | |
231 // Do the same, but this time add the tab first. | |
232 { | |
233 TabContents tab_contents(CreateTestWebContents()); | |
234 | |
235 TestTabStripModelDelegate tab_strip_delegate; | |
236 TabStripModel tab_strip(&tab_strip_delegate, profile()); | |
237 tab_strip.InsertTabContentsAt(0, &tab_contents, TabStripModel::ADD_ACTIVE); | |
238 aura::Window window(NULL); | |
239 window.Init(ui::LAYER_NOT_DRAWN); | |
240 root_window()->AddChild(&window); | |
241 BrowserLauncherItemController updater( | |
242 &window, &tab_strip, launcher_delegate_.get(), | |
243 BrowserLauncherItemController::TYPE_TABBED, std::string()); | |
244 updater.Init(); | |
245 | |
246 // There should be one more item. | |
247 ASSERT_EQ(initial_size + 1, launcher_model_->items().size()); | |
248 // New item should be added at the end. | |
249 EXPECT_EQ(ash::TYPE_TABBED, GetItem(&updater).type); | |
250 } | |
251 } | |
252 | |
253 // Verifies Panels items work. | |
254 TEST_F(BrowserLauncherItemControllerTest, PanelItem) { | |
255 size_t initial_size = launcher_model_->items().size(); | |
256 | |
257 // Add an App panel. | |
258 { | |
259 aura::Window window(NULL); | |
260 TestTabStripModelDelegate tab_strip_delegate; | |
261 TabStripModel tab_strip(&tab_strip_delegate, profile()); | |
262 TabContents panel_tab(CreateTestWebContents()); | |
263 app_tab_helper_->SetAppID(&panel_tab, "1"); // Panels are apps. | |
264 tab_strip.InsertTabContentsAt(0, &panel_tab, TabStripModel::ADD_ACTIVE); | |
265 BrowserLauncherItemController updater( | |
266 &window, &tab_strip, launcher_delegate_.get(), | |
267 BrowserLauncherItemController::TYPE_APP_PANEL, std::string()); | |
268 updater.Init(); | |
269 ASSERT_EQ(initial_size + 1, launcher_model_->items().size()); | |
270 EXPECT_EQ(ash::TYPE_APP_PANEL, GetItem(&updater).type); | |
271 EXPECT_EQ(static_cast<void*>(NULL), updater.favicon_loader_.get()); | |
272 } | |
273 | |
274 // Add an Extension panel. | |
275 { | |
276 aura::Window window(NULL); | |
277 TestTabStripModelDelegate tab_strip_delegate; | |
278 TabStripModel tab_strip(&tab_strip_delegate, profile()); | |
279 TabContents panel_tab(CreateTestWebContents()); | |
280 app_tab_helper_->SetAppID(&panel_tab, "1"); // Panels are apps. | |
281 tab_strip.InsertTabContentsAt(0, &panel_tab, TabStripModel::ADD_ACTIVE); | |
282 BrowserLauncherItemController updater( | |
283 &window, &tab_strip, launcher_delegate_.get(), | |
284 BrowserLauncherItemController::TYPE_EXTENSION_PANEL, std::string()); | |
285 updater.Init(); | |
286 ASSERT_EQ(initial_size + 1, launcher_model_->items().size()); | |
287 EXPECT_EQ(ash::TYPE_APP_PANEL, GetItem(&updater).type); | |
288 EXPECT_NE(static_cast<void*>(NULL), updater.favicon_loader_.get()); | |
289 } | |
290 } | |
291 | |
292 // Verifies pinned apps are persisted and restored. | |
293 TEST_F(BrowserLauncherItemControllerTest, PersistPinned) { | |
294 size_t initial_size = launcher_model_->items().size(); | |
295 TabContents tab1(CreateTestWebContents()); | |
296 | |
297 app_tab_helper_->SetAppID(&tab1, "1"); | |
298 | |
299 app_icon_loader_->GetAndClearFetchCount(); | |
300 launcher_delegate_->PinAppWithID("1"); | |
301 EXPECT_GT(app_icon_loader_->GetAndClearFetchCount(), 0); | |
302 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, | |
303 launcher_model_->items()[1].type); | |
304 EXPECT_TRUE(launcher_delegate_->IsAppPinned("1")); | |
305 EXPECT_FALSE(launcher_delegate_->IsAppPinned("0")); | |
306 EXPECT_EQ(initial_size + 1, launcher_model_->items().size()); | |
307 | |
308 launcher_delegate_.reset( | |
309 new ChromeLauncherController(profile(), launcher_model_.get())); | |
310 app_tab_helper_ = new AppTabHelperImpl; | |
311 app_tab_helper_->SetAppID(&tab1, "1"); | |
312 ResetAppTabHelper(); | |
313 app_icon_loader_ = new AppIconLoaderImpl; | |
314 ResetAppIconLoader(); | |
315 launcher_delegate_->Init(); | |
316 EXPECT_GT(app_icon_loader_->GetAndClearFetchCount(), 0); | |
317 ASSERT_EQ(initial_size + 1, launcher_model_->items().size()); | |
318 EXPECT_TRUE(launcher_delegate_->IsAppPinned("1")); | |
319 EXPECT_FALSE(launcher_delegate_->IsAppPinned("0")); | |
320 EXPECT_EQ(ash::TYPE_APP_SHORTCUT, | |
321 launcher_model_->items()[1].type); | |
322 | |
323 UnpinAppsWithID("1"); | |
324 ASSERT_EQ(initial_size, launcher_model_->items().size()); | |
325 } | |
326 | |
327 // Confirm that tabbed browsers handle activation correctly. | |
328 TEST_F(BrowserLauncherItemControllerTest, ActivateBrowsers) { | |
329 State state1(this, std::string(), BrowserLauncherItemController::TYPE_TABBED); | |
330 | |
331 // First browser is active. | |
332 EXPECT_EQ(ash::STATUS_ACTIVE, state1.GetUpdaterItem().status); | |
333 | |
334 { | |
335 // Both running. | |
336 State state2(this, std::string(), | |
337 BrowserLauncherItemController::TYPE_TABBED); | |
338 EXPECT_EQ(ash::STATUS_ACTIVE, state2.GetUpdaterItem().status); | |
339 EXPECT_EQ(ash::STATUS_RUNNING, state1.GetUpdaterItem().status); | |
340 | |
341 // Make first browser active again. | |
342 activation_client_->ActivateWindow(&state1.window); | |
343 EXPECT_EQ(ash::STATUS_ACTIVE, state1.GetUpdaterItem().status); | |
344 EXPECT_EQ(ash::STATUS_RUNNING, state2.GetUpdaterItem().status); | |
345 | |
346 // And back to second. | |
347 activation_client_->ActivateWindow(&state2.window); | |
348 EXPECT_EQ(ash::STATUS_ACTIVE, state2.GetUpdaterItem().status); | |
349 EXPECT_EQ(ash::STATUS_RUNNING, state1.GetUpdaterItem().status); | |
350 } | |
351 | |
352 // First browser should be active again after second is closed. | |
353 EXPECT_EQ(ash::STATUS_ACTIVE, state1.GetUpdaterItem().status); | |
354 } | |
355 | |
356 // Confirm that window activation works through the model. | |
357 TEST_F(BrowserLauncherItemControllerTest, SwitchDirectlyToApp) { | |
358 State state1(this, std::string(), | |
359 BrowserLauncherItemController::TYPE_TABBED); | |
360 int index1 = launcher_model_->ItemIndexByID(state1.GetUpdaterItem().id); | |
361 | |
362 // Second app is active and first is inactive. | |
363 State state2(this, std::string(), | |
364 BrowserLauncherItemController::TYPE_TABBED); | |
365 int index2 = launcher_model_->ItemIndexByID(state2.GetUpdaterItem().id); | |
366 | |
367 EXPECT_EQ(ash::STATUS_RUNNING, state1.GetUpdaterItem().status); | |
368 EXPECT_EQ(ash::STATUS_ACTIVE, state2.GetUpdaterItem().status); | |
369 EXPECT_EQ(&state2.window, activation_client_->GetActiveWindow()); | |
370 | |
371 // Test that we can properly switch to the first item. | |
372 ash::LauncherItem new_item1(launcher_model_->items()[index1]); | |
373 new_item1.status = ash::STATUS_ACTIVE; | |
374 launcher_model_->Set(index1, new_item1); | |
375 EXPECT_EQ(ash::STATUS_ACTIVE, launcher_model_->items()[index1].status); | |
376 EXPECT_EQ(ash::STATUS_RUNNING, launcher_model_->items()[index2].status); | |
377 EXPECT_EQ(&state1.window, activation_client_->GetActiveWindow()); | |
378 | |
379 // And to the second item active. | |
380 ash::LauncherItem new_item2(launcher_model_->items()[index2]); | |
381 new_item2.status = ash::STATUS_ACTIVE; | |
382 launcher_model_->Set(index2, new_item2); | |
383 EXPECT_EQ(ash::STATUS_RUNNING, launcher_model_->items()[index1].status); | |
384 EXPECT_EQ(ash::STATUS_ACTIVE, launcher_model_->items()[index2].status); | |
385 EXPECT_EQ(&state2.window, activation_client_->GetActiveWindow()); | |
386 } | |
387 | |
388 // Test attention states of windows. | |
389 TEST_F(BrowserLauncherItemControllerTest, FlashWindow) { | |
390 // App panel first | |
391 State app_state(this, "1", BrowserLauncherItemController::TYPE_APP_PANEL); | |
392 EXPECT_EQ(ash::STATUS_ACTIVE, app_state.GetUpdaterItem().status); | |
393 | |
394 // Active windows don't show attention. | |
395 app_state.window.SetProperty(aura::client::kDrawAttentionKey, true); | |
396 EXPECT_EQ(ash::STATUS_ACTIVE, app_state.GetUpdaterItem().status); | |
397 | |
398 // Then browser window | |
399 State browser_state( | |
400 this, std::string(), BrowserLauncherItemController::TYPE_TABBED); | |
401 // First browser is active. | |
402 EXPECT_EQ(ash::STATUS_ACTIVE, browser_state.GetUpdaterItem().status); | |
403 EXPECT_EQ(ash::STATUS_RUNNING, app_state.GetUpdaterItem().status); | |
404 | |
405 // App window should go to attention state. | |
406 app_state.window.SetProperty(aura::client::kDrawAttentionKey, true); | |
407 EXPECT_EQ(ash::STATUS_ATTENTION, app_state.GetUpdaterItem().status); | |
408 | |
409 // Activating app window should clear attention state. | |
410 activation_client_->ActivateWindow(&app_state.window); | |
411 EXPECT_EQ(ash::STATUS_ACTIVE, app_state.GetUpdaterItem().status); | |
412 } | |
OLD | NEW |