From d8e1826e05bd7829827110ec4bb2ab34805c36b7 Mon Sep 17 00:00:00 2001 From: Adeel Kazmi Date: Mon, 20 Jul 2020 18:39:10 +0100 Subject: [PATCH] Use touch consumed return to set whether we process a gesture or not Change-Id: I386caa5819a68b5d98d3ef8860b492b516c174d1 --- .../dali-test-suite-utils/test-touch-data-utils.h | 44 ++++++++++++++++++ .../src/dali/utc-Dali-LongPressGestureDetector.cpp | 44 ++++++++++++++++++ .../src/dali/utc-Dali-PanGestureDetector.cpp | 45 +++++++++++++++++++ .../src/dali/utc-Dali-PinchGestureDetector.cpp | 52 ++++++++++++++++++++++ .../src/dali/utc-Dali-RotationGestureDetector.cpp | 49 ++++++++++++++++++++ .../src/dali/utc-Dali-TapGestureDetector.cpp | 39 ++++++++++++++++ dali/internal/event/events/event-processor.cpp | 16 +++++-- .../pinch-gesture/pinch-gesture-recognizer.cpp | 14 ++++-- .../rotation-gesture-recognizer.cpp | 14 ++++-- .../event/events/touch-event-processor.cpp | 11 ++++- dali/internal/event/events/touch-event-processor.h | 3 +- dali/public-api/actors/actor.h | 6 +-- 12 files changed, 320 insertions(+), 17 deletions(-) create mode 100644 automated-tests/src/dali/dali-test-suite-utils/test-touch-data-utils.h diff --git a/automated-tests/src/dali/dali-test-suite-utils/test-touch-data-utils.h b/automated-tests/src/dali/dali-test-suite-utils/test-touch-data-utils.h new file mode 100644 index 0000000..a259179 --- /dev/null +++ b/automated-tests/src/dali/dali-test-suite-utils/test-touch-data-utils.h @@ -0,0 +1,44 @@ +#ifndef TEST_TOUCH_DATA_UTILS_H +#define TEST_TOUCH_DATA_UTILS_H + +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +/** + * Functor to be connected to an Actor's TouchSignal. + * Allows the user to specify whether the functor should return true (consumed) or false. + */ +struct TouchDataFunctorConsumeSetter +{ + TouchDataFunctorConsumeSetter( bool& consume ) + : mConsume( consume ) + { + } + + bool operator()(Dali::Actor actor, const Dali::TouchData& touch) + { + return mConsume; + } + +private: + bool& mConsume; +}; + +#endif // TEST_TOUCH_DATA_UTILS_H + diff --git a/automated-tests/src/dali/utc-Dali-LongPressGestureDetector.cpp b/automated-tests/src/dali/utc-Dali-LongPressGestureDetector.cpp index e0f68d5..5b29232 100644 --- a/automated-tests/src/dali/utc-Dali-LongPressGestureDetector.cpp +++ b/automated-tests/src/dali/utc-Dali-LongPressGestureDetector.cpp @@ -25,6 +25,7 @@ #include #include #include +#include using namespace Dali; @@ -996,3 +997,46 @@ int UtcDaliLongPressGestureSetMinimumHoldingTime(void) END_TEST; } + +int UtcDaliLongPressGestureInterruptedWhenTouchConsumed(void) +{ + TestApplication application; + + Actor actor = Actor::New(); + actor.SetProperty( Actor::Property::SIZE, Vector2( 100.0f, 100.0f ) ); + actor.SetProperty( Actor::Property::ANCHOR_POINT,AnchorPoint::TOP_LEFT); + application.GetScene().Add(actor); + + bool consume = false; + TouchDataFunctorConsumeSetter touchFunctor(consume); + actor.TouchSignal().Connect(&application,touchFunctor); + + // Render and notify + application.SendNotification(); + application.Render(); + + SignalData data; + GestureReceivedFunctor functor(data); + + LongPressGestureDetector detector = LongPressGestureDetector::New(); + detector.Attach(actor); + detector.DetectedSignal().Connect(&application, functor); + + // Start gesture within the actor's area, we should receive the gesture as the touch is NOT being consumed + TestGenerateLongPress( application, 50.0f, 50.0f ); + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + data.Reset(); + TestEndLongPress(application, 50.0f,50.0f); + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + data.Reset(); + + // Another gesture in the same location, this time we will not receive it as touch is being consumed + consume = true; + TestGenerateLongPress( application, 50.0f, 50.0f ); + DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION); + data.Reset(); + TestEndLongPress(application, 50.0f,50.0f); + DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION); + + END_TEST; +} diff --git a/automated-tests/src/dali/utc-Dali-PanGestureDetector.cpp b/automated-tests/src/dali/utc-Dali-PanGestureDetector.cpp index b4c66d4..e394526 100644 --- a/automated-tests/src/dali/utc-Dali-PanGestureDetector.cpp +++ b/automated-tests/src/dali/utc-Dali-PanGestureDetector.cpp @@ -26,6 +26,7 @@ #include #include #include +#include using namespace Dali; @@ -2845,3 +2846,47 @@ int UtcDaliPanGestureNoTimeDiff(void) END_TEST; } + +int UtcDaliPanGestureInterruptedWhenTouchConsumed(void) +{ + TestApplication application; + + Actor actor = Actor::New(); + actor.SetProperty( Actor::Property::SIZE, Vector2( 100.0f, 100.0f ) ); + actor.SetProperty( Actor::Property::ANCHOR_POINT,AnchorPoint::TOP_LEFT); + application.GetScene().Add(actor); + + bool consume = false; + TouchDataFunctorConsumeSetter touchFunctor(consume); + actor.TouchSignal().Connect(&application,touchFunctor); + + // Render and notify + application.SendNotification(); + application.Render(); + + SignalData data; + GestureReceivedFunctor functor(data); + + PanGestureDetector detector = PanGestureDetector::New(); + detector.Attach(actor); + detector.DetectedSignal().Connect(&application, functor); + + // Start gesture within the actor's area, we should receive the pan as the touch is NOT being consumed + uint32_t time = 100; + TestStartPan( application, Vector2( 10.0f, 20.0f ), Vector2( 26.0f, 20.0f ), time ); + + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(Gesture::Started, data.receivedGesture.state, TEST_LOCATION); + data.Reset(); + + // Continue the gesture within the actor's area, but now the touch consumes thus cancelling the gesture + consume = true; + + TestMovePan( application, Vector2(26.0f, 4.0f), time ); + time += TestGetFrameInterval(); + + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(Gesture::Cancelled, data.receivedGesture.state, TEST_LOCATION); + + END_TEST; +} diff --git a/automated-tests/src/dali/utc-Dali-PinchGestureDetector.cpp b/automated-tests/src/dali/utc-Dali-PinchGestureDetector.cpp index 0c271c7..64d1c03 100644 --- a/automated-tests/src/dali/utc-Dali-PinchGestureDetector.cpp +++ b/automated-tests/src/dali/utc-Dali-PinchGestureDetector.cpp @@ -23,6 +23,7 @@ #include #include #include +#include using namespace Dali; @@ -1114,3 +1115,54 @@ int UtcDaliPinchGestureLayerConsumesTouch(void) END_TEST; } + +int UtcDaliPinchGestureInterruptedWhenTouchConsumed(void) +{ + TestApplication application; + + Actor actor = Actor::New(); + actor.SetProperty( Actor::Property::SIZE, Vector2( 100.0f, 100.0f ) ); + actor.SetProperty( Actor::Property::ANCHOR_POINT,AnchorPoint::TOP_LEFT); + application.GetScene().Add(actor); + + bool consume = false; + TouchDataFunctorConsumeSetter touchFunctor(consume); + actor.TouchSignal().Connect(&application,touchFunctor); + + // Render and notify + application.SendNotification(); + application.Render(); + + SignalData data; + GestureReceivedFunctor functor(data); + + PinchGestureDetector detector = PinchGestureDetector::New(); + detector.Attach(actor); + detector.DetectedSignal().Connect(&application, functor); + + // Start gesture within the actor's area, we should receive the pinch as the touch is NOT being consumed + TestStartPinch( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ), + Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 100 ); + + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(Gesture::Started, data.receivedGesture.state, TEST_LOCATION); + data.Reset(); + + // Continue the gesture within the actor's area, but now the touch consumes thus cancelling the gesture + consume = true; + + TestContinuePinch( application, Vector2( 112.0f, 100.0f ), Vector2( 112.0f, 124.0f ), + Vector2( 5.0f, 5.0f ), Vector2( 35.0f, 35.0f ), 200 ); + + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(Gesture::Cancelled, data.receivedGesture.state, TEST_LOCATION); + data.Reset(); + + // Start another pinch, we should not even get the callback this time + TestStartPinch( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ), + Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 100 ); + DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION); + + END_TEST; +} + diff --git a/automated-tests/src/dali/utc-Dali-RotationGestureDetector.cpp b/automated-tests/src/dali/utc-Dali-RotationGestureDetector.cpp index cfe42b0..00eb270 100644 --- a/automated-tests/src/dali/utc-Dali-RotationGestureDetector.cpp +++ b/automated-tests/src/dali/utc-Dali-RotationGestureDetector.cpp @@ -26,6 +26,7 @@ #include #include #include +#include using namespace Dali; @@ -1105,3 +1106,51 @@ int UtcDaliRotationGestureLayerConsumesTouch(void) END_TEST; } +int UtcDaliRotationGestureInterruptedWhenTouchConsumed(void) +{ + TestApplication application; + + Actor actor = Actor::New(); + actor.SetProperty( Actor::Property::SIZE, Vector2( 100.0f, 100.0f ) ); + actor.SetProperty( Actor::Property::ANCHOR_POINT,AnchorPoint::TOP_LEFT); + application.GetScene().Add(actor); + + bool consume = false; + TouchDataFunctorConsumeSetter touchFunctor(consume); + actor.TouchSignal().Connect(&application,touchFunctor); + + // Render and notify + application.SendNotification(); + application.Render(); + + SignalData data; + GestureReceivedFunctor functor(data); + + RotationGestureDetector detector = RotationGestureDetector::New(); + detector.Attach(actor); + detector.DetectedSignal().Connect(&application, functor); + + // Start gesture within the actor's area, we should receive the pinch as the touch is NOT being consumed + TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ), + Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 100 ); + + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(Gesture::Started, data.receivedGesture.state, TEST_LOCATION); + data.Reset(); + + // Continue the gesture within the actor's area, but now the touch consumes thus cancelling the gesture + consume = true; + + TestContinueRotation( application, Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), + Vector2( 15.0f, 20.0f ), Vector2( 25.0f, 20.0f ), 500 ); + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + DALI_TEST_EQUALS(Gesture::Cancelled, data.receivedGesture.state, TEST_LOCATION); + data.Reset(); + + // Start another pinch, we should not even get the callback this time + TestStartRotation( application, Vector2( 2.0f, 20.0f ), Vector2( 38.0f, 20.0f ), + Vector2( 10.0f, 20.0f ), Vector2( 30.0f, 20.0f ), 100 ); + DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION); + + END_TEST; +} diff --git a/automated-tests/src/dali/utc-Dali-TapGestureDetector.cpp b/automated-tests/src/dali/utc-Dali-TapGestureDetector.cpp index 30966d4..9295aa0 100644 --- a/automated-tests/src/dali/utc-Dali-TapGestureDetector.cpp +++ b/automated-tests/src/dali/utc-Dali-TapGestureDetector.cpp @@ -23,6 +23,7 @@ #include #include #include +#include using namespace Dali; @@ -913,3 +914,41 @@ int UtcDaliTapGestureLayerConsumesTouch(void) END_TEST; } + +int UtcDaliTapGestureInterruptedWhenTouchConsumed(void) +{ + TestApplication application; + + Actor actor = Actor::New(); + actor.SetProperty( Actor::Property::SIZE, Vector2( 100.0f, 100.0f ) ); + actor.SetProperty( Actor::Property::ANCHOR_POINT,AnchorPoint::TOP_LEFT); + application.GetScene().Add(actor); + + bool consume = false; + TouchDataFunctorConsumeSetter touchFunctor(consume); + actor.TouchSignal().Connect(&application,touchFunctor); + + // Render and notify + application.SendNotification(); + application.Render(); + + SignalData data; + GestureReceivedFunctor functor(data); + + TapGestureDetector detector = TapGestureDetector::New(); + detector.Attach(actor); + detector.DetectedSignal().Connect(&application, functor); + + // Start gesture within the actor's area, we should receive the gesture as the touch is NOT being consumed + TestGenerateTap( application, 50.0f, 50.0f ); + DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION); + data.Reset(); + + // Another gesture in the same location, this time we will not receive it as touch is being consumed + consume = true; + TestGenerateTap( application, 50.0f, 50.0f ); + DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION); + data.Reset(); + + END_TEST; +} diff --git a/dali/internal/event/events/event-processor.cpp b/dali/internal/event/events/event-processor.cpp index 06250ba..fed209a 100644 --- a/dali/internal/event/events/event-processor.cpp +++ b/dali/internal/event/events/event-processor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -152,8 +152,18 @@ void EventProcessor::ProcessEvents() { case Event::Touch: { - mTouchEventProcessor.ProcessTouchEvent( static_cast(*event) ); - mGestureEventProcessor.ProcessTouchEvent(mScene, static_cast(*event)); + Integration::TouchEvent& touchEvent = static_cast(*event); + const bool consumed = mTouchEventProcessor.ProcessTouchEvent( touchEvent ); + + // If touch is consumed, then gestures should be cancelled + // Do this by sending an interrupted event to the GestureEventProcessor + if( consumed ) + { + Integration::Point& point = touchEvent.GetPoint(0); + point.SetState( PointState::INTERRUPTED ); + } + + mGestureEventProcessor.ProcessTouchEvent(mScene, touchEvent); break; } diff --git a/dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.cpp b/dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.cpp index 13e171e..808c4ad 100644 --- a/dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.cpp +++ b/dali/internal/event/events/pinch-gesture/pinch-gesture-recognizer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -117,7 +117,7 @@ void PinchGestureRecognizer::SendEvent(const Integration::TouchEvent& event) const Integration::Point& currentPoint1 = event.points[0]; const Integration::Point& currentPoint2 = event.points[1]; - if (currentPoint1.GetState() == PointState::UP || currentPoint2.GetState() == PointState::UP) + if (currentPoint1.GetState() == PointState::UP || currentPoint2.GetState() == PointState::UP || currentPoint1.GetState() == PointState::INTERRUPTED) { // One of our touch points has an Up event so change our state back to Clear. mState = Clear; @@ -170,7 +170,15 @@ void PinchGestureRecognizer::SendEvent(const Integration::TouchEvent& event) case Started: { - if (pointCount != 2) + if(event.points[0].GetState() == PointState::INTERRUPTED) + { + // System interruption occurred, pinch should be cancelled + mTouchEvents.clear(); + SendPinch(Gesture::Cancelled, event); + mState = Clear; + mTouchEvents.clear(); + } + else if (pointCount != 2) { // Send pinch finished event SendPinch(Gesture::Finished, event); diff --git a/dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.cpp b/dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.cpp index b0a99a8..d190d6d 100644 --- a/dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.cpp +++ b/dali/internal/event/events/rotation-gesture/rotation-gesture-recognizer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -96,7 +96,7 @@ void RotationGestureRecognizer::SendEvent( const Integration::TouchEvent& event const Integration::Point& currentPoint1 = event.points[0]; const Integration::Point& currentPoint2 = event.points[1]; - if( currentPoint1.GetState() == PointState::UP || currentPoint2.GetState() == PointState::UP ) + if( currentPoint1.GetState() == PointState::UP || currentPoint2.GetState() == PointState::UP || currentPoint1.GetState() == PointState::INTERRUPTED ) { // One of our touch points has an Up event so change our state back to Clear. mState = Clear; @@ -138,7 +138,15 @@ void RotationGestureRecognizer::SendEvent( const Integration::TouchEvent& event case Started: { - if( pointCount != 2 ) + if(event.points[0].GetState() == PointState::INTERRUPTED) + { + // System interruption occurred, rotation should be cancelled + mTouchEvents.clear(); + SendRotation(Gesture::Cancelled, event); + mState = Clear; + mTouchEvents.clear(); + } + else if( pointCount != 2 ) { // Send rotation finished event SendRotation( Gesture::Finished, event ); diff --git a/dali/internal/event/events/touch-event-processor.cpp b/dali/internal/event/events/touch-event-processor.cpp index cc08da8..6a79fa8 100644 --- a/dali/internal/event/events/touch-event-processor.cpp +++ b/dali/internal/event/events/touch-event-processor.cpp @@ -207,7 +207,7 @@ TouchEventProcessor::~TouchEventProcessor() DALI_LOG_TRACE_METHOD( gLogFilter ); } -void TouchEventProcessor::ProcessTouchEvent( const Integration::TouchEvent& event ) +bool TouchEventProcessor::ProcessTouchEvent( const Integration::TouchEvent& event ) { DALI_LOG_TRACE_METHOD( gLogFilter ); DALI_ASSERT_ALWAYS( !event.points.empty() && "Empty TouchEvent sent from Integration\n" ); @@ -271,7 +271,7 @@ void TouchEventProcessor::ProcessTouchEvent( const Integration::TouchEvent& even touchData->AddPoint( currentPoint ); mScene.EmitTouchedSignal( touchEvent, touchDataHandle ); - return; // No need for hit testing + return false; // No need for hit testing & already an interrupted event so just return false } // 2) Hit Testing. @@ -318,11 +318,14 @@ void TouchEventProcessor::ProcessTouchEvent( const Integration::TouchEvent& even // 3) Recursively deliver events to the actor and its parents, until the event is consumed or the stage is reached. + bool consumed = false; + // Emit the touch signal Dali::Actor consumedActor; if ( currentRenderTask ) { consumedActor = EmitTouchSignals( touchData->GetPoint( 0 ).GetHitActor(), touchEvent, touchDataHandle ); + consumed = consumedActor ? true : false; } Integration::Point& primaryPoint = touchData->GetPoint( 0 ); @@ -372,6 +375,8 @@ void TouchEventProcessor::ProcessTouchEvent( const Integration::TouchEvent& even } } + consumed |= leaveEventConsumer ? true : false; + // Check if the motion event has been consumed by another actor's listener. In this case, the previously // consumed actor's listeners may need to be informed (through a leave event). // Further checks here to ensure we do not signal the same actor twice for the same event. @@ -483,6 +488,8 @@ void TouchEventProcessor::ProcessTouchEvent( const Integration::TouchEvent& even } } } + + return consumed; } void TouchEventProcessor::OnObservedActorDisconnected( Actor* actor ) diff --git a/dali/internal/event/events/touch-event-processor.h b/dali/internal/event/events/touch-event-processor.h index 9306e6f..c2e4bc7 100644 --- a/dali/internal/event/events/touch-event-processor.h +++ b/dali/internal/event/events/touch-event-processor.h @@ -67,8 +67,9 @@ public: /** * This function is called by the event processor whenever a touch event occurs. * @param[in] event The touch event that has occurred. + * @return true if consumed */ - void ProcessTouchEvent( const Integration::TouchEvent& event ); + bool ProcessTouchEvent( const Integration::TouchEvent& event ); private: diff --git a/dali/public-api/actors/actor.h b/dali/public-api/actors/actor.h index e828e59..2504456 100644 --- a/dali/public-api/actors/actor.h +++ b/dali/public-api/actors/actor.h @@ -49,7 +49,6 @@ class Renderer; struct Degree; class Quaternion; class Layer; -struct KeyEvent; class TouchData; struct TouchEvent; struct HoverEvent; @@ -217,10 +216,6 @@ typedef Rect Padding; ///< Padding definition @SINCE_1_0.0 * - If the consumed actor on hover-start is not the same as the consumed actor on hover-finished, then * hover signals are also emitted from the hover-started actor with an "Interrupted" state. * - *

Key Events:

- * - * Key events are received by an actor once set to grab key events, only one actor can be set as focused. - * * @nosubgrouping * * Signals @@ -1192,6 +1187,7 @@ public: // Signals * @endcode * The return value of True, indicates that the touch event has been consumed. * Otherwise the signal will be emitted on the next sensitive parent of the actor. + * A true return will also cancel any ongoing gestures. * @SINCE_1_1.37 * @return The signal to connect to * @pre The Actor has been initialized. -- 2.7.4