Home | History | Annotate | Download | only in launcher
      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/ash/launcher/browser_launcher_item_controller.h"
      6 
      7 #include <map>
      8 #include <string>
      9 
     10 #include "ash/ash_switches.h"
     11 #include "ash/launcher/launcher_model.h"
     12 #include "base/command_line.h"
     13 #include "base/memory/scoped_ptr.h"
     14 #include "chrome/browser/favicon/favicon_tab_helper.h"
     15 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
     16 #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
     17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     18 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
     19 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
     20 #include "chrome/test/base/testing_profile.h"
     21 #include "content/public/browser/web_contents.h"
     22 #include "testing/gtest/include/gtest/gtest.h"
     23 #include "third_party/skia/include/core/SkBitmap.h"
     24 #include "ui/aura/client/activation_change_observer.h"
     25 #include "ui/aura/client/activation_delegate.h"
     26 #include "ui/aura/client/aura_constants.h"
     27 #include "ui/aura/root_window.h"
     28 #include "ui/aura/test/test_activation_client.h"
     29 #include "ui/aura/test/test_window_delegate.h"
     30 #include "ui/aura/window.h"
     31 #include "ui/aura/window_delegate.h"
     32 #include "ui/base/events/event.h"
     33 
     34 // TODO(skuhne): Remove this module together with the
     35 // browser_launcher_item_controller.* when the old launcher goes away.
     36 
     37 namespace {
     38 
     39 // Test implementation of AppTabHelper.
     40 class AppTabHelperImpl : public ChromeLauncherController::AppTabHelper {
     41  public:
     42   AppTabHelperImpl() {}
     43   virtual ~AppTabHelperImpl() {}
     44 
     45   // Sets the id for the specified tab. The id is removed if Remove() is
     46   // invoked.
     47   void SetAppID(content::WebContents* tab, const std::string& id) {
     48     tab_id_map_[tab] = id;
     49   }
     50 
     51   // Returns true if there is an id registered for |tab|.
     52   bool HasAppID(content::WebContents* tab) const {
     53     return tab_id_map_.find(tab) != tab_id_map_.end();
     54   }
     55 
     56   // AppTabHelper implementation:
     57   virtual std::string GetAppID(content::WebContents* tab) OVERRIDE {
     58     return tab_id_map_.find(tab) != tab_id_map_.end() ? tab_id_map_[tab] :
     59         std::string();
     60   }
     61 
     62   virtual bool IsValidID(const std::string& id) OVERRIDE {
     63     for (TabToStringMap::const_iterator i = tab_id_map_.begin();
     64          i != tab_id_map_.end(); ++i) {
     65       if (i->second == id)
     66         return true;
     67     }
     68     return false;
     69   }
     70 
     71  private:
     72   typedef std::map<content::WebContents*, std::string> TabToStringMap;
     73 
     74   TabToStringMap tab_id_map_;
     75 
     76   DISALLOW_COPY_AND_ASSIGN(AppTabHelperImpl);
     77 };
     78 
     79 // Test implementation of AppIconLoader.
     80 class AppIconLoaderImpl : public extensions::AppIconLoader {
     81  public:
     82   AppIconLoaderImpl() : fetch_count_(0) {}
     83   virtual ~AppIconLoaderImpl() {}
     84 
     85   // Returns the number of times FetchImage() has been invoked and resets the
     86   // count to 0.
     87   int GetAndClearFetchCount() {
     88     int value = fetch_count_;
     89     fetch_count_ = 0;
     90     return value;
     91   }
     92 
     93   // AppIconLoader implementation:
     94   virtual void FetchImage(const std::string& id) OVERRIDE {
     95     fetch_count_++;
     96   }
     97   virtual void ClearImage(const std::string& id) OVERRIDE {
     98   }
     99   virtual void UpdateImage(const std::string& id) OVERRIDE {
    100   }
    101 
    102  private:
    103   int fetch_count_;
    104 
    105   DISALLOW_COPY_AND_ASSIGN(AppIconLoaderImpl);
    106 };
    107 
    108 // Test implementation of TabStripModelDelegate.
    109 class TabHelperTabStripModelDelegate : public TestTabStripModelDelegate {
    110  public:
    111   TabHelperTabStripModelDelegate() {}
    112   virtual ~TabHelperTabStripModelDelegate() {}
    113 
    114   virtual void WillAddWebContents(content::WebContents* contents) OVERRIDE {
    115     // BrowserLauncherItemController assumes that all WebContents passed to it
    116     // have attached an extensions::TabHelper and a FaviconTabHelper. The
    117     // TestTabStripModelDelegate adds an extensions::TabHelper.
    118     TestTabStripModelDelegate::WillAddWebContents(contents);
    119     FaviconTabHelper::CreateForWebContents(contents);
    120   }
    121 
    122  private:
    123   DISALLOW_COPY_AND_ASSIGN(TabHelperTabStripModelDelegate);
    124 };
    125 
    126 }  // namespace
    127 
    128 // TODO(skuhne): Several of these unit tests need to be moved into a new home
    129 // when the old launcher & the browser launcher item controller are removed
    130 // (several of these tests are not testing the BrowserLauncherItemController -
    131 // but the LauncherController framework).
    132 class LauncherItemControllerPerAppTest
    133     : public ChromeRenderViewHostTestHarness {
    134  public:
    135   virtual void SetUp() OVERRIDE {
    136     ChromeRenderViewHostTestHarness::SetUp();
    137 
    138     activation_client_.reset(
    139         new aura::test::TestActivationClient(root_window()));
    140     launcher_model_.reset(new ash::LauncherModel);
    141     launcher_delegate_.reset(
    142         ChromeLauncherController::CreateInstance(profile(),
    143                                                  launcher_model_.get()));
    144     app_tab_helper_ = new AppTabHelperImpl;
    145     app_icon_loader_ = new AppIconLoaderImpl;
    146     launcher_delegate_->SetAppTabHelperForTest(app_tab_helper_);
    147     launcher_delegate_->SetAppIconLoaderForTest(app_icon_loader_);
    148     launcher_delegate_->Init();
    149   }
    150 
    151   virtual void TearDown() OVERRIDE {
    152     launcher_delegate_.reset();
    153     ChromeRenderViewHostTestHarness::TearDown();
    154   }
    155 
    156  protected:
    157   // Contains all the objects needed to create a BrowserLauncherItemController.
    158   struct State : public aura::client::ActivationDelegate,
    159                  public aura::client::ActivationChangeObserver {
    160    public:
    161     State(LauncherItemControllerPerAppTest* test,
    162           const std::string& app_id,
    163           BrowserLauncherItemController::Type launcher_type)
    164         : launcher_test(test),
    165           window(NULL),
    166           tab_strip(&tab_strip_delegate, test->profile()),
    167           updater(launcher_type,
    168                   &window,
    169                   &tab_strip,
    170                   test->launcher_delegate_.get(),
    171                   app_id) {
    172       window.Init(ui::LAYER_NOT_DRAWN);
    173       launcher_test->root_window()->AddChild(&window);
    174       launcher_test->activation_client_->ActivateWindow(&window);
    175       aura::client::SetActivationDelegate(&window, this);
    176       aura::client::SetActivationChangeObserver(&window, this);
    177       updater.Init();
    178     }
    179 
    180     ash::LauncherItem GetUpdaterItem() {
    181       ash::LauncherID launcher_id =
    182           BrowserLauncherItemController::TestApi(&updater).item_id();
    183       int index = launcher_test->launcher_model_->ItemIndexByID(launcher_id);
    184       return launcher_test->launcher_model_->items()[index];
    185     }
    186 
    187     // aura::client::ActivationDelegate overrides.
    188     virtual bool ShouldActivate() const OVERRIDE {
    189       return true;
    190     }
    191 
    192     // aura::client::ActivationChangeObserver overrides:
    193     virtual void OnWindowActivated(aura::Window* gained_active,
    194                                    aura::Window* lost_active) OVERRIDE {
    195       DCHECK(&window == gained_active || &window == lost_active);
    196       updater.BrowserActivationStateChanged();
    197     }
    198 
    199     LauncherItemControllerPerAppTest* launcher_test;
    200     aura::Window window;
    201     TabHelperTabStripModelDelegate tab_strip_delegate;
    202     TabStripModel tab_strip;
    203     BrowserLauncherItemController updater;
    204 
    205    private:
    206     DISALLOW_COPY_AND_ASSIGN(State);
    207   };
    208 
    209   const std::string& GetAppID(ash::LauncherID id) const {
    210     return launcher_delegate_->GetAppIdFromLauncherIdForTest(id);
    211   }
    212 
    213   void ResetAppTabHelper() {
    214     launcher_delegate_->SetAppTabHelperForTest(app_tab_helper_);
    215   }
    216 
    217   void ResetAppIconLoader() {
    218     launcher_delegate_->SetAppIconLoaderForTest(app_icon_loader_);
    219   }
    220 
    221   void UnpinAppsWithID(const std::string& app_id) {
    222     launcher_delegate_->UnpinAppsWithID(app_id);
    223   }
    224 
    225   const ash::LauncherItem& GetItem(BrowserLauncherItemController* updater) {
    226     int index = launcher_model_->ItemIndexByID(
    227         BrowserLauncherItemController::TestApi(updater).item_id());
    228     return launcher_model_->items()[index];
    229   }
    230 
    231   scoped_ptr<ash::LauncherModel> launcher_model_;
    232   scoped_ptr<ChromeLauncherController> launcher_delegate_;
    233 
    234   // Owned by BrowserLauncherItemController.
    235   AppTabHelperImpl* app_tab_helper_;
    236   AppIconLoaderImpl* app_icon_loader_;
    237 
    238   scoped_ptr<aura::test::TestActivationClient> activation_client_;
    239 };
    240 
    241 // Verify that the launcher item positions are persisted and restored.
    242 TEST_F(LauncherItemControllerPerAppTest, PersistLauncherItemPositions) {
    243   EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT,
    244             launcher_model_->items()[0].type);
    245   EXPECT_EQ(ash::TYPE_APP_LIST,
    246             launcher_model_->items()[1].type);
    247   scoped_ptr<content::WebContents> tab1(CreateTestWebContents());
    248   scoped_ptr<content::WebContents> tab2(CreateTestWebContents());
    249   app_tab_helper_->SetAppID(tab1.get(), "1");
    250   app_tab_helper_->SetAppID(tab1.get(), "2");
    251 
    252   EXPECT_FALSE(launcher_delegate_->IsAppPinned("1"));
    253   launcher_delegate_->PinAppWithID("1");
    254   EXPECT_TRUE(launcher_delegate_->IsAppPinned("1"));
    255   launcher_delegate_->PinAppWithID("2");
    256 
    257   EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT,
    258             launcher_model_->items()[0].type);
    259   EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
    260             launcher_model_->items()[1].type);
    261   EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
    262             launcher_model_->items()[2].type);
    263   EXPECT_EQ(ash::TYPE_APP_LIST,
    264             launcher_model_->items()[3].type);
    265 
    266   launcher_model_->Move(0, 2);
    267   EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
    268             launcher_model_->items()[0].type);
    269   EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
    270             launcher_model_->items()[1].type);
    271   EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT,
    272             launcher_model_->items()[2].type);
    273   EXPECT_EQ(ash::TYPE_APP_LIST,
    274             launcher_model_->items()[3].type);
    275 
    276   launcher_delegate_.reset();
    277   launcher_model_.reset(new ash::LauncherModel);
    278   launcher_delegate_.reset(
    279       ChromeLauncherController::CreateInstance(profile(),
    280                                                launcher_model_.get()));
    281   app_tab_helper_ = new AppTabHelperImpl;
    282   app_tab_helper_->SetAppID(tab1.get(), "1");
    283   app_tab_helper_->SetAppID(tab2.get(), "2");
    284   ResetAppTabHelper();
    285 
    286   launcher_delegate_->Init();
    287 
    288   EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
    289             launcher_model_->items()[0].type);
    290   EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
    291             launcher_model_->items()[1].type);
    292   EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT,
    293             launcher_model_->items()[2].type);
    294   EXPECT_EQ(ash::TYPE_APP_LIST,
    295             launcher_model_->items()[3].type);
    296 }
    297 
    298 class BrowserLauncherItemControllerTest
    299     : public LauncherItemControllerPerAppTest {
    300  public:
    301   BrowserLauncherItemControllerTest() {}
    302 
    303   virtual void SetUp() OVERRIDE {
    304     CommandLine::ForCurrentProcess()->AppendSwitch(
    305         ash::switches::kAshDisablePerAppLauncher);
    306 
    307     LauncherItemControllerPerAppTest::SetUp();
    308   }
    309 
    310   virtual void TearDown() OVERRIDE {
    311     LauncherItemControllerPerAppTest::TearDown();
    312   }
    313 };
    314 
    315 // Verifies a new launcher item is added for TYPE_TABBED.
    316 TEST_F(BrowserLauncherItemControllerTest, TabbedSetup) {
    317   size_t initial_size = launcher_model_->items().size();
    318   {
    319     scoped_ptr<content::WebContents> web_contents(CreateTestWebContents());
    320     State state(this, std::string(),
    321                 BrowserLauncherItemController::TYPE_TABBED);
    322 
    323     // There should be one more item.
    324     ASSERT_EQ(initial_size + 1, launcher_model_->items().size());
    325     // New item should be added at the end.
    326     EXPECT_EQ(ash::TYPE_TABBED, state.GetUpdaterItem().type);
    327   }
    328 
    329   // Deleting the BrowserLauncherItemController should have removed the item.
    330   ASSERT_EQ(initial_size, launcher_model_->items().size());
    331 
    332   // Do the same, but this time add the tab first.
    333   {
    334     scoped_ptr<content::WebContents> web_contents(CreateTestWebContents());
    335 
    336     TabHelperTabStripModelDelegate tab_strip_delegate;
    337     TabStripModel tab_strip(&tab_strip_delegate, profile());
    338     tab_strip.InsertWebContentsAt(0,
    339                                   web_contents.get(),
    340                                   TabStripModel::ADD_ACTIVE);
    341     aura::Window window(NULL);
    342     window.Init(ui::LAYER_NOT_DRAWN);
    343     root_window()->AddChild(&window);
    344     BrowserLauncherItemController updater(
    345         LauncherItemController::TYPE_TABBED,
    346         &window, &tab_strip, launcher_delegate_.get(),
    347         std::string());
    348     updater.Init();
    349 
    350     // There should be one more item.
    351     ASSERT_EQ(initial_size + 1, launcher_model_->items().size());
    352     // New item should be added at the end.
    353     EXPECT_EQ(ash::TYPE_TABBED, GetItem(&updater).type);
    354   }
    355 }
    356 
    357 // Verifies pinned apps are persisted and restored.
    358 TEST_F(BrowserLauncherItemControllerTest, PersistPinned) {
    359   size_t initial_size = launcher_model_->items().size();
    360   scoped_ptr<content::WebContents> tab1(CreateTestWebContents());
    361 
    362   app_tab_helper_->SetAppID(tab1.get(), "1");
    363 
    364   app_icon_loader_->GetAndClearFetchCount();
    365   launcher_delegate_->PinAppWithID("1");
    366   ash::LauncherID id = launcher_delegate_->GetLauncherIDForAppID("1");
    367   int app_index = launcher_model_->ItemIndexByID(id);
    368   EXPECT_GT(app_icon_loader_->GetAndClearFetchCount(), 0);
    369   EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
    370             launcher_model_->items()[app_index].type);
    371   EXPECT_TRUE(launcher_delegate_->IsAppPinned("1"));
    372   EXPECT_FALSE(launcher_delegate_->IsAppPinned("0"));
    373   EXPECT_EQ(initial_size + 1, launcher_model_->items().size());
    374 
    375   launcher_delegate_.reset();
    376   launcher_model_.reset(new ash::LauncherModel);
    377   launcher_delegate_.reset(
    378       ChromeLauncherController::CreateInstance(profile(),
    379                                                launcher_model_.get()));
    380   app_tab_helper_ = new AppTabHelperImpl;
    381   app_tab_helper_->SetAppID(tab1.get(), "1");
    382   ResetAppTabHelper();
    383   app_icon_loader_ = new AppIconLoaderImpl;
    384   ResetAppIconLoader();
    385   launcher_delegate_->Init();
    386   EXPECT_GT(app_icon_loader_->GetAndClearFetchCount(), 0);
    387   ASSERT_EQ(initial_size + 1, launcher_model_->items().size());
    388   EXPECT_TRUE(launcher_delegate_->IsAppPinned("1"));
    389   EXPECT_FALSE(launcher_delegate_->IsAppPinned("0"));
    390   EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
    391             launcher_model_->items()[app_index].type);
    392 
    393   UnpinAppsWithID("1");
    394   ASSERT_EQ(initial_size, launcher_model_->items().size());
    395 }
    396 
    397 // Verify that launcher item positions are persisted and restored.
    398 TEST_F(BrowserLauncherItemControllerTest,
    399     PersistLauncherItemPositionsPerBrowser) {
    400   int browser_shortcut_index = 0;
    401   int app_list_index = 1;
    402 
    403   EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT,
    404             launcher_model_->items()[browser_shortcut_index].type);
    405   EXPECT_EQ(ash::TYPE_APP_LIST,
    406             launcher_model_->items()[app_list_index].type);
    407 
    408   scoped_ptr<content::WebContents> tab1(CreateTestWebContents());
    409   scoped_ptr<content::WebContents> tab2(CreateTestWebContents());
    410 
    411   app_tab_helper_->SetAppID(tab1.get(), "1");
    412   app_tab_helper_->SetAppID(tab2.get(), "2");
    413 
    414   app_icon_loader_->GetAndClearFetchCount();
    415   launcher_delegate_->PinAppWithID("1");
    416   ash::LauncherID id = launcher_delegate_->GetLauncherIDForAppID("1");
    417   int app1_index = launcher_model_->ItemIndexByID(id);
    418 
    419   launcher_delegate_->PinAppWithID("2");
    420   id = launcher_delegate_->GetLauncherIDForAppID("2");
    421   int app2_index = launcher_model_->ItemIndexByID(id);
    422 
    423   launcher_model_->Move(browser_shortcut_index, app1_index);
    424 
    425   browser_shortcut_index = 1;
    426   app1_index = 0;
    427 
    428   EXPECT_GT(app_icon_loader_->GetAndClearFetchCount(), 0);
    429   EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
    430             launcher_model_->items()[app1_index].type);
    431   EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT,
    432             launcher_model_->items()[browser_shortcut_index].type);
    433   EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
    434             launcher_model_->items()[app2_index].type);
    435 
    436   launcher_delegate_.reset();
    437   launcher_model_.reset(new ash::LauncherModel);
    438   launcher_delegate_.reset(
    439       ChromeLauncherController::CreateInstance(profile(),
    440                                                launcher_model_.get()));
    441 
    442   app_tab_helper_ = new AppTabHelperImpl;
    443   app_tab_helper_->SetAppID(tab1.get(), "1");
    444   app_tab_helper_->SetAppID(tab2.get(), "2");
    445   ResetAppTabHelper();
    446   app_icon_loader_ = new AppIconLoaderImpl;
    447   ResetAppIconLoader();
    448   launcher_delegate_->Init();
    449 
    450   EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
    451             launcher_model_->items()[app1_index].type);
    452   EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT,
    453             launcher_model_->items()[browser_shortcut_index].type);
    454   EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
    455             launcher_model_->items()[app2_index].type);
    456 }
    457 
    458 // Confirm that tabbed browsers handle activation correctly.
    459 TEST_F(BrowserLauncherItemControllerTest, ActivateBrowsers) {
    460   State state1(this, std::string(), BrowserLauncherItemController::TYPE_TABBED);
    461 
    462   // First browser is active.
    463   EXPECT_EQ(ash::STATUS_ACTIVE, state1.GetUpdaterItem().status);
    464 
    465   {
    466     // Both running.
    467     State state2(this, std::string(),
    468                  BrowserLauncherItemController::TYPE_TABBED);
    469     EXPECT_EQ(ash::STATUS_ACTIVE, state2.GetUpdaterItem().status);
    470     EXPECT_EQ(ash::STATUS_RUNNING, state1.GetUpdaterItem().status);
    471 
    472     // Make first browser active again.
    473     activation_client_->ActivateWindow(&state1.window);
    474     EXPECT_EQ(ash::STATUS_ACTIVE, state1.GetUpdaterItem().status);
    475     EXPECT_EQ(ash::STATUS_RUNNING, state2.GetUpdaterItem().status);
    476 
    477     // And back to second.
    478     activation_client_->ActivateWindow(&state2.window);
    479     EXPECT_EQ(ash::STATUS_ACTIVE, state2.GetUpdaterItem().status);
    480     EXPECT_EQ(ash::STATUS_RUNNING, state1.GetUpdaterItem().status);
    481   }
    482 
    483   // First browser should be active again after second is closed.
    484   EXPECT_EQ(ash::STATUS_ACTIVE, state1.GetUpdaterItem().status);
    485 }
    486 
    487 // Confirm that window activation works through the model.
    488 TEST_F(BrowserLauncherItemControllerTest, SwitchDirectlyToApp) {
    489   State state1(this, std::string(),
    490                BrowserLauncherItemController::TYPE_TABBED);
    491   int index1 = launcher_model_->ItemIndexByID(state1.GetUpdaterItem().id);
    492 
    493   // Second app is active and first is inactive.
    494   State state2(this, std::string(),
    495                BrowserLauncherItemController::TYPE_TABBED);
    496   int index2 = launcher_model_->ItemIndexByID(state2.GetUpdaterItem().id);
    497 
    498   EXPECT_EQ(ash::STATUS_RUNNING, state1.GetUpdaterItem().status);
    499   EXPECT_EQ(ash::STATUS_ACTIVE, state2.GetUpdaterItem().status);
    500   EXPECT_EQ(&state2.window, activation_client_->GetActiveWindow());
    501 
    502   // Test that we can properly switch to the first item.
    503   ash::LauncherItem new_item1(launcher_model_->items()[index1]);
    504   new_item1.status = ash::STATUS_ACTIVE;
    505   launcher_model_->Set(index1, new_item1);
    506   EXPECT_EQ(ash::STATUS_ACTIVE, launcher_model_->items()[index1].status);
    507   EXPECT_EQ(ash::STATUS_RUNNING, launcher_model_->items()[index2].status);
    508   EXPECT_EQ(&state1.window, activation_client_->GetActiveWindow());
    509 
    510   // And to the second item active.
    511   ash::LauncherItem new_item2(launcher_model_->items()[index2]);
    512   new_item2.status = ash::STATUS_ACTIVE;
    513   launcher_model_->Set(index2, new_item2);
    514   EXPECT_EQ(ash::STATUS_RUNNING, launcher_model_->items()[index1].status);
    515   EXPECT_EQ(ash::STATUS_ACTIVE, launcher_model_->items()[index2].status);
    516   EXPECT_EQ(&state2.window, activation_client_->GetActiveWindow());
    517 }
    518 
    519 // Test attention states of windows.
    520 TEST_F(BrowserLauncherItemControllerTest, FlashWindow) {
    521   // App panel first
    522   State app_state(this, "1", BrowserLauncherItemController::TYPE_APP_PANEL);
    523   EXPECT_EQ(ash::STATUS_ACTIVE, app_state.GetUpdaterItem().status);
    524 
    525   // Active windows don't show attention.
    526   app_state.window.SetProperty(aura::client::kDrawAttentionKey, true);
    527   EXPECT_EQ(ash::STATUS_ACTIVE, app_state.GetUpdaterItem().status);
    528 
    529   // Then browser window
    530   State browser_state(
    531       this, std::string(), BrowserLauncherItemController::TYPE_TABBED);
    532   // First browser is active.
    533   EXPECT_EQ(ash::STATUS_ACTIVE, browser_state.GetUpdaterItem().status);
    534   EXPECT_EQ(ash::STATUS_RUNNING, app_state.GetUpdaterItem().status);
    535 
    536   // App window should go to attention state.
    537   app_state.window.SetProperty(aura::client::kDrawAttentionKey, true);
    538   EXPECT_EQ(ash::STATUS_ATTENTION, app_state.GetUpdaterItem().status);
    539 
    540   // Activating app window should clear attention state.
    541   activation_client_->ActivateWindow(&app_state.window);
    542   EXPECT_EQ(ash::STATUS_ACTIVE, app_state.GetUpdaterItem().status);
    543 }
    544