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