Add Timer at TapGestureRecognizer 45/260645/14
authorJoogab Yun <joogab.yun@samsung.com>
Wed, 30 Jun 2021 07:06:18 +0000 (16:06 +0900)
committerJoogab Yun <joogab.yun@samsung.com>
Mon, 19 Jul 2021 01:46:19 +0000 (10:46 +0900)
Currently, when double tap operation is performed,
single tap and double tap are always transmitted together.

So, when single and double taps are required, then after one tap, we wait for the timeout,
if the timeout happens, then we emit the single-tap,
if we tap again during this time, then we emit a double-tap instead.

Change-Id: I4a5faecc8cf1cc50734b51ad1701e4823c44baab

automated-tests/src/dali/dali-test-suite-utils/test-gesture-generator.cpp
automated-tests/src/dali/dali-test-suite-utils/test-gesture-generator.h
automated-tests/src/dali/utc-Dali-TapGestureRecognizer.cpp
dali/internal/event/events/tap-gesture/tap-gesture-recognizer.cpp
dali/internal/event/events/tap-gesture/tap-gesture-recognizer.h

index 4b465a777191176fc9a319d5a3f7fc5fc79cd889..4532c6e6ad0b030b21422d12310f11e80561d2d3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
@@ -149,16 +149,23 @@ void TestEndPan(TestApplication& application, Vector2 pos, uint32_t time)
   application.ProcessEvent(GenerateSingleTouch(PointState::UP, pos, time));
 }
 
+void TestTriggerTap(TestApplication& application)
+{
+  application.GetPlatform().TriggerTimer();
+}
+
 void TestGenerateTap(TestApplication& application, float x, float y, uint32_t time_down)
 {
   application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(x, y), time_down));
   application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(x, y), time_down + 20));
+  TestTriggerTap(application);
 }
 
 void TestGenerateTwoPointTap(TestApplication& application, float x1, float y1, float x2, float y2, uint32_t time_down)
 {
   application.ProcessEvent(GenerateDoubleTouch(PointState::DOWN, Vector2(x1, y1), PointState::DOWN, Vector2(x2, y2), time_down));
   application.ProcessEvent(GenerateDoubleTouch(PointState::UP, Vector2(x1, y1), PointState::UP, Vector2(x2, y2), time_down + 20));
+  TestTriggerTap(application);
 }
 
 void TestGenerateRotation(TestApplication& application)
index e6e367d01c902d48e895243b7f00e6b21a09460a..cb3b1a6d89ecec4d713f11251d587331a4761997 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TEST_GESTURE_GENERATOR_H
 
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 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.
@@ -93,6 +93,11 @@ void TestMovePan(TestApplication& application, Vector2 pos, uint32_t time = 400)
  */
 void TestEndPan(TestApplication& application, Vector2 pos, uint32_t time = 500);
 
+/**
+ * Triggers the timer to begin a tap gesture
+ */
+void TestTriggerTap(TestApplication& application);
+
 /**
  * Produces a single point tap gesture with a 20ms interval
  */
index 403b25218d23daed3824ad5cd4322f989c666c3c..e39e244c200b76478f9e44efb135e88f81d6913c 100644 (file)
@@ -211,6 +211,7 @@ int UtcDaliTapGestureRecognizerMoveTooFar(void)
   TestApplication application;
 
   TapGestureDetector detector = TapGestureDetector::New();
+  detector.SetMaximumTapsRequired(2);
 
   Actor actor = Actor::New();
   actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
@@ -233,6 +234,7 @@ int UtcDaliTapGestureRecognizerMoveTooFar(void)
 
   application.SendNotification();
 
+  application.GetPlatform().TriggerTimer();
   DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
 
   END_TEST;
@@ -487,6 +489,7 @@ int UtcDaliTapGestureRecognizerMultipleDetectors(void)
 
   application.SendNotification();
 
+  application.GetPlatform().TriggerTimer();
   DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
   DALI_TEST_EQUALS(true, actor == data.tappedActor, TEST_LOCATION);
   data.Reset();
@@ -506,6 +509,7 @@ int UtcDaliTapGestureRecognizerMultipleDetectors(void)
 
   application.SendNotification();
 
+  application.GetPlatform().TriggerTimer();
   DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
   DALI_TEST_EQUALS(true, data2.functorCalled, TEST_LOCATION);
 
index 975c847ce545f681ac5046e29f6b0c61f122f4d6..748794477f9fea5d284688724bc59992d644fef3 100644 (file)
 
 #include <dali/public-api/math/vector2.h>
 
-#include <dali/integration-api/events/touch-event-integ.h>
-
 // INTERNAL INCLUDES
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/platform-abstraction.h>
 #include <dali/internal/event/common/scene-impl.h>
+#include <dali/internal/event/common/thread-local-storage.h>
 #include <dali/internal/event/events/gesture-requests.h>
 
 namespace Dali
@@ -50,11 +51,20 @@ TapGestureRecognizer::TapGestureRecognizer(Observer& observer, Vector2 screenSiz
   mTouchPosition(),
   mTouchTime(0u),
   mLastTapTime(0u),
-  mGestureSourceType(GestureSourceType::INVALID)
+  mEventTime(0u),
+  mGestureSourceType(GestureSourceType::INVALID),
+  mTimerId(0)
 {
 }
 
-TapGestureRecognizer::~TapGestureRecognizer() = default;
+TapGestureRecognizer::~TapGestureRecognizer()
+{
+  if(mTimerId != 0 && ThreadLocalStorage::Created())
+  {
+    Dali::Integration::PlatformAbstraction& platformAbstraction = ThreadLocalStorage::Get().GetPlatformAbstraction();
+    platformAbstraction.CancelTimer(mTimerId);
+  }
+}
 
 void TapGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
 {
@@ -62,8 +72,9 @@ void TapGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
 
   if(event.GetPointCount() == 1)
   {
-    const Integration::Point& point      = event.points[0];
-    PointState::Type          pointState = point.GetState();
+    const Integration::Point&               point               = event.points[0];
+    PointState::Type                        pointState          = point.GetState();
+    Dali::Integration::PlatformAbstraction& platformAbstraction = ThreadLocalStorage::Get().GetPlatformAbstraction();
 
     MouseButton::Type mouseButton = point.GetMouseButton();
     switch(mouseButton)
@@ -114,6 +125,12 @@ void TapGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
         {
           if(deltaBetweenTouchDownTouchUp < MAXIMUM_TIME_ALLOWED)
           {
+            if(mMaximumTapsRequired > mMinimumTapsRequired)
+            {
+              mEventTime = event.time;
+              mTimerId   = platformAbstraction.StartTimer(MAXIMUM_TIME_ALLOWED, MakeCallback(this, &TapGestureRecognizer::TimerCallback));
+            }
+
             mLastTapTime = mTouchTime;
             EmitSingleTap(event.time, point);
             mState = REGISTERED;
@@ -145,7 +162,15 @@ void TapGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
           else if(deltaBetweenTouchDownTouchUp < MAXIMUM_TIME_ALLOWED)
           {
             ++mTapsRegistered;
-            EmitGesture(GestureState::STARTED, event.time);
+            if(mMaximumTapsRequired > mMinimumTapsRequired)
+            {
+              mEventTime = event.time;
+              mTimerId   = platformAbstraction.StartTimer(MAXIMUM_TIME_ALLOWED, MakeCallback(this, &TapGestureRecognizer::TimerCallback));
+            }
+            else
+            {
+              EmitGesture(GestureState::STARTED, event.time);
+            }
           }
           else // Delta between touch down and touch up too long to be considered a TAP event
           {
@@ -170,6 +195,12 @@ void TapGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
           {
             EmitPossibleState(event);
           }
+
+          if(mTimerId != 0)
+          {
+            platformAbstraction.CancelTimer(mTimerId);
+            mTimerId = 0;
+          }
         }
         break;
       }
@@ -191,6 +222,14 @@ void TapGestureRecognizer::SendEvent(const Integration::TouchEvent& event)
   }
 }
 
+bool TapGestureRecognizer::TimerCallback()
+{
+  EmitGesture(GestureState::STARTED, mEventTime);
+
+  mTimerId = 0;
+  return false;
+}
+
 void TapGestureRecognizer::SetupForTouchDown(const Integration::TouchEvent& event, const Integration::Point& point)
 {
   mTouchPosition  = point.GetScreenPosition();
@@ -238,13 +277,22 @@ void TapGestureRecognizer::EmitSingleTap(uint32_t time, const Integration::Point
   Vector2         distanceDelta(std::abs(mTouchPosition.x - screen.x),
                         std::abs(mTouchPosition.y - screen.y));
 
+  mTapsRegistered = 1u;
   if(distanceDelta.x > MAXIMUM_MOTION_ALLOWED ||
      distanceDelta.y > MAXIMUM_MOTION_ALLOWED)
   {
     event.state = GestureState::CANCELLED;
+    if(mTimerId != 0)
+    {
+      Dali::Integration::PlatformAbstraction& platformAbstraction = ThreadLocalStorage::Get().GetPlatformAbstraction();
+      platformAbstraction.CancelTimer(mTimerId);
+      mTimerId = 0;
+    }
+  }
+  if(mTimerId == 0)
+  {
+    EmitTap(time, event);
   }
-  mTapsRegistered = 1u;
-  EmitTap(time, event);
 }
 
 void TapGestureRecognizer::EmitTap(uint32_t time, TapGestureEvent& event)
index f87d2ec82944c126a64dfa088555d91b99a87329..5b019820e4a0c250c4ad6a23662e9fc66f350897 100644 (file)
@@ -117,6 +117,12 @@ private:
    */
   void ProcessEvent(TapGestureEvent& event);
 
+  /**
+   * Timer Callback
+   * @return will return false; one-shot timer.
+   */
+  bool TimerCallback();
+
 private:
   // Reference to the gesture processor for this recognizer
   Observer& mObserver;
@@ -141,8 +147,11 @@ private:
   Vector2  mTouchPosition; ///< The initial touch down position.
   uint32_t mTouchTime;     ///< The initial touch down time.
   uint32_t mLastTapTime;   ///< Time last tap gesture was registered
+  uint32_t mEventTime;     ///< The touch event time.
 
   GestureSourceType mGestureSourceType; /// < Gesture input source type value.
+
+  uint32_t mTimerId;
 };
 
 } // namespace Internal