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 4b465a7..4532c6e 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 e6e367d..cb3b1a6 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.
@@ -94,6 +94,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
  */
 void TestGenerateTap(TestApplication& application, float x = 20.0f, float y = 20.0f, uint32_t time_down = 100);
index 403b252..e39e244 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 975c847..7487944 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 f87d2ec..5b01982 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