blob: 78a01f68cd03b044181737eb4f5665e9552c05c0 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/test/gtest_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/android/event_forwarder.h"
#include "ui/android/view_android.h"
#include "ui/android/view_client.h"
#include "ui/events/android/motion_event_android.h"
namespace ui {
using base::android::JavaParamRef;
class TestViewClient : public ViewClient {
public:
TestViewClient() : handle_event_(true), called_(false) {}
void SetHandleEvent(bool handle_event) { handle_event_ = handle_event; }
bool OnTouchEvent(const MotionEventAndroid& event,
bool for_touch_handle) override {
called_ = true;
return handle_event_;
}
bool EventHandled() { return called_ && handle_event_; }
bool EventCalled() { return called_; }
void Reset() { called_ = false; }
private:
bool handle_event_; // Marks as event was consumed. True by default.
bool called_;
};
class ViewAndroidBoundsTest : public testing::Test {
public:
ViewAndroidBoundsTest()
: root_(nullptr),
view1_(&client1_),
view2_(&client2_),
view3_(&client3_) {
root_.GetEventForwarder();
root_.SetLayout(ViewAndroid::LayoutParams::MatchParent());
}
void Reset() {
client1_.Reset();
client2_.Reset();
client3_.Reset();
}
void GenerateTouchEventAt(float x, float y) {
ui::MotionEventAndroid::Pointer pointer0(0, x, y, 0, 0, 0, 0, 0);
ui::MotionEventAndroid::Pointer pointer1(0, 0, 0, 0, 0, 0, 0, 0);
ui::MotionEventAndroid event(nullptr, JavaParamRef<jobject>(nullptr), 1.f,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
&pointer0, &pointer1);
root_.OnTouchEvent(event, false);
}
void ExpectHit(const TestViewClient& hitClient) {
TestViewClient* clients[3] = {&client1_, &client2_, &client3_};
for (auto* client : clients) {
if (&hitClient == client)
EXPECT_TRUE(client->EventHandled());
else
EXPECT_FALSE(client->EventHandled());
}
Reset();
}
ViewAndroid root_;
ViewAndroid view1_;
ViewAndroid view2_;
ViewAndroid view3_;
TestViewClient client1_;
TestViewClient client2_;
TestViewClient client3_;
};
TEST_F(ViewAndroidBoundsTest, MatchesViewInFront) {
view1_.SetLayout(ViewAndroid::LayoutParams::Normal(50, 50, 400, 600));
view2_.SetLayout(ViewAndroid::LayoutParams::Normal(50, 50, 400, 600));
root_.AddChild(&view2_);
root_.AddChild(&view1_);
GenerateTouchEventAt(100.f, 100.f);
ExpectHit(client1_);
// View 2 moves up to the top, and events should hit it from now.
root_.MoveToFront(&view2_);
GenerateTouchEventAt(100.f, 100.f);
ExpectHit(client2_);
}
TEST_F(ViewAndroidBoundsTest, MatchesViewArea) {
view1_.SetLayout(ViewAndroid::LayoutParams::Normal(50, 50, 200, 200));
view2_.SetLayout(ViewAndroid::LayoutParams::Normal(20, 20, 400, 600));
root_.AddChild(&view2_);
root_.AddChild(&view1_);
// Falls within |view1_|'s bounds
GenerateTouchEventAt(100.f, 100.f);
ExpectHit(client1_);
// Falls within |view2_|'s bounds
GenerateTouchEventAt(300.f, 400.f);
ExpectHit(client2_);
}
TEST_F(ViewAndroidBoundsTest, MatchesViewAfterMove) {
view1_.SetLayout(ViewAndroid::LayoutParams::Normal(50, 50, 200, 200));
view2_.SetLayout(ViewAndroid::LayoutParams::Normal(20, 20, 400, 600));
root_.AddChild(&view2_);
root_.AddChild(&view1_);
GenerateTouchEventAt(100.f, 100.f);
ExpectHit(client1_);
view1_.SetLayout(ViewAndroid::LayoutParams::Normal(150, 150, 200, 200));
GenerateTouchEventAt(100.f, 100.f);
ExpectHit(client2_);
}
TEST_F(ViewAndroidBoundsTest, MatchesViewSizeOfkMatchParent) {
view1_.SetLayout(ViewAndroid::LayoutParams::Normal(20, 20, 400, 600));
view3_.SetLayout(ViewAndroid::LayoutParams::MatchParent());
view2_.SetLayout(ViewAndroid::LayoutParams::Normal(50, 50, 200, 200));
root_.AddChild(&view1_);
root_.AddChild(&view2_);
view1_.AddChild(&view3_);
GenerateTouchEventAt(100.f, 100.f);
ExpectHit(client2_);
GenerateTouchEventAt(300.f, 400.f);
ExpectHit(client1_);
client1_.SetHandleEvent(false);
GenerateTouchEventAt(300.f, 400.f);
EXPECT_TRUE(client1_.EventCalled());
ExpectHit(client3_);
}
TEST_F(ViewAndroidBoundsTest, MatchesViewsWithOffset) {
view1_.SetLayout(ViewAndroid::LayoutParams::Normal(10, 20, 150, 100));
view2_.SetLayout(ViewAndroid::LayoutParams::Normal(20, 30, 40, 30));
view3_.SetLayout(ViewAndroid::LayoutParams::Normal(70, 30, 40, 30));
root_.AddChild(&view1_);
view1_.AddChild(&view2_);
view1_.AddChild(&view3_);
GenerateTouchEventAt(70, 30);
ExpectHit(client1_);
client1_.SetHandleEvent(false);
GenerateTouchEventAt(40, 60);
EXPECT_TRUE(client1_.EventCalled());
ExpectHit(client2_);
GenerateTouchEventAt(100, 70);
EXPECT_TRUE(client1_.EventCalled());
ExpectHit(client3_);
}
TEST(ViewAndroidTest, ChecksMultipleEventForwarders) {
ViewAndroid parent;
ViewAndroid child;
parent.GetEventForwarder();
child.GetEventForwarder();
EXPECT_DCHECK_DEATH(parent.AddChild(&child));
ViewAndroid parent2;
ViewAndroid child2;
parent2.GetEventForwarder();
parent2.AddChild(&child2);
EXPECT_DCHECK_DEATH(child2.GetEventForwarder());
ViewAndroid window;
ViewAndroid wcv1, wcv2;
ViewAndroid rwhv1a, rwhv1b, rwhv2;
wcv1.GetEventForwarder();
wcv2.GetEventForwarder();
window.AddChild(&wcv1);
wcv1.AddChild(&rwhv1a);
wcv1.AddChild(&rwhv1b);
wcv2.AddChild(&rwhv2);
// window should be able to add wcv2 since there's only one event forwarder
// in the path window - wcv2* - rwvh2
window.AddChild(&wcv2);
// Additional event forwarder will cause failure.
EXPECT_DCHECK_DEATH(rwhv2.GetEventForwarder());
}
} // namespace ui