Adjust the z-order of the virtual keyboard to ensure that it does not overlap context menus.  Previously, the virtual keyboard was placed just below the cursor container.  Adding a test case to ensure that the virtual keyboard overlaps normal windows but not menus.

BUG=377180

Review URL: https://codereview.chromium.org/565373002

Cr-Commit-Position: refs/heads/master@{#295268}
diff --git a/ash/root_window_controller_unittest.cc b/ash/root_window_controller_unittest.cc
index a692722..3be8a01 100644
--- a/ash/root_window_controller_unittest.cc
+++ b/ash/root_window_controller_unittest.cc
@@ -15,6 +15,7 @@
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
 #include "ui/aura/client/focus_change_observer.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/client/window_tree_client.h"
@@ -647,6 +648,21 @@
   DISALLOW_COPY_AND_ASSIGN(MockTextInputClient);
 };
 
+class TargetHitTestEventHandler : public ui::test::TestEventHandler {
+ public:
+  TargetHitTestEventHandler() {}
+
+  // ui::test::TestEventHandler overrides.
+  virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
+    if (event->type() == ui::ET_MOUSE_PRESSED)
+      ui::test::TestEventHandler::OnMouseEvent(event);
+    event->StopPropagation();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TargetHitTestEventHandler);
+};
+
 // Test for http://crbug.com/297858. Virtual keyboard container should only show
 // on primary root window.
 TEST_F(VirtualKeyboardRootWindowControllerTest,
@@ -841,5 +857,92 @@
   }
 }
 
+// Tests that the virtual keyboard does not block context menus. The virtual
+// keyboard should appear in front of most content, but not context menus. See
+// crbug/377180.
+TEST_F(VirtualKeyboardRootWindowControllerTest, ZOrderTest) {
+  UpdateDisplay("800x600");
+  keyboard::KeyboardController* keyboard_controller =
+      keyboard::KeyboardController::GetInstance();
+  keyboard::KeyboardControllerProxy* proxy = keyboard_controller->proxy();
+
+  aura::Window* root_window = Shell::GetPrimaryRootWindow();
+  aura::Window* keyboard_container =
+      Shell::GetContainer(root_window, kShellWindowId_VirtualKeyboardContainer);
+  ASSERT_TRUE(keyboard_container);
+  keyboard_container->Show();
+
+  const int keyboard_height = 200;
+  aura::Window* keyboard_window = proxy->GetKeyboardWindow();
+  keyboard_container->AddChild(keyboard_window);
+  keyboard_window->set_owned_by_parent(false);
+  gfx::Rect keyboard_bounds = keyboard::KeyboardBoundsFromWindowBounds(
+      keyboard_container->bounds(), keyboard_height);
+  keyboard_window->SetBounds(keyboard_bounds);
+  keyboard_window->Show();
+
+  ui::test::EventGenerator generator(root_window);
+
+  // Cover the screen with two windows: a normal window on the left side and a
+  // context menu on the right side. When the virtual keyboard is displayed it
+  // partially occludes the normal window, but not the context menu. Compute
+  // positions for generating synthetic click events to perform hit tests,
+  // ensuring the correct window layering. 'top' is above the VK, whereas
+  // 'bottom' lies within the VK. 'left' is centered in the normal window, and
+  // 'right' is centered in the context menu.
+  int window_height = keyboard_bounds.bottom();
+  int window_width = keyboard_bounds.width() / 2;
+  int left = window_width / 2;
+  int right = 3 * window_width / 2;
+  int top = keyboard_bounds.y() / 2;
+  int bottom = window_height - keyboard_height / 2;
+
+  // Normal window is partially occluded by the virtual keyboard.
+  aura::test::TestWindowDelegate delegate;
+  scoped_ptr<aura::Window> normal(CreateTestWindowInShellWithDelegateAndType(
+      &delegate,
+      ui::wm::WINDOW_TYPE_NORMAL,
+      0,
+      gfx::Rect(0, 0, window_width, window_height)));
+  normal->set_owned_by_parent(false);
+  normal->Show();
+  TargetHitTestEventHandler normal_handler;
+  normal->AddPreTargetHandler(&normal_handler);
+
+  // Test that only the click on the top portion of the window is picked up. The
+  // click on the bottom hits the virtual keyboard instead.
+  generator.MoveMouseTo(left, top);
+  generator.ClickLeftButton();
+  EXPECT_EQ(1, normal_handler.num_mouse_events());
+  generator.MoveMouseTo(left, bottom);
+  generator.ClickLeftButton();
+  EXPECT_EQ(1, normal_handler.num_mouse_events());
+
+  // Menu overlaps virtual keyboard.
+  aura::test::TestWindowDelegate delegate2;
+  scoped_ptr<aura::Window> menu(CreateTestWindowInShellWithDelegateAndType(
+      &delegate2,
+      ui::wm::WINDOW_TYPE_MENU,
+      0,
+      gfx::Rect(window_width, 0, window_width, window_height)));
+  menu->set_owned_by_parent(false);
+  menu->Show();
+  TargetHitTestEventHandler menu_handler;
+  menu->AddPreTargetHandler(&menu_handler);
+
+  // Test that both clicks register.
+  generator.MoveMouseTo(right, top);
+  generator.ClickLeftButton();
+  EXPECT_EQ(1, menu_handler.num_mouse_events());
+  generator.MoveMouseTo(right, bottom);
+  generator.ClickLeftButton();
+  EXPECT_EQ(2, menu_handler.num_mouse_events());
+
+  // Cleanup to ensure that the test windows are destroyed before their
+  // delegates.
+  normal.reset();
+  menu.reset();
+}
+
 }  // namespace test
 }  // namespace ash