Improved pan gesture prediction
[platform/core/uifw/dali-core.git] / automated-tests / src / dali / utc-Dali-PanGestureDetector.cpp
index 0e950a7..a902e9f 100644 (file)
 #include <iostream>
 
 #include <stdlib.h>
-#include <dali/dali.h>
+#include <cmath>
+#include <dali/public-api/dali-core.h>
 #include <dali/integration-api/events/touch-event-integ.h>
 #include <dali/integration-api/events/pan-gesture-event.h>
 #include <dali/integration-api/system-overlay.h>
 #include <dali/integration-api/profiling.h>
+#include <dali/integration-api/input-options.h>
 #include <dali-test-suite-utils.h>
 #include <test-touch-utils.h>
 
@@ -43,6 +45,8 @@ namespace
 {
 typedef Dali::PanGestureDetector::AngleContainer::size_type AngleSizeType;
 
+const int PAN_EVENT_TIME_DELTA = 8;
+const int PAN_GESTURE_UPDATE_COUNT = 50;
 
 // Stores data that is populated in the callback and will be read by the test cases
 struct SignalData
@@ -65,7 +69,7 @@ struct SignalData
     receivedGesture.screenPosition = Vector2(0.0f, 0.0f);
     receivedGesture.numberOfTouches = 0;
 
-    pannedActor = NULL;
+    pannedActor.Reset();
   }
 
   bool functorCalled;
@@ -79,7 +83,7 @@ struct GestureReceivedFunctor
 {
   GestureReceivedFunctor(SignalData& data) : signalData(data) { }
 
-  void operator()(Actor actor, PanGesture pan)
+  void operator()(Actor actor, const PanGesture& pan)
   {
     signalData.functorCalled = true;
     signalData.receivedGesture = pan;
@@ -103,7 +107,7 @@ struct UnstageActorFunctor : public GestureReceivedFunctor
   {
   }
 
-  void operator()( Actor actor, PanGesture pan )
+  void operator()( Actor actor, const PanGesture& pan )
   {
     GestureReceivedFunctor::operator()( actor, pan );
 
@@ -135,13 +139,15 @@ struct ConstraintData
 
   Vector2 screenPosition;
   Vector2 screenDisplacement;
+  Vector2 screenVelocity;
   Vector2 localPosition;
   Vector2 localDisplacement;
+  Vector2 localVelocity;
   bool called;
 
   void Reset()
   {
-    screenPosition = screenDisplacement = localPosition = localDisplacement = Vector2::ZERO;
+    screenPosition = screenDisplacement = screenVelocity = localPosition = localDisplacement = localVelocity = Vector2::ZERO;
     called = false;
   }
 };
@@ -154,13 +160,17 @@ struct PanConstraint
   Vector3 operator()(const Vector3&       current,
                      const PropertyInput& screenPositionProperty,
                      const PropertyInput& screenDisplacementProperty,
+                     const PropertyInput& screenVelocityProperty,
                      const PropertyInput& localPositionProperty,
-                     const PropertyInput& localDisplacementProperty)
+                     const PropertyInput& localDisplacementProperty,
+                     const PropertyInput& localVelocityProperty)
   {
     constraintData.screenPosition = screenPositionProperty.GetVector2();
     constraintData.screenDisplacement = screenDisplacementProperty.GetVector2();
+    constraintData.screenVelocity = screenVelocityProperty.GetVector2();
     constraintData.localPosition = localPositionProperty.GetVector2();
     constraintData.localDisplacement = localDisplacementProperty.GetVector2();
+    constraintData.localVelocity = localVelocityProperty.GetVector2();
     constraintData.called = true;
     return Vector3::ZERO;
   }
@@ -195,7 +205,8 @@ PanGesture GeneratePan( unsigned int time,
                         Vector2 localPosition,
                         Vector2 screenDisplacement = Vector2::ONE,
                         Vector2 localDisplacement = Vector2::ONE,
-                        Vector2 velocity = Vector2::ONE,
+                        Vector2 screenVelocity = Vector2::ONE,
+                        Vector2 localVelocity = Vector2::ONE,
                         unsigned int numberOfTouches = 1 )
 {
   PanGesture pan( state );
@@ -208,12 +219,67 @@ PanGesture GeneratePan( unsigned int time,
   pan.screenDisplacement = screenDisplacement;
   pan.displacement = localDisplacement;
 
-  pan.screenVelocity = pan.velocity = velocity;
+  pan.screenVelocity = screenVelocity;
+  pan.velocity = localVelocity;
+
   pan.numberOfTouches = numberOfTouches;
 
   return pan;
 }
 
+/**
+ * Helper to generate PanGestureEvent
+ *
+ * @param[in] application Application instance
+ * @param[in] state The Gesture State
+ * @param[in] pos The current position of touch.
+ */
+static void SendPan(TestApplication& application, Gesture::State state, const Vector2& pos)
+{
+  static Vector2 last;
+  static int LastTime = 0;
+
+  if( (state == Gesture::Started) ||
+      (state == Gesture::Possible) )
+  {
+    last.x = pos.x;
+    last.y = pos.y;
+  }
+
+  application.ProcessEvent(GeneratePan(state, last, pos, PAN_EVENT_TIME_DELTA));
+
+  last.x = pos.x;
+  last.y = pos.y;
+  LastTime += PAN_EVENT_TIME_DELTA;
+}
+
+static Vector2 PerformSwipeGestureSwipe(TestApplication& application, Vector2 start, Vector2 direction, int frames, bool finish = true)
+{
+  // Now do a pan starting from (start) and heading (direction)
+  Vector2 pos(start);
+  SendPan(application, Gesture::Possible, pos);
+  SendPan(application, Gesture::Started, pos);
+  application.SendNotification();
+  application.Render();
+
+  for(int i = 0;i<frames;i++)
+  {
+    pos += direction; // Move in this direction
+    SendPan(application, Gesture::Continuing, pos);
+    application.SendNotification();
+    application.Render();
+  }
+
+  if(finish)
+  {
+    SendPan(application, Gesture::Finished, pos);
+    application.SendNotification();
+    application.Render();
+  }
+
+  return pos;
+}
+
 } // anon namespace
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1491,7 +1557,7 @@ int UtcDaliPanGestureActorStagedAndDestroyed(void)
   application.Render();
 
   // Delete actor as well
-  actor = NULL;
+  actor.Reset();
 
   // Render and notify
   application.SendNotification();
@@ -1998,11 +2064,195 @@ int UtcDaliPanGestureDirectionProcessing(void)
   END_TEST;
 }
 
+int UtcDaliPanGestureNoPredictionNoSmoothing(void)
+{
+  TestApplication application;
+  Integration::SetPanGesturePredictionMode(0);
+  Integration::SetPanGestureSmoothingMode(0);
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Add a pan detector
+  PanGestureDetector detector = PanGestureDetector::New();
+  detector.Attach( actor );
+  SignalData data;
+  GestureReceivedFunctor functor( data );
+  detector.DetectedSignal().Connect( &application, functor );
+
+  Property::Index property = actor.RegisterProperty( "Dummy Property", Vector3::ZERO );
+
+  ConstraintData constraintData;
+  actor.ApplyConstraint( Constraint::New<Vector3>( property, Source( detector, PanGestureDetector::SCREEN_POSITION ),
+                                                             Source( detector, PanGestureDetector::SCREEN_DISPLACEMENT ),
+                                                             Source( detector, PanGestureDetector::SCREEN_VELOCITY ),
+                                                             Source( detector, PanGestureDetector::LOCAL_POSITION ),
+                                                             Source( detector, PanGestureDetector::LOCAL_DISPLACEMENT ),
+                                                             Source( detector, PanGestureDetector::LOCAL_VELOCITY ),
+                                                             PanConstraint( constraintData ) ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Vector2 direction(Vector2::XAXIS * -5.0f);
+  Vector2 startPosition( 1.0f, 1.0f );
+  PerformSwipeGestureSwipe(application, startPosition, direction, PAN_GESTURE_UPDATE_COUNT, true);
+  DALI_TEST_EQUALS( true,  data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( constraintData.called, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( constraintData.screenPosition, startPosition + (direction * PAN_GESTURE_UPDATE_COUNT), 0.1f, TEST_LOCATION );
+  DALI_TEST_EQUALS( constraintData.localPosition,  startPosition + (direction * PAN_GESTURE_UPDATE_COUNT), 0.1f, TEST_LOCATION );
+
+  constraintData.Reset();
+  END_TEST;
+}
+
+int UtcDaliPanGestureNoPredictionSmoothing(void)
+{
+  TestApplication application;
+  Integration::SetPanGesturePredictionMode(0);
+  Integration::SetPanGestureSmoothingMode(1);
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Add a pan detector
+  PanGestureDetector detector = PanGestureDetector::New();
+  detector.Attach( actor );
+  SignalData data;
+  GestureReceivedFunctor functor( data );
+  detector.DetectedSignal().Connect( &application, functor );
+
+  Property::Index property = actor.RegisterProperty( "Dummy Property", Vector3::ZERO );
+
+  ConstraintData constraintData;
+  actor.ApplyConstraint( Constraint::New<Vector3>( property, Source( detector, PanGestureDetector::SCREEN_POSITION ),
+                                                             Source( detector, PanGestureDetector::SCREEN_DISPLACEMENT ),
+                                                             Source( detector, PanGestureDetector::SCREEN_VELOCITY ),
+                                                             Source( detector, PanGestureDetector::LOCAL_POSITION ),
+                                                             Source( detector, PanGestureDetector::LOCAL_DISPLACEMENT ),
+                                                             Source( detector, PanGestureDetector::LOCAL_VELOCITY ),
+                                                             PanConstraint( constraintData ) ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Vector2 direction(Vector2::XAXIS * -5.0f);
+  Vector2 previousPosition( 20.0f, 20.0f );
+  Vector2 currentPosition( 20.0f, 10.0f );
+  PerformSwipeGestureSwipe(application, Vector2(1.0f, 1.0f), direction, PAN_GESTURE_UPDATE_COUNT, true);
+  DALI_TEST_EQUALS( true,  data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( constraintData.called, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( constraintData.screenPosition, Vector2(1.0f, 1.0f) + (direction * PAN_GESTURE_UPDATE_COUNT), 0.1f, TEST_LOCATION );
+  DALI_TEST_EQUALS( constraintData.localPosition,  Vector2(1.0f, 1.0f) + (direction * PAN_GESTURE_UPDATE_COUNT), 0.1f, TEST_LOCATION );
+
+  constraintData.Reset();
+  END_TEST;
+}
+
+int UtcDaliPanGesturePredictionNoSmoothing(void)
+{
+  TestApplication application;
+  Integration::SetPanGesturePredictionMode(1);
+  Integration::SetPanGestureSmoothingMode(0);
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Add a pan detector
+  PanGestureDetector detector = PanGestureDetector::New();
+  detector.Attach( actor );
+  SignalData data;
+  GestureReceivedFunctor functor( data );
+  detector.DetectedSignal().Connect( &application, functor );
+
+  Property::Index property = actor.RegisterProperty( "Dummy Property", Vector3::ZERO );
+
+  ConstraintData constraintData;
+  actor.ApplyConstraint( Constraint::New<Vector3>( property, Source( detector, PanGestureDetector::SCREEN_POSITION ),
+                                                             Source( detector, PanGestureDetector::SCREEN_DISPLACEMENT ),
+                                                             Source( detector, PanGestureDetector::SCREEN_VELOCITY ),
+                                                             Source( detector, PanGestureDetector::LOCAL_POSITION ),
+                                                             Source( detector, PanGestureDetector::LOCAL_DISPLACEMENT ),
+                                                             Source( detector, PanGestureDetector::LOCAL_VELOCITY ),
+                                                             PanConstraint( constraintData ) ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Vector2 direction(Vector2::XAXIS * -1.0f);
+  Vector2 previousPosition( 20.0f, 20.0f );
+  Vector2 currentPosition( 20.0f, 10.0f );
+  PerformSwipeGestureSwipe(application, Vector2(1.0f, 1.0f), direction, PAN_GESTURE_UPDATE_COUNT, true);
+  DALI_TEST_EQUALS( true,  data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( constraintData.called, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( constraintData.screenPosition, Vector2(1.0f, 1.0f) + (direction * PAN_GESTURE_UPDATE_COUNT), 10.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( constraintData.localPosition,  Vector2(1.0f, 1.0f) + (direction * PAN_GESTURE_UPDATE_COUNT), 10.0f, TEST_LOCATION );
+
+  constraintData.Reset();
+  END_TEST;
+}
+
+int UtcDaliPanGesturePredictionSmoothing(void)
+{
+  TestApplication application;
+  Integration::SetPanGesturePredictionMode(1);
+  Integration::SetPanGestureSmoothingMode(1);
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Add a pan detector
+  PanGestureDetector detector = PanGestureDetector::New();
+  detector.Attach( actor );
+  SignalData data;
+  GestureReceivedFunctor functor( data );
+  detector.DetectedSignal().Connect( &application, functor );
+
+  Property::Index property = actor.RegisterProperty( "Dummy Property", Vector3::ZERO );
+
+  ConstraintData constraintData;
+  actor.ApplyConstraint( Constraint::New<Vector3>( property, Source( detector, PanGestureDetector::SCREEN_POSITION ),
+                                                             Source( detector, PanGestureDetector::SCREEN_DISPLACEMENT ),
+                                                             Source( detector, PanGestureDetector::SCREEN_VELOCITY ),
+                                                             Source( detector, PanGestureDetector::LOCAL_POSITION ),
+                                                             Source( detector, PanGestureDetector::LOCAL_DISPLACEMENT ),
+                                                             Source( detector, PanGestureDetector::LOCAL_VELOCITY ),
+                                                             PanConstraint( constraintData ) ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Vector2 direction(Vector2::XAXIS * -1.0f);
+  Vector2 previousPosition( 20.0f, 20.0f );
+  Vector2 currentPosition( 20.0f, 10.0f );
+  PerformSwipeGestureSwipe(application, Vector2(1.0f, 1.0f), direction, PAN_GESTURE_UPDATE_COUNT, true);
+  DALI_TEST_EQUALS( true,  data.functorCalled, TEST_LOCATION );
+  DALI_TEST_EQUALS( constraintData.called, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( constraintData.screenPosition, Vector2(1.0f, 1.0f) + (direction * PAN_GESTURE_UPDATE_COUNT), 10.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( constraintData.localPosition,  Vector2(1.0f, 1.0f) + (direction * PAN_GESTURE_UPDATE_COUNT), 10.0f, TEST_LOCATION );
+
+  constraintData.Reset();
+  END_TEST;
+}
+
 int UtcDaliPanGestureSetProperties(void)
 {
   TestApplication application;
   TestRenderController& renderController( application.GetRenderController() );
   Integration::SetPanGesturePredictionMode(0);
+  Integration::SetPanGestureSmoothingMode(0);
 
   Actor actor = Actor::New();
   actor.SetSize(100.0f, 100.0f);
@@ -2021,8 +2271,10 @@ int UtcDaliPanGestureSetProperties(void)
   ConstraintData constraintData;
   actor.ApplyConstraint( Constraint::New<Vector3>( property, Source( detector, PanGestureDetector::SCREEN_POSITION ),
                                                              Source( detector, PanGestureDetector::SCREEN_DISPLACEMENT ),
+                                                             Source( detector, PanGestureDetector::SCREEN_VELOCITY ),
                                                              Source( detector, PanGestureDetector::LOCAL_POSITION ),
                                                              Source( detector, PanGestureDetector::LOCAL_DISPLACEMENT ),
+                                                             Source( detector, PanGestureDetector::LOCAL_VELOCITY ),
                                                              PanConstraint( constraintData ) ) );
 
   // Render and notify
@@ -2034,10 +2286,12 @@ int UtcDaliPanGestureSetProperties(void)
 
   Vector2 screenPosition( 20.0f, 20.0f );
   Vector2 screenDisplacement( 1.0f, 1.0f );
+  Vector2 screenVelocity( 1.3f, 4.0f );
   Vector2 localPosition( 21.0f, 21.0f );
   Vector2 localDisplacement( 0.5f, 0.5f );
+  Vector2 localVelocity( 1.5f, 2.5f );
 
-  PanGestureDetector::SetPanGestureProperties( GeneratePan( 1u, Gesture::Started, screenPosition, localPosition, screenDisplacement, localDisplacement ) );
+  PanGestureDetector::SetPanGestureProperties( GeneratePan( 1u, Gesture::Started, screenPosition, localPosition, screenDisplacement, localDisplacement, screenVelocity, localVelocity ) );
   DALI_TEST_EQUALS( renderController.WasCalled( TestRenderController::RequestUpdateFunc ), true, TEST_LOCATION );
 
   // Render and notify
@@ -2049,6 +2303,8 @@ int UtcDaliPanGestureSetProperties(void)
   DALI_TEST_EQUALS( constraintData.localPosition,      localPosition,      TEST_LOCATION );
   DALI_TEST_EQUALS( constraintData.screenDisplacement, screenDisplacement, TEST_LOCATION );
   DALI_TEST_EQUALS( constraintData.localDisplacement,  localDisplacement,  TEST_LOCATION );
+  DALI_TEST_EQUALS( constraintData.screenVelocity,     screenVelocity,     TEST_LOCATION );
+  DALI_TEST_EQUALS( constraintData.localVelocity,      localVelocity,      TEST_LOCATION );
   constraintData.Reset();
   END_TEST;
 }
@@ -2075,8 +2331,10 @@ int UtcDaliPanGestureSetPropertiesAlreadyPanning(void)
   ConstraintData constraintData;
   actor.ApplyConstraint( Constraint::New<Vector3>( property, Source( detector, PanGestureDetector::SCREEN_POSITION ),
                                                              Source( detector, PanGestureDetector::SCREEN_DISPLACEMENT ),
+                                                             Source( detector, PanGestureDetector::SCREEN_VELOCITY ),
                                                              Source( detector, PanGestureDetector::LOCAL_POSITION ),
                                                              Source( detector, PanGestureDetector::LOCAL_DISPLACEMENT ),
+                                                             Source( detector, PanGestureDetector::LOCAL_VELOCITY ),
                                                              PanConstraint( constraintData ) ) );
 
   // Render and notify
@@ -2116,3 +2374,90 @@ int UtcDaliPanGesturePropertyIndices(void)
   DALI_TEST_EQUALS( indices.size(), detector.GetPropertyCount(), TEST_LOCATION );
   END_TEST;
 }
+
+int UtcDaliPanGestureLayerConsumesTouch(void)
+{
+  TestApplication application;
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Add a pan detector
+  PanGestureDetector detector = PanGestureDetector::New();
+  detector.Attach( actor );
+  SignalData data;
+  GestureReceivedFunctor functor( data );
+  detector.DetectedSignal().Connect( &application, functor );
+
+  // Add a layer to overlap the actor
+  Layer layer = Layer::New();
+  layer.SetSize(100.0f, 100.0f);
+  layer.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add( layer );
+  layer.RaiseToTop();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit signals, should receive
+  application.ProcessEvent(GeneratePan(Gesture::Possible, Vector2(10.0f, 20.0f), Vector2(20.0f, 20.0f), 10));
+  application.ProcessEvent(GeneratePan(Gesture::Started, Vector2(10.0f, 20.0f), Vector2(20.0f, 20.0f), 10));
+  application.ProcessEvent(GeneratePan(Gesture::Finished, Vector2(10.0f, 20.0f), Vector2(20.0f, 20.0f), 10));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Set layer to consume all touch
+  layer.SetTouchConsumed( true );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit the same signals again, should not receive
+  application.ProcessEvent(GeneratePan(Gesture::Possible, Vector2(10.0f, 20.0f), Vector2(20.0f, 20.0f), 10));
+  application.ProcessEvent(GeneratePan(Gesture::Started, Vector2(10.0f, 20.0f), Vector2(20.0f, 20.0f), 10));
+  application.ProcessEvent(GeneratePan(Gesture::Finished, Vector2(10.0f, 20.0f), Vector2(20.0f, 20.0f), 10));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliPanGestureNoTimeDiff(void)
+{
+  TestApplication application;
+
+  Actor actor = Actor::New();
+  actor.SetSize(100.0f, 100.0f);
+  actor.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(actor);
+
+  // Add a pan detector
+  PanGestureDetector detector = PanGestureDetector::New();
+  detector.Attach( actor );
+  SignalData data;
+  GestureReceivedFunctor functor( data );
+  detector.DetectedSignal().Connect( &application, functor );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit signals, should receive
+  application.ProcessEvent(GeneratePan(Gesture::Possible, Vector2(10.0f, 20.0f), Vector2(20.0f, 20.0f), 0));
+  application.ProcessEvent(GeneratePan(Gesture::Started, Vector2(10.0f, 20.0f), Vector2(20.0f, 20.0f), 0));
+  application.ProcessEvent(GeneratePan(Gesture::Finished, Vector2(10.0f, 20.0f), Vector2(20.0f, 20.0f), 0));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_CHECK( !std::isinf( data.receivedGesture.velocity.x ) );
+  DALI_TEST_CHECK( !std::isinf( data.receivedGesture.velocity.y ) );
+  DALI_TEST_CHECK( !std::isinf( data.receivedGesture.screenVelocity.x ) );
+  DALI_TEST_CHECK( !std::isinf( data.receivedGesture.screenVelocity.y ) );
+  data.Reset();
+
+  data.Reset();
+
+  END_TEST;
+}