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