blob: 566e561c9c846e65a51377d88311ebf73d668a3f [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
Michael Thiessenf42f9f32022-02-03 22:23:065#include "ui/android/view_android.h"
jinsukkime98211462017-05-12 09:57:046#include "base/test/gtest_util.h"
jinsukkim5c3a1202017-03-10 00:02:147#include "testing/gtest/include/gtest/gtest.h"
8#include "ui/android/event_forwarder.h"
9#include "ui/android/view_android.h"
Jinsuk Kimd5d29a22017-08-29 01:39:4410#include "ui/android/view_android_observer.h"
Jinsuk Kimd5d29a22017-08-29 01:39:4411#include "ui/android/window_android.h"
Jinsuk Kim1f8f47a32018-04-23 02:08:2212#include "ui/events/android/event_handler_android.h"
jinsukkim5c3a1202017-03-10 00:02:1413#include "ui/events/android/motion_event_android.h"
Majid Valipour7f256682018-01-17 06:35:3714#include "ui/events/test/scoped_event_test_tick_clock.h"
jinsukkim5c3a1202017-03-10 00:02:1415
16namespace ui {
17
18using base::android::JavaParamRef;
19
Jinsuk Kim86071c82017-09-07 00:49:0520class TestViewAndroid : public ViewAndroid {
21 public:
Jinsuk Kim1f8f47a32018-04-23 02:08:2222 TestViewAndroid(ViewAndroid::LayoutType layout_type)
23 : ViewAndroid(layout_type) {}
Jinsuk Kim86071c82017-09-07 00:49:0524
25 float GetDipScale() override { return 1.f; }
26};
27
Jinsuk Kim1f8f47a32018-04-23 02:08:2228class TestEventHandler : public EventHandlerAndroid {
jinsukkim5c3a1202017-03-10 00:02:1429 public:
Jinsuk Kim1f8f47a32018-04-23 02:08:2230 TestEventHandler() {}
jinsukkim5c3a1202017-03-10 00:02:1431
Jinsuk Kim2b859472017-08-30 02:47:1932 bool OnTouchEvent(const MotionEventAndroid& event) override {
Jinsuk Kim86071c82017-09-07 00:49:0533 touch_called_ = true;
jinsukkim5c3a1202017-03-10 00:02:1434 return handle_event_;
35 }
Jinsuk Kim86071c82017-09-07 00:49:0536 void OnSizeChanged() override { onsize_called_ = true; }
jinsukkim5c3a1202017-03-10 00:02:1437
Jinsuk Kim86071c82017-09-07 00:49:0538 void SetHandleEvent(bool handle_event) { handle_event_ = handle_event; }
39 bool TouchEventHandled() { return touch_called_ && handle_event_; }
40 bool TouchEventCalled() { return touch_called_; }
41 bool OnSizeCalled() { return onsize_called_; }
42 void Reset() {
43 touch_called_ = false;
44 onsize_called_ = false;
45 }
jinsukkim5c3a1202017-03-10 00:02:1446
47 private:
Jinsuk Kim86071c82017-09-07 00:49:0548 bool handle_event_{true}; // Marks as event was consumed. True by default.
49 bool touch_called_{false};
50 bool onsize_called_{false};
jinsukkim5c3a1202017-03-10 00:02:1451};
52
53class ViewAndroidBoundsTest : public testing::Test {
54 public:
55 ViewAndroidBoundsTest()
Jinsuk Kim1f8f47a32018-04-23 02:08:2256 : root_(ViewAndroid::LayoutType::MATCH_PARENT),
57 view1_(ViewAndroid::LayoutType::NORMAL),
58 view2_(ViewAndroid::LayoutType::NORMAL),
59 view3_(ViewAndroid::LayoutType::NORMAL),
60 viewm_(ViewAndroid::LayoutType::MATCH_PARENT) {
jinsukkim5c3a1202017-03-10 00:02:1461 root_.GetEventForwarder();
Jinsuk Kim1f8f47a32018-04-23 02:08:2262 view1_.set_event_handler(&handler1_);
63 view2_.set_event_handler(&handler2_);
64 view3_.set_event_handler(&handler3_);
65 viewm_.set_event_handler(&handlerm_);
jinsukkim5c3a1202017-03-10 00:02:1466 }
67
68 void Reset() {
Jinsuk Kim1f8f47a32018-04-23 02:08:2269 handler1_.Reset();
70 handler2_.Reset();
71 handler3_.Reset();
72 handlerm_.Reset();
Majid Valipour7f256682018-01-17 06:35:3773 test_clock_.SetNowTicks(base::TimeTicks());
jinsukkim5c3a1202017-03-10 00:02:1474 }
75
76 void GenerateTouchEventAt(float x, float y) {
77 ui::MotionEventAndroid::Pointer pointer0(0, x, y, 0, 0, 0, 0, 0);
78 ui::MotionEventAndroid::Pointer pointer1(0, 0, 0, 0, 0, 0, 0, 0);
jinsukkimb40b402c2017-03-29 09:39:0879 ui::MotionEventAndroid event(nullptr, JavaParamRef<jobject>(nullptr), 1.f,
Navid Zolghadr97233bd2020-06-01 18:01:5980 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
81 false, &pointer0, &pointer1);
Jinsuk Kim2b859472017-08-30 02:47:1982 root_.OnTouchEvent(event);
jinsukkim5c3a1202017-03-10 00:02:1483 }
84
Jinsuk Kim1f8f47a32018-04-23 02:08:2285 void ExpectHit(const TestEventHandler& hitHandler) {
86 TestEventHandler* handlers[4] = {&handler1_, &handler2_, &handler3_,
87 &handlerm_};
88 for (auto* handler : handlers) {
89 if (&hitHandler == handler)
90 EXPECT_TRUE(handler->TouchEventHandled());
jinsukkim5c3a1202017-03-10 00:02:1491 else
Jinsuk Kim1f8f47a32018-04-23 02:08:2292 EXPECT_FALSE(handler->TouchEventHandled());
jinsukkim5c3a1202017-03-10 00:02:1493 }
94 Reset();
95 }
96
Jinsuk Kim86071c82017-09-07 00:49:0597 TestViewAndroid root_;
98 TestViewAndroid view1_;
99 TestViewAndroid view2_;
100 TestViewAndroid view3_;
Jinsuk Kim7d04c9e2017-09-13 00:22:18101 TestViewAndroid viewm_; // match-parent view
Jinsuk Kim1f8f47a32018-04-23 02:08:22102 TestEventHandler handler1_;
103 TestEventHandler handler2_;
104 TestEventHandler handler3_;
105 TestEventHandler handlerm_;
Majid Valipour7f256682018-01-17 06:35:37106 ui::test::ScopedEventTestTickClock test_clock_;
jinsukkim5c3a1202017-03-10 00:02:14107};
108
109TEST_F(ViewAndroidBoundsTest, MatchesViewInFront) {
Jinsuk Kim7d04c9e2017-09-13 00:22:18110 view1_.SetLayoutForTesting(50, 50, 400, 600);
111 view2_.SetLayoutForTesting(50, 50, 400, 600);
jinsukkim5c3a1202017-03-10 00:02:14112 root_.AddChild(&view2_);
113 root_.AddChild(&view1_);
114
115 GenerateTouchEventAt(100.f, 100.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22116 ExpectHit(handler1_);
jinsukkim5c3a1202017-03-10 00:02:14117
118 // View 2 moves up to the top, and events should hit it from now.
119 root_.MoveToFront(&view2_);
120 GenerateTouchEventAt(100.f, 100.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22121 ExpectHit(handler2_);
Kevin McNee18430052018-08-10 16:50:56122
123 // View 2 moves back to the bottom, and events should hit View 1 again.
124 root_.MoveToBack(&view2_);
125 GenerateTouchEventAt(100.f, 100.f);
126 ExpectHit(handler1_);
jinsukkim5c3a1202017-03-10 00:02:14127}
128
129TEST_F(ViewAndroidBoundsTest, MatchesViewArea) {
Jinsuk Kim7d04c9e2017-09-13 00:22:18130 view1_.SetLayoutForTesting(50, 50, 200, 200);
131 view2_.SetLayoutForTesting(20, 20, 400, 600);
jinsukkim5c3a1202017-03-10 00:02:14132
133 root_.AddChild(&view2_);
134 root_.AddChild(&view1_);
135
136 // Falls within |view1_|'s bounds
137 GenerateTouchEventAt(100.f, 100.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22138 ExpectHit(handler1_);
jinsukkim5c3a1202017-03-10 00:02:14139
140 // Falls within |view2_|'s bounds
141 GenerateTouchEventAt(300.f, 400.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22142 ExpectHit(handler2_);
jinsukkim5c3a1202017-03-10 00:02:14143}
144
145TEST_F(ViewAndroidBoundsTest, MatchesViewAfterMove) {
Jinsuk Kim7d04c9e2017-09-13 00:22:18146 view1_.SetLayoutForTesting(50, 50, 200, 200);
147 view2_.SetLayoutForTesting(20, 20, 400, 600);
jinsukkim5c3a1202017-03-10 00:02:14148 root_.AddChild(&view2_);
149 root_.AddChild(&view1_);
150
151 GenerateTouchEventAt(100.f, 100.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22152 ExpectHit(handler1_);
jinsukkim5c3a1202017-03-10 00:02:14153
Jinsuk Kim7d04c9e2017-09-13 00:22:18154 view1_.SetLayoutForTesting(150, 150, 200, 200);
jinsukkim5c3a1202017-03-10 00:02:14155 GenerateTouchEventAt(100.f, 100.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22156 ExpectHit(handler2_);
jinsukkim5c3a1202017-03-10 00:02:14157}
158
159TEST_F(ViewAndroidBoundsTest, MatchesViewSizeOfkMatchParent) {
Jinsuk Kim7d04c9e2017-09-13 00:22:18160 view1_.SetLayoutForTesting(20, 20, 400, 600);
161 view2_.SetLayoutForTesting(50, 50, 200, 200);
jinsukkim5c3a1202017-03-10 00:02:14162
163 root_.AddChild(&view1_);
164 root_.AddChild(&view2_);
Jinsuk Kim7d04c9e2017-09-13 00:22:18165 view1_.AddChild(&viewm_);
jinsukkim5c3a1202017-03-10 00:02:14166
167 GenerateTouchEventAt(100.f, 100.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22168 ExpectHit(handler2_);
jinsukkim5c3a1202017-03-10 00:02:14169
170 GenerateTouchEventAt(300.f, 400.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22171 ExpectHit(handler1_);
jinsukkim5c3a1202017-03-10 00:02:14172
Jinsuk Kim1f8f47a32018-04-23 02:08:22173 handler1_.SetHandleEvent(false);
jinsukkim5c3a1202017-03-10 00:02:14174 GenerateTouchEventAt(300.f, 400.f);
Jinsuk Kim1f8f47a32018-04-23 02:08:22175 EXPECT_TRUE(handler1_.TouchEventCalled());
176 ExpectHit(handlerm_);
jinsukkim5c3a1202017-03-10 00:02:14177}
178
179TEST_F(ViewAndroidBoundsTest, MatchesViewsWithOffset) {
Jinsuk Kim7d04c9e2017-09-13 00:22:18180 view1_.SetLayoutForTesting(10, 20, 150, 100);
181 view2_.SetLayoutForTesting(20, 30, 40, 30);
182 view3_.SetLayoutForTesting(70, 30, 40, 30);
jinsukkim5c3a1202017-03-10 00:02:14183
184 root_.AddChild(&view1_);
185 view1_.AddChild(&view2_);
186 view1_.AddChild(&view3_);
187
188 GenerateTouchEventAt(70, 30);
Jinsuk Kim1f8f47a32018-04-23 02:08:22189 ExpectHit(handler1_);
jinsukkim5c3a1202017-03-10 00:02:14190
Jinsuk Kim1f8f47a32018-04-23 02:08:22191 handler1_.SetHandleEvent(false);
jinsukkim5c3a1202017-03-10 00:02:14192 GenerateTouchEventAt(40, 60);
Jinsuk Kim1f8f47a32018-04-23 02:08:22193 EXPECT_TRUE(handler1_.TouchEventCalled());
194 ExpectHit(handler2_);
jinsukkim5c3a1202017-03-10 00:02:14195
196 GenerateTouchEventAt(100, 70);
Jinsuk Kim1f8f47a32018-04-23 02:08:22197 EXPECT_TRUE(handler1_.TouchEventCalled());
198 ExpectHit(handler3_);
jinsukkim5c3a1202017-03-10 00:02:14199}
200
Jinsuk Kim86071c82017-09-07 00:49:05201TEST_F(ViewAndroidBoundsTest, OnSizeChanged) {
202 root_.AddChild(&view1_);
Jinsuk Kim7d04c9e2017-09-13 00:22:18203 view1_.AddChild(&viewm_);
Jinsuk Kim86071c82017-09-07 00:49:05204 view1_.AddChild(&view3_);
205
Jinsuk Kim86071c82017-09-07 00:49:05206 // Size event propagates to non-match-parent children only.
207 view1_.OnSizeChanged(100, 100);
Jinsuk Kim1f8f47a32018-04-23 02:08:22208 EXPECT_TRUE(handler1_.OnSizeCalled());
209 EXPECT_TRUE(handlerm_.OnSizeCalled());
210 EXPECT_FALSE(handler3_.OnSizeCalled());
Jinsuk Kim86071c82017-09-07 00:49:05211
212 Reset();
213
Jinsuk Kim7d04c9e2017-09-13 00:22:18214 // Match-parent view should not receivee size events in the first place.
215 EXPECT_DCHECK_DEATH(viewm_.OnSizeChanged(100, 200));
Jinsuk Kim1f8f47a32018-04-23 02:08:22216 EXPECT_FALSE(handlerm_.OnSizeCalled());
217 EXPECT_FALSE(handler3_.OnSizeCalled());
Jinsuk Kim86071c82017-09-07 00:49:05218
Jinsuk Kimd602a12a2017-12-14 01:27:19219 viewm_.RemoveFromParent();
220 viewm_.OnSizeChangedInternal(gfx::Size(0, 0)); // Reset the size.
221
Jinsuk Kim86071c82017-09-07 00:49:05222 Reset();
223
Jinsuk Kim86071c82017-09-07 00:49:05224 view1_.OnSizeChanged(100, 100);
225
226 // Size event is generated for a newly added, match-parent child view.
Jinsuk Kim1f8f47a32018-04-23 02:08:22227 EXPECT_FALSE(handlerm_.OnSizeCalled());
Jinsuk Kim7d04c9e2017-09-13 00:22:18228 view1_.AddChild(&viewm_);
Jinsuk Kim1f8f47a32018-04-23 02:08:22229 EXPECT_TRUE(handlerm_.OnSizeCalled());
230 EXPECT_FALSE(handler3_.OnSizeCalled());
Jinsuk Kimd602a12a2017-12-14 01:27:19231
232 viewm_.RemoveFromParent();
233
234 Reset();
235
236 view1_.OnSizeChanged(100, 100);
237
238 // Size event won't propagate if the children already have the same size.
239 view1_.AddChild(&viewm_);
Jinsuk Kim1f8f47a32018-04-23 02:08:22240 EXPECT_FALSE(handlerm_.OnSizeCalled());
241 EXPECT_FALSE(handler3_.OnSizeCalled());
Jinsuk Kim86071c82017-09-07 00:49:05242}
243
jinsukkime98211462017-05-12 09:57:04244TEST(ViewAndroidTest, ChecksMultipleEventForwarders) {
245 ViewAndroid parent;
246 ViewAndroid child;
247 parent.GetEventForwarder();
248 child.GetEventForwarder();
249 EXPECT_DCHECK_DEATH(parent.AddChild(&child));
250
251 ViewAndroid parent2;
252 ViewAndroid child2;
253 parent2.GetEventForwarder();
254 parent2.AddChild(&child2);
255 EXPECT_DCHECK_DEATH(child2.GetEventForwarder());
256
257 ViewAndroid window;
258 ViewAndroid wcv1, wcv2;
259 ViewAndroid rwhv1a, rwhv1b, rwhv2;
260 wcv1.GetEventForwarder();
261 wcv2.GetEventForwarder();
262
263 window.AddChild(&wcv1);
264 wcv1.AddChild(&rwhv1a);
265 wcv1.AddChild(&rwhv1b);
266
267 wcv2.AddChild(&rwhv2);
268
269 // window should be able to add wcv2 since there's only one event forwarder
270 // in the path window - wcv2* - rwvh2
271 window.AddChild(&wcv2);
272
273 // Additional event forwarder will cause failure.
274 EXPECT_DCHECK_DEATH(rwhv2.GetEventForwarder());
275}
276
Jinsuk Kimd5d29a22017-08-29 01:39:44277class Observer : public ViewAndroidObserver {
278 public:
Ted Choc0322c902020-02-25 19:00:46279 Observer() : attached_(false), destroyed_(false) {}
Jinsuk Kimd5d29a22017-08-29 01:39:44280
281 void OnAttachedToWindow() override { attached_ = true; }
282
283 void OnDetachedFromWindow() override { attached_ = false; }
284
Ted Choc0322c902020-02-25 19:00:46285 void OnViewAndroidDestroyed() override { destroyed_ = true; }
286
Jinsuk Kimd5d29a22017-08-29 01:39:44287 bool attached_;
Ted Choc0322c902020-02-25 19:00:46288 bool destroyed_;
Jinsuk Kimd5d29a22017-08-29 01:39:44289};
290
291TEST(ViewAndroidTest, Observer) {
Michael Thiessenf42f9f32022-02-03 22:23:06292 std::unique_ptr<ui::WindowAndroid::ScopedWindowAndroidForTesting> window =
293 ui::WindowAndroid::CreateForTesting();
Jinsuk Kimd5d29a22017-08-29 01:39:44294
295 Observer top_observer;
296 Observer bottom_observer;
Jinsuk Kimd5d29a22017-08-29 01:39:44297 Observer top_observer2;
Jinsuk Kimd5d29a22017-08-29 01:39:44298
Ted Choc0322c902020-02-25 19:00:46299 {
300 ViewAndroid top;
301 ViewAndroid bottom;
Jinsuk Kimd5d29a22017-08-29 01:39:44302
Ted Choc0322c902020-02-25 19:00:46303 top.AddObserver(&top_observer);
304 bottom.AddObserver(&bottom_observer);
Jinsuk Kimd5d29a22017-08-29 01:39:44305
Ted Choc0322c902020-02-25 19:00:46306 top.AddChild(&bottom);
Jinsuk Kimd5d29a22017-08-29 01:39:44307
Ted Choc0322c902020-02-25 19:00:46308 EXPECT_FALSE(top_observer.attached_);
309 EXPECT_FALSE(bottom_observer.attached_);
310
311 // Views in a tree all get notified of 'attached' event.
Michael Thiessenf42f9f32022-02-03 22:23:06312 window->get()->AddChild(&top);
Ted Choc0322c902020-02-25 19:00:46313 EXPECT_TRUE(top_observer.attached_);
314 EXPECT_TRUE(bottom_observer.attached_);
315
316 // Observer, upon addition, does not get notified of the current
317 // attached state.
318 top.AddObserver(&top_observer2);
319 EXPECT_FALSE(top_observer2.attached_);
320
321 bottom.RemoveFromParent();
322 EXPECT_FALSE(bottom_observer.attached_);
323 top.RemoveFromParent();
324 EXPECT_FALSE(top_observer.attached_);
325
Michael Thiessenf42f9f32022-02-03 22:23:06326 window->get()->AddChild(&top);
Ted Choc0322c902020-02-25 19:00:46327 EXPECT_TRUE(top_observer.attached_);
328
329 // View, upon addition to a tree in the attached state, should be notified.
330 top.AddChild(&bottom);
331 EXPECT_TRUE(bottom_observer.attached_);
332
333 // Views in a tree all get notified of 'detached' event.
334 top.RemoveFromParent();
335 EXPECT_FALSE(top_observer.attached_);
336 EXPECT_FALSE(bottom_observer.attached_);
337
338 // Remove the second top observer to test the destruction notification.
339 top.RemoveObserver(&top_observer2);
340 }
341
342 EXPECT_TRUE(top_observer.destroyed_);
343 EXPECT_FALSE(top_observer2.destroyed_);
344 EXPECT_TRUE(bottom_observer.destroyed_);
Jinsuk Kimd5d29a22017-08-29 01:39:44345}
346
Jinsuk Kim7a903d42018-06-26 18:03:30347TEST(ViewAndroidTest, WindowAndroidDestructionDetachesAllViewAndroid) {
Michael Thiessenf42f9f32022-02-03 22:23:06348 std::unique_ptr<ui::WindowAndroid::ScopedWindowAndroidForTesting> window =
349 ui::WindowAndroid::CreateForTesting();
Jinsuk Kim7a903d42018-06-26 18:03:30350 ViewAndroid top;
351 ViewAndroid bottom;
352
353 Observer top_observer;
354 Observer bottom_observer;
355
356 top.AddObserver(&top_observer);
357 bottom.AddObserver(&bottom_observer);
358
Michael Thiessenf42f9f32022-02-03 22:23:06359 window->get()->AddChild(&top);
Jinsuk Kim7a903d42018-06-26 18:03:30360 top.AddChild(&bottom);
361
362 EXPECT_TRUE(top_observer.attached_);
363 EXPECT_TRUE(bottom_observer.attached_);
364
365 window.reset();
366
367 EXPECT_FALSE(top_observer.attached_);
368 EXPECT_FALSE(bottom_observer.attached_);
Ted Choc0322c902020-02-25 19:00:46369
370 top.RemoveObserver(&top_observer);
371 bottom.RemoveObserver(&bottom_observer);
Jinsuk Kim7a903d42018-06-26 18:03:30372}
373
jinsukkim5c3a1202017-03-10 00:02:14374} // namespace ui