blob: 9a90bf51ed4af0d0b1edd782f13d98d870aa2f62 [file] [log] [blame]
jinsukkim5c3a1202017-03-10 00:02:141// Copyright 2017 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
jinsukkime98211462017-05-12 09:57:045#include "base/test/gtest_util.h"
jinsukkim5c3a1202017-03-10 00:02:146#include "testing/gtest/include/gtest/gtest.h"
7#include "ui/android/event_forwarder.h"
8#include "ui/android/view_android.h"
Jinsuk Kimd5d29a22017-08-29 01:39:449#include "ui/android/view_android_observer.h"
Jinsuk Kimd5d29a22017-08-29 01:39:4410#include "ui/android/window_android.h"
Jinsuk Kim1f8f47a32018-04-23 02:08:2211#include "ui/events/android/event_handler_android.h"
jinsukkim5c3a1202017-03-10 00:02:1412#include "ui/events/android/motion_event_android.h"
Majid Valipour7f256682018-01-17 06:35:3713#include "ui/events/test/scoped_event_test_tick_clock.h"
jinsukkim5c3a1202017-03-10 00:02:1414
15namespace ui {
16
17using base::android::JavaParamRef;
18
Jinsuk Kim86071c82017-09-07 00:49:0519class TestViewAndroid : public ViewAndroid {
20 public:
Jinsuk Kim1f8f47a32018-04-23 02:08:2221 TestViewAndroid(ViewAndroid::LayoutType layout_type)
22 : ViewAndroid(layout_type) {}
Jinsuk Kim86071c82017-09-07 00:49:0523
24 float GetDipScale() override { return 1.f; }
25};
26
Jinsuk Kim1f8f47a32018-04-23 02:08:2227class TestEventHandler : public EventHandlerAndroid {
jinsukkim5c3a1202017-03-10 00:02:1428 public:
Jinsuk Kim1f8f47a32018-04-23 02:08:2229 TestEventHandler() {}
jinsukkim5c3a1202017-03-10 00:02:1430
Jinsuk Kim2b859472017-08-30 02:47:1931 bool OnTouchEvent(const MotionEventAndroid& event) override {
Jinsuk Kim86071c82017-09-07 00:49:0532 touch_called_ = true;
jinsukkim5c3a1202017-03-10 00:02:1433 return handle_event_;
34 }
Jinsuk Kim86071c82017-09-07 00:49:0535 void OnSizeChanged() override { onsize_called_ = true; }
jinsukkim5c3a1202017-03-10 00:02:1436
Jinsuk Kim86071c82017-09-07 00:49:0537 void SetHandleEvent(bool handle_event) { handle_event_ = handle_event; }
38 bool TouchEventHandled() { return touch_called_ && handle_event_; }
39 bool TouchEventCalled() { return touch_called_; }
40 bool OnSizeCalled() { return onsize_called_; }
41 void Reset() {
42 touch_called_ = false;
43 onsize_called_ = false;
44 }
jinsukkim5c3a1202017-03-10 00:02:1445
46 private:
Jinsuk Kim86071c82017-09-07 00:49:0547 bool handle_event_{true}; // Marks as event was consumed. True by default.
48 bool touch_called_{false};
49 bool onsize_called_{false};
jinsukkim5c3a1202017-03-10 00:02:1450};
51
52class ViewAndroidBoundsTest : public testing::Test {
53 public:
54 ViewAndroidBoundsTest()
Jinsuk Kim1f8f47a32018-04-23 02:08:2255 : root_(ViewAndroid::LayoutType::MATCH_PARENT),
56 view1_(ViewAndroid::LayoutType::NORMAL),
57 view2_(ViewAndroid::LayoutType::NORMAL),
58 view3_(ViewAndroid::LayoutType::NORMAL),
59 viewm_(ViewAndroid::LayoutType::MATCH_PARENT) {
jinsukkim5c3a1202017-03-10 00:02:1460 root_.GetEventForwarder();
Jinsuk Kim1f8f47a32018-04-23 02:08:2261 view1_.set_event_handler(&handler1_);
62 view2_.set_event_handler(&handler2_);
63 view3_.set_event_handler(&handler3_);
64 viewm_.set_event_handler(&handlerm_);
jinsukkim5c3a1202017-03-10 00:02:1465 }
66
67 void Reset() {
Jinsuk Kim1f8f47a32018-04-23 02:08:2268 handler1_.Reset();
69 handler2_.Reset();
70 handler3_.Reset();
71 handlerm_.Reset();
Majid Valipour7f256682018-01-17 06:35:3772 test_clock_.SetNowTicks(base::TimeTicks());
jinsukkim5c3a1202017-03-10 00:02:1473 }
74
75 void GenerateTouchEventAt(float x, float y) {
76 ui::MotionEventAndroid::Pointer pointer0(0, x, y, 0, 0, 0, 0, 0);
77 ui::MotionEventAndroid::Pointer pointer1(0, 0, 0, 0, 0, 0, 0, 0);
jinsukkimb40b402c2017-03-29 09:39:0878 ui::MotionEventAndroid event(nullptr, JavaParamRef<jobject>(nullptr), 1.f,
Jinsuk Kim2b859472017-08-30 02:47:1979 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, false,
jinsukkimb40b402c2017-03-29 09:39:0880 &pointer0, &pointer1);
Jinsuk Kim2b859472017-08-30 02:47:1981 root_.OnTouchEvent(event);
jinsukkim5c3a1202017-03-10 00:02:1482 }
83
Jinsuk Kim1f8f47a32018-04-23 02:08:2284 void ExpectHit(const TestEventHandler& hitHandler) {
85 TestEventHandler* handlers[4] = {&handler1_, &handler2_, &handler3_,
86 &handlerm_};
87 for (auto* handler : handlers) {
88 if (&hitHandler == handler)
89 EXPECT_TRUE(handler->TouchEventHandled());
jinsukkim5c3a1202017-03-10 00:02:1490 else
Jinsuk Kim1f8f47a32018-04-23 02:08:2291 EXPECT_FALSE(handler->TouchEventHandled());
jinsukkim5c3a1202017-03-10 00:02:1492 }
93 Reset();
94 }
95
Jinsuk Kim86071c82017-09-07 00:49:0596 TestViewAndroid root_;
97 TestViewAndroid view1_;
98 TestViewAndroid view2_;
99 TestViewAndroid view3_;
Jinsuk Kim7d04c9e2017-09-13 00:22:18100 TestViewAndroid viewm_; // match-parent view
Jinsuk Kim1f8f47a32018-04-23 02:08:22101 TestEventHandler handler1_;
102 TestEventHandler handler2_;
103 TestEventHandler handler3_;
104 TestEventHandler handlerm_;
Majid Valipour7f256682018-01-17 06:35:37105 ui::test::ScopedEventTestTickClock test_clock_;
jinsukkim5c3a1202017-03-10 00:02:14106};
107
108TEST_F(ViewAndroidBoundsTest, MatchesViewInFront) {
Jinsuk Kim7d04c9e2017-09-13 00:22:18109 view1_.SetLayoutForTesting(50, 50, 400, 600);
110 view2_.SetLayoutForTesting(50, 50, 400, 600);
jinsukkim5c3a1202017-03-10 00:02:14111 root_.AddChild(&view2_);
112 root_.AddChild(&view1_);
113
114 GenerateTouchEventAt(100.f, 100.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22115 ExpectHit(handler1_);
jinsukkim5c3a1202017-03-10 00:02:14116
117 // View 2 moves up to the top, and events should hit it from now.
118 root_.MoveToFront(&view2_);
119 GenerateTouchEventAt(100.f, 100.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22120 ExpectHit(handler2_);
jinsukkim5c3a1202017-03-10 00:02:14121}
122
123TEST_F(ViewAndroidBoundsTest, MatchesViewArea) {
Jinsuk Kim7d04c9e2017-09-13 00:22:18124 view1_.SetLayoutForTesting(50, 50, 200, 200);
125 view2_.SetLayoutForTesting(20, 20, 400, 600);
jinsukkim5c3a1202017-03-10 00:02:14126
127 root_.AddChild(&view2_);
128 root_.AddChild(&view1_);
129
130 // Falls within |view1_|'s bounds
131 GenerateTouchEventAt(100.f, 100.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22132 ExpectHit(handler1_);
jinsukkim5c3a1202017-03-10 00:02:14133
134 // Falls within |view2_|'s bounds
135 GenerateTouchEventAt(300.f, 400.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22136 ExpectHit(handler2_);
jinsukkim5c3a1202017-03-10 00:02:14137}
138
139TEST_F(ViewAndroidBoundsTest, MatchesViewAfterMove) {
Jinsuk Kim7d04c9e2017-09-13 00:22:18140 view1_.SetLayoutForTesting(50, 50, 200, 200);
141 view2_.SetLayoutForTesting(20, 20, 400, 600);
jinsukkim5c3a1202017-03-10 00:02:14142 root_.AddChild(&view2_);
143 root_.AddChild(&view1_);
144
145 GenerateTouchEventAt(100.f, 100.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22146 ExpectHit(handler1_);
jinsukkim5c3a1202017-03-10 00:02:14147
Jinsuk Kim7d04c9e2017-09-13 00:22:18148 view1_.SetLayoutForTesting(150, 150, 200, 200);
jinsukkim5c3a1202017-03-10 00:02:14149 GenerateTouchEventAt(100.f, 100.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22150 ExpectHit(handler2_);
jinsukkim5c3a1202017-03-10 00:02:14151}
152
153TEST_F(ViewAndroidBoundsTest, MatchesViewSizeOfkMatchParent) {
Jinsuk Kim7d04c9e2017-09-13 00:22:18154 view1_.SetLayoutForTesting(20, 20, 400, 600);
155 view2_.SetLayoutForTesting(50, 50, 200, 200);
jinsukkim5c3a1202017-03-10 00:02:14156
157 root_.AddChild(&view1_);
158 root_.AddChild(&view2_);
Jinsuk Kim7d04c9e2017-09-13 00:22:18159 view1_.AddChild(&viewm_);
jinsukkim5c3a1202017-03-10 00:02:14160
161 GenerateTouchEventAt(100.f, 100.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22162 ExpectHit(handler2_);
jinsukkim5c3a1202017-03-10 00:02:14163
164 GenerateTouchEventAt(300.f, 400.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22165 ExpectHit(handler1_);
jinsukkim5c3a1202017-03-10 00:02:14166
Jinsuk Kim1f8f47a32018-04-23 02:08:22167 handler1_.SetHandleEvent(false);
jinsukkim5c3a1202017-03-10 00:02:14168 GenerateTouchEventAt(300.f, 400.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22169 EXPECT_TRUE(handler1_.TouchEventCalled());
170 ExpectHit(handlerm_);
jinsukkim5c3a1202017-03-10 00:02:14171}
172
173TEST_F(ViewAndroidBoundsTest, MatchesViewsWithOffset) {
Jinsuk Kim7d04c9e2017-09-13 00:22:18174 view1_.SetLayoutForTesting(10, 20, 150, 100);
175 view2_.SetLayoutForTesting(20, 30, 40, 30);
176 view3_.SetLayoutForTesting(70, 30, 40, 30);
jinsukkim5c3a1202017-03-10 00:02:14177
178 root_.AddChild(&view1_);
179 view1_.AddChild(&view2_);
180 view1_.AddChild(&view3_);
181
182 GenerateTouchEventAt(70, 30);
Jinsuk Kim1f8f47a32018-04-23 02:08:22183 ExpectHit(handler1_);
jinsukkim5c3a1202017-03-10 00:02:14184
Jinsuk Kim1f8f47a32018-04-23 02:08:22185 handler1_.SetHandleEvent(false);
jinsukkim5c3a1202017-03-10 00:02:14186 GenerateTouchEventAt(40, 60);
Jinsuk Kim1f8f47a32018-04-23 02:08:22187 EXPECT_TRUE(handler1_.TouchEventCalled());
188 ExpectHit(handler2_);
jinsukkim5c3a1202017-03-10 00:02:14189
190 GenerateTouchEventAt(100, 70);
Jinsuk Kim1f8f47a32018-04-23 02:08:22191 EXPECT_TRUE(handler1_.TouchEventCalled());
192 ExpectHit(handler3_);
jinsukkim5c3a1202017-03-10 00:02:14193}
194
Jinsuk Kim86071c82017-09-07 00:49:05195TEST_F(ViewAndroidBoundsTest, OnSizeChanged) {
196 root_.AddChild(&view1_);
Jinsuk Kim7d04c9e2017-09-13 00:22:18197 view1_.AddChild(&viewm_);
Jinsuk Kim86071c82017-09-07 00:49:05198 view1_.AddChild(&view3_);
199
Jinsuk Kim86071c82017-09-07 00:49:05200 // Size event propagates to non-match-parent children only.
201 view1_.OnSizeChanged(100, 100);
Jinsuk Kim1f8f47a32018-04-23 02:08:22202 EXPECT_TRUE(handler1_.OnSizeCalled());
203 EXPECT_TRUE(handlerm_.OnSizeCalled());
204 EXPECT_FALSE(handler3_.OnSizeCalled());
Jinsuk Kim86071c82017-09-07 00:49:05205
206 Reset();
207
Jinsuk Kim7d04c9e2017-09-13 00:22:18208 // Match-parent view should not receivee size events in the first place.
209 EXPECT_DCHECK_DEATH(viewm_.OnSizeChanged(100, 200));
Jinsuk Kim1f8f47a32018-04-23 02:08:22210 EXPECT_FALSE(handlerm_.OnSizeCalled());
211 EXPECT_FALSE(handler3_.OnSizeCalled());
Jinsuk Kim86071c82017-09-07 00:49:05212
Jinsuk Kimd602a12a2017-12-14 01:27:19213 viewm_.RemoveFromParent();
214 viewm_.OnSizeChangedInternal(gfx::Size(0, 0)); // Reset the size.
215
Jinsuk Kim86071c82017-09-07 00:49:05216 Reset();
217
Jinsuk Kim86071c82017-09-07 00:49:05218 view1_.OnSizeChanged(100, 100);
219
220 // Size event is generated for a newly added, match-parent child view.
Jinsuk Kim1f8f47a32018-04-23 02:08:22221 EXPECT_FALSE(handlerm_.OnSizeCalled());
Jinsuk Kim7d04c9e2017-09-13 00:22:18222 view1_.AddChild(&viewm_);
Jinsuk Kim1f8f47a32018-04-23 02:08:22223 EXPECT_TRUE(handlerm_.OnSizeCalled());
224 EXPECT_FALSE(handler3_.OnSizeCalled());
Jinsuk Kimd602a12a2017-12-14 01:27:19225
226 viewm_.RemoveFromParent();
227
228 Reset();
229
230 view1_.OnSizeChanged(100, 100);
231
232 // Size event won't propagate if the children already have the same size.
233 view1_.AddChild(&viewm_);
Jinsuk Kim1f8f47a32018-04-23 02:08:22234 EXPECT_FALSE(handlerm_.OnSizeCalled());
235 EXPECT_FALSE(handler3_.OnSizeCalled());
Jinsuk Kim86071c82017-09-07 00:49:05236}
237
jinsukkime98211462017-05-12 09:57:04238TEST(ViewAndroidTest, ChecksMultipleEventForwarders) {
239 ViewAndroid parent;
240 ViewAndroid child;
241 parent.GetEventForwarder();
242 child.GetEventForwarder();
243 EXPECT_DCHECK_DEATH(parent.AddChild(&child));
244
245 ViewAndroid parent2;
246 ViewAndroid child2;
247 parent2.GetEventForwarder();
248 parent2.AddChild(&child2);
249 EXPECT_DCHECK_DEATH(child2.GetEventForwarder());
250
251 ViewAndroid window;
252 ViewAndroid wcv1, wcv2;
253 ViewAndroid rwhv1a, rwhv1b, rwhv2;
254 wcv1.GetEventForwarder();
255 wcv2.GetEventForwarder();
256
257 window.AddChild(&wcv1);
258 wcv1.AddChild(&rwhv1a);
259 wcv1.AddChild(&rwhv1b);
260
261 wcv2.AddChild(&rwhv2);
262
263 // window should be able to add wcv2 since there's only one event forwarder
264 // in the path window - wcv2* - rwvh2
265 window.AddChild(&wcv2);
266
267 // Additional event forwarder will cause failure.
268 EXPECT_DCHECK_DEATH(rwhv2.GetEventForwarder());
269}
270
Jinsuk Kimd5d29a22017-08-29 01:39:44271class Observer : public ViewAndroidObserver {
272 public:
273 Observer() : attached_(false) {}
274
275 void OnAttachedToWindow() override { attached_ = true; }
276
277 void OnDetachedFromWindow() override { attached_ = false; }
278
279 bool attached_;
280};
281
282TEST(ViewAndroidTest, Observer) {
283 std::unique_ptr<WindowAndroid> window(WindowAndroid::CreateForTesting());
284 ViewAndroid top;
285 ViewAndroid bottom;
286
287 Observer top_observer;
288 Observer bottom_observer;
289
290 top.AddObserver(&top_observer);
291 bottom.AddObserver(&bottom_observer);
292
293 top.AddChild(&bottom);
294
295 EXPECT_FALSE(top_observer.attached_);
296 EXPECT_FALSE(bottom_observer.attached_);
297
298 // Views in a tree all get notified of 'attached' event.
299 window->AddChild(&top);
300 EXPECT_TRUE(top_observer.attached_);
301 EXPECT_TRUE(bottom_observer.attached_);
302
303 // Observer, upon addition, does not get notified of the current
304 // attached state.
305 Observer top_observer2;
306 top.AddObserver(&top_observer2);
307 EXPECT_FALSE(top_observer2.attached_);
308
309 bottom.RemoveFromParent();
310 EXPECT_FALSE(bottom_observer.attached_);
311 top.RemoveFromParent();
312 EXPECT_FALSE(top_observer.attached_);
313
314 window->AddChild(&top);
315 EXPECT_TRUE(top_observer.attached_);
316
317 // View, upon addition to a tree in the attached state, should be notified.
318 top.AddChild(&bottom);
319 EXPECT_TRUE(bottom_observer.attached_);
320
321 // Views in a tree all get notified of 'detached' event.
322 top.RemoveFromParent();
323 EXPECT_FALSE(top_observer.attached_);
324 EXPECT_FALSE(bottom_observer.attached_);
325}
326
jinsukkim5c3a1202017-03-10 00:02:14327} // namespace ui