Home | History | Annotate | Download | only in ash
      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 "ash/display/display_controller.h"
      6 #include "ash/display/display_manager.h"
      7 #include "ash/root_window_controller.h"
      8 #include "ash/screen_util.h"
      9 #include "ash/shell.h"
     10 #include "ash/shell_window_ids.h"
     11 #include "ash/system/tray/system_tray.h"
     12 #include "ash/test/ash_test_base.h"
     13 #include "ash/wm/coordinate_conversion.h"
     14 #include "ash/wm/window_properties.h"
     15 #include "ash/wm/window_util.h"
     16 #include "base/strings/string_util.h"
     17 #include "base/strings/utf_string_conversions.h"
     18 #include "ui/aura/client/capture_client.h"
     19 #include "ui/aura/client/focus_client.h"
     20 #include "ui/aura/test/test_windows.h"
     21 #include "ui/aura/test/window_test_api.h"
     22 #include "ui/aura/window.h"
     23 #include "ui/aura/window_event_dispatcher.h"
     24 #include "ui/base/cursor/cursor.h"
     25 #include "ui/events/event_handler.h"
     26 #include "ui/events/test/event_generator.h"
     27 #include "ui/gfx/display.h"
     28 #include "ui/gfx/screen.h"
     29 #include "ui/views/controls/textfield/textfield.h"
     30 #include "ui/views/widget/widget.h"
     31 #include "ui/views/widget/widget_delegate.h"
     32 #include "ui/wm/public/activation_client.h"
     33 
     34 namespace ash {
     35 namespace {
     36 
     37 void SetSecondaryDisplayLayout(DisplayLayout::Position position) {
     38   DisplayLayout layout =
     39       Shell::GetInstance()->display_manager()->GetCurrentDisplayLayout();
     40   layout.position = position;
     41   Shell::GetInstance()->display_manager()->
     42       SetLayoutForCurrentDisplays(layout);
     43 }
     44 
     45 class ModalWidgetDelegate : public views::WidgetDelegateView {
     46  public:
     47   ModalWidgetDelegate() {}
     48   virtual ~ModalWidgetDelegate() {}
     49 
     50   // Overridden from views::WidgetDelegate:
     51   virtual views::View* GetContentsView() OVERRIDE {
     52     return this;
     53   }
     54   virtual ui::ModalType GetModalType() const OVERRIDE {
     55     return ui::MODAL_TYPE_SYSTEM;
     56   }
     57 
     58  private:
     59   DISALLOW_COPY_AND_ASSIGN(ModalWidgetDelegate);
     60 };
     61 
     62 // An event handler which moves the target window to the secondary root window
     63 // at pre-handle phase of a mouse release event.
     64 class MoveWindowByClickEventHandler : public ui::EventHandler {
     65  public:
     66   explicit MoveWindowByClickEventHandler(aura::Window* target)
     67       : target_(target) {}
     68   virtual ~MoveWindowByClickEventHandler() {}
     69 
     70  private:
     71   // ui::EventHandler overrides:
     72   virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
     73     if (event->type() == ui::ET_MOUSE_RELEASED) {
     74       aura::Window::Windows root_windows = Shell::GetAllRootWindows();
     75       DCHECK_LT(1u, root_windows.size());
     76       root_windows[1]->AddChild(target_);
     77     }
     78   }
     79 
     80   aura::Window* target_;
     81   DISALLOW_COPY_AND_ASSIGN(MoveWindowByClickEventHandler);
     82 };
     83 
     84 // An event handler which records the event's locations.
     85 class EventLocationRecordingEventHandler : public ui::EventHandler {
     86  public:
     87   explicit EventLocationRecordingEventHandler() {
     88     reset();
     89   }
     90   virtual ~EventLocationRecordingEventHandler() {}
     91 
     92   std::string GetLocationsAndReset() {
     93     std::string result =
     94         location_.ToString() + " " + root_location_.ToString();
     95     reset();
     96     return result;
     97   }
     98 
     99  private:
    100   // ui::EventHandler overrides:
    101   virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
    102     if (event->type() == ui::ET_MOUSE_MOVED ||
    103         event->type() == ui::ET_MOUSE_DRAGGED) {
    104       location_ = event->location();
    105       root_location_ = event->root_location();
    106     }
    107   }
    108 
    109   void reset() {
    110     location_.SetPoint(-999, -999);
    111     root_location_.SetPoint(-999, -999);
    112   }
    113 
    114   gfx::Point root_location_;
    115   gfx::Point location_;
    116 
    117   DISALLOW_COPY_AND_ASSIGN(EventLocationRecordingEventHandler);
    118 };
    119 
    120 class EventLocationHandler : public ui::EventHandler {
    121  public:
    122   EventLocationHandler() {}
    123   virtual ~EventLocationHandler() {}
    124 
    125   const gfx::Point& press_location() const { return press_location_; }
    126   const gfx::Point& release_location() const { return release_location_; }
    127 
    128  private:
    129   // ui::EventHandler:
    130   virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
    131     if (event->type() == ui::ET_MOUSE_PRESSED)
    132       press_location_ = event->location();
    133     else if (event->type() == ui::ET_MOUSE_RELEASED)
    134       release_location_ = event->location();
    135   }
    136 
    137   gfx::Point press_location_;
    138   gfx::Point release_location_;
    139 
    140   DISALLOW_COPY_AND_ASSIGN(EventLocationHandler);
    141 };
    142 
    143 }  // namespace
    144 
    145 class ExtendedDesktopTest : public test::AshTestBase {
    146  public:
    147   views::Widget* CreateTestWidget(const gfx::Rect& bounds) {
    148     return CreateTestWidgetWithParentAndContext(
    149         NULL, CurrentContext(), bounds, false);
    150   }
    151 
    152   views::Widget* CreateTestWidgetWithParent(views::Widget* parent,
    153                                             const gfx::Rect& bounds,
    154                                             bool child) {
    155     CHECK(parent);
    156     return CreateTestWidgetWithParentAndContext(parent, NULL, bounds, child);
    157   }
    158 
    159   views::Widget* CreateTestWidgetWithParentAndContext(views::Widget* parent,
    160                                                       gfx::NativeView context,
    161                                                       const gfx::Rect& bounds,
    162                                                       bool child) {
    163     views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
    164     if (parent)
    165       params.parent = parent->GetNativeView();
    166     params.context = context;
    167     params.bounds = bounds;
    168     params.child = child;
    169     views::Widget* widget = new views::Widget;
    170     widget->Init(params);
    171     widget->Show();
    172     return widget;
    173   }
    174 };
    175 
    176 // Test conditions that root windows in extended desktop mode
    177 // must satisfy.
    178 TEST_F(ExtendedDesktopTest, Basic) {
    179   if (!SupportsMultipleDisplays())
    180     return;
    181 
    182   UpdateDisplay("1000x600,600x400");
    183   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    184 
    185   // All root windows must have the root window controller.
    186   ASSERT_EQ(2U, root_windows.size());
    187   for (aura::Window::Windows::const_iterator iter = root_windows.begin();
    188        iter != root_windows.end(); ++iter) {
    189     EXPECT_TRUE(GetRootWindowController(*iter) != NULL);
    190   }
    191   // Make sure root windows share the same controllers.
    192   EXPECT_EQ(aura::client::GetFocusClient(root_windows[0]),
    193             aura::client::GetFocusClient(root_windows[1]));
    194   EXPECT_EQ(aura::client::GetActivationClient(root_windows[0]),
    195             aura::client::GetActivationClient(root_windows[1]));
    196   EXPECT_EQ(aura::client::GetCaptureClient(root_windows[0]),
    197             aura::client::GetCaptureClient(root_windows[1]));
    198 }
    199 
    200 TEST_F(ExtendedDesktopTest, Activation) {
    201   if (!SupportsMultipleDisplays())
    202     return;
    203 
    204   UpdateDisplay("1000x600,600x400");
    205   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    206 
    207   views::Widget* widget_on_1st = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
    208   views::Widget* widget_on_2nd =
    209       CreateTestWidget(gfx::Rect(1200, 10, 100, 100));
    210   EXPECT_EQ(root_windows[0], widget_on_1st->GetNativeView()->GetRootWindow());
    211   EXPECT_EQ(root_windows[1], widget_on_2nd->GetNativeView()->GetRootWindow());
    212 
    213   EXPECT_EQ(widget_on_2nd->GetNativeView(),
    214             aura::client::GetFocusClient(root_windows[0])->GetFocusedWindow());
    215   EXPECT_TRUE(wm::IsActiveWindow(widget_on_2nd->GetNativeView()));
    216 
    217   ui::test::EventGenerator& event_generator(GetEventGenerator());
    218   // Clicking a window changes the active window and active root window.
    219   event_generator.MoveMouseToCenterOf(widget_on_1st->GetNativeView());
    220   event_generator.ClickLeftButton();
    221 
    222   EXPECT_EQ(widget_on_1st->GetNativeView(),
    223             aura::client::GetFocusClient(root_windows[0])->GetFocusedWindow());
    224   EXPECT_TRUE(wm::IsActiveWindow(widget_on_1st->GetNativeView()));
    225 
    226   event_generator.MoveMouseToCenterOf(widget_on_2nd->GetNativeView());
    227   event_generator.ClickLeftButton();
    228 
    229   EXPECT_EQ(widget_on_2nd->GetNativeView(),
    230             aura::client::GetFocusClient(root_windows[0])->GetFocusedWindow());
    231   EXPECT_TRUE(wm::IsActiveWindow(widget_on_2nd->GetNativeView()));
    232 }
    233 
    234 TEST_F(ExtendedDesktopTest, SystemModal) {
    235   if (!SupportsMultipleDisplays())
    236     return;
    237 
    238   UpdateDisplay("1000x600,600x400");
    239   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    240 
    241   views::Widget* widget_on_1st = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
    242   EXPECT_TRUE(wm::IsActiveWindow(widget_on_1st->GetNativeView()));
    243   EXPECT_EQ(root_windows[0], widget_on_1st->GetNativeView()->GetRootWindow());
    244   EXPECT_EQ(root_windows[0], Shell::GetTargetRootWindow());
    245 
    246   // Open system modal. Make sure it's on 2nd root window and active.
    247   views::Widget* modal_widget = views::Widget::CreateWindowWithContextAndBounds(
    248       new ModalWidgetDelegate(),
    249       CurrentContext(),
    250       gfx::Rect(1200, 100, 100, 100));
    251   modal_widget->Show();
    252   EXPECT_TRUE(wm::IsActiveWindow(modal_widget->GetNativeView()));
    253   EXPECT_EQ(root_windows[1], modal_widget->GetNativeView()->GetRootWindow());
    254   EXPECT_EQ(root_windows[1], Shell::GetTargetRootWindow());
    255 
    256   ui::test::EventGenerator& event_generator(GetEventGenerator());
    257 
    258   // Clicking a widget on widget_on_1st display should not change activation.
    259   event_generator.MoveMouseToCenterOf(widget_on_1st->GetNativeView());
    260   event_generator.ClickLeftButton();
    261   EXPECT_TRUE(wm::IsActiveWindow(modal_widget->GetNativeView()));
    262   EXPECT_EQ(root_windows[1], Shell::GetTargetRootWindow());
    263 
    264   // Close system modal and so clicking a widget should work now.
    265   modal_widget->Close();
    266   event_generator.MoveMouseToCenterOf(widget_on_1st->GetNativeView());
    267   event_generator.ClickLeftButton();
    268   EXPECT_TRUE(wm::IsActiveWindow(widget_on_1st->GetNativeView()));
    269   EXPECT_EQ(root_windows[0], Shell::GetTargetRootWindow());
    270 }
    271 
    272 TEST_F(ExtendedDesktopTest, TestCursor) {
    273   if (!SupportsMultipleDisplays())
    274     return;
    275 
    276   UpdateDisplay("1000x600,600x400");
    277   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    278   aura::WindowTreeHost* host0 = root_windows[0]->GetHost();
    279   aura::WindowTreeHost* host1 = root_windows[1]->GetHost();
    280   EXPECT_EQ(ui::kCursorPointer, host0->last_cursor().native_type());
    281   EXPECT_EQ(ui::kCursorPointer, host1->last_cursor().native_type());
    282   Shell::GetInstance()->cursor_manager()->SetCursor(ui::kCursorCopy);
    283   EXPECT_EQ(ui::kCursorCopy, host0->last_cursor().native_type());
    284   EXPECT_EQ(ui::kCursorCopy, host1->last_cursor().native_type());
    285 }
    286 
    287 TEST_F(ExtendedDesktopTest, TestCursorLocation) {
    288   if (!SupportsMultipleDisplays())
    289     return;
    290 
    291   UpdateDisplay("1000x600,600x400");
    292   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    293   aura::test::WindowTestApi root_window0_test_api(root_windows[0]);
    294   aura::test::WindowTestApi root_window1_test_api(root_windows[1]);
    295 
    296   root_windows[0]->MoveCursorTo(gfx::Point(10, 10));
    297   EXPECT_EQ("10,10", Shell::GetScreen()->GetCursorScreenPoint().ToString());
    298   EXPECT_TRUE(root_window0_test_api.ContainsMouse());
    299   EXPECT_FALSE(root_window1_test_api.ContainsMouse());
    300   root_windows[1]->MoveCursorTo(gfx::Point(10, 20));
    301   EXPECT_EQ("1010,20", Shell::GetScreen()->GetCursorScreenPoint().ToString());
    302   EXPECT_FALSE(root_window0_test_api.ContainsMouse());
    303   EXPECT_TRUE(root_window1_test_api.ContainsMouse());
    304   root_windows[0]->MoveCursorTo(gfx::Point(20, 10));
    305   EXPECT_EQ("20,10", Shell::GetScreen()->GetCursorScreenPoint().ToString());
    306   EXPECT_TRUE(root_window0_test_api.ContainsMouse());
    307   EXPECT_FALSE(root_window1_test_api.ContainsMouse());
    308 }
    309 
    310 TEST_F(ExtendedDesktopTest, GetRootWindowAt) {
    311   if (!SupportsMultipleDisplays())
    312     return;
    313 
    314   UpdateDisplay("700x500,500x500");
    315   SetSecondaryDisplayLayout(DisplayLayout::LEFT);
    316   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    317 
    318   EXPECT_EQ(root_windows[1], wm::GetRootWindowAt(gfx::Point(-400, 100)));
    319   EXPECT_EQ(root_windows[1], wm::GetRootWindowAt(gfx::Point(-1, 100)));
    320   EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(0, 300)));
    321   EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(700, 300)));
    322 
    323   // Zero origin.
    324   EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(0, 0)));
    325 
    326   // Out of range point should return the nearest root window
    327   EXPECT_EQ(root_windows[1], wm::GetRootWindowAt(gfx::Point(-600, 0)));
    328   EXPECT_EQ(root_windows[0], wm::GetRootWindowAt(gfx::Point(701, 100)));
    329 }
    330 
    331 TEST_F(ExtendedDesktopTest, GetRootWindowMatching) {
    332   if (!SupportsMultipleDisplays())
    333     return;
    334 
    335   UpdateDisplay("700x500,500x500");
    336   SetSecondaryDisplayLayout(DisplayLayout::LEFT);
    337 
    338   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    339 
    340   // Containing rect.
    341   EXPECT_EQ(root_windows[1],
    342             wm::GetRootWindowMatching(gfx::Rect(-300, 10, 50, 50)));
    343   EXPECT_EQ(root_windows[0],
    344             wm::GetRootWindowMatching(gfx::Rect(100, 10, 50, 50)));
    345 
    346   // Intersecting rect.
    347   EXPECT_EQ(root_windows[1],
    348             wm::GetRootWindowMatching(gfx::Rect(-200, 0, 300, 300)));
    349   EXPECT_EQ(root_windows[0],
    350             wm::GetRootWindowMatching(gfx::Rect(-100, 0, 300, 300)));
    351 
    352   // Zero origin.
    353   EXPECT_EQ(root_windows[0],
    354             wm::GetRootWindowMatching(gfx::Rect(0, 0, 0, 0)));
    355   EXPECT_EQ(root_windows[0],
    356             wm::GetRootWindowMatching(gfx::Rect(0, 0, 1, 1)));
    357 
    358   // Empty rect.
    359   EXPECT_EQ(root_windows[1],
    360             wm::GetRootWindowMatching(gfx::Rect(-400, 100, 0, 0)));
    361   EXPECT_EQ(root_windows[0],
    362             wm::GetRootWindowMatching(gfx::Rect(100, 100, 0, 0)));
    363 
    364   // Out of range rect should return the primary root window.
    365   EXPECT_EQ(root_windows[0],
    366             wm::GetRootWindowMatching(gfx::Rect(-600, -300, 50, 50)));
    367   EXPECT_EQ(root_windows[0],
    368             wm::GetRootWindowMatching(gfx::Rect(0, 1000, 50, 50)));
    369 }
    370 
    371 TEST_F(ExtendedDesktopTest, Capture) {
    372   if (!SupportsMultipleDisplays())
    373     return;
    374 
    375   UpdateDisplay("1000x600,600x400");
    376   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    377 
    378   aura::test::EventCountDelegate r1_d1;
    379   aura::test::EventCountDelegate r1_d2;
    380   aura::test::EventCountDelegate r2_d1;
    381 
    382   scoped_ptr<aura::Window> r1_w1(aura::test::CreateTestWindowWithDelegate(
    383       &r1_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
    384   scoped_ptr<aura::Window> r1_w2(aura::test::CreateTestWindowWithDelegate(
    385       &r1_d2, 0, gfx::Rect(10, 100, 100, 100), root_windows[0]));
    386   scoped_ptr<aura::Window> r2_w1(aura::test::CreateTestWindowWithDelegate(
    387       &r2_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[1]));
    388 
    389   r1_w1->SetCapture();
    390 
    391   EXPECT_EQ(r1_w1.get(),
    392             aura::client::GetCaptureWindow(r2_w1->GetRootWindow()));
    393 
    394   ui::test::EventGenerator& generator = GetEventGenerator();
    395   generator.MoveMouseToCenterOf(r2_w1.get());
    396   // |r1_w1| will receive the events because it has capture.
    397   EXPECT_EQ("1 1 0", r1_d1.GetMouseMotionCountsAndReset());
    398   EXPECT_EQ("0 0 0", r1_d2.GetMouseMotionCountsAndReset());
    399   EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
    400 
    401   generator.ClickLeftButton();
    402   EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
    403   EXPECT_EQ("0 0", r2_d1.GetMouseButtonCountsAndReset());
    404   // The mouse is outside. On chromeos, the mouse is warped to the
    405   // dest root window, but it's not implemented on Win yet, so
    406   // no mouse move event on Win.
    407   EXPECT_EQ("0 0 0", r1_d1.GetMouseMotionCountsAndReset());
    408   EXPECT_EQ("1 1", r1_d1.GetMouseButtonCountsAndReset());
    409 
    410   generator.MoveMouseTo(15, 15);
    411   EXPECT_EQ("0 1 0", r1_d1.GetMouseMotionCountsAndReset());
    412   EXPECT_EQ("0 0 0", r1_d2.GetMouseMotionCountsAndReset());
    413 
    414   r1_w2->SetCapture();
    415   EXPECT_EQ(r1_w2.get(),
    416             aura::client::GetCaptureWindow(r2_w1->GetRootWindow()));
    417   generator.MoveMouseBy(10, 10);
    418   // |r1_w2| has the capture. So it will receive the mouse-move event.
    419   EXPECT_EQ("0 0 0", r1_d1.GetMouseMotionCountsAndReset());
    420   EXPECT_EQ("0 1 0", r1_d2.GetMouseMotionCountsAndReset());
    421   EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
    422 
    423   generator.ClickLeftButton();
    424   EXPECT_EQ("0 0 0", r2_d1.GetMouseMotionCountsAndReset());
    425   EXPECT_EQ("0 0", r2_d1.GetMouseButtonCountsAndReset());
    426   EXPECT_EQ("0 0 0", r1_d2.GetMouseMotionCountsAndReset());
    427   EXPECT_EQ("1 1", r1_d2.GetMouseButtonCountsAndReset());
    428 
    429   r1_w2->ReleaseCapture();
    430   EXPECT_EQ(NULL, aura::client::GetCaptureWindow(r2_w1->GetRootWindow()));
    431 
    432   generator.MoveMouseToCenterOf(r2_w1.get());
    433   generator.ClickLeftButton();
    434   EXPECT_EQ("1 1 0", r2_d1.GetMouseMotionCountsAndReset());
    435   EXPECT_EQ("1 1", r2_d1.GetMouseButtonCountsAndReset());
    436   // Make sure the mouse_moved_handler_ is properly reset.
    437   EXPECT_EQ("0 0 0", r1_d2.GetMouseMotionCountsAndReset());
    438   EXPECT_EQ("0 0", r1_d2.GetMouseButtonCountsAndReset());
    439 }
    440 
    441 TEST_F(ExtendedDesktopTest, CaptureEventLocation) {
    442   if (!SupportsMultipleDisplays())
    443     return;
    444 
    445   UpdateDisplay("1000x600,600x400");
    446   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    447 
    448   aura::test::EventCountDelegate r1_d1;
    449   aura::test::EventCountDelegate r1_d2;
    450   aura::test::EventCountDelegate r2_d1;
    451 
    452   scoped_ptr<aura::Window> r1_w1(aura::test::CreateTestWindowWithDelegate(
    453       &r1_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
    454   scoped_ptr<aura::Window> r1_w2(aura::test::CreateTestWindowWithDelegate(
    455       &r1_d2, 0, gfx::Rect(10, 100, 100, 100), root_windows[0]));
    456   scoped_ptr<aura::Window> r2_w1(aura::test::CreateTestWindowWithDelegate(
    457       &r2_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[1]));
    458 
    459   r1_w1->SetCapture();
    460 
    461   ui::test::EventGenerator& generator = GetEventGenerator();
    462   generator.MoveMouseToCenterOf(r2_w1.get());
    463   EXPECT_EQ(gfx::Point(1060, 60).ToString(),
    464             generator.current_location().ToString());
    465 
    466   EventLocationHandler location_handler;
    467   r1_w1->AddPreTargetHandler(&location_handler);
    468   generator.ClickLeftButton();
    469   r1_w1->RemovePreTargetHandler(&location_handler);
    470   EXPECT_EQ(gfx::Point(1050, 50).ToString(),
    471             location_handler.press_location().ToString());
    472   EXPECT_EQ(gfx::Point(1050, 50).ToString(),
    473             location_handler.release_location().ToString());
    474 }
    475 
    476 TEST_F(ExtendedDesktopTest, CaptureEventLocationHighDPI) {
    477   if (!SupportsMultipleDisplays())
    478     return;
    479 
    480   UpdateDisplay("1000x600*2,600x400");
    481   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    482 
    483   aura::test::EventCountDelegate r1_d1;
    484   aura::test::EventCountDelegate r1_d2;
    485   aura::test::EventCountDelegate r2_d1;
    486 
    487   scoped_ptr<aura::Window> r1_w1(aura::test::CreateTestWindowWithDelegate(
    488       &r1_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
    489   scoped_ptr<aura::Window> r1_w2(aura::test::CreateTestWindowWithDelegate(
    490       &r1_d2, 0, gfx::Rect(10, 100, 100, 100), root_windows[0]));
    491   scoped_ptr<aura::Window> r2_w1(aura::test::CreateTestWindowWithDelegate(
    492       &r2_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[1]));
    493 
    494   r1_w1->SetCapture();
    495 
    496   ui::test::EventGenerator& generator = GetEventGenerator();
    497   generator.MoveMouseToCenterOf(r2_w1.get());
    498   EXPECT_EQ(gfx::Point(560, 60).ToString(),
    499             generator.current_location().ToString());
    500 
    501   EventLocationHandler location_handler;
    502   r1_w1->AddPreTargetHandler(&location_handler);
    503   generator.ClickLeftButton();
    504   r1_w1->RemovePreTargetHandler(&location_handler);
    505   EXPECT_EQ(gfx::Point(550, 50).ToString(),
    506             location_handler.press_location().ToString());
    507   EXPECT_EQ(gfx::Point(550, 50).ToString(),
    508             location_handler.release_location().ToString());
    509 }
    510 
    511 TEST_F(ExtendedDesktopTest, CaptureEventLocationHighDPI_2) {
    512   if (!SupportsMultipleDisplays())
    513     return;
    514 
    515   UpdateDisplay("1000x600,600x400*2");
    516   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    517 
    518   aura::test::EventCountDelegate r1_d1;
    519   aura::test::EventCountDelegate r1_d2;
    520   aura::test::EventCountDelegate r2_d1;
    521 
    522   scoped_ptr<aura::Window> r1_w1(aura::test::CreateTestWindowWithDelegate(
    523       &r1_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
    524   scoped_ptr<aura::Window> r1_w2(aura::test::CreateTestWindowWithDelegate(
    525       &r1_d2, 0, gfx::Rect(10, 100, 100, 100), root_windows[0]));
    526   scoped_ptr<aura::Window> r2_w1(aura::test::CreateTestWindowWithDelegate(
    527       &r2_d1, 0, gfx::Rect(10, 10, 100, 100), root_windows[1]));
    528 
    529   r1_w1->SetCapture();
    530 
    531   ui::test::EventGenerator& generator = GetEventGenerator();
    532   generator.MoveMouseToCenterOf(r2_w1.get());
    533   EXPECT_EQ(gfx::Point(1060, 60).ToString(),
    534             generator.current_location().ToString());
    535 
    536   EventLocationHandler location_handler;
    537   r1_w1->AddPreTargetHandler(&location_handler);
    538   generator.ClickLeftButton();
    539   r1_w1->RemovePreTargetHandler(&location_handler);
    540   // Event-generator dispatches the event in the primary root-window's coord
    541   // space. Since the location is (1060, 60), it goes to the secondary
    542   // root-window as (30, 30) since the secondary root-window has a device scale
    543   // factor of 2.
    544   EXPECT_EQ(gfx::Point(1020, 20).ToString(),
    545             location_handler.press_location().ToString());
    546   EXPECT_EQ(gfx::Point(1020, 20).ToString(),
    547             location_handler.release_location().ToString());
    548 }
    549 
    550 TEST_F(ExtendedDesktopTest, MoveWindow) {
    551   if (!SupportsMultipleDisplays())
    552     return;
    553 
    554   UpdateDisplay("1000x600,600x400");
    555   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    556   views::Widget* d1 = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
    557 
    558   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
    559 
    560   d1->SetBounds(gfx::Rect(1010, 10, 100, 100));
    561   EXPECT_EQ("1010,10 100x100",
    562             d1->GetWindowBoundsInScreen().ToString());
    563 
    564   EXPECT_EQ(root_windows[1], d1->GetNativeView()->GetRootWindow());
    565 
    566   d1->SetBounds(gfx::Rect(10, 10, 100, 100));
    567   EXPECT_EQ("10,10 100x100",
    568             d1->GetWindowBoundsInScreen().ToString());
    569 
    570   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
    571 
    572   // Make sure the bounds which doesn't fit to the root window
    573   // works correctly.
    574   d1->SetBounds(gfx::Rect(1560, 30, 100, 100));
    575   EXPECT_EQ(root_windows[1], d1->GetNativeView()->GetRootWindow());
    576   EXPECT_EQ("1560,30 100x100",
    577             d1->GetWindowBoundsInScreen().ToString());
    578 
    579   // Setting outside of root windows will be moved to primary root window.
    580   // TODO(oshima): This one probably should pick the closest root window.
    581   d1->SetBounds(gfx::Rect(200, 10, 100, 100));
    582   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
    583 }
    584 
    585 // Verifies if the mouse event arrives to the window even when the window
    586 // moves to another root in a pre-target handler.  See: crbug.com/157583
    587 TEST_F(ExtendedDesktopTest, MoveWindowByMouseClick) {
    588   if (!SupportsMultipleDisplays())
    589     return;
    590 
    591   UpdateDisplay("1000x600,600x400");
    592 
    593   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    594   aura::test::EventCountDelegate delegate;
    595   scoped_ptr<aura::Window> window(aura::test::CreateTestWindowWithDelegate(
    596       &delegate, 0, gfx::Rect(10, 10, 100, 100), root_windows[0]));
    597   MoveWindowByClickEventHandler event_handler(window.get());
    598   window->AddPreTargetHandler(&event_handler);
    599 
    600   ui::test::EventGenerator& event_generator(GetEventGenerator());
    601 
    602   event_generator.MoveMouseToCenterOf(window.get());
    603   event_generator.ClickLeftButton();
    604   // Both mouse pressed and released arrive at the window and its delegate.
    605   EXPECT_EQ("1 1", delegate.GetMouseButtonCountsAndReset());
    606   // Also event_handler moves the window to another root at mouse release.
    607   EXPECT_EQ(root_windows[1], window->GetRootWindow());
    608 }
    609 
    610 TEST_F(ExtendedDesktopTest, MoveWindowToDisplay) {
    611   if (!SupportsMultipleDisplays())
    612     return;
    613 
    614   UpdateDisplay("1000x1000,1000x1000");
    615   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    616 
    617   gfx::Display display0 = Shell::GetScreen()->GetDisplayMatching(
    618       root_windows[0]->GetBoundsInScreen());
    619   gfx::Display display1 = Shell::GetScreen()->GetDisplayMatching(
    620       root_windows[1]->GetBoundsInScreen());
    621   EXPECT_NE(display0.id(), display1.id());
    622 
    623   views::Widget* d1 = CreateTestWidget(gfx::Rect(10, 10, 1000, 100));
    624   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
    625 
    626   // Move the window where the window spans both root windows. Since the second
    627   // parameter is |display1|, the window should be shown on the secondary root.
    628   d1->GetNativeWindow()->SetBoundsInScreen(gfx::Rect(500, 10, 1000, 100),
    629                                            display1);
    630   EXPECT_EQ("500,10 1000x100",
    631             d1->GetWindowBoundsInScreen().ToString());
    632   EXPECT_EQ(root_windows[1], d1->GetNativeView()->GetRootWindow());
    633 
    634   // Move to the primary root.
    635   d1->GetNativeWindow()->SetBoundsInScreen(gfx::Rect(500, 10, 1000, 100),
    636                                            display0);
    637   EXPECT_EQ("500,10 1000x100",
    638             d1->GetWindowBoundsInScreen().ToString());
    639   EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow());
    640 }
    641 
    642 TEST_F(ExtendedDesktopTest, MoveWindowWithTransient) {
    643   if (!SupportsMultipleDisplays())
    644     return;
    645 
    646   UpdateDisplay("1000x600,600x400");
    647   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    648   views::Widget* w1 = CreateTestWidget(gfx::Rect(10, 10, 100, 100));
    649   views::Widget* w1_t1 = CreateTestWidgetWithParent(
    650       w1, gfx::Rect(50, 50, 50, 50), false /* transient */);
    651   // Transient child of the transient child.
    652   views::Widget* w1_t11 = CreateTestWidgetWithParent(
    653       w1_t1, gfx::Rect(1200, 70, 35, 35), false /* transient */);
    654 
    655   views::Widget* w11 = CreateTestWidgetWithParent(
    656       w1, gfx::Rect(10, 10, 40, 40), true /* child */);
    657   views::Widget* w11_t1 = CreateTestWidgetWithParent(
    658       w1, gfx::Rect(1300, 100, 80, 80), false /* transient */);
    659 
    660   EXPECT_EQ(root_windows[0], w1->GetNativeView()->GetRootWindow());
    661   EXPECT_EQ(root_windows[0], w11->GetNativeView()->GetRootWindow());
    662   EXPECT_EQ(root_windows[0], w1_t1->GetNativeView()->GetRootWindow());
    663   EXPECT_EQ(root_windows[0], w1_t11->GetNativeView()->GetRootWindow());
    664   EXPECT_EQ(root_windows[0], w11_t1->GetNativeView()->GetRootWindow());
    665   EXPECT_EQ("50,50 50x50",
    666             w1_t1->GetWindowBoundsInScreen().ToString());
    667   EXPECT_EQ("1200,70 35x35",
    668             w1_t11->GetWindowBoundsInScreen().ToString());
    669   EXPECT_EQ("20,20 40x40",
    670             w11->GetWindowBoundsInScreen().ToString());
    671   EXPECT_EQ("1300,100 80x80",
    672             w11_t1->GetWindowBoundsInScreen().ToString());
    673 
    674   w1->SetBounds(gfx::Rect(1100, 10, 100, 100));
    675 
    676   EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow());
    677   EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow());
    678   EXPECT_EQ(root_windows[1], w1_t11->GetNativeView()->GetRootWindow());
    679   EXPECT_EQ(root_windows[1], w11->GetNativeView()->GetRootWindow());
    680   EXPECT_EQ(root_windows[1], w11_t1->GetNativeView()->GetRootWindow());
    681 
    682   EXPECT_EQ("1110,20 40x40",
    683             w11->GetWindowBoundsInScreen().ToString());
    684   // Transient window's screen bounds stays the same.
    685   EXPECT_EQ("50,50 50x50",
    686             w1_t1->GetWindowBoundsInScreen().ToString());
    687   EXPECT_EQ("1200,70 35x35",
    688             w1_t11->GetWindowBoundsInScreen().ToString());
    689   EXPECT_EQ("1300,100 80x80",
    690             w11_t1->GetWindowBoundsInScreen().ToString());
    691 
    692   // Transient window doesn't move between root window unless
    693   // its transient parent moves.
    694   w1_t1->SetBounds(gfx::Rect(10, 50, 50, 50));
    695   EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow());
    696   EXPECT_EQ("10,50 50x50",
    697             w1_t1->GetWindowBoundsInScreen().ToString());
    698 }
    699 
    700 // Test if the Window::ConvertPointToTarget works across root windows.
    701 // TODO(oshima): Move multiple display suport and this test to aura.
    702 TEST_F(ExtendedDesktopTest, ConvertPoint) {
    703   if (!SupportsMultipleDisplays())
    704     return;
    705   gfx::Screen* screen = Shell::GetScreen();
    706   UpdateDisplay("1000x600,600x400");
    707   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    708   gfx::Display display_1 = screen->GetDisplayNearestWindow(root_windows[0]);
    709   EXPECT_EQ("0,0", display_1.bounds().origin().ToString());
    710   gfx::Display display_2 = screen->GetDisplayNearestWindow(root_windows[1]);
    711   EXPECT_EQ("1000,0", display_2.bounds().origin().ToString());
    712 
    713   aura::Window* d1 =
    714       CreateTestWidget(gfx::Rect(10, 10, 100, 100))->GetNativeView();
    715   aura::Window* d2 =
    716       CreateTestWidget(gfx::Rect(1020, 20, 100, 100))->GetNativeView();
    717   EXPECT_EQ(root_windows[0], d1->GetRootWindow());
    718   EXPECT_EQ(root_windows[1], d2->GetRootWindow());
    719 
    720   // Convert point in the Root2's window to the Root1's window Coord.
    721   gfx::Point p(0, 0);
    722   aura::Window::ConvertPointToTarget(root_windows[1], root_windows[0], &p);
    723   EXPECT_EQ("1000,0", p.ToString());
    724   p.SetPoint(0, 0);
    725   aura::Window::ConvertPointToTarget(d2, d1, &p);
    726   EXPECT_EQ("1010,10", p.ToString());
    727 
    728   // Convert point in the Root1's window to the Root2's window Coord.
    729   p.SetPoint(0, 0);
    730   aura::Window::ConvertPointToTarget(root_windows[0], root_windows[1], &p);
    731   EXPECT_EQ("-1000,0", p.ToString());
    732   p.SetPoint(0, 0);
    733   aura::Window::ConvertPointToTarget(d1, d2, &p);
    734   EXPECT_EQ("-1010,-10", p.ToString());
    735 
    736   // Move the 2nd display to the bottom and test again.
    737   SetSecondaryDisplayLayout(DisplayLayout::BOTTOM);
    738 
    739   display_2 = screen->GetDisplayNearestWindow(root_windows[1]);
    740   EXPECT_EQ("0,600", display_2.bounds().origin().ToString());
    741 
    742   // Convert point in Root2's window to Root1's window Coord.
    743   p.SetPoint(0, 0);
    744   aura::Window::ConvertPointToTarget(root_windows[1], root_windows[0], &p);
    745   EXPECT_EQ("0,600", p.ToString());
    746   p.SetPoint(0, 0);
    747   aura::Window::ConvertPointToTarget(d2, d1, &p);
    748   EXPECT_EQ("10,610", p.ToString());
    749 
    750   // Convert point in Root1's window to Root2's window Coord.
    751   p.SetPoint(0, 0);
    752   aura::Window::ConvertPointToTarget(root_windows[0], root_windows[1], &p);
    753   EXPECT_EQ("0,-600", p.ToString());
    754   p.SetPoint(0, 0);
    755   aura::Window::ConvertPointToTarget(d1, d2, &p);
    756   EXPECT_EQ("-10,-610", p.ToString());
    757 }
    758 
    759 TEST_F(ExtendedDesktopTest, OpenSystemTray) {
    760   if (!SupportsMultipleDisplays())
    761     return;
    762 
    763   UpdateDisplay("500x600,600x400");
    764   SystemTray* tray = ash::Shell::GetInstance()->GetPrimarySystemTray();
    765   ASSERT_FALSE(tray->HasSystemBubble());
    766 
    767   ui::test::EventGenerator& event_generator(GetEventGenerator());
    768 
    769   // Opens the tray by a dummy click event and makes sure that adding/removing
    770   // displays doesn't break anything.
    771   event_generator.MoveMouseToCenterOf(tray->GetWidget()->GetNativeWindow());
    772   event_generator.ClickLeftButton();
    773   EXPECT_TRUE(tray->HasSystemBubble());
    774 
    775   UpdateDisplay("500x600");
    776   EXPECT_TRUE(tray->HasSystemBubble());
    777   UpdateDisplay("500x600,600x400");
    778   EXPECT_TRUE(tray->HasSystemBubble());
    779 
    780   // Closes the tray and again makes sure that adding/removing displays doesn't
    781   // break anything.
    782   event_generator.ClickLeftButton();
    783   RunAllPendingInMessageLoop();
    784 
    785   EXPECT_FALSE(tray->HasSystemBubble());
    786 
    787   UpdateDisplay("500x600");
    788   EXPECT_FALSE(tray->HasSystemBubble());
    789   UpdateDisplay("500x600,600x400");
    790   EXPECT_FALSE(tray->HasSystemBubble());
    791 }
    792 
    793 TEST_F(ExtendedDesktopTest, StayInSameRootWindow) {
    794   if (!SupportsMultipleDisplays())
    795     return;
    796 
    797   UpdateDisplay("100x100,200x200");
    798   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    799   views::Widget* w1 = CreateTestWidget(gfx::Rect(10, 10, 50, 50));
    800   EXPECT_EQ(root_windows[0], w1->GetNativeView()->GetRootWindow());
    801   w1->SetBounds(gfx::Rect(150, 10, 50, 50));
    802   EXPECT_EQ(root_windows[1], w1->GetNativeView()->GetRootWindow());
    803 
    804   // The widget stays in the same root if kStayInSameRootWindowKey is set to
    805   // true.
    806   w1->GetNativeView()->SetProperty(kStayInSameRootWindowKey, true);
    807   w1->SetBounds(gfx::Rect(10, 10, 50, 50));
    808   EXPECT_EQ(root_windows[1], w1->GetNativeView()->GetRootWindow());
    809 
    810   // The widget should now move to the 1st root window without the property.
    811   w1->GetNativeView()->ClearProperty(kStayInSameRootWindowKey);
    812   w1->SetBounds(gfx::Rect(10, 10, 50, 50));
    813   EXPECT_EQ(root_windows[0], w1->GetNativeView()->GetRootWindow());
    814 
    815   // a window in SettingsBubbleContainer and StatusContainer should
    816   // not move to another root window regardles of the bounds specified.
    817   aura::Window* settings_bubble_container =
    818       Shell::GetPrimaryRootWindowController()->GetContainer(
    819           kShellWindowId_SettingBubbleContainer);
    820   aura::Window* window = aura::test::CreateTestWindowWithId(
    821       100, settings_bubble_container);
    822   window->SetBoundsInScreen(gfx::Rect(150, 10, 50, 50),
    823                             ScreenUtil::GetSecondaryDisplay());
    824   EXPECT_EQ(root_windows[0], window->GetRootWindow());
    825 
    826   aura::Window* status_container =
    827       Shell::GetPrimaryRootWindowController()->GetContainer(
    828           kShellWindowId_StatusContainer);
    829   window = aura::test::CreateTestWindowWithId(100, status_container);
    830   window->SetBoundsInScreen(gfx::Rect(150, 10, 50, 50),
    831                             ScreenUtil::GetSecondaryDisplay());
    832   EXPECT_EQ(root_windows[0], window->GetRootWindow());
    833 }
    834 
    835 TEST_F(ExtendedDesktopTest, KeyEventsOnLockScreen) {
    836   if (!SupportsMultipleDisplays())
    837     return;
    838 
    839   UpdateDisplay("100x100,200x200");
    840   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
    841 
    842   // Create normal windows on both displays.
    843   views::Widget* widget1 = CreateTestWidget(
    844       Shell::GetScreen()->GetPrimaryDisplay().bounds());
    845   widget1->Show();
    846   EXPECT_EQ(root_windows[0], widget1->GetNativeView()->GetRootWindow());
    847   views::Widget* widget2 = CreateTestWidget(
    848       ScreenUtil::GetSecondaryDisplay().bounds());
    849   widget2->Show();
    850   EXPECT_EQ(root_windows[1], widget2->GetNativeView()->GetRootWindow());
    851 
    852   // Create a LockScreen window.
    853   views::Widget* lock_widget = CreateTestWidget(
    854       Shell::GetScreen()->GetPrimaryDisplay().bounds());
    855   views::Textfield* textfield = new views::Textfield;
    856   lock_widget->client_view()->AddChildView(textfield);
    857 
    858   ash::Shell::GetContainer(Shell::GetPrimaryRootWindow(),
    859                            ash::kShellWindowId_LockScreenContainer)
    860       ->AddChild(lock_widget->GetNativeView());
    861   lock_widget->Show();
    862   textfield->RequestFocus();
    863 
    864   aura::client::FocusClient* focus_client =
    865       aura::client::GetFocusClient(root_windows[0]);
    866   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
    867 
    868   // The lock window should get events on both root windows.
    869   ui::test::EventGenerator& event_generator(GetEventGenerator());
    870 
    871   event_generator.set_current_target(root_windows[0]);
    872   event_generator.PressKey(ui::VKEY_A, 0);
    873   event_generator.ReleaseKey(ui::VKEY_A, 0);
    874   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
    875   EXPECT_EQ("a", base::UTF16ToASCII(textfield->text()));
    876 
    877   event_generator.set_current_target(root_windows[1]);
    878   event_generator.PressKey(ui::VKEY_B, 0);
    879   event_generator.ReleaseKey(ui::VKEY_B, 0);
    880   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
    881   EXPECT_EQ("ab", base::UTF16ToASCII(textfield->text()));
    882 
    883   // Deleting 2nd display. The lock window still should get the events.
    884   UpdateDisplay("100x100");
    885   event_generator.PressKey(ui::VKEY_C, 0);
    886   event_generator.ReleaseKey(ui::VKEY_C, 0);
    887   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
    888   EXPECT_EQ("abc", base::UTF16ToASCII(textfield->text()));
    889 
    890   // Creating 2nd display again, and lock window still should get events
    891   // on both root windows.
    892   UpdateDisplay("100x100,200x200");
    893   root_windows = Shell::GetAllRootWindows();
    894   event_generator.set_current_target(root_windows[0]);
    895   event_generator.PressKey(ui::VKEY_D, 0);
    896   event_generator.ReleaseKey(ui::VKEY_D, 0);
    897   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
    898   EXPECT_EQ("abcd", base::UTF16ToASCII(textfield->text()));
    899 
    900   event_generator.set_current_target(root_windows[1]);
    901   event_generator.PressKey(ui::VKEY_E, 0);
    902   event_generator.ReleaseKey(ui::VKEY_E, 0);
    903   EXPECT_EQ(lock_widget->GetNativeView(), focus_client->GetFocusedWindow());
    904   EXPECT_EQ("abcde", base::UTF16ToASCII(textfield->text()));
    905 }
    906 
    907 TEST_F(ExtendedDesktopTest, PassiveGrab) {
    908   if (!SupportsMultipleDisplays())
    909     return;
    910 
    911   EventLocationRecordingEventHandler event_handler;
    912   ash::Shell::GetInstance()->AddPreTargetHandler(&event_handler);
    913 
    914   UpdateDisplay("300x300,200x200");
    915 
    916   views::Widget* widget = CreateTestWidget(gfx::Rect(50, 50, 200, 200));
    917   widget->Show();
    918   ASSERT_EQ("50,50 200x200", widget->GetWindowBoundsInScreen().ToString());
    919 
    920   ui::test::EventGenerator& generator(GetEventGenerator());
    921   generator.MoveMouseTo(150, 150);
    922   EXPECT_EQ("100,100 150,150", event_handler.GetLocationsAndReset());
    923 
    924   generator.PressLeftButton();
    925   generator.MoveMouseTo(400, 150);
    926 
    927   EXPECT_EQ("350,100 400,150", event_handler.GetLocationsAndReset());
    928 
    929   generator.ReleaseLeftButton();
    930   EXPECT_EQ("-999,-999 -999,-999", event_handler.GetLocationsAndReset());
    931 
    932   generator.MoveMouseTo(400, 150);
    933   EXPECT_EQ("100,150 100,150", event_handler.GetLocationsAndReset());
    934 
    935   ash::Shell::GetInstance()->RemovePreTargetHandler(&event_handler);
    936 }
    937 
    938 }  // namespace ash
    939