File: back_gesture_browsertest.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (210 lines) | stat: -rw-r--r-- 8,800 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/public/cpp/test/shell_test_api.h"
#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
#include "base/containers/contains.h"
#include "base/path_service.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_base.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/hit_test_region_observer.h"
#include "net/dns/mock_host_resolver.h"
#include "ui/aura/window.h"
#include "ui/display/screen.h"
#include "ui/events/test/event_generator.h"
#include "ui/events/types/event_type.h"

namespace {

// The class to record received gesture events and key events to verify if back
// gesture has been performed.
class BackGestureEventRecorder : public ui::EventHandler {
 public:
  BackGestureEventRecorder() = default;
  BackGestureEventRecorder(const BackGestureEventRecorder&) = delete;
  BackGestureEventRecorder& operator=(const BackGestureEventRecorder&) = delete;
  ~BackGestureEventRecorder() override = default;

  // ui::EventHandler:
  void OnGestureEvent(ui::GestureEvent* event) override {
    received_event_types_.insert(event->type());
    if (wait_for_event_ == event->type() && run_loop_) {
      run_loop_->Quit();
      wait_for_event_ = ui::EventType::kUnknown;
    }
  }

  void OnKeyEvent(ui::KeyEvent* event) override {
    // If back gesture can be performed, a ui::VKEY_BROWSR_BACK key pressed and
    // key released will be generated.
    received_event_types_.insert(event->type());
  }

  void WaitUntilReceivedGestureEvent(ui::EventType event_type) {
    wait_for_event_ = event_type;
    run_loop_ = std::make_unique<base::RunLoop>();
    run_loop_->Run();
  }

  bool HasReceivedEvent(ui::EventType event_type) {
    return base::Contains(received_event_types_, event_type);
  }

  void Reset() {
    received_event_types_.clear();
    wait_for_event_ = ui::EventType::kUnknown;
    if (run_loop_) {
      run_loop_->Quit();
    }
  }

 private:
  // Stores the event types of the received gesture events.
  base::flat_set<ui::EventType> received_event_types_;
  ui::EventType wait_for_event_ = ui::EventType::kUnknown;
  std::unique_ptr<base::RunLoop> run_loop_;
};

}  // namespace

class BackGestureBrowserTest : public InProcessBrowserTest {
 public:
  BackGestureBrowserTest() = default;
  BackGestureBrowserTest(const BackGestureBrowserTest&) = delete;
  BackGestureBrowserTest& operator=(const BackGestureBrowserTest&) = delete;
  ~BackGestureBrowserTest() override = default;

  void SetUpOnMainThread() override {
    InProcessBrowserTest::SetUpOnMainThread();
    host_resolver()->AddRule("*", "127.0.0.1");
    base::FilePath test_data_dir;
    ASSERT_TRUE(
        base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &test_data_dir));
    embedded_test_server()->ServeFilesFromDirectory(
        test_data_dir.AppendASCII("chrome/test/data/ash/back_gesture"));
    ASSERT_TRUE(embedded_test_server()->Start());

    // Enter tablet mode.
    ash::TabletModeControllerTestApi().EnterTabletMode();
    ASSERT_TRUE(display::Screen::GetScreen()->InTabletMode());
  }

  content::RenderWidgetHost* GetRenderWidgetHost() {
    return browser()
        ->tab_strip_model()
        ->GetActiveWebContents()
        ->GetRenderWidgetHostView()
        ->GetRenderWidgetHost();
  }

  // Navigate to |url| and wait until browser thread is synchronized with render
  // thread. It's needed so that the touch action is correctly initialized.
  void NavigateToURLAndWaitForMainFrame(const GURL& url) {
    ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url));
    content::MainThreadFrameObserver frame_observer(GetRenderWidgetHost());
    frame_observer.Wait();
  }
};

// Test back gesture behavior with different touch actions.
IN_PROC_BROWSER_TEST_F(BackGestureBrowserTest, TouchActions) {
  // Navigate to a page with {touch-action: none} defined.
  NavigateToURLAndWaitForMainFrame(
      embedded_test_server()->GetURL("/page_touch_action_none.html"));
  ASSERT_EQ(browser()->tab_strip_model()->count(), 1);

  aura::Window* browser_window = browser()->window()->GetNativeWindow();
  const gfx::Rect bounds = browser()->window()->GetBounds();
  const gfx::Point start_point = bounds.left_center();
  const gfx::Point end_point =
      gfx::Point(start_point.x() + 200, start_point.y());

  BackGestureEventRecorder recorder;
  browser_window->AddPreTargetHandler(&recorder);

  ui::test::EventGenerator event_generator(browser_window->GetRootWindow(),
                                           browser_window);
  event_generator.set_current_screen_location(start_point);
  event_generator.PressTouch();
  event_generator.MoveTouch(end_point);
  event_generator.ReleaseTouch();
  recorder.WaitUntilReceivedGestureEvent(ui::EventType::kGestureEnd);

  // BackGestureEventHandler did not handle gesture scroll events, so |recorder|
  // should be able to get the scroll events.
  EXPECT_TRUE(recorder.HasReceivedEvent(ui::EventType::kGestureTapDown));
  EXPECT_TRUE(recorder.HasReceivedEvent(ui::EventType::kGestureScrollBegin));
  EXPECT_TRUE(recorder.HasReceivedEvent(ui::EventType::kGestureScrollUpdate));
  EXPECT_TRUE(recorder.HasReceivedEvent(ui::EventType::kGestureScrollEnd) ||
              recorder.HasReceivedEvent(ui::EventType::kScrollFlingStart));
  // ui::VKEY_BROWSR_BACK key pressed and key released will not be generated
  // because back operation is not performed.
  EXPECT_FALSE(recorder.HasReceivedEvent(ui::EventType::kKeyPressed));
  EXPECT_FALSE(recorder.HasReceivedEvent(ui::EventType::kKeyReleased));

  recorder.Reset();

  // Now navigate to a page with {touch-action: auto} defined.
  NavigateToURLAndWaitForMainFrame(
      embedded_test_server()->GetURL("/page_touch_action_auto.html"));

  event_generator.set_current_screen_location(start_point);
  event_generator.PressTouch();
  event_generator.MoveTouch(end_point);
  event_generator.ReleaseTouch();
  recorder.WaitUntilReceivedGestureEvent(ui::EventType::kGestureEnd);

  // BackGestureEventHandler has handled gesture scroll events, so |recorder|
  // should not be able to get the scroll events.
  EXPECT_FALSE(recorder.HasReceivedEvent(ui::EventType::kGestureTapDown));
  EXPECT_FALSE(recorder.HasReceivedEvent(ui::EventType::kGestureScrollBegin));
  EXPECT_FALSE(recorder.HasReceivedEvent(ui::EventType::kGestureScrollUpdate));
  EXPECT_FALSE(recorder.HasReceivedEvent(ui::EventType::kGestureScrollEnd));
  EXPECT_FALSE(recorder.HasReceivedEvent(ui::EventType::kScrollFlingStart));
  // ui::VKEY_BROWSR_BACK key pressed and key released will be generated because
  // back operation can be performed.
  EXPECT_TRUE(recorder.HasReceivedEvent(ui::EventType::kKeyPressed));
  EXPECT_TRUE(recorder.HasReceivedEvent(ui::EventType::kKeyReleased));
  browser_window->RemovePreTargetHandler(&recorder);
}

// Test the back gesture behavior on page that has prevented default touch
// behavior.
IN_PROC_BROWSER_TEST_F(BackGestureBrowserTest, PreventDefault) {
  NavigateToURLAndWaitForMainFrame(
      embedded_test_server()->GetURL("/page_prevent_default.html"));
  ASSERT_EQ(browser()->tab_strip_model()->count(), 1);

  aura::Window* browser_window = browser()->window()->GetNativeWindow();
  const gfx::Rect bounds = browser()->window()->GetBounds();
  BackGestureEventRecorder recorder;
  browser_window->AddPreTargetHandler(&recorder);

  // Start drag on the page that prevents default touch behavior.
  const gfx::Point start_point = bounds.left_center();
  const gfx::Point end_point =
      gfx::Point(start_point.x() + 200, start_point.y());
  ui::test::EventGenerator event_generator(browser_window->GetRootWindow(),
                                           browser_window);
  event_generator.set_current_screen_location(start_point);
  event_generator.PressTouch();
  event_generator.MoveTouch(end_point);
  event_generator.ReleaseTouch();
  recorder.WaitUntilReceivedGestureEvent(ui::EventType::kGestureEnd);

  // ui::VKEY_BROWSR_BACK key pressed and key released will not be generated
  // because back operation is not performed.
  EXPECT_FALSE(recorder.HasReceivedEvent(ui::EventType::kKeyPressed));
  EXPECT_FALSE(recorder.HasReceivedEvent(ui::EventType::kKeyReleased));
  browser_window->RemovePreTargetHandler(&recorder);
}