blob: 220566840e56c8e5d92bfbfd6f0f20233e4d126b [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"
jinsukkim5c3a1202017-03-10 00:02:1410#include "ui/android/view_client.h"
Jinsuk Kimd5d29a22017-08-29 01:39:4411#include "ui/android/window_android.h"
jinsukkim5c3a1202017-03-10 00:02:1412#include "ui/events/android/motion_event_android.h"
13
14namespace ui {
15
16using base::android::JavaParamRef;
17
18class TestViewClient : public ViewClient {
19 public:
20 TestViewClient() : handle_event_(true), called_(false) {}
21
22 void SetHandleEvent(bool handle_event) { handle_event_ = handle_event; }
Jinsuk Kim2b859472017-08-30 02:47:1923 bool OnTouchEvent(const MotionEventAndroid& event) override {
jinsukkim5c3a1202017-03-10 00:02:1424 called_ = true;
25 return handle_event_;
26 }
27
28 bool EventHandled() { return called_ && handle_event_; }
29 bool EventCalled() { return called_; }
30 void Reset() { called_ = false; }
31
32 private:
33 bool handle_event_; // Marks as event was consumed. True by default.
34 bool called_;
35};
36
37class ViewAndroidBoundsTest : public testing::Test {
38 public:
39 ViewAndroidBoundsTest()
40 : root_(nullptr),
41 view1_(&client1_),
42 view2_(&client2_),
43 view3_(&client3_) {
44 root_.GetEventForwarder();
45 root_.SetLayout(ViewAndroid::LayoutParams::MatchParent());
46 }
47
48 void Reset() {
49 client1_.Reset();
50 client2_.Reset();
51 client3_.Reset();
52 }
53
54 void GenerateTouchEventAt(float x, float y) {
55 ui::MotionEventAndroid::Pointer pointer0(0, x, y, 0, 0, 0, 0, 0);
56 ui::MotionEventAndroid::Pointer pointer1(0, 0, 0, 0, 0, 0, 0, 0);
jinsukkimb40b402c2017-03-29 09:39:0857 ui::MotionEventAndroid event(nullptr, JavaParamRef<jobject>(nullptr), 1.f,
Jinsuk Kim2b859472017-08-30 02:47:1958 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, false,
jinsukkimb40b402c2017-03-29 09:39:0859 &pointer0, &pointer1);
Jinsuk Kim2b859472017-08-30 02:47:1960 root_.OnTouchEvent(event);
jinsukkim5c3a1202017-03-10 00:02:1461 }
62
63 void ExpectHit(const TestViewClient& hitClient) {
64 TestViewClient* clients[3] = {&client1_, &client2_, &client3_};
65 for (auto* client : clients) {
66 if (&hitClient == client)
67 EXPECT_TRUE(client->EventHandled());
68 else
69 EXPECT_FALSE(client->EventHandled());
70 }
71 Reset();
72 }
73
74 ViewAndroid root_;
75 ViewAndroid view1_;
76 ViewAndroid view2_;
77 ViewAndroid view3_;
78 TestViewClient client1_;
79 TestViewClient client2_;
80 TestViewClient client3_;
81};
82
83TEST_F(ViewAndroidBoundsTest, MatchesViewInFront) {
84 view1_.SetLayout(ViewAndroid::LayoutParams::Normal(50, 50, 400, 600));
85 view2_.SetLayout(ViewAndroid::LayoutParams::Normal(50, 50, 400, 600));
86 root_.AddChild(&view2_);
87 root_.AddChild(&view1_);
88
89 GenerateTouchEventAt(100.f, 100.f);
90 ExpectHit(client1_);
91
92 // View 2 moves up to the top, and events should hit it from now.
93 root_.MoveToFront(&view2_);
94 GenerateTouchEventAt(100.f, 100.f);
95 ExpectHit(client2_);
96}
97
98TEST_F(ViewAndroidBoundsTest, MatchesViewArea) {
99 view1_.SetLayout(ViewAndroid::LayoutParams::Normal(50, 50, 200, 200));
100 view2_.SetLayout(ViewAndroid::LayoutParams::Normal(20, 20, 400, 600));
101
102 root_.AddChild(&view2_);
103 root_.AddChild(&view1_);
104
105 // Falls within |view1_|'s bounds
106 GenerateTouchEventAt(100.f, 100.f);
107 ExpectHit(client1_);
108
109 // Falls within |view2_|'s bounds
110 GenerateTouchEventAt(300.f, 400.f);
111 ExpectHit(client2_);
112}
113
114TEST_F(ViewAndroidBoundsTest, MatchesViewAfterMove) {
115 view1_.SetLayout(ViewAndroid::LayoutParams::Normal(50, 50, 200, 200));
116 view2_.SetLayout(ViewAndroid::LayoutParams::Normal(20, 20, 400, 600));
117 root_.AddChild(&view2_);
118 root_.AddChild(&view1_);
119
120 GenerateTouchEventAt(100.f, 100.f);
121 ExpectHit(client1_);
122
123 view1_.SetLayout(ViewAndroid::LayoutParams::Normal(150, 150, 200, 200));
124 GenerateTouchEventAt(100.f, 100.f);
125 ExpectHit(client2_);
126}
127
128TEST_F(ViewAndroidBoundsTest, MatchesViewSizeOfkMatchParent) {
129 view1_.SetLayout(ViewAndroid::LayoutParams::Normal(20, 20, 400, 600));
130 view3_.SetLayout(ViewAndroid::LayoutParams::MatchParent());
131 view2_.SetLayout(ViewAndroid::LayoutParams::Normal(50, 50, 200, 200));
132
133 root_.AddChild(&view1_);
134 root_.AddChild(&view2_);
135 view1_.AddChild(&view3_);
136
137 GenerateTouchEventAt(100.f, 100.f);
138 ExpectHit(client2_);
139
140 GenerateTouchEventAt(300.f, 400.f);
141 ExpectHit(client1_);
142
143 client1_.SetHandleEvent(false);
144 GenerateTouchEventAt(300.f, 400.f);
145 EXPECT_TRUE(client1_.EventCalled());
146 ExpectHit(client3_);
147}
148
149TEST_F(ViewAndroidBoundsTest, MatchesViewsWithOffset) {
150 view1_.SetLayout(ViewAndroid::LayoutParams::Normal(10, 20, 150, 100));
151 view2_.SetLayout(ViewAndroid::LayoutParams::Normal(20, 30, 40, 30));
152 view3_.SetLayout(ViewAndroid::LayoutParams::Normal(70, 30, 40, 30));
153
154 root_.AddChild(&view1_);
155 view1_.AddChild(&view2_);
156 view1_.AddChild(&view3_);
157
158 GenerateTouchEventAt(70, 30);
159 ExpectHit(client1_);
160
161 client1_.SetHandleEvent(false);
162 GenerateTouchEventAt(40, 60);
163 EXPECT_TRUE(client1_.EventCalled());
164 ExpectHit(client2_);
165
166 GenerateTouchEventAt(100, 70);
167 EXPECT_TRUE(client1_.EventCalled());
168 ExpectHit(client3_);
169}
170
jinsukkime98211462017-05-12 09:57:04171TEST(ViewAndroidTest, ChecksMultipleEventForwarders) {
172 ViewAndroid parent;
173 ViewAndroid child;
174 parent.GetEventForwarder();
175 child.GetEventForwarder();
176 EXPECT_DCHECK_DEATH(parent.AddChild(&child));
177
178 ViewAndroid parent2;
179 ViewAndroid child2;
180 parent2.GetEventForwarder();
181 parent2.AddChild(&child2);
182 EXPECT_DCHECK_DEATH(child2.GetEventForwarder());
183
184 ViewAndroid window;
185 ViewAndroid wcv1, wcv2;
186 ViewAndroid rwhv1a, rwhv1b, rwhv2;
187 wcv1.GetEventForwarder();
188 wcv2.GetEventForwarder();
189
190 window.AddChild(&wcv1);
191 wcv1.AddChild(&rwhv1a);
192 wcv1.AddChild(&rwhv1b);
193
194 wcv2.AddChild(&rwhv2);
195
196 // window should be able to add wcv2 since there's only one event forwarder
197 // in the path window - wcv2* - rwvh2
198 window.AddChild(&wcv2);
199
200 // Additional event forwarder will cause failure.
201 EXPECT_DCHECK_DEATH(rwhv2.GetEventForwarder());
202}
203
Jinsuk Kimd5d29a22017-08-29 01:39:44204class Observer : public ViewAndroidObserver {
205 public:
206 Observer() : attached_(false) {}
207
208 void OnAttachedToWindow() override { attached_ = true; }
209
210 void OnDetachedFromWindow() override { attached_ = false; }
211
212 bool attached_;
213};
214
215TEST(ViewAndroidTest, Observer) {
216 std::unique_ptr<WindowAndroid> window(WindowAndroid::CreateForTesting());
217 ViewAndroid top;
218 ViewAndroid bottom;
219
220 Observer top_observer;
221 Observer bottom_observer;
222
223 top.AddObserver(&top_observer);
224 bottom.AddObserver(&bottom_observer);
225
226 top.AddChild(&bottom);
227
228 EXPECT_FALSE(top_observer.attached_);
229 EXPECT_FALSE(bottom_observer.attached_);
230
231 // Views in a tree all get notified of 'attached' event.
232 window->AddChild(&top);
233 EXPECT_TRUE(top_observer.attached_);
234 EXPECT_TRUE(bottom_observer.attached_);
235
236 // Observer, upon addition, does not get notified of the current
237 // attached state.
238 Observer top_observer2;
239 top.AddObserver(&top_observer2);
240 EXPECT_FALSE(top_observer2.attached_);
241
242 bottom.RemoveFromParent();
243 EXPECT_FALSE(bottom_observer.attached_);
244 top.RemoveFromParent();
245 EXPECT_FALSE(top_observer.attached_);
246
247 window->AddChild(&top);
248 EXPECT_TRUE(top_observer.attached_);
249
250 // View, upon addition to a tree in the attached state, should be notified.
251 top.AddChild(&bottom);
252 EXPECT_TRUE(bottom_observer.attached_);
253
254 // Views in a tree all get notified of 'detached' event.
255 top.RemoveFromParent();
256 EXPECT_FALSE(top_observer.attached_);
257 EXPECT_FALSE(bottom_observer.attached_);
258}
259
jinsukkim5c3a1202017-03-10 00:02:14260} // namespace ui