123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 |
- // 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 "ui/android/view_android.h"
- #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_android_observer.h"
- #include "ui/android/window_android.h"
- #include "ui/events/android/event_handler_android.h"
- #include "ui/events/android/motion_event_android.h"
- #include "ui/events/test/scoped_event_test_tick_clock.h"
- namespace ui {
- using base::android::JavaParamRef;
- class TestViewAndroid : public ViewAndroid {
- public:
- TestViewAndroid(ViewAndroid::LayoutType layout_type)
- : ViewAndroid(layout_type) {}
- float GetDipScale() override { return 1.f; }
- };
- class TestEventHandler : public EventHandlerAndroid {
- public:
- TestEventHandler() {}
- bool OnTouchEvent(const MotionEventAndroid& event) override {
- touch_called_ = true;
- return handle_event_;
- }
- void OnSizeChanged() override { onsize_called_ = true; }
- void SetHandleEvent(bool handle_event) { handle_event_ = handle_event; }
- bool TouchEventHandled() { return touch_called_ && handle_event_; }
- bool TouchEventCalled() { return touch_called_; }
- bool OnSizeCalled() { return onsize_called_; }
- void Reset() {
- touch_called_ = false;
- onsize_called_ = false;
- }
- private:
- bool handle_event_{true}; // Marks as event was consumed. True by default.
- bool touch_called_{false};
- bool onsize_called_{false};
- };
- class ViewAndroidBoundsTest : public testing::Test {
- public:
- ViewAndroidBoundsTest()
- : root_(ViewAndroid::LayoutType::MATCH_PARENT),
- view1_(ViewAndroid::LayoutType::NORMAL),
- view2_(ViewAndroid::LayoutType::NORMAL),
- view3_(ViewAndroid::LayoutType::NORMAL),
- viewm_(ViewAndroid::LayoutType::MATCH_PARENT) {
- root_.GetEventForwarder();
- view1_.set_event_handler(&handler1_);
- view2_.set_event_handler(&handler2_);
- view3_.set_event_handler(&handler3_);
- viewm_.set_event_handler(&handlerm_);
- }
- void Reset() {
- handler1_.Reset();
- handler2_.Reset();
- handler3_.Reset();
- handlerm_.Reset();
- test_clock_.SetNowTicks(base::TimeTicks());
- }
- 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, 0,
- false, &pointer0, &pointer1);
- root_.OnTouchEvent(event);
- }
- void ExpectHit(const TestEventHandler& hitHandler) {
- TestEventHandler* handlers[4] = {&handler1_, &handler2_, &handler3_,
- &handlerm_};
- for (auto* handler : handlers) {
- if (&hitHandler == handler)
- EXPECT_TRUE(handler->TouchEventHandled());
- else
- EXPECT_FALSE(handler->TouchEventHandled());
- }
- Reset();
- }
- TestViewAndroid root_;
- TestViewAndroid view1_;
- TestViewAndroid view2_;
- TestViewAndroid view3_;
- TestViewAndroid viewm_; // match-parent view
- TestEventHandler handler1_;
- TestEventHandler handler2_;
- TestEventHandler handler3_;
- TestEventHandler handlerm_;
- ui::test::ScopedEventTestTickClock test_clock_;
- };
- TEST_F(ViewAndroidBoundsTest, MatchesViewInFront) {
- view1_.SetLayoutForTesting(50, 50, 400, 600);
- view2_.SetLayoutForTesting(50, 50, 400, 600);
- root_.AddChild(&view2_);
- root_.AddChild(&view1_);
- GenerateTouchEventAt(100.f, 100.f);
- ExpectHit(handler1_);
- // View 2 moves up to the top, and events should hit it from now.
- root_.MoveToFront(&view2_);
- GenerateTouchEventAt(100.f, 100.f);
- ExpectHit(handler2_);
- // View 2 moves back to the bottom, and events should hit View 1 again.
- root_.MoveToBack(&view2_);
- GenerateTouchEventAt(100.f, 100.f);
- ExpectHit(handler1_);
- }
- TEST_F(ViewAndroidBoundsTest, MatchesViewArea) {
- view1_.SetLayoutForTesting(50, 50, 200, 200);
- view2_.SetLayoutForTesting(20, 20, 400, 600);
- root_.AddChild(&view2_);
- root_.AddChild(&view1_);
- // Falls within |view1_|'s bounds
- GenerateTouchEventAt(100.f, 100.f);
- ExpectHit(handler1_);
- // Falls within |view2_|'s bounds
- GenerateTouchEventAt(300.f, 400.f);
- ExpectHit(handler2_);
- }
- TEST_F(ViewAndroidBoundsTest, MatchesViewAfterMove) {
- view1_.SetLayoutForTesting(50, 50, 200, 200);
- view2_.SetLayoutForTesting(20, 20, 400, 600);
- root_.AddChild(&view2_);
- root_.AddChild(&view1_);
- GenerateTouchEventAt(100.f, 100.f);
- ExpectHit(handler1_);
- view1_.SetLayoutForTesting(150, 150, 200, 200);
- GenerateTouchEventAt(100.f, 100.f);
- ExpectHit(handler2_);
- }
- TEST_F(ViewAndroidBoundsTest, MatchesViewSizeOfkMatchParent) {
- view1_.SetLayoutForTesting(20, 20, 400, 600);
- view2_.SetLayoutForTesting(50, 50, 200, 200);
- root_.AddChild(&view1_);
- root_.AddChild(&view2_);
- view1_.AddChild(&viewm_);
- GenerateTouchEventAt(100.f, 100.f);
- ExpectHit(handler2_);
- GenerateTouchEventAt(300.f, 400.f);
- ExpectHit(handler1_);
- handler1_.SetHandleEvent(false);
- GenerateTouchEventAt(300.f, 400.f);
- EXPECT_TRUE(handler1_.TouchEventCalled());
- ExpectHit(handlerm_);
- }
- TEST_F(ViewAndroidBoundsTest, MatchesViewsWithOffset) {
- view1_.SetLayoutForTesting(10, 20, 150, 100);
- view2_.SetLayoutForTesting(20, 30, 40, 30);
- view3_.SetLayoutForTesting(70, 30, 40, 30);
- root_.AddChild(&view1_);
- view1_.AddChild(&view2_);
- view1_.AddChild(&view3_);
- GenerateTouchEventAt(70, 30);
- ExpectHit(handler1_);
- handler1_.SetHandleEvent(false);
- GenerateTouchEventAt(40, 60);
- EXPECT_TRUE(handler1_.TouchEventCalled());
- ExpectHit(handler2_);
- GenerateTouchEventAt(100, 70);
- EXPECT_TRUE(handler1_.TouchEventCalled());
- ExpectHit(handler3_);
- }
- TEST_F(ViewAndroidBoundsTest, OnSizeChanged) {
- root_.AddChild(&view1_);
- view1_.AddChild(&viewm_);
- view1_.AddChild(&view3_);
- // Size event propagates to non-match-parent children only.
- view1_.OnSizeChanged(100, 100);
- EXPECT_TRUE(handler1_.OnSizeCalled());
- EXPECT_TRUE(handlerm_.OnSizeCalled());
- EXPECT_FALSE(handler3_.OnSizeCalled());
- Reset();
- // Match-parent view should not receivee size events in the first place.
- EXPECT_DCHECK_DEATH(viewm_.OnSizeChanged(100, 200));
- EXPECT_FALSE(handlerm_.OnSizeCalled());
- EXPECT_FALSE(handler3_.OnSizeCalled());
- viewm_.RemoveFromParent();
- viewm_.OnSizeChangedInternal(gfx::Size(0, 0)); // Reset the size.
- Reset();
- view1_.OnSizeChanged(100, 100);
- // Size event is generated for a newly added, match-parent child view.
- EXPECT_FALSE(handlerm_.OnSizeCalled());
- view1_.AddChild(&viewm_);
- EXPECT_TRUE(handlerm_.OnSizeCalled());
- EXPECT_FALSE(handler3_.OnSizeCalled());
- viewm_.RemoveFromParent();
- Reset();
- view1_.OnSizeChanged(100, 100);
- // Size event won't propagate if the children already have the same size.
- view1_.AddChild(&viewm_);
- EXPECT_FALSE(handlerm_.OnSizeCalled());
- EXPECT_FALSE(handler3_.OnSizeCalled());
- }
- 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());
- }
- class Observer : public ViewAndroidObserver {
- public:
- Observer() : attached_(false), destroyed_(false) {}
- void OnAttachedToWindow() override { attached_ = true; }
- void OnDetachedFromWindow() override { attached_ = false; }
- void OnViewAndroidDestroyed() override { destroyed_ = true; }
- bool attached_;
- bool destroyed_;
- };
- TEST(ViewAndroidTest, Observer) {
- std::unique_ptr<ui::WindowAndroid::ScopedWindowAndroidForTesting> window =
- ui::WindowAndroid::CreateForTesting();
- Observer top_observer;
- Observer bottom_observer;
- Observer top_observer2;
- {
- ViewAndroid top;
- ViewAndroid bottom;
- top.AddObserver(&top_observer);
- bottom.AddObserver(&bottom_observer);
- top.AddChild(&bottom);
- EXPECT_FALSE(top_observer.attached_);
- EXPECT_FALSE(bottom_observer.attached_);
- // Views in a tree all get notified of 'attached' event.
- window->get()->AddChild(&top);
- EXPECT_TRUE(top_observer.attached_);
- EXPECT_TRUE(bottom_observer.attached_);
- // Observer, upon addition, does not get notified of the current
- // attached state.
- top.AddObserver(&top_observer2);
- EXPECT_FALSE(top_observer2.attached_);
- bottom.RemoveFromParent();
- EXPECT_FALSE(bottom_observer.attached_);
- top.RemoveFromParent();
- EXPECT_FALSE(top_observer.attached_);
- window->get()->AddChild(&top);
- EXPECT_TRUE(top_observer.attached_);
- // View, upon addition to a tree in the attached state, should be notified.
- top.AddChild(&bottom);
- EXPECT_TRUE(bottom_observer.attached_);
- // Views in a tree all get notified of 'detached' event.
- top.RemoveFromParent();
- EXPECT_FALSE(top_observer.attached_);
- EXPECT_FALSE(bottom_observer.attached_);
- // Remove the second top observer to test the destruction notification.
- top.RemoveObserver(&top_observer2);
- }
- EXPECT_TRUE(top_observer.destroyed_);
- EXPECT_FALSE(top_observer2.destroyed_);
- EXPECT_TRUE(bottom_observer.destroyed_);
- }
- TEST(ViewAndroidTest, WindowAndroidDestructionDetachesAllViewAndroid) {
- std::unique_ptr<ui::WindowAndroid::ScopedWindowAndroidForTesting> window =
- ui::WindowAndroid::CreateForTesting();
- ViewAndroid top;
- ViewAndroid bottom;
- Observer top_observer;
- Observer bottom_observer;
- top.AddObserver(&top_observer);
- bottom.AddObserver(&bottom_observer);
- window->get()->AddChild(&top);
- top.AddChild(&bottom);
- EXPECT_TRUE(top_observer.attached_);
- EXPECT_TRUE(bottom_observer.attached_);
- window.reset();
- EXPECT_FALSE(top_observer.attached_);
- EXPECT_FALSE(bottom_observer.attached_);
- top.RemoveObserver(&top_observer);
- bottom.RemoveObserver(&bottom_observer);
- }
- } // namespace ui
|