Home | History | Annotate | Download | only in panels
      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/panels/base_panel_browser_test.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/command_line.h"
      9 #include "base/memory/weak_ptr.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/path_service.h"
     12 #include "base/strings/string_number_conversions.h"
     13 #include "chrome/browser/chrome_notification_types.h"
     14 #include "chrome/browser/extensions/extension_prefs.h"
     15 #include "chrome/browser/extensions/extension_service.h"
     16 #include "chrome/browser/profiles/profile.h"
     17 #include "chrome/browser/ui/browser.h"
     18 #include "chrome/browser/ui/browser_window.h"
     19 #include "chrome/browser/ui/panels/detached_panel_collection.h"
     20 #include "chrome/browser/ui/panels/native_panel.h"
     21 #include "chrome/browser/ui/panels/panel_collection.h"
     22 #include "chrome/browser/ui/panels/panel_mouse_watcher.h"
     23 #include "chrome/browser/ui/panels/stacked_panel_collection.h"
     24 #include "chrome/browser/ui/panels/test_panel_active_state_observer.h"
     25 #include "chrome/browser/ui/panels/test_panel_mouse_watcher.h"
     26 #include "chrome/common/chrome_paths.h"
     27 #include "chrome/common/chrome_switches.h"
     28 #include "chrome/common/extensions/extension_manifest_constants.h"
     29 #include "chrome/test/base/interactive_test_utils.h"
     30 #include "chrome/test/base/ui_test_utils.h"
     31 #include "content/public/browser/notification_service.h"
     32 #include "content/public/common/url_constants.h"
     33 #include "content/public/test/web_contents_tester.h"
     34 #include "sync/api/string_ordinal.h"
     35 
     36 #if defined(OS_LINUX)
     37 #include "chrome/browser/ui/browser_window.h"
     38 #include "ui/base/x/x11_util.h"
     39 #endif
     40 
     41 #if defined(OS_LINUX) && !defined(USE_AURA)
     42 #include "ui/base/x/active_window_watcher_x.h"
     43 #endif
     44 
     45 #if defined(OS_MACOSX)
     46 #include "base/mac/scoped_nsautorelease_pool.h"
     47 #include "chrome/browser/ui/cocoa/run_loop_testing.h"
     48 #endif
     49 
     50 using content::WebContentsTester;
     51 using extensions::Extension;
     52 
     53 namespace {
     54 
     55 const gfx::Rect kTestingPrimaryDisplayArea = gfx::Rect(0, 0, 800, 600);
     56 const gfx::Rect kTestingPrimaryWorkArea = gfx::Rect(0, 0, 800, 580);
     57 
     58 struct MockDesktopBar {
     59   bool auto_hiding_enabled;
     60   DisplaySettingsProvider::DesktopBarVisibility visibility;
     61   int thickness;
     62 };
     63 
     64 class MockDisplaySettingsProviderImpl :
     65     public BasePanelBrowserTest::MockDisplaySettingsProvider {
     66  public:
     67   explicit MockDisplaySettingsProviderImpl();
     68   virtual ~MockDisplaySettingsProviderImpl() { }
     69 
     70   // Overridden from DisplaySettingsProvider:
     71   virtual gfx::Rect GetPrimaryDisplayArea() const OVERRIDE;
     72   virtual gfx::Rect GetPrimaryWorkArea() const OVERRIDE;
     73   virtual gfx::Rect GetDisplayAreaMatching(
     74       const gfx::Rect& bounds) const OVERRIDE;
     75   virtual gfx::Rect GetWorkAreaMatching(
     76       const gfx::Rect& bounds) const OVERRIDE;
     77   virtual bool IsAutoHidingDesktopBarEnabled(
     78       DesktopBarAlignment alignment) OVERRIDE;
     79   virtual int GetDesktopBarThickness(
     80       DesktopBarAlignment alignment) const OVERRIDE;
     81   virtual DesktopBarVisibility GetDesktopBarVisibility(
     82       DesktopBarAlignment alignment) const OVERRIDE;
     83 
     84   // Overridden from MockDisplaySettingsProvider:
     85   virtual void SetPrimaryDisplay(
     86       const gfx::Rect& display_area, const gfx::Rect& work_area) OVERRIDE;
     87   virtual void SetSecondaryDisplay(
     88       const gfx::Rect& display_area, const gfx::Rect& work_area) OVERRIDE;
     89   virtual void EnableAutoHidingDesktopBar(DesktopBarAlignment alignment,
     90                                           bool enabled,
     91                                           int thickness) OVERRIDE;
     92   virtual void SetDesktopBarVisibility(
     93       DesktopBarAlignment alignment, DesktopBarVisibility visibility) OVERRIDE;
     94   virtual void SetDesktopBarThickness(DesktopBarAlignment alignment,
     95                                       int thickness) OVERRIDE;
     96 
     97  private:
     98   gfx::Rect primary_display_area_;
     99   gfx::Rect primary_work_area_;
    100   gfx::Rect secondary_display_area_;
    101   gfx::Rect secondary_work_area_;
    102   MockDesktopBar mock_desktop_bars[3];
    103 
    104   DISALLOW_COPY_AND_ASSIGN(MockDisplaySettingsProviderImpl);
    105 };
    106 
    107 
    108 MockDisplaySettingsProviderImpl::MockDisplaySettingsProviderImpl() {
    109   memset(mock_desktop_bars, 0, sizeof(mock_desktop_bars));
    110 }
    111 
    112 gfx::Rect MockDisplaySettingsProviderImpl::GetPrimaryDisplayArea() const {
    113   return primary_display_area_;
    114 }
    115 
    116 gfx::Rect MockDisplaySettingsProviderImpl::GetPrimaryWorkArea() const {
    117   return primary_work_area_;
    118 }
    119 
    120 gfx::Rect MockDisplaySettingsProviderImpl::GetDisplayAreaMatching(
    121     const gfx::Rect& bounds) const {
    122   if (secondary_display_area_.IsEmpty())
    123     return primary_display_area_;
    124 
    125   gfx::Rect primary_intersection =
    126       gfx::IntersectRects(bounds, primary_display_area_);
    127   int primary_intersection_size =
    128       primary_intersection.width() * primary_intersection.height();
    129 
    130   gfx::Rect secondary_intersection =
    131       gfx::IntersectRects(bounds, secondary_display_area_);
    132   int secondary_intersection_size =
    133       secondary_intersection.width() * secondary_intersection.height();
    134 
    135   return primary_intersection_size >= secondary_intersection_size ?
    136       primary_display_area_ : secondary_display_area_;
    137 }
    138 
    139 gfx::Rect MockDisplaySettingsProviderImpl::GetWorkAreaMatching(
    140     const gfx::Rect& bounds) const {
    141   if (secondary_work_area_.IsEmpty())
    142     return primary_work_area_;
    143 
    144   gfx::Rect primary_intersection =
    145       gfx::IntersectRects(bounds, primary_work_area_);
    146   int primary_intersection_size =
    147       primary_intersection.width() * primary_intersection.height();
    148 
    149   gfx::Rect secondary_intersection =
    150       gfx::IntersectRects(bounds, secondary_work_area_);
    151   int secondary_intersection_size =
    152       secondary_intersection.width() * secondary_intersection.height();
    153 
    154   return primary_intersection_size >= secondary_intersection_size ?
    155       primary_work_area_ : secondary_work_area_;
    156 }
    157 
    158 bool MockDisplaySettingsProviderImpl::IsAutoHidingDesktopBarEnabled(
    159     DesktopBarAlignment alignment) {
    160   return mock_desktop_bars[static_cast<int>(alignment)].auto_hiding_enabled;
    161 }
    162 
    163 int MockDisplaySettingsProviderImpl::GetDesktopBarThickness(
    164     DesktopBarAlignment alignment) const {
    165   return mock_desktop_bars[static_cast<int>(alignment)].thickness;
    166 }
    167 
    168 DisplaySettingsProvider::DesktopBarVisibility
    169 MockDisplaySettingsProviderImpl::GetDesktopBarVisibility(
    170     DesktopBarAlignment alignment) const {
    171   return mock_desktop_bars[static_cast<int>(alignment)].visibility;
    172 }
    173 
    174 void MockDisplaySettingsProviderImpl::EnableAutoHidingDesktopBar(
    175     DesktopBarAlignment alignment, bool enabled, int thickness) {
    176   MockDesktopBar* bar = &(mock_desktop_bars[static_cast<int>(alignment)]);
    177   bar->auto_hiding_enabled = enabled;
    178   bar->thickness = thickness;
    179 }
    180 
    181 void MockDisplaySettingsProviderImpl::SetPrimaryDisplay(
    182     const gfx::Rect& display_area, const gfx::Rect& work_area) {
    183   DCHECK(display_area.Contains(work_area));
    184   primary_display_area_ = display_area;
    185   primary_work_area_ = work_area;
    186   OnDisplaySettingsChanged();
    187 }
    188 
    189 void MockDisplaySettingsProviderImpl::SetSecondaryDisplay(
    190     const gfx::Rect& display_area, const gfx::Rect& work_area) {
    191   DCHECK(display_area.Contains(work_area));
    192   secondary_display_area_ = display_area;
    193   secondary_work_area_ = work_area;
    194   OnDisplaySettingsChanged();
    195 }
    196 
    197 void MockDisplaySettingsProviderImpl::SetDesktopBarVisibility(
    198     DesktopBarAlignment alignment, DesktopBarVisibility visibility) {
    199   MockDesktopBar* bar = &(mock_desktop_bars[static_cast<int>(alignment)]);
    200   if (!bar->auto_hiding_enabled)
    201     return;
    202   if (visibility == bar->visibility)
    203     return;
    204   bar->visibility = visibility;
    205   FOR_EACH_OBSERVER(
    206       DesktopBarObserver,
    207       desktop_bar_observers(),
    208       OnAutoHidingDesktopBarVisibilityChanged(alignment, visibility));
    209 }
    210 
    211 void MockDisplaySettingsProviderImpl::SetDesktopBarThickness(
    212     DesktopBarAlignment alignment, int thickness) {
    213   MockDesktopBar* bar = &(mock_desktop_bars[static_cast<int>(alignment)]);
    214   if (!bar->auto_hiding_enabled)
    215     return;
    216   if (thickness == bar->thickness)
    217     return;
    218   bar->thickness = thickness;
    219   FOR_EACH_OBSERVER(
    220       DesktopBarObserver,
    221       desktop_bar_observers(),
    222       OnAutoHidingDesktopBarThicknessChanged(alignment, thickness));
    223 }
    224 
    225 }  // namespace
    226 
    227 const base::FilePath::CharType* BasePanelBrowserTest::kTestDir =
    228     FILE_PATH_LITERAL("panels");
    229 
    230 BasePanelBrowserTest::BasePanelBrowserTest()
    231     : InProcessBrowserTest(),
    232       mock_display_settings_enabled_(true) {
    233 }
    234 
    235 BasePanelBrowserTest::~BasePanelBrowserTest() {
    236 }
    237 
    238 bool BasePanelBrowserTest::SkipTestIfIceWM() {
    239 #if defined(OS_LINUX)
    240   return ui::GuessWindowManager() == ui::WM_ICE_WM;
    241 #else
    242   return false;
    243 #endif
    244 }
    245 
    246 bool BasePanelBrowserTest::SkipTestIfCompizWM() {
    247 #if defined(OS_LINUX)
    248   return ui::GuessWindowManager() == ui::WM_COMPIZ;
    249 #else
    250   return false;
    251 #endif
    252 }
    253 
    254 void BasePanelBrowserTest::SetUpCommandLine(CommandLine* command_line) {
    255   command_line->AppendSwitch(switches::kEnablePanels);
    256 }
    257 
    258 void BasePanelBrowserTest::SetUpOnMainThread() {
    259   InProcessBrowserTest::SetUpOnMainThread();
    260 
    261   // Setup the work area and desktop bar so that we have consistent testing
    262   // environment for all panel related tests.
    263   if (mock_display_settings_enabled_) {
    264     mock_display_settings_provider_ = new MockDisplaySettingsProviderImpl();
    265     mock_display_settings_provider_->SetPrimaryDisplay(
    266         kTestingPrimaryDisplayArea, kTestingPrimaryWorkArea);
    267     PanelManager::SetDisplaySettingsProviderForTesting(
    268         mock_display_settings_provider_);
    269   }
    270 
    271   PanelManager* panel_manager = PanelManager::GetInstance();
    272   panel_manager->enable_auto_sizing(false);
    273 
    274   PanelManager::shorten_time_intervals_for_testing();
    275 
    276   // Simulate the mouse movement so that tests are not affected by actual mouse
    277   // events.
    278   PanelMouseWatcher* mouse_watcher = new TestPanelMouseWatcher();
    279   panel_manager->SetMouseWatcherForTesting(mouse_watcher);
    280 
    281   // This is needed so the subsequently created panels can be activated.
    282   // On a Mac, it transforms background-only test process into foreground one.
    283   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
    284 }
    285 
    286 void BasePanelBrowserTest::WaitForPanelActiveState(
    287     Panel* panel, ActiveState expected_state) {
    288   DCHECK(expected_state == SHOW_AS_ACTIVE ||
    289          expected_state == SHOW_AS_INACTIVE);
    290 
    291 #if defined(OS_MACOSX)
    292   scoped_ptr<NativePanelTesting> panel_testing(
    293       CreateNativePanelTesting(panel));
    294   ASSERT_TRUE(panel_testing->EnsureApplicationRunOnForeground()) <<
    295       "Failed to bring application to foreground. Bail out.";
    296 #endif
    297 
    298   PanelActiveStateObserver signal(panel, expected_state == SHOW_AS_ACTIVE);
    299   signal.Wait();
    300 }
    301 
    302 void BasePanelBrowserTest::WaitForWindowSizeAvailable(Panel* panel) {
    303   scoped_ptr<NativePanelTesting> panel_testing(
    304       CreateNativePanelTesting(panel));
    305   content::WindowedNotificationObserver signal(
    306       chrome::NOTIFICATION_PANEL_WINDOW_SIZE_KNOWN,
    307       content::Source<Panel>(panel));
    308   if (panel_testing->IsWindowSizeKnown())
    309     return;
    310   signal.Wait();
    311   EXPECT_TRUE(panel_testing->IsWindowSizeKnown());
    312 }
    313 
    314 void BasePanelBrowserTest::WaitForBoundsAnimationFinished(Panel* panel) {
    315   scoped_ptr<NativePanelTesting> panel_testing(
    316       CreateNativePanelTesting(panel));
    317   // Sometimes there are several animations in sequence due to content
    318   // auto resizing. Wait for all animations to finish.
    319   while (panel_testing->IsAnimatingBounds()) {
    320     content::WindowedNotificationObserver signal(
    321         chrome::NOTIFICATION_PANEL_BOUNDS_ANIMATIONS_FINISHED,
    322         content::Source<Panel>(panel));
    323     if (!panel_testing->IsAnimatingBounds())
    324       return;
    325     signal.Wait();
    326   }
    327 }
    328 
    329 BasePanelBrowserTest::CreatePanelParams::CreatePanelParams(
    330     const std::string& name,
    331     const gfx::Rect& bounds,
    332     ActiveState show_flag)
    333     : name(name),
    334       bounds(bounds),
    335       show_flag(show_flag),
    336       wait_for_fully_created(true),
    337       expected_active_state(show_flag),
    338       create_mode(PanelManager::CREATE_AS_DOCKED),
    339       profile(NULL) {
    340 }
    341 
    342 Panel* BasePanelBrowserTest::CreatePanelWithParams(
    343     const CreatePanelParams& params) {
    344 #if defined(OS_MACOSX)
    345   // Opening panels on a Mac causes NSWindowController of the Panel window
    346   // to be autoreleased. We need a pool drained after it's done so the test
    347   // can close correctly. The NSWindowController of the Panel window controls
    348   // lifetime of the Panel object so we want to release it as soon as
    349   // possible. In real Chrome, this is done by message pump.
    350   // On non-Mac platform, this is an empty class.
    351   base::mac::ScopedNSAutoreleasePool autorelease_pool;
    352 #endif
    353 
    354   content::WindowedNotificationObserver observer(
    355       content::NOTIFICATION_LOAD_STOP,
    356       content::NotificationService::AllSources());
    357 
    358   PanelManager* manager = PanelManager::GetInstance();
    359   Panel* panel = manager->CreatePanel(
    360       params.name,
    361       params.profile ? params.profile : browser()->profile(),
    362       params.url,
    363       params.bounds,
    364       params.create_mode);
    365 
    366   if (!params.url.is_empty())
    367     observer.Wait();
    368 
    369   if (!manager->auto_sizing_enabled() ||
    370       params.bounds.width() || params.bounds.height()) {
    371     EXPECT_FALSE(panel->auto_resizable());
    372   } else {
    373     EXPECT_TRUE(panel->auto_resizable());
    374   }
    375 
    376   if (params.show_flag == SHOW_AS_ACTIVE) {
    377     panel->Show();
    378   } else {
    379     panel->ShowInactive();
    380   }
    381 
    382   if (params.wait_for_fully_created) {
    383     base::MessageLoopForUI::current()->RunUntilIdle();
    384 
    385 #if defined(OS_LINUX)
    386     // On bots, we might have a simple window manager which always activates new
    387     // windows, and can't always deactivate them. Re-activate the main tabbed
    388     // browser to "deactivate" the newly created panel.
    389     if (params.expected_active_state == SHOW_AS_INACTIVE &&
    390         ui::GuessWindowManager() == ui::WM_ICE_WM) {
    391       // Wait for new panel to become active before deactivating to ensure
    392       // the activated notification is consumed before we wait for the panel
    393       // to become inactive.
    394       WaitForPanelActiveState(panel, SHOW_AS_ACTIVE);
    395       browser()->window()->Activate();
    396     }
    397 #endif
    398     // More waiting, because gaining or losing focus may require inter-process
    399     // asynchronous communication, and it is not enough to just run the local
    400     // message loop to make sure this activity has completed.
    401     WaitForPanelActiveState(panel, params.expected_active_state);
    402 
    403     // On Linux, window size is not available right away and we should wait
    404     // before moving forward with the test.
    405     WaitForWindowSizeAvailable(panel);
    406 
    407     // Wait for the bounds animations on creation to finish.
    408     WaitForBoundsAnimationFinished(panel);
    409   }
    410 
    411   return panel;
    412 }
    413 
    414 Panel* BasePanelBrowserTest::CreatePanelWithBounds(
    415     const std::string& panel_name, const gfx::Rect& bounds) {
    416   CreatePanelParams params(panel_name, bounds, SHOW_AS_ACTIVE);
    417   return CreatePanelWithParams(params);
    418 }
    419 
    420 Panel* BasePanelBrowserTest::CreatePanel(const std::string& panel_name) {
    421   CreatePanelParams params(panel_name, gfx::Rect(), SHOW_AS_ACTIVE);
    422   return CreatePanelWithParams(params);
    423 }
    424 
    425 Panel* BasePanelBrowserTest::CreateDockedPanel(const std::string& name,
    426                                                const gfx::Rect& bounds) {
    427   Panel* panel = CreatePanelWithBounds(name, bounds);
    428   EXPECT_EQ(PanelCollection::DOCKED, panel->collection()->type());
    429   return panel;
    430 }
    431 
    432 Panel* BasePanelBrowserTest::CreateDetachedPanel(const std::string& name,
    433                                                  const gfx::Rect& bounds) {
    434   Panel* panel = CreatePanelWithBounds(name, bounds);
    435   PanelManager* panel_manager = panel->manager();
    436   panel_manager->MovePanelToCollection(panel,
    437                                        panel_manager->detached_collection(),
    438                                        PanelCollection::DEFAULT_POSITION);
    439   EXPECT_EQ(PanelCollection::DETACHED, panel->collection()->type());
    440   // The panel is first created as docked panel, which ignores the specified
    441   // origin in |bounds|. We need to reposition the panel after it becomes
    442   // detached.
    443   panel->SetPanelBounds(bounds);
    444   WaitForBoundsAnimationFinished(panel);
    445   return panel;
    446 }
    447 
    448 Panel* BasePanelBrowserTest::CreateStackedPanel(const std::string& name,
    449                                                 const gfx::Rect& bounds,
    450                                                 StackedPanelCollection* stack) {
    451   Panel* panel = CreateDetachedPanel(name, bounds);
    452   panel->manager()->MovePanelToCollection(
    453       panel,
    454       stack,
    455       static_cast<PanelCollection::PositioningMask>(
    456           PanelCollection::DEFAULT_POSITION |
    457           PanelCollection::COLLAPSE_TO_FIT));
    458   EXPECT_EQ(PanelCollection::STACKED, panel->collection()->type());
    459   WaitForBoundsAnimationFinished(panel);
    460   return panel;
    461 }
    462 
    463 Panel* BasePanelBrowserTest::CreateInactivePanel(const std::string& name) {
    464   // Create an active panel first, instead of inactive panel. This is because
    465   // certain window managers on Linux, like icewm, will always activate the
    466   // new window.
    467   Panel* panel = CreatePanel(name);
    468 
    469   DeactivatePanel(panel);
    470   WaitForPanelActiveState(panel, SHOW_AS_INACTIVE);
    471 
    472   return panel;
    473 }
    474 
    475 Panel* BasePanelBrowserTest::CreateInactiveDockedPanel(
    476     const std::string& name, const gfx::Rect& bounds) {
    477   // Create an active panel first, instead of inactive panel. This is because
    478   // certain window managers on Linux, like icewm, will always activate the
    479   // new window.
    480   Panel* panel = CreateDockedPanel(name, bounds);
    481 
    482   DeactivatePanel(panel);
    483   WaitForPanelActiveState(panel, SHOW_AS_INACTIVE);
    484 
    485   return panel;
    486 }
    487 
    488 Panel* BasePanelBrowserTest::CreateInactiveDetachedPanel(
    489     const std::string& name, const gfx::Rect& bounds) {
    490   // Create an active panel first, instead of inactive panel. This is because
    491   // certain window managers on Linux, like icewm, will always activate the
    492   // new window.
    493   Panel* panel = CreateDetachedPanel(name, bounds);
    494 
    495   DeactivatePanel(panel);
    496   WaitForPanelActiveState(panel, SHOW_AS_INACTIVE);
    497 
    498   return panel;
    499 }
    500 
    501 void BasePanelBrowserTest::ActivatePanel(Panel* panel) {
    502   // For certain window managers on Linux, the window activation/deactivation
    503   // signals might not be sent. To work around this, we explicitly deactivate
    504   // all other panels first.
    505 #if defined(OS_LINUX)
    506   std::vector<Panel*> panels = PanelManager::GetInstance()->panels();
    507   for (std::vector<Panel*>::const_iterator iter = panels.begin();
    508        iter != panels.end(); ++iter) {
    509     Panel* current_panel = *iter;
    510     if (panel != current_panel)
    511       current_panel->Deactivate();
    512   }
    513 #endif
    514 
    515   panel->Activate();
    516 }
    517 
    518 void BasePanelBrowserTest::DeactivatePanel(Panel* panel) {
    519 #if defined(OS_LINUX)
    520   // For certain window managers on Linux, like icewm, panel activation and
    521   // deactivation notification might not get tiggered when non-panel window is
    522   // activated or deactivated. So we deactivate the panel directly.
    523   panel->Deactivate();
    524 #else
    525   // Make the panel lose focus by activating the browser window. This is
    526   // because:
    527   // 1) On Windows, deactivating the panel window might cause the application
    528   //    to lose the foreground status. When this occurs, trying to activate
    529   //    the panel window again will not be allowed by the system.
    530   // 2) On MacOS, deactivating a window is not supported by Cocoa.
    531   browser()->window()->Activate();
    532 #endif
    533 }
    534 
    535 // static
    536 NativePanelTesting* BasePanelBrowserTest::CreateNativePanelTesting(
    537     Panel* panel) {
    538   return panel->native_panel()->CreateNativePanelTesting();
    539 }
    540 
    541 scoped_refptr<Extension> BasePanelBrowserTest::CreateExtension(
    542     const base::FilePath::StringType& path,
    543     extensions::Manifest::Location location,
    544     const DictionaryValue& extra_value) {
    545   extensions::ExtensionPrefs* extension_prefs =
    546       extensions::ExtensionPrefs::Get(browser()->profile());
    547   base::FilePath full_path = extension_prefs->install_directory().Append(path);
    548 
    549   scoped_ptr<DictionaryValue> input_value(extra_value.DeepCopy());
    550   input_value->SetString(extension_manifest_keys::kVersion, "1.0.0.0");
    551   input_value->SetString(extension_manifest_keys::kName, "Sample Extension");
    552 
    553   std::string error;
    554   scoped_refptr<Extension> extension = Extension::Create(
    555       full_path,  location, *input_value, Extension::NO_FLAGS, &error);
    556   EXPECT_TRUE(extension.get());
    557   EXPECT_STREQ("", error.c_str());
    558   browser()->profile()->GetExtensionService()->
    559       OnExtensionInstalled(extension.get(),
    560                            syncer::StringOrdinal(),
    561                            false /* no requirement errors */,
    562                            extensions::Blacklist::NOT_BLACKLISTED,
    563                            false /* don't wait for idle */);
    564   return extension;
    565 }
    566 
    567 void BasePanelBrowserTest::CloseWindowAndWait(Panel* panel) {
    568   // Closing a panel may involve several async tasks. Need to use
    569   // message pump and wait for the notification.
    570   PanelManager* manager = PanelManager::GetInstance();
    571   int panel_count = manager->num_panels();
    572   content::WindowedNotificationObserver signal(
    573       chrome::NOTIFICATION_PANEL_CLOSED,
    574       content::Source<Panel>(panel));
    575   panel->Close();
    576   signal.Wait();
    577   // Now we have one less panel.
    578   EXPECT_EQ(panel_count - 1, manager->num_panels());
    579 
    580 #if defined(OS_MACOSX)
    581   // Mac window controllers may be autoreleased, and in the non-test
    582   // environment, may actually depend on the autorelease pool being recycled
    583   // with the run loop in order to perform important work. Replicate this in
    584   // the test environment.
    585   AutoreleasePool()->Recycle();
    586 
    587   // Make sure that everything has a chance to run.
    588   chrome::testing::NSRunLoopRunAllPending();
    589 #endif  // OS_MACOSX
    590 }
    591 
    592 void BasePanelBrowserTest::MoveMouseAndWaitForExpansionStateChange(
    593     Panel* panel,
    594     const gfx::Point& position) {
    595   content::WindowedNotificationObserver signal(
    596       chrome::NOTIFICATION_PANEL_CHANGED_EXPANSION_STATE,
    597       content::Source<Panel>(panel));
    598   MoveMouse(position);
    599   signal.Wait();
    600 }
    601 
    602 void BasePanelBrowserTest::MoveMouse(const gfx::Point& position) {
    603   PanelManager::GetInstance()->mouse_watcher()->NotifyMouseMovement(position);
    604 }
    605 
    606 std::string BasePanelBrowserTest::MakePanelName(int index) {
    607   std::string panel_name("Panel");
    608   return panel_name + base::IntToString(index);
    609 }
    610 
    611 bool BasePanelBrowserTest::WmSupportWindowActivation() {
    612 #if defined(OS_LINUX) && !defined(USE_AURA)
    613   return ui::ActiveWindowWatcherX::WMSupportsActivation();
    614 #else
    615   return true;
    616 #endif
    617 }
    618