Touch and Hover event propagrated by geometry way. 21/301821/33
authorjoogab.yun <joogab.yun@samsung.com>
Wed, 6 Sep 2023 07:44:52 +0000 (16:44 +0900)
committerjoogab yun <joogab.yun@samsung.com>
Mon, 11 Dec 2023 06:51:37 +0000 (06:51 +0000)
This is similar to how Android works.

1. Events are propagated based on geometry.
2. TouchEvent
  - If there is an actor who consumes, only the actor who consumes will receive the event that comes after.
3. Gesture will be a way for apps to receive and recognize touch events in the future.

Change-Id: Iac58129b729446d3dffa54ad0aacc8d5e8135f19

21 files changed:
automated-tests/src/dali/CMakeLists.txt
automated-tests/src/dali/utc-Dali-Actor.cpp
automated-tests/src/dali/utc-Dali-GeoHitTestAlgorithm.cpp [new file with mode: 0644]
automated-tests/src/dali/utc-Dali-GeoHoverProcessing.cpp [new file with mode: 0644]
automated-tests/src/dali/utc-Dali-GeoTouchProcessing.cpp [new file with mode: 0644]
automated-tests/src/dali/utc-Dali-Scene.cpp
dali/devel-api/events/hit-test-algorithm.cpp
dali/devel-api/events/hit-test-algorithm.h
dali/integration-api/scene.cpp
dali/integration-api/scene.h
dali/internal/event/actors/actor-impl.cpp
dali/internal/event/actors/actor-impl.h
dali/internal/event/common/scene-impl.cpp
dali/internal/event/common/scene-impl.h
dali/internal/event/events/gesture-processor.cpp
dali/internal/event/events/hit-test-algorithm-impl.cpp
dali/internal/event/events/hit-test-algorithm-impl.h
dali/internal/event/events/hover-event-processor.cpp
dali/internal/event/events/hover-event-processor.h
dali/internal/event/events/touch-event-processor.cpp
dali/internal/event/events/touch-event-processor.h

index 64aa025..c115058 100644 (file)
@@ -34,6 +34,9 @@ SET(TC_SOURCES
         utc-Dali-FrameCallbackInterface.cpp
         utc-Dali-FreeList.cpp
         utc-Dali-Geometry.cpp
+        utc-Dali-GeoHitTestAlgorithm.cpp
+        utc-Dali-GeoHoverProcessing.cpp
+        utc-Dali-GeoTouchProcessing.cpp
         utc-Dali-GestureDetector.cpp
         utc-Dali-Handle.cpp
         utc-Dali-Hash.cpp
index 9a027fc..1cb1723 100644 (file)
@@ -128,6 +128,20 @@ static void ResetTouchCallbacks()
   gTouchCallBackCalled3 = false;
 }
 
+static void ResetTouchCallbacks(TestApplication& application)
+{
+  // reset touch
+  Dali::Integration::Point point;
+  point.SetDeviceId(1);
+  point.SetState(PointState::UP);
+  point.SetScreenPosition(Vector2(10.f, 10.f));
+  Dali::Integration::TouchEvent touchEvent;
+  touchEvent.AddPoint(point);
+  application.ProcessEvent(touchEvent);
+
+  ResetTouchCallbacks();
+}
+
 static bool TestCallback3(Actor actor, const HoverEvent& event)
 {
   gHoverCallBackCalled = true;
@@ -3148,6 +3162,37 @@ int UtcDaliActorTouchedSignal(void)
   END_TEST;
 }
 
+int UtcDaliActorGeoTouchedSignal(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+  ResetTouchCallbacks(application);
+
+  // get the root layer
+  Actor actor = application.GetScene().GetRootLayer();
+  DALI_TEST_CHECK(gTouchCallBackCalled == false);
+
+  application.SendNotification();
+  application.Render();
+
+  // connect to its touch signal
+  actor.TouchedSignal().Connect(TestTouchCallback);
+
+  // simulate a touch event in the middle of the screen
+  Vector2                  touchPoint(application.GetScene().GetSize() * 0.5);
+  Dali::Integration::Point point;
+  point.SetDeviceId(1);
+  point.SetState(PointState::DOWN);
+  point.SetScreenPosition(Vector2(touchPoint.x, touchPoint.y));
+  Dali::Integration::TouchEvent touchEvent;
+  touchEvent.AddPoint(point);
+  application.ProcessEvent(touchEvent);
+
+  DALI_TEST_CHECK(gTouchCallBackCalled == true);
+  END_TEST;
+}
+
 int UtcDaliActorHoveredSignal(void)
 {
   TestApplication application;
@@ -3404,6 +3449,90 @@ int UtcDaliActorHitTest(void)
   END_TEST;
 }
 
+int UtcDaliActorGeoHitTest(void)
+{
+  struct HitTestData
+  {
+  public:
+    HitTestData(const Vector3& scale, const Vector2& touchPoint, bool result)
+    : mScale(scale),
+      mTouchPoint(touchPoint),
+      mResult(result)
+    {
+    }
+
+    Vector3 mScale;
+    Vector2 mTouchPoint;
+    bool    mResult;
+  };
+
+  TestApplication application;
+  tet_infoline(" UtcDaliActorHitTest");
+
+  // Fill a vector with different hit tests.
+  struct HitTestData* hitTestData[] = {
+    //                    scale                     touch point           result
+    new HitTestData(Vector3(100.f, 100.f, 1.f), Vector2(289.f, 400.f), true),  // touch point close to the right edge (inside)
+    new HitTestData(Vector3(100.f, 100.f, 1.f), Vector2(291.f, 400.f), false), // touch point close to the right edge (outside)
+    new HitTestData(Vector3(110.f, 100.f, 1.f), Vector2(291.f, 400.f), true),  // same point as above with a wider scale. Should be inside.
+    new HitTestData(Vector3(100.f, 100.f, 1.f), Vector2(200.f, 451.f), false), // touch point close to the down edge (outside)
+    new HitTestData(Vector3(100.f, 110.f, 1.f), Vector2(200.f, 451.f), true),  // same point as above with a wider scale. Should be inside.
+    NULL,
+  };
+
+  // get the root layer
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  application.GetScene().Add(actor);
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  ResetTouchCallbacks(application);
+
+  unsigned int index = 0;
+  while(NULL != hitTestData[index])
+  {
+    actor.SetProperty(Actor::Property::SIZE, Vector2(1.f, 1.f));
+    actor.SetProperty(Actor::Property::SCALE, Vector3(hitTestData[index]->mScale.x, hitTestData[index]->mScale.y, hitTestData[index]->mScale.z));
+
+    // flush the queue and render once
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_CHECK(!gTouchCallBackCalled);
+
+    // connect to its touch signal
+    actor.TouchedSignal().Connect(TestTouchCallback);
+
+    Dali::Integration::Point point;
+    point.SetState(PointState::DOWN);
+    point.SetScreenPosition(Vector2(hitTestData[index]->mTouchPoint.x, hitTestData[index]->mTouchPoint.y));
+    Dali::Integration::TouchEvent event;
+    event.AddPoint(point);
+
+    // flush the queue and render once
+    application.SendNotification();
+    application.Render();
+    application.ProcessEvent(event);
+
+    DALI_TEST_CHECK(gTouchCallBackCalled == hitTestData[index]->mResult);
+
+    if(gTouchCallBackCalled != hitTestData[index]->mResult)
+      tet_printf("Test failed:\nScale %f %f %f\nTouchPoint %f, %f\nResult %d\n",
+                 hitTestData[index]->mScale.x,
+                 hitTestData[index]->mScale.y,
+                 hitTestData[index]->mScale.z,
+                 hitTestData[index]->mTouchPoint.x,
+                 hitTestData[index]->mTouchPoint.y,
+                 hitTestData[index]->mResult);
+
+    ResetTouchCallbacks(application);
+    ++index;
+  }
+  END_TEST;
+}
+
 int UtcDaliActorSetDrawMode(void)
 {
   TestApplication application;
@@ -5692,6 +5821,142 @@ int UtcDaliActorRaiseLower(void)
   END_TEST;
 }
 
+int UtcDaliActorGeoTouchRaiseLower(void)
+{
+  tet_infoline("UtcDaliActor Raise and Lower test\n");
+
+  TestApplication application;
+
+  Debug::Filter::SetGlobalLogLevel(Debug::Verbose);
+  Debug::Filter::EnableGlobalTrace();
+
+  Integration::Scene stage(application.GetScene());
+
+  Actor actorA = Actor::New();
+  Actor actorB = Actor::New();
+  Actor actorC = Actor::New();
+
+  actorA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorB.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorC.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorC.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorA.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorA.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorB.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorB.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorC.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorC.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  stage.Add(actorA);
+  stage.Add(actorB);
+  stage.Add(actorC);
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+  ResetTouchCallbacks(application);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
+  // Only top actor will get touched.
+  actorA.TouchedSignal().Connect(TestTouchCallback);
+  actorB.TouchedSignal().Connect(TestTouchCallback2);
+  actorC.TouchedSignal().Connect(TestTouchCallback3);
+
+  // Connect ChildOrderChangedSignal
+  bool                     orderChangedSignal(false);
+  Actor                    orderChangedActor;
+  ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
+  DevelActor::ChildOrderChangedSignal(stage.GetRootLayer()).Connect(&application, f);
+
+  Dali::Integration::Point point;
+  point.SetDeviceId(1);
+  point.SetState(PointState::DOWN);
+  point.SetScreenPosition(Vector2(10.f, 10.f));
+  Dali::Integration::TouchEvent touchEvent;
+  touchEvent.AddPoint(point);
+
+  application.ProcessEvent(touchEvent);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
+
+  ResetTouchCallbacks(application);
+
+  tet_printf("Testing Raising of Actor\n");
+
+  int preActorOrder(0);
+  int postActorOrder(0);
+
+  Property::Value value = actorB.GetProperty(Dali::DevelActor::Property::SIBLING_ORDER);
+  value.Get(preActorOrder);
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorB.Raise();
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorB, TEST_LOCATION);
+
+  // Ensure sort order is calculated before next touch event
+  application.SendNotification();
+
+  value = actorB.GetProperty(Dali::DevelActor::Property::SIBLING_ORDER);
+  value.Get(postActorOrder);
+
+  tet_printf("Raised ActorB from (%d) to (%d) \n", preActorOrder, postActorOrder);
+
+  application.ProcessEvent(touchEvent);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  ResetTouchCallbacks(application);
+
+  tet_printf("Testing Lowering of Actor\n");
+
+  value = actorB.GetProperty(Dali::DevelActor::Property::SIBLING_ORDER);
+  value.Get(preActorOrder);
+
+  orderChangedSignal = false;
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorB.Lower();
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorB, TEST_LOCATION);
+
+  application.SendNotification(); // ensure sort order calculated before next touch event
+
+  value = actorB.GetProperty(Dali::DevelActor::Property::SIBLING_ORDER);
+  value.Get(postActorOrder);
+
+  tet_printf("Lowered ActorB from (%d) to (%d) \n", preActorOrder, postActorOrder);
+
+  application.ProcessEvent(touchEvent);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
+
+  ResetTouchCallbacks(application);
+
+  Debug::Filter::DisableGlobalTrace();
+  Debug::Filter::SetGlobalLogLevel(Debug::NoLogging);
+
+  END_TEST;
+}
+
 int UtcDaliActorRaiseToTopLowerToBottom(void)
 {
   tet_infoline("UtcDaliActorRaiseToTop and LowerToBottom test \n");
@@ -5923,9 +6188,9 @@ int UtcDaliActorRaiseToTopLowerToBottom(void)
   END_TEST;
 }
 
-int UtcDaliActorRaiseAbove(void)
+int UtcDaliActorGeoTouchRaiseToTopLowerToBottom(void)
 {
-  tet_infoline("UtcDaliActor RaiseToAbove test \n");
+  tet_infoline("UtcDaliActorRaiseToTop and LowerToBottom test \n");
 
   TestApplication application;
 
@@ -5935,10 +6200,33 @@ int UtcDaliActorRaiseAbove(void)
   Actor actorB = Actor::New();
   Actor actorC = Actor::New();
 
-  actorA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
-  actorA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
-
-  actorB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  // Set up renderers to add to Actors, float value 1, 2, 3 assigned to each
+  // enables checking of which actor the uniform is assigned too
+  Shader shaderA = CreateShader();
+  shaderA.RegisterProperty("uRendererColor", 1.f);
+
+  Shader shaderB = CreateShader();
+  shaderB.RegisterProperty("uRendererColor", 2.f);
+
+  Shader shaderC = CreateShader();
+  shaderC.RegisterProperty("uRendererColor", 3.f);
+
+  Geometry geometry = CreateQuadGeometry();
+
+  // Add renderers to Actors so ( uRendererColor, 1 ) is A, ( uRendererColor, 2 ) is B, and ( uRendererColor, 3 ) is C,
+  Renderer rendererA = Renderer::New(geometry, shaderA);
+  actorA.AddRenderer(rendererA);
+
+  Renderer rendererB = Renderer::New(geometry, shaderB);
+  actorB.AddRenderer(rendererB);
+
+  Renderer rendererC = Renderer::New(geometry, shaderC);
+  actorC.AddRenderer(rendererC);
+
+  actorA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
   actorB.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
 
   actorC.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
@@ -5957,11 +6245,36 @@ int UtcDaliActorRaiseAbove(void)
   stage.Add(actorB);
   stage.Add(actorC);
 
-  ResetTouchCallbacks();
+  application.GetScene().SetGeometryHittestEnabled(true);
+  ResetTouchCallbacks(application);
+
+  // Connect ChildOrderChangedSignal
+  bool                     orderChangedSignal(false);
+  Actor                    orderChangedActor;
+  ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
+  DevelActor::ChildOrderChangedSignal(stage.GetRootLayer()).Connect(&application, f);
+
+  // Set up gl abstraction trace so can query the set uniform order
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  glAbstraction.EnableSetUniformCallTrace(true);
+  glAbstraction.ResetSetUniformCallStack();
+
+  TraceCallStack& glSetUniformStack = glAbstraction.GetSetUniformTrace();
 
   application.SendNotification();
   application.Render();
 
+  tet_printf("Trace Output:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+  // Test order of uniforms in stack
+  int indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
+  int indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
+  int indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+
+  bool CBA = (indexC > indexB) && (indexB > indexA);
+
+  DALI_TEST_EQUALS(CBA, true, TEST_LOCATION);
+
   DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
@@ -5972,11 +6285,6 @@ int UtcDaliActorRaiseAbove(void)
   actorB.TouchedSignal().Connect(TestTouchCallback2);
   actorC.TouchedSignal().Connect(TestTouchCallback3);
 
-  bool                     orderChangedSignal(false);
-  Actor                    orderChangedActor;
-  ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
-  DevelActor::ChildOrderChangedSignal(stage.GetRootLayer()).Connect(&application, f);
-
   Dali::Integration::Point point;
   point.SetDeviceId(1);
   point.SetState(PointState::DOWN);
@@ -5990,51 +6298,131 @@ int UtcDaliActorRaiseAbove(void)
   DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
 
-  ResetTouchCallbacks();
+  ResetTouchCallbacks(application);
 
-  tet_printf("Raise actor B Above Actor C\n");
+  tet_printf("RaiseToTop ActorA\n");
 
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
-  actorB.RaiseAbove(actorC);
+  actorA.RaiseToTop();
   DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(orderChangedActor, actorB, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorA, TEST_LOCATION);
+
+  application.SendNotification(); // ensure sorting order is calculated before next touch event
+
+  application.ProcessEvent(touchEvent);
+
+  glSetUniformStack.Reset();
 
-  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
   application.SendNotification();
+  application.Render();
+
+  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+  // Test order of uniforms in stack
+  indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
+  indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
+  indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+
+  tet_infoline("Testing A above C and B at bottom\n");
+  bool ACB = (indexA > indexC) && (indexC > indexB);
+
+  DALI_TEST_EQUALS(ACB, true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  ResetTouchCallbacks(application);
+
+  tet_printf("RaiseToTop ActorB\n");
+
+  orderChangedSignal = false;
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorB.RaiseToTop();
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorB, TEST_LOCATION);
+
+  application.SendNotification(); // Ensure sort order is calculated before next touch event
+
   application.ProcessEvent(touchEvent);
 
+  glSetUniformStack.Reset();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+  // Test order of uniforms in stack
+  indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
+  indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
+  indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+
+  tet_infoline("Testing B above A and C at bottom\n");
+  bool BAC = (indexB > indexA) && (indexA > indexC);
+
+  DALI_TEST_EQUALS(BAC, true, TEST_LOCATION);
+
   DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
 
-  ResetTouchCallbacks();
+  ResetTouchCallbacks(application);
 
-  tet_printf("Raise actor A Above Actor B\n");
+  tet_printf("LowerToBottom ActorA then ActorB leaving Actor C at Top\n");
 
   orderChangedSignal = false;
 
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
-  actorA.RaiseAbove(actorB);
+  actorA.LowerToBottom();
   DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
   DALI_TEST_EQUALS(orderChangedActor, actorA, TEST_LOCATION);
 
-  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
   application.SendNotification();
+  application.Render();
 
-  application.ProcessEvent(touchEvent); // process a touch event on ordered actors.
+  orderChangedSignal = false;
 
-  DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorB.LowerToBottom();
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorB, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(touchEvent);
+
+  glSetUniformStack.Reset();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+  // Test order of uniforms in stack
+  indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
+  indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
+  indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+
+  tet_infoline("Testing C above A and B at bottom\n");
+  bool CAB = (indexC > indexA) && (indexA > indexB);
+
+  DALI_TEST_EQUALS(CAB, true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
-  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
 
-  ResetTouchCallbacks();
+  ResetTouchCallbacks(application);
 
   END_TEST;
 }
 
-int UtcDaliActorRaiseAbove2(void)
+int UtcDaliActorRaiseAbove(void)
 {
-  tet_infoline("UtcDaliActor RaiseToAbove test using SIBLING_ORDER property\n");
+  tet_infoline("UtcDaliActor RaiseToAbove test \n");
 
   TestApplication application;
 
@@ -6104,8 +6492,7 @@ int UtcDaliActorRaiseAbove2(void)
   tet_printf("Raise actor B Above Actor C\n");
 
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
-  int newOrder                                = actorC[DevelActor::Property::SIBLING_ORDER];
-  actorB[DevelActor::Property::SIBLING_ORDER] = newOrder;
+  actorB.RaiseAbove(actorC);
   DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
   DALI_TEST_EQUALS(orderChangedActor, actorB, TEST_LOCATION);
 
@@ -6124,8 +6511,7 @@ int UtcDaliActorRaiseAbove2(void)
   orderChangedSignal = false;
 
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
-  newOrder                                    = actorB[DevelActor::Property::SIBLING_ORDER];
-  actorA[DevelActor::Property::SIBLING_ORDER] = newOrder;
+  actorA.RaiseAbove(actorB);
   DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
   DALI_TEST_EQUALS(orderChangedActor, actorA, TEST_LOCATION);
 
@@ -6143,41 +6529,18 @@ int UtcDaliActorRaiseAbove2(void)
   END_TEST;
 }
 
-int UtcDaliActorLowerBelow(void)
+int UtcDaliActorGeoTouchRaiseAbove(void)
 {
-  tet_infoline("UtcDaliActor LowerBelow test \n");
+  tet_infoline("UtcDaliActor RaiseToAbove test \n");
 
   TestApplication application;
 
   Integration::Scene stage(application.GetScene());
 
-  // Set up renderers to add to Actors, float value 1, 2, 3 assigned to each
-  // enables checking of which actor the uniform is assigned too
-  Shader shaderA = CreateShader();
-  shaderA.RegisterProperty("uRendererColor", 1.f);
-
-  Shader shaderB = CreateShader();
-  shaderB.RegisterProperty("uRendererColor", 2.f);
-
-  Shader shaderC = CreateShader();
-  shaderC.RegisterProperty("uRendererColor", 3.f);
-
   Actor actorA = Actor::New();
   Actor actorB = Actor::New();
   Actor actorC = Actor::New();
 
-  // Add renderers to Actors so ( uRendererColor, 1 ) is A, ( uRendererColor, 2 ) is B, and ( uRendererColor, 3 ) is C,
-  Geometry geometry = CreateQuadGeometry();
-
-  Renderer rendererA = Renderer::New(geometry, shaderA);
-  actorA.AddRenderer(rendererA);
-
-  Renderer rendererB = Renderer::New(geometry, shaderB);
-  actorB.AddRenderer(rendererB);
-
-  Renderer rendererC = Renderer::New(geometry, shaderC);
-  actorC.AddRenderer(rendererC);
-
   actorA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
   actorA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
 
@@ -6196,46 +6559,16 @@ int UtcDaliActorLowerBelow(void)
   actorC.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
   actorC.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
 
-  Actor container = Actor::New();
-  container.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
-  container.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
-  stage.Add(container);
-
-  container.Add(actorA);
-  container.Add(actorB);
-  container.Add(actorC);
-
-  ResetTouchCallbacks();
-
-  // Connect ChildOrderChangedSignal
-  bool                     orderChangedSignal(false);
-  Actor                    orderChangedActor;
-  ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
-  DevelActor::ChildOrderChangedSignal(container).Connect(&application, f);
-
-  // Set up gl abstraction trace so can query the set uniform order
-  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
-  glAbstraction.EnableSetUniformCallTrace(true);
-  glAbstraction.ResetSetUniformCallStack();
-  TraceCallStack& glSetUniformStack = glAbstraction.GetSetUniformTrace();
+  stage.Add(actorA);
+  stage.Add(actorB);
+  stage.Add(actorC);
 
-  glAbstraction.ResetSetUniformCallStack();
+  application.GetScene().SetGeometryHittestEnabled(true);
+  ResetTouchCallbacks(application);
 
   application.SendNotification();
   application.Render();
 
-  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
-
-  // Test order of uniforms in stack
-  int indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
-  int indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
-  int indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
-
-  tet_infoline("Testing C above B and A at bottom\n");
-  bool CBA = (indexC > indexB) && (indexB > indexA);
-
-  DALI_TEST_EQUALS(CBA, true, TEST_LOCATION);
-
   DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
@@ -6246,6 +6579,11 @@ int UtcDaliActorLowerBelow(void)
   actorB.TouchedSignal().Connect(TestTouchCallback2);
   actorC.TouchedSignal().Connect(TestTouchCallback3);
 
+  bool                     orderChangedSignal(false);
+  Actor                    orderChangedActor;
+  ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
+  DevelActor::ChildOrderChangedSignal(stage.GetRootLayer()).Connect(&application, f);
+
   Dali::Integration::Point point;
   point.SetDeviceId(1);
   point.SetState(PointState::DOWN);
@@ -6253,44 +6591,135 @@ int UtcDaliActorLowerBelow(void)
   Dali::Integration::TouchEvent touchEvent;
   touchEvent.AddPoint(point);
 
-  tet_infoline("UtcDaliActor Test Set up completed \n");
-
   application.ProcessEvent(touchEvent);
 
   DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
 
-  ResetTouchCallbacks();
+  ResetTouchCallbacks(application);
 
-  tet_printf("Lower actor C below Actor B ( actor B and A on same level due to insertion order) so C is below both \n");
+  tet_printf("Raise actor B Above Actor C\n");
 
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
-  actorC.LowerBelow(actorB);
+  actorB.RaiseAbove(actorC);
   DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(orderChangedActor, actorC, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorB, TEST_LOCATION);
 
   // Ensure sorting happens at end of Core::ProcessEvents() before next touch
   application.SendNotification();
-  application.Render();
+  application.ProcessEvent(touchEvent);
 
-  application.ProcessEvent(touchEvent); // touch event
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
 
-  glSetUniformStack.Reset();
+  ResetTouchCallbacks(application);
 
-  application.SendNotification();
-  application.Render();
+  tet_printf("Raise actor A Above Actor B\n");
 
-  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+  orderChangedSignal = false;
 
-  // Test order of uniforms in stack
-  indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
-  indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
-  indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorA.RaiseAbove(actorB);
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorA, TEST_LOCATION);
 
-  tet_infoline("Testing render order is A, C, B");
-  DALI_TEST_EQUALS(indexC > indexA, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(indexB > indexC, true, TEST_LOCATION);
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+
+  application.ProcessEvent(touchEvent); // process a touch event on ordered actors.
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  ResetTouchCallbacks(application);
+
+  END_TEST;
+}
+
+
+int UtcDaliActorRaiseAbove2(void)
+{
+  tet_infoline("UtcDaliActor RaiseToAbove test using SIBLING_ORDER property\n");
+
+  TestApplication application;
+
+  Integration::Scene stage(application.GetScene());
+
+  Actor actorA = Actor::New();
+  Actor actorB = Actor::New();
+  Actor actorC = Actor::New();
+
+  actorA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorB.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorC.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorC.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorA.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorA.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorB.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorB.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorC.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorC.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  stage.Add(actorA);
+  stage.Add(actorB);
+  stage.Add(actorC);
+
+  ResetTouchCallbacks();
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
+  // Only top actor will get touched.
+  actorA.TouchedSignal().Connect(TestTouchCallback);
+  actorB.TouchedSignal().Connect(TestTouchCallback2);
+  actorC.TouchedSignal().Connect(TestTouchCallback3);
+
+  bool                     orderChangedSignal(false);
+  Actor                    orderChangedActor;
+  ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
+  DevelActor::ChildOrderChangedSignal(stage.GetRootLayer()).Connect(&application, f);
+
+  Dali::Integration::Point point;
+  point.SetDeviceId(1);
+  point.SetState(PointState::DOWN);
+  point.SetScreenPosition(Vector2(10.f, 10.f));
+  Dali::Integration::TouchEvent touchEvent;
+  touchEvent.AddPoint(point);
+
+  application.ProcessEvent(touchEvent);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
+
+  ResetTouchCallbacks();
+
+  tet_printf("Raise actor B Above Actor C\n");
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  int newOrder                                = actorC[DevelActor::Property::SIBLING_ORDER];
+  actorB[DevelActor::Property::SIBLING_ORDER] = newOrder;
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorB, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+  application.ProcessEvent(touchEvent);
 
   DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
@@ -6298,74 +6727,145 @@ int UtcDaliActorLowerBelow(void)
 
   ResetTouchCallbacks();
 
-  tet_printf("Lower actor C below Actor A leaving B on top\n");
+  tet_printf("Raise actor A Above Actor B\n");
 
   orderChangedSignal = false;
 
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
-  actorC.LowerBelow(actorA);
+  newOrder                                    = actorB[DevelActor::Property::SIBLING_ORDER];
+  actorA[DevelActor::Property::SIBLING_ORDER] = newOrder;
   DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(orderChangedActor, actorC, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorA, TEST_LOCATION);
 
   // Ensure sorting happens at end of Core::ProcessEvents() before next touch
   application.SendNotification();
+
+  application.ProcessEvent(touchEvent); // process a touch event on ordered actors.
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  ResetTouchCallbacks();
+
+  END_TEST;
+}
+
+int UtcDaliActorGeoTouchRaiseAbove2(void)
+{
+  tet_infoline("UtcDaliActor RaiseToAbove test using SIBLING_ORDER property\n");
+
+  TestApplication application;
+
+  Integration::Scene stage(application.GetScene());
+
+  Actor actorA = Actor::New();
+  Actor actorB = Actor::New();
+  Actor actorC = Actor::New();
+
+  actorA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorB.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorC.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorC.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorA.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorA.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorB.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorB.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorC.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorC.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  stage.Add(actorA);
+  stage.Add(actorB);
+  stage.Add(actorC);
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+  ResetTouchCallbacks(application);
+
+  application.SendNotification();
   application.Render();
 
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
+  // Only top actor will get touched.
+  actorA.TouchedSignal().Connect(TestTouchCallback);
+  actorB.TouchedSignal().Connect(TestTouchCallback2);
+  actorC.TouchedSignal().Connect(TestTouchCallback3);
+
+  bool                     orderChangedSignal(false);
+  Actor                    orderChangedActor;
+  ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
+  DevelActor::ChildOrderChangedSignal(stage.GetRootLayer()).Connect(&application, f);
+
+  Dali::Integration::Point point;
+  point.SetDeviceId(1);
+  point.SetState(PointState::DOWN);
+  point.SetScreenPosition(Vector2(10.f, 10.f));
+  Dali::Integration::TouchEvent touchEvent;
+  touchEvent.AddPoint(point);
+
   application.ProcessEvent(touchEvent);
 
-  glSetUniformStack.Reset();
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
 
-  application.Render();
-  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+  ResetTouchCallbacks(application);
 
-  // Test order of uniforms in stack
-  indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
-  indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
-  indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+  tet_printf("Raise actor B Above Actor C\n");
 
-  DALI_TEST_EQUALS(indexA > indexC, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(indexB > indexA, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  int newOrder                                = actorC[DevelActor::Property::SIBLING_ORDER];
+  actorB[DevelActor::Property::SIBLING_ORDER] = newOrder;
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorB, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+  application.ProcessEvent(touchEvent);
 
   DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
 
-  ResetTouchCallbacks();
+  ResetTouchCallbacks(application);
 
-  tet_printf("Lower actor B below Actor C leaving A on top\n");
+  tet_printf("Raise actor A Above Actor B\n");
 
   orderChangedSignal = false;
 
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
-  actorB.LowerBelow(actorC);
+  newOrder                                    = actorB[DevelActor::Property::SIBLING_ORDER];
+  actorA[DevelActor::Property::SIBLING_ORDER] = newOrder;
   DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(orderChangedActor, actorB, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorA, TEST_LOCATION);
 
   // Ensure sorting happens at end of Core::ProcessEvents() before next touch
   application.SendNotification();
-  application.Render();
-
-  application.ProcessEvent(touchEvent);
-
-  glSetUniformStack.Reset();
 
-  application.Render();
-  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+  application.ProcessEvent(touchEvent); // process a touch event on ordered actors.
 
-  // Test order of uniforms in stack
-  indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
-  indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
-  indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+  DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
 
-  DALI_TEST_EQUALS(indexC > indexB, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(indexA > indexC, true, TEST_LOCATION);
+  ResetTouchCallbacks(application);
 
   END_TEST;
 }
 
-int UtcDaliActorLowerBelow2(void)
+int UtcDaliActorLowerBelow(void)
 {
-  tet_infoline("UtcDaliActor LowerBelow test using SIBLING_ORDER property\n");
+  tet_infoline("UtcDaliActor LowerBelow test \n");
 
   TestApplication application;
 
@@ -6486,7 +6986,7 @@ int UtcDaliActorLowerBelow2(void)
   tet_printf("Lower actor C below Actor B ( actor B and A on same level due to insertion order) so C is below both \n");
 
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
-  actorC[DevelActor::Property::SIBLING_ORDER] = 1;
+  actorC.LowerBelow(actorB);
   DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
   DALI_TEST_EQUALS(orderChangedActor, actorC, TEST_LOCATION);
 
@@ -6523,7 +7023,7 @@ int UtcDaliActorLowerBelow2(void)
   orderChangedSignal = false;
 
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
-  actorC[DevelActor::Property::SIBLING_ORDER] = 0;
+  actorC.LowerBelow(actorA);
   DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
   DALI_TEST_EQUALS(orderChangedActor, actorC, TEST_LOCATION);
 
@@ -6557,7 +7057,7 @@ int UtcDaliActorLowerBelow2(void)
   orderChangedSignal = false;
 
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
-  actorB[DevelActor::Property::SIBLING_ORDER] = 0;
+  actorB.LowerBelow(actorC);
   DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
   DALI_TEST_EQUALS(orderChangedActor, actorB, TEST_LOCATION);
 
@@ -6583,39 +7083,1064 @@ int UtcDaliActorLowerBelow2(void)
   END_TEST;
 }
 
-int UtcDaliActorRaiseAboveDifferentParentsN(void)
+int UtcDaliActorGeoTouchLowerBelow(void)
 {
-  tet_infoline("UtcDaliActor RaiseToAbove test with actor and target actor having different parents \n");
+  tet_infoline("UtcDaliActor LowerBelow test \n");
 
   TestApplication application;
 
   Integration::Scene stage(application.GetScene());
 
-  Actor parentA = Actor::New();
-  Actor parentB = Actor::New();
-  parentA.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
-  parentA.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
-  parentB.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
-  parentB.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+  // Set up renderers to add to Actors, float value 1, 2, 3 assigned to each
+  // enables checking of which actor the uniform is assigned too
+  Shader shaderA = CreateShader();
+  shaderA.RegisterProperty("uRendererColor", 1.f);
 
-  parentA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
-  parentA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  Shader shaderB = CreateShader();
+  shaderB.RegisterProperty("uRendererColor", 2.f);
+
+  Shader shaderC = CreateShader();
+  shaderC.RegisterProperty("uRendererColor", 3.f);
+
+  Actor actorA = Actor::New();
+  Actor actorB = Actor::New();
+  Actor actorC = Actor::New();
+
+  // Add renderers to Actors so ( uRendererColor, 1 ) is A, ( uRendererColor, 2 ) is B, and ( uRendererColor, 3 ) is C,
+  Geometry geometry = CreateQuadGeometry();
+
+  Renderer rendererA = Renderer::New(geometry, shaderA);
+  actorA.AddRenderer(rendererA);
+
+  Renderer rendererB = Renderer::New(geometry, shaderB);
+  actorB.AddRenderer(rendererB);
+
+  Renderer rendererC = Renderer::New(geometry, shaderC);
+  actorC.AddRenderer(rendererC);
+
+  actorA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorB.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorC.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorC.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorA.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorA.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorB.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorB.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorC.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorC.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  Actor container = Actor::New();
+  container.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  container.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  stage.Add(container);
+
+  container.Add(actorA);
+  container.Add(actorB);
+  container.Add(actorC);
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+  ResetTouchCallbacks(application);
+
+  // Connect ChildOrderChangedSignal
+  bool                     orderChangedSignal(false);
+  Actor                    orderChangedActor;
+  ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
+  DevelActor::ChildOrderChangedSignal(container).Connect(&application, f);
+
+  // Set up gl abstraction trace so can query the set uniform order
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  glAbstraction.EnableSetUniformCallTrace(true);
+  glAbstraction.ResetSetUniformCallStack();
+  TraceCallStack& glSetUniformStack = glAbstraction.GetSetUniformTrace();
+
+  glAbstraction.ResetSetUniformCallStack();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+  // Test order of uniforms in stack
+  int indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
+  int indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
+  int indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+
+  tet_infoline("Testing C above B and A at bottom\n");
+  bool CBA = (indexC > indexB) && (indexB > indexA);
+
+  DALI_TEST_EQUALS(CBA, true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
+  // Only top actor will get touched.
+  actorA.TouchedSignal().Connect(TestTouchCallback);
+  actorB.TouchedSignal().Connect(TestTouchCallback2);
+  actorC.TouchedSignal().Connect(TestTouchCallback3);
+
+  Dali::Integration::Point point;
+  point.SetDeviceId(1);
+  point.SetState(PointState::DOWN);
+  point.SetScreenPosition(Vector2(10.f, 10.f));
+  Dali::Integration::TouchEvent touchEvent;
+  touchEvent.AddPoint(point);
+
+  tet_infoline("UtcDaliActor Test Set up completed \n");
+
+  application.ProcessEvent(touchEvent);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
+
+  ResetTouchCallbacks(application);
+
+  tet_printf("Lower actor C below Actor B ( actor B and A on same level due to insertion order) so C is below both \n");
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorC.LowerBelow(actorB);
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorC, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(touchEvent); // touch event
+
+  glSetUniformStack.Reset();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+  // Test order of uniforms in stack
+  indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
+  indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
+  indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+
+  tet_infoline("Testing render order is A, C, B");
+  DALI_TEST_EQUALS(indexC > indexA, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(indexB > indexC, true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  ResetTouchCallbacks(application);
+
+  tet_printf("Lower actor C below Actor A leaving B on top\n");
+
+  orderChangedSignal = false;
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorC.LowerBelow(actorA);
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorC, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(touchEvent);
+
+  glSetUniformStack.Reset();
+
+  application.Render();
+  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+  // Test order of uniforms in stack
+  indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
+  indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
+  indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+
+  DALI_TEST_EQUALS(indexA > indexC, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(indexB > indexA, true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  ResetTouchCallbacks(application);
+
+  tet_printf("Lower actor B below Actor C leaving A on top\n");
+
+  orderChangedSignal = false;
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorB.LowerBelow(actorC);
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorB, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(touchEvent);
+
+  glSetUniformStack.Reset();
+
+  application.Render();
+  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+  // Test order of uniforms in stack
+  indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
+  indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
+  indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+
+  DALI_TEST_EQUALS(indexC > indexB, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(indexA > indexC, true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliActorLowerBelow2(void)
+{
+  tet_infoline("UtcDaliActor LowerBelow test using SIBLING_ORDER property\n");
+
+  TestApplication application;
+
+  Integration::Scene stage(application.GetScene());
+
+  // Set up renderers to add to Actors, float value 1, 2, 3 assigned to each
+  // enables checking of which actor the uniform is assigned too
+  Shader shaderA = CreateShader();
+  shaderA.RegisterProperty("uRendererColor", 1.f);
+
+  Shader shaderB = CreateShader();
+  shaderB.RegisterProperty("uRendererColor", 2.f);
+
+  Shader shaderC = CreateShader();
+  shaderC.RegisterProperty("uRendererColor", 3.f);
+
+  Actor actorA = Actor::New();
+  Actor actorB = Actor::New();
+  Actor actorC = Actor::New();
+
+  // Add renderers to Actors so ( uRendererColor, 1 ) is A, ( uRendererColor, 2 ) is B, and ( uRendererColor, 3 ) is C,
+  Geometry geometry = CreateQuadGeometry();
+
+  Renderer rendererA = Renderer::New(geometry, shaderA);
+  actorA.AddRenderer(rendererA);
+
+  Renderer rendererB = Renderer::New(geometry, shaderB);
+  actorB.AddRenderer(rendererB);
+
+  Renderer rendererC = Renderer::New(geometry, shaderC);
+  actorC.AddRenderer(rendererC);
+
+  actorA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorB.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorC.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorC.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorA.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorA.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorB.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorB.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorC.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorC.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  Actor container = Actor::New();
+  container.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  container.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  stage.Add(container);
+
+  container.Add(actorA);
+  container.Add(actorB);
+  container.Add(actorC);
+
+  ResetTouchCallbacks();
+
+  // Connect ChildOrderChangedSignal
+  bool                     orderChangedSignal(false);
+  Actor                    orderChangedActor;
+  ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
+  DevelActor::ChildOrderChangedSignal(container).Connect(&application, f);
+
+  // Set up gl abstraction trace so can query the set uniform order
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  glAbstraction.EnableSetUniformCallTrace(true);
+  glAbstraction.ResetSetUniformCallStack();
+  TraceCallStack& glSetUniformStack = glAbstraction.GetSetUniformTrace();
+
+  glAbstraction.ResetSetUniformCallStack();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+  // Test order of uniforms in stack
+  int indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
+  int indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
+  int indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+
+  tet_infoline("Testing C above B and A at bottom\n");
+  bool CBA = (indexC > indexB) && (indexB > indexA);
+
+  DALI_TEST_EQUALS(CBA, true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
+  // Only top actor will get touched.
+  actorA.TouchedSignal().Connect(TestTouchCallback);
+  actorB.TouchedSignal().Connect(TestTouchCallback2);
+  actorC.TouchedSignal().Connect(TestTouchCallback3);
+
+  Dali::Integration::Point point;
+  point.SetDeviceId(1);
+  point.SetState(PointState::DOWN);
+  point.SetScreenPosition(Vector2(10.f, 10.f));
+  Dali::Integration::TouchEvent touchEvent;
+  touchEvent.AddPoint(point);
+
+  tet_infoline("UtcDaliActor Test Set up completed \n");
+
+  application.ProcessEvent(touchEvent);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
+
+  ResetTouchCallbacks();
+
+  tet_printf("Lower actor C below Actor B ( actor B and A on same level due to insertion order) so C is below both \n");
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorC[DevelActor::Property::SIBLING_ORDER] = 1;
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorC, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(touchEvent); // touch event
+
+  glSetUniformStack.Reset();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+  // Test order of uniforms in stack
+  indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
+  indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
+  indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+
+  tet_infoline("Testing render order is A, C, B");
+  DALI_TEST_EQUALS(indexC > indexA, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(indexB > indexC, true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  ResetTouchCallbacks();
+
+  tet_printf("Lower actor C below Actor A leaving B on top\n");
+
+  orderChangedSignal = false;
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorC[DevelActor::Property::SIBLING_ORDER] = 0;
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorC, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(touchEvent);
+
+  glSetUniformStack.Reset();
+
+  application.Render();
+  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+  // Test order of uniforms in stack
+  indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
+  indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
+  indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+
+  DALI_TEST_EQUALS(indexA > indexC, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(indexB > indexA, true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  ResetTouchCallbacks();
+
+  tet_printf("Lower actor B below Actor C leaving A on top\n");
+
+  orderChangedSignal = false;
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorB[DevelActor::Property::SIBLING_ORDER] = 0;
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorB, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(touchEvent);
+
+  glSetUniformStack.Reset();
+
+  application.Render();
+  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+  // Test order of uniforms in stack
+  indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
+  indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
+  indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+
+  DALI_TEST_EQUALS(indexC > indexB, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(indexA > indexC, true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliActorGeoTouchLowerBelow2(void)
+{
+  tet_infoline("UtcDaliActor LowerBelow test using SIBLING_ORDER property\n");
+
+  TestApplication application;
+
+  Integration::Scene stage(application.GetScene());
+
+  // Set up renderers to add to Actors, float value 1, 2, 3 assigned to each
+  // enables checking of which actor the uniform is assigned too
+  Shader shaderA = CreateShader();
+  shaderA.RegisterProperty("uRendererColor", 1.f);
+
+  Shader shaderB = CreateShader();
+  shaderB.RegisterProperty("uRendererColor", 2.f);
+
+  Shader shaderC = CreateShader();
+  shaderC.RegisterProperty("uRendererColor", 3.f);
+
+  Actor actorA = Actor::New();
+  Actor actorB = Actor::New();
+  Actor actorC = Actor::New();
+
+  // Add renderers to Actors so ( uRendererColor, 1 ) is A, ( uRendererColor, 2 ) is B, and ( uRendererColor, 3 ) is C,
+  Geometry geometry = CreateQuadGeometry();
+
+  Renderer rendererA = Renderer::New(geometry, shaderA);
+  actorA.AddRenderer(rendererA);
+
+  Renderer rendererB = Renderer::New(geometry, shaderB);
+  actorB.AddRenderer(rendererB);
+
+  Renderer rendererC = Renderer::New(geometry, shaderC);
+  actorC.AddRenderer(rendererC);
+
+  actorA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorB.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorC.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorC.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorA.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorA.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorB.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorB.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorC.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorC.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  Actor container = Actor::New();
+  container.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  container.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  stage.Add(container);
+
+  container.Add(actorA);
+  container.Add(actorB);
+  container.Add(actorC);
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+  ResetTouchCallbacks(application);
+
+  // Connect ChildOrderChangedSignal
+  bool                     orderChangedSignal(false);
+  Actor                    orderChangedActor;
+  ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
+  DevelActor::ChildOrderChangedSignal(container).Connect(&application, f);
+
+  // Set up gl abstraction trace so can query the set uniform order
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  glAbstraction.EnableSetUniformCallTrace(true);
+  glAbstraction.ResetSetUniformCallStack();
+  TraceCallStack& glSetUniformStack = glAbstraction.GetSetUniformTrace();
+
+  glAbstraction.ResetSetUniformCallStack();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+  // Test order of uniforms in stack
+  int indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
+  int indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
+  int indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+
+  tet_infoline("Testing C above B and A at bottom\n");
+  bool CBA = (indexC > indexB) && (indexB > indexA);
+
+  DALI_TEST_EQUALS(CBA, true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
+  // Only top actor will get touched.
+  actorA.TouchedSignal().Connect(TestTouchCallback);
+  actorB.TouchedSignal().Connect(TestTouchCallback2);
+  actorC.TouchedSignal().Connect(TestTouchCallback3);
+
+  Dali::Integration::Point point;
+  point.SetDeviceId(1);
+  point.SetState(PointState::DOWN);
+  point.SetScreenPosition(Vector2(10.f, 10.f));
+  Dali::Integration::TouchEvent touchEvent;
+  touchEvent.AddPoint(point);
+
+  tet_infoline("UtcDaliActor Test Set up completed \n");
+
+  application.ProcessEvent(touchEvent);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
+
+  ResetTouchCallbacks(application);
+
+  tet_printf("Lower actor C below Actor B ( actor B and A on same level due to insertion order) so C is below both \n");
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorC[DevelActor::Property::SIBLING_ORDER] = 1;
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorC, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(touchEvent); // touch event
+
+  glSetUniformStack.Reset();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+  // Test order of uniforms in stack
+  indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
+  indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
+  indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+
+  tet_infoline("Testing render order is A, C, B");
+  DALI_TEST_EQUALS(indexC > indexA, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(indexB > indexC, true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  ResetTouchCallbacks(application);
+
+  tet_printf("Lower actor C below Actor A leaving B on top\n");
+
+  orderChangedSignal = false;
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorC[DevelActor::Property::SIBLING_ORDER] = 0;
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorC, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(touchEvent);
+
+  glSetUniformStack.Reset();
+
+  application.Render();
+  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+  // Test order of uniforms in stack
+  indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
+  indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
+  indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+
+  DALI_TEST_EQUALS(indexA > indexC, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(indexB > indexA, true, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  ResetTouchCallbacks(application);
+
+  tet_printf("Lower actor B below Actor C leaving A on top\n");
+
+  orderChangedSignal = false;
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorB[DevelActor::Property::SIBLING_ORDER] = 0;
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorB, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(touchEvent);
+
+  glSetUniformStack.Reset();
+
+  application.Render();
+  tet_printf("Trace:%s \n", glSetUniformStack.GetTraceString().c_str());
+
+  // Test order of uniforms in stack
+  indexC = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "3.000000");
+  indexB = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "2.000000");
+  indexA = glSetUniformStack.FindIndexFromMethodAndParams("uRendererColor", "1.000000");
+
+  DALI_TEST_EQUALS(indexC > indexB, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(indexA > indexC, true, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliActorRaiseAboveDifferentParentsN(void)
+{
+  tet_infoline("UtcDaliActor RaiseToAbove test with actor and target actor having different parents \n");
+
+  TestApplication application;
+
+  Integration::Scene stage(application.GetScene());
+
+  Actor parentA = Actor::New();
+  Actor parentB = Actor::New();
+  parentA.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  parentA.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+  parentB.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  parentB.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  parentA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  parentA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  parentB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  parentB.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  stage.Add(parentA);
+  stage.Add(parentB);
+
+  Actor actorA = Actor::New();
+  Actor actorB = Actor::New();
+  Actor actorC = Actor::New();
+
+  parentA.Add(actorA);
+  parentA.Add(actorB);
+
+  tet_printf("Actor C added to different parent from A and B \n");
+  parentB.Add(actorC);
+
+  actorA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorB.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorC.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorC.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorA.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorA.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorB.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorB.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorC.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorC.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  ResetTouchCallbacks();
+
+  // Connect ChildOrderChangedSignal
+  bool                     orderChangedSignal(false);
+  Actor                    orderChangedActor;
+  ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
+  DevelActor::ChildOrderChangedSignal(stage.GetRootLayer()).Connect(&application, f);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
+  // Only top actor will get touched.
+  actorA.TouchedSignal().Connect(TestTouchCallback);
+  actorB.TouchedSignal().Connect(TestTouchCallback2);
+  actorC.TouchedSignal().Connect(TestTouchCallback3);
+
+  Dali::Integration::Point point;
+  point.SetDeviceId(1);
+  point.SetState(PointState::DOWN);
+  point.SetScreenPosition(Vector2(10.f, 10.f));
+  Dali::Integration::TouchEvent touchEvent;
+  touchEvent.AddPoint(point);
+
+  application.ProcessEvent(touchEvent);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
+
+  ResetTouchCallbacks();
+
+  tet_printf("Raise actor A Above Actor C which have different parents\n");
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorA.RaiseAbove(actorC);
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+
+  application.ProcessEvent(touchEvent); // touch event
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
+
+  ResetTouchCallbacks();
+
+  END_TEST;
+}
+
+int UtcDaliActorGeoTouchRaiseAboveDifferentParentsN(void)
+{
+  tet_infoline("UtcDaliActor RaiseToAbove test with actor and target actor having different parents \n");
+
+  TestApplication application;
+
+  Integration::Scene stage(application.GetScene());
+
+  Actor parentA = Actor::New();
+  Actor parentB = Actor::New();
+  parentA.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  parentA.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+  parentB.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  parentB.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  parentA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  parentA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  parentB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  parentB.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  stage.Add(parentA);
+  stage.Add(parentB);
+
+  Actor actorA = Actor::New();
+  Actor actorB = Actor::New();
+  Actor actorC = Actor::New();
+
+  parentA.Add(actorA);
+  parentA.Add(actorB);
+
+  tet_printf("Actor C added to different parent from A and B \n");
+  parentB.Add(actorC);
+
+  actorA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorB.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorC.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorC.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorA.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorA.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorB.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorB.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorC.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorC.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+  ResetTouchCallbacks(application);
+
+  // Connect ChildOrderChangedSignal
+  bool                     orderChangedSignal(false);
+  Actor                    orderChangedActor;
+  ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
+  DevelActor::ChildOrderChangedSignal(stage.GetRootLayer()).Connect(&application, f);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
+  // Only top actor will get touched.
+  actorA.TouchedSignal().Connect(TestTouchCallback);
+  actorB.TouchedSignal().Connect(TestTouchCallback2);
+  actorC.TouchedSignal().Connect(TestTouchCallback3);
+
+  Dali::Integration::Point point;
+  point.SetDeviceId(1);
+  point.SetState(PointState::DOWN);
+  point.SetScreenPosition(Vector2(10.f, 10.f));
+  Dali::Integration::TouchEvent touchEvent;
+  touchEvent.AddPoint(point);
+
+  application.ProcessEvent(touchEvent);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
+
+  ResetTouchCallbacks(application);
+
+  tet_printf("Raise actor A Above Actor C which have different parents\n");
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorA.RaiseAbove(actorC);
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+
+  application.ProcessEvent(touchEvent); // touch event
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
 
-  parentB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
-  parentB.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  ResetTouchCallbacks(application);
 
-  stage.Add(parentA);
-  stage.Add(parentB);
+  END_TEST;
+}
+
+int UtcDaliActorRaiseLowerWhenUnparentedTargetN(void)
+{
+  tet_infoline("UtcDaliActor Test  raiseAbove and lowerBelow api when target Actor has no parent \n");
+
+  TestApplication application;
+
+  Integration::Scene stage(application.GetScene());
 
   Actor actorA = Actor::New();
   Actor actorB = Actor::New();
   Actor actorC = Actor::New();
 
-  parentA.Add(actorA);
-  parentA.Add(actorB);
+  actorA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
 
-  tet_printf("Actor C added to different parent from A and B \n");
-  parentB.Add(actorC);
+  actorB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorB.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorC.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorC.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorA.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorA.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorB.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorB.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorC.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorC.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  ResetTouchCallbacks();
+
+  // Connect ChildOrderChangedSignal
+  bool                     orderChangedSignal(false);
+  Actor                    orderChangedActor;
+  ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
+  DevelActor::ChildOrderChangedSignal(stage.GetRootLayer()).Connect(&application, f);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
+  // Only top actor will get touched.
+  actorA.TouchedSignal().Connect(TestTouchCallback);
+  actorB.TouchedSignal().Connect(TestTouchCallback2);
+  actorC.TouchedSignal().Connect(TestTouchCallback3);
+
+  Dali::Integration::Point point;
+  point.SetDeviceId(1);
+  point.SetState(PointState::DOWN);
+  point.SetScreenPosition(Vector2(10.f, 10.f));
+  Dali::Integration::TouchEvent touchEvent;
+  touchEvent.AddPoint(point);
+
+  tet_printf("Raise actor A Above Actor C which have no parents\n");
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorA.RaiseAbove(actorC);
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+
+  application.ProcessEvent(touchEvent);
+
+  tet_printf("Not parented so RaiseAbove should show no effect\n");
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  ResetTouchCallbacks();
+
+  orderChangedSignal = false;
+
+  stage.Add(actorB);
+  tet_printf("Lower actor A below Actor C when only A is not on stage \n");
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorA.LowerBelow(actorC);
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(touchEvent);
+
+  tet_printf("Actor A not parented so LowerBelow should show no effect\n");
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  ResetTouchCallbacks();
+
+  orderChangedSignal = false;
+
+  tet_printf("Adding Actor A to stage, will be on top\n");
+
+  stage.Add(actorA);
+  application.SendNotification();
+  application.Render();
+
+  tet_printf("Raise actor B Above Actor C when only B has a parent\n");
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorB.RaiseAbove(actorC);
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+
+  application.ProcessEvent(touchEvent);
+
+  tet_printf("C not parented so RaiseAbove should show no effect\n");
+  DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  ResetTouchCallbacks();
+
+  orderChangedSignal = false;
+
+  tet_printf("Lower actor A below Actor C when only A has a parent\n");
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorA.LowerBelow(actorC);
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+
+  application.ProcessEvent(touchEvent);
+
+  tet_printf("C not parented so LowerBelow should show no effect\n");
+  DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  ResetTouchCallbacks();
+
+  orderChangedSignal = false;
+
+  stage.Add(actorC);
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorA.RaiseAbove(actorC);
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorA, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(touchEvent);
+
+  tet_printf("Raise actor A Above Actor C, now both have same parent \n");
+  DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliActorGeoTouchRaiseLowerWhenUnparentedTargetN(void)
+{
+  tet_infoline("UtcDaliActor Test  raiseAbove and lowerBelow api when target Actor has no parent \n");
+
+  TestApplication application;
+
+  Integration::Scene stage(application.GetScene());
+
+  Actor actorA = Actor::New();
+  Actor actorB = Actor::New();
+  Actor actorC = Actor::New();
 
   actorA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
   actorA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
@@ -6635,65 +8160,148 @@ int UtcDaliActorRaiseAboveDifferentParentsN(void)
   actorC.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
   actorC.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
 
-  ResetTouchCallbacks();
+  application.GetScene().SetGeometryHittestEnabled(true);
+  ResetTouchCallbacks(application);
+
+  // Connect ChildOrderChangedSignal
+  bool                     orderChangedSignal(false);
+  Actor                    orderChangedActor;
+  ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
+  DevelActor::ChildOrderChangedSignal(stage.GetRootLayer()).Connect(&application, f);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
+  // Only top actor will get touched.
+  actorA.TouchedSignal().Connect(TestTouchCallback);
+  actorB.TouchedSignal().Connect(TestTouchCallback2);
+  actorC.TouchedSignal().Connect(TestTouchCallback3);
+
+  Dali::Integration::Point point;
+  point.SetDeviceId(1);
+  point.SetState(PointState::DOWN);
+  point.SetScreenPosition(Vector2(10.f, 10.f));
+  Dali::Integration::TouchEvent touchEvent;
+  touchEvent.AddPoint(point);
+
+  tet_printf("Raise actor A Above Actor C which have no parents\n");
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorA.RaiseAbove(actorC);
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+
+  application.ProcessEvent(touchEvent);
+
+  tet_printf("Not parented so RaiseAbove should show no effect\n");
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  ResetTouchCallbacks(application);
+
+  orderChangedSignal = false;
+
+  stage.Add(actorB);
+  tet_printf("Lower actor A below Actor C when only A is not on stage \n");
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorA.LowerBelow(actorC);
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(touchEvent);
+
+  tet_printf("Actor A not parented so LowerBelow should show no effect\n");
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  ResetTouchCallbacks(application);
+
+  orderChangedSignal = false;
+
+  tet_printf("Adding Actor A to stage, will be on top\n");
+
+  stage.Add(actorA);
+  application.SendNotification();
+  application.Render();
+
+  tet_printf("Raise actor B Above Actor C when only B has a parent\n");
 
-  // Connect ChildOrderChangedSignal
-  bool                     orderChangedSignal(false);
-  Actor                    orderChangedActor;
-  ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
-  DevelActor::ChildOrderChangedSignal(stage.GetRootLayer()).Connect(&application, f);
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorB.RaiseAbove(actorC);
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
 
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
   application.SendNotification();
-  application.Render();
 
-  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  application.ProcessEvent(touchEvent);
+
+  tet_printf("C not parented so RaiseAbove should show no effect\n");
+  DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
 
-  // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
-  // Only top actor will get touched.
-  actorA.TouchedSignal().Connect(TestTouchCallback);
-  actorB.TouchedSignal().Connect(TestTouchCallback2);
-  actorC.TouchedSignal().Connect(TestTouchCallback3);
+  ResetTouchCallbacks(application);
 
-  Dali::Integration::Point point;
-  point.SetDeviceId(1);
-  point.SetState(PointState::DOWN);
-  point.SetScreenPosition(Vector2(10.f, 10.f));
-  Dali::Integration::TouchEvent touchEvent;
-  touchEvent.AddPoint(point);
+  orderChangedSignal = false;
+
+  tet_printf("Lower actor A below Actor C when only A has a parent\n");
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorA.LowerBelow(actorC);
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+
+  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  application.SendNotification();
 
   application.ProcessEvent(touchEvent);
 
-  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  tet_printf("C not parented so LowerBelow should show no effect\n");
+  DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
-  DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
 
-  ResetTouchCallbacks();
+  ResetTouchCallbacks(application);
 
-  tet_printf("Raise actor A Above Actor C which have different parents\n");
+  orderChangedSignal = false;
+
+  stage.Add(actorC);
 
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
   actorA.RaiseAbove(actorC);
-  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorA, TEST_LOCATION);
 
   // Ensure sorting happens at end of Core::ProcessEvents() before next touch
   application.SendNotification();
+  application.Render();
 
-  application.ProcessEvent(touchEvent); // touch event
+  application.ProcessEvent(touchEvent);
 
-  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  tet_printf("Raise actor A Above Actor C, now both have same parent \n");
+  DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
-  DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
-
-  ResetTouchCallbacks();
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
 
   END_TEST;
 }
 
-int UtcDaliActorRaiseLowerWhenUnparentedTargetN(void)
+int UtcDaliActorTestAllAPIwhenActorNotParented(void)
 {
-  tet_infoline("UtcDaliActor Test  raiseAbove and lowerBelow api when target Actor has no parent \n");
+  tet_infoline("UtcDaliActor Test all raise/lower api when actor has no parent \n");
 
   TestApplication application;
 
@@ -6729,13 +8337,6 @@ int UtcDaliActorRaiseLowerWhenUnparentedTargetN(void)
   ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
   DevelActor::ChildOrderChangedSignal(stage.GetRootLayer()).Connect(&application, f);
 
-  application.SendNotification();
-  application.Render();
-
-  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
-  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
-  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
-
   // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
   // Only top actor will get touched.
   actorA.TouchedSignal().Connect(TestTouchCallback);
@@ -6749,117 +8350,116 @@ int UtcDaliActorRaiseLowerWhenUnparentedTargetN(void)
   Dali::Integration::TouchEvent touchEvent;
   touchEvent.AddPoint(point);
 
-  tet_printf("Raise actor A Above Actor C which have no parents\n");
+  stage.Add(actorA);
+  tet_printf("Raise actor B Above Actor C but B not parented\n");
 
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
-  actorA.RaiseAbove(actorC);
+  actorB.Raise();
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
 
-  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
   application.SendNotification();
+  application.Render();
 
   application.ProcessEvent(touchEvent);
 
   tet_printf("Not parented so RaiseAbove should show no effect\n");
 
-  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
 
+  tet_printf("Raise actor B Above Actor C but B not parented\n");
   ResetTouchCallbacks();
 
   orderChangedSignal = false;
 
-  stage.Add(actorB);
-  tet_printf("Lower actor A below Actor C when only A is not on stage \n");
-
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
-  actorA.LowerBelow(actorC);
+  actorC.Lower();
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
 
-  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  // Sort actor tree before next touch event
   application.SendNotification();
   application.Render();
 
   application.ProcessEvent(touchEvent);
 
-  tet_printf("Actor A not parented so LowerBelow should show no effect\n");
-  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
-  DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+  tet_printf("Not parented so RaiseAbove should show no effect\n");
 
+  DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
   ResetTouchCallbacks();
 
   orderChangedSignal = false;
 
-  tet_printf("Adding Actor A to stage, will be on top\n");
-
-  stage.Add(actorA);
-  application.SendNotification();
-  application.Render();
-
-  tet_printf("Raise actor B Above Actor C when only B has a parent\n");
+  tet_printf("Lower actor C below B but C not parented\n");
 
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
-  actorB.RaiseAbove(actorC);
+  actorB.Lower();
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
 
-  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  // Sort actor tree before next touch event
   application.SendNotification();
+  application.Render();
 
   application.ProcessEvent(touchEvent);
 
-  tet_printf("C not parented so RaiseAbove should show no effect\n");
+  tet_printf("Not parented so Lower should show no effect\n");
+
   DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
-
   ResetTouchCallbacks();
 
   orderChangedSignal = false;
 
-  tet_printf("Lower actor A below Actor C when only A has a parent\n");
+  tet_printf("Raise actor B to top\n");
 
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
-  actorA.LowerBelow(actorC);
+  actorB.RaiseToTop();
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
 
-  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
+  // Sort actor tree before next touch event
   application.SendNotification();
+  application.Render();
 
   application.ProcessEvent(touchEvent);
 
-  tet_printf("C not parented so LowerBelow should show no effect\n");
+  tet_printf("Not parented so RaiseToTop should show no effect\n");
+
   DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
-
   ResetTouchCallbacks();
 
   orderChangedSignal = false;
 
-  stage.Add(actorC);
+  tet_printf("Add ActorB to stage so only Actor C not parented\n");
+
+  stage.Add(actorB);
+
+  tet_printf("Lower actor C to Bottom, B stays at top\n");
 
   DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
-  actorA.RaiseAbove(actorC);
-  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(orderChangedActor, actorA, TEST_LOCATION);
+  actorC.LowerToBottom();
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
 
-  // Ensure sorting happens at end of Core::ProcessEvents() before next touch
   application.SendNotification();
   application.Render();
 
   application.ProcessEvent(touchEvent);
 
-  tet_printf("Raise actor A Above Actor C, now both have same parent \n");
-  DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
-  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  tet_printf("Not parented so LowerToBottom should show no effect\n");
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+  ResetTouchCallbacks();
 
   END_TEST;
 }
 
-int UtcDaliActorTestAllAPIwhenActorNotParented(void)
+int UtcDaliActorGeoTouchTestAllAPIwhenActorNotParented(void)
 {
   tet_infoline("UtcDaliActor Test all raise/lower api when actor has no parent \n");
 
@@ -6889,7 +8489,8 @@ int UtcDaliActorTestAllAPIwhenActorNotParented(void)
   actorC.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
   actorC.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
 
-  ResetTouchCallbacks();
+  application.GetScene().SetGeometryHittestEnabled(true);
+  ResetTouchCallbacks(application);
 
   // Connect ChildOrderChangedSignal
   bool                     orderChangedSignal(false);
@@ -6929,7 +8530,7 @@ int UtcDaliActorTestAllAPIwhenActorNotParented(void)
   DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
 
   tet_printf("Raise actor B Above Actor C but B not parented\n");
-  ResetTouchCallbacks();
+  ResetTouchCallbacks(application);
 
   orderChangedSignal = false;
 
@@ -6948,7 +8549,7 @@ int UtcDaliActorTestAllAPIwhenActorNotParented(void)
   DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
-  ResetTouchCallbacks();
+  ResetTouchCallbacks(application);
 
   orderChangedSignal = false;
 
@@ -6969,7 +8570,7 @@ int UtcDaliActorTestAllAPIwhenActorNotParented(void)
   DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
-  ResetTouchCallbacks();
+  ResetTouchCallbacks(application);
 
   orderChangedSignal = false;
 
@@ -6990,7 +8591,7 @@ int UtcDaliActorTestAllAPIwhenActorNotParented(void)
   DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
-  ResetTouchCallbacks();
+  ResetTouchCallbacks(application);
 
   orderChangedSignal = false;
 
@@ -7014,7 +8615,7 @@ int UtcDaliActorTestAllAPIwhenActorNotParented(void)
   DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled2, true, TEST_LOCATION);
   DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
-  ResetTouchCallbacks();
+  ResetTouchCallbacks(application);
 
   END_TEST;
 }
@@ -7125,6 +8726,113 @@ int UtcDaliActorRaiseAboveActorAndTargetTheSameN(void)
   END_TEST;
 }
 
+int UtcDaliActorGeoTouchRaiseAboveActorAndTargetTheSameN(void)
+{
+  tet_infoline("UtcDaliActor RaiseToAbove and  test with actor provided as target resulting in a no operation \n");
+
+  TestApplication application;
+
+  Integration::Scene stage(application.GetScene());
+
+  Actor actorA = Actor::New();
+  Actor actorB = Actor::New();
+  Actor actorC = Actor::New();
+
+  actorA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorB.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorC.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actorC.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  actorA.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorA.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorB.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorB.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  actorC.SetProperty(Actor::Property::WIDTH_RESIZE_POLICY, "FILL_TO_PARENT");
+  actorC.SetProperty(Actor::Property::HEIGHT_RESIZE_POLICY, "FILL_TO_PARENT");
+
+  stage.Add(actorA);
+  stage.Add(actorB);
+  stage.Add(actorC);
+
+  // connect to actor touch signals, will use touch callbacks to determine which actor is on top.
+  // Only top actor will get touched.
+  actorA.TouchedSignal().Connect(TestTouchCallback);
+  actorB.TouchedSignal().Connect(TestTouchCallback2);
+  actorC.TouchedSignal().Connect(TestTouchCallback3);
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+  ResetTouchCallbacks(application);
+
+  // Connect ChildOrderChangedSignal
+  bool                     orderChangedSignal(false);
+  Actor                    orderChangedActor;
+  ChildOrderChangedFunctor f(orderChangedSignal, orderChangedActor);
+  DevelActor::ChildOrderChangedSignal(stage.GetRootLayer()).Connect(&application, f);
+
+  application.SendNotification();
+  application.Render();
+
+  Dali::Integration::Point point;
+  point.SetDeviceId(1);
+  point.SetState(PointState::DOWN);
+  point.SetScreenPosition(Vector2(10.f, 10.f));
+  Dali::Integration::TouchEvent touchEvent;
+  touchEvent.AddPoint(point);
+
+  application.ProcessEvent(touchEvent);
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
+
+  ResetTouchCallbacks(application);
+
+  tet_infoline("Raise actor A Above Actor A which is the same actor!!\n");
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorA.RaiseAbove(actorA);
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorA, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(touchEvent);
+
+  tet_infoline("No target is source Actor so RaiseAbove should show no effect\n");
+
+  DALI_TEST_EQUALS(gTouchCallBackCalled, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, true, TEST_LOCATION);
+
+  ResetTouchCallbacks(application);
+
+  orderChangedSignal = false;
+
+  DALI_TEST_EQUALS(orderChangedSignal, false, TEST_LOCATION);
+  actorA.RaiseAbove(actorC);
+  DALI_TEST_EQUALS(orderChangedSignal, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(orderChangedActor, actorA, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(touchEvent);
+
+  tet_infoline("Raise actor A Above Actor C which will now be successful \n");
+  DALI_TEST_EQUALS(gTouchCallBackCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled2, false, TEST_LOCATION);
+  DALI_TEST_EQUALS(gTouchCallBackCalled3, false, TEST_LOCATION);
+
+  END_TEST;
+}
+
 int UtcDaliActorGetScreenPosition(void)
 {
   tet_infoline("UtcDaliActorGetScreenPosition Get screen coordinates of Actor \n");
diff --git a/automated-tests/src/dali/utc-Dali-GeoHitTestAlgorithm.cpp b/automated-tests/src/dali/utc-Dali-GeoHitTestAlgorithm.cpp
new file mode 100644 (file)
index 0000000..bc7d30b
--- /dev/null
@@ -0,0 +1,892 @@
+/*
+ * Copyright (c) 2023 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 <dali-test-suite-utils.h>
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/devel-api/events/hit-test-algorithm.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/public-api/dali-core.h>
+#include <stdlib.h>
+
+#include <iostream>
+
+using namespace Dali;
+
+namespace
+{
+
+/**
+ * The functor to be used in the hit-test algorithm to check whether the actor is hittable.
+ */
+bool IsActorHittableFunction(Actor actor, Dali::HitTestAlgorithm::TraverseType type)
+{
+  bool hittable = false;
+
+  switch(type)
+  {
+    case Dali::HitTestAlgorithm::CHECK_ACTOR:
+    {
+      // Check whether the actor is visible and not fully transparent.
+      if(actor.GetCurrentProperty<bool>(Actor::Property::VISIBLE) && actor.GetCurrentProperty<Vector4>(Actor::Property::WORLD_COLOR).a > 0.01f) // not FULLY_TRANSPARENT
+      {
+        // Check whether the actor has the specific name "HittableActor"
+        if(actor.GetProperty<std::string>(Actor::Property::NAME) == "HittableActor")
+        {
+          hittable = true;
+        }
+      }
+      break;
+    }
+    case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
+    {
+      if(actor.GetCurrentProperty<bool>(Actor::Property::VISIBLE)) // Actor is visible, if not visible then none of its children are visible.
+      {
+        hittable = true;
+      }
+      break;
+    }
+    default:
+    {
+      break;
+    }
+  }
+
+  return hittable;
+};
+
+bool DefaultIsActorTouchableFunction(Dali::Actor actor, Dali::HitTestAlgorithm::TraverseType type)
+{
+  bool hittable = false;
+
+  switch(type)
+  {
+    case Dali::HitTestAlgorithm::CHECK_ACTOR:
+    {
+      if(actor.GetCurrentProperty<bool>(Actor::Property::VISIBLE) &&
+         actor.GetProperty<bool>(Actor::Property::SENSITIVE) &&
+         actor.GetCurrentProperty<Vector4>(Actor::Property::WORLD_COLOR).a > 0.01f)
+      {
+        hittable = true;
+      }
+      break;
+    }
+    case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
+    {
+      if(actor.GetCurrentProperty<bool>(Actor::Property::VISIBLE) && // Actor is visible, if not visible then none of its children are visible.
+         actor.GetProperty<bool>(Actor::Property::SENSITIVE))        // Actor is sensitive, if insensitive none of its children should be hittable either.
+      {
+        hittable = true;
+      }
+      break;
+    }
+    default:
+    {
+      break;
+    }
+  }
+
+  return hittable;
+};
+
+} // anonymous namespace
+
+// Positive test case for a method
+int UtcDaliGeoHitTestAlgorithmWithFunctor(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::HitTestAlgorithm functor");
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Stage stage = Stage::GetCurrent();
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  actor.SetProperty(Actor::Property::NAME, "NonHittableActor");
+  stage.Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Vector2 screenCoordinates(10.0f, 10.0f);
+  Vector2 localCoordinates;
+  actor.ScreenToLocal(localCoordinates.x, localCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+
+  // Perform a hit-test at the given screen coordinates
+  Dali::HitTestAlgorithm::Results results;
+  Dali::HitTestAlgorithm::HitTest(stage, screenCoordinates, results, IsActorHittableFunction, true);
+  DALI_TEST_CHECK(results.actor != actor);
+
+  actor.SetProperty(Actor::Property::NAME, "HittableActor");
+
+  results.actor            = Actor();
+  results.actorCoordinates = Vector2::ZERO;
+
+  // Perform a hit-test at the given screen coordinates
+  Dali::HitTestAlgorithm::HitTest(stage, screenCoordinates, results, IsActorHittableFunction, true);
+  DALI_TEST_CHECK(results.actor == actor);
+  DALI_TEST_EQUALS(localCoordinates, results.actorCoordinates, 0.1f, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliGeoHitTestAlgorithmOrtho01(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::HitTestAlgorithm with parallel Ortho camera()");
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Stage             stage             = Stage::GetCurrent();
+  RenderTaskList    renderTaskList    = stage.GetRenderTaskList();
+  RenderTask        defaultRenderTask = renderTaskList.GetTask(0u);
+  Dali::CameraActor cameraActor       = defaultRenderTask.GetCameraActor();
+
+  Vector2 stageSize(stage.GetSize());
+  cameraActor.SetOrthographicProjection(stageSize);
+  cameraActor.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, 1600.0f));
+
+  Vector2 actorSize(stageSize * 0.5f);
+  // Create two actors with half the size of the stage and set them to be partially overlapping
+  Actor blue = Actor::New();
+  blue.SetProperty(Actor::Property::NAME, "Blue");
+  blue.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  blue.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(1.0f / 3.0f, 1.0f / 3.0f, 0.5f));
+  blue.SetProperty(Actor::Property::SIZE, actorSize);
+  blue.SetProperty(Actor::Property::POSITION_Z, 30.0f);
+
+  Actor green = Actor::New();
+  green.SetProperty(Actor::Property::NAME, "Green");
+  green.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  green.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(2.0f / 3.0f, 2.0f / 3.0f, 0.5f));
+  green.SetProperty(Actor::Property::SIZE, actorSize);
+
+  // Add the actors to the view
+  stage.Add(blue);
+  stage.Add(green);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(0);
+  application.Render(10);
+
+  HitTestAlgorithm::Results results;
+  HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction, true);
+  DALI_TEST_CHECK(results.actor == green);
+  DALI_TEST_EQUALS(results.actorCoordinates, actorSize * 1.0f / 6.0f, TEST_LOCATION);
+
+  HitTest(stage, stageSize / 3.0f, results, &DefaultIsActorTouchableFunction, true);
+  DALI_TEST_CHECK(results.actor == blue);
+  DALI_TEST_EQUALS(results.actorCoordinates, actorSize * 0.5f, TEST_LOCATION);
+
+  HitTest(stage, stageSize * 2.0f / 3.0f, results, &DefaultIsActorTouchableFunction, true);
+  DALI_TEST_CHECK(results.actor == green);
+  DALI_TEST_EQUALS(results.actorCoordinates, actorSize * 0.5f, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliGeoHitTestAlgorithmOrtho02(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::HitTestAlgorithm with offset Ortho camera()");
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Stage             stage             = Stage::GetCurrent();
+  RenderTaskList    renderTaskList    = stage.GetRenderTaskList();
+  RenderTask        defaultRenderTask = renderTaskList.GetTask(0u);
+  Dali::CameraActor cameraActor       = defaultRenderTask.GetCameraActor();
+
+  Vector2 stageSize(stage.GetSize());
+  cameraActor.SetOrthographicProjection(stageSize);
+  cameraActor.SetNearClippingPlane(800.0f);
+  cameraActor.SetFarClippingPlane(4895.0f);
+
+  // Move camera not centered position.
+  cameraActor.SetProperty(Actor::Property::POSITION, Vector3(stageSize.x * 0.2f, stageSize.y * 0.2f, 1600.0f));
+
+  Vector2 actorSize(stageSize * 0.5f);
+  // Create two actors with half the size of the stage and set them to be partially overlapping
+  Actor blue = Actor::New();
+  blue.SetProperty(Actor::Property::NAME, "Blue");
+  blue.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  blue.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(0.2f, 0.2f, 0.5f));
+  blue.SetProperty(Actor::Property::SIZE, actorSize);
+  blue.SetProperty(Actor::Property::POSITION_Z, 30.0f);
+
+  Actor green = Actor::New();
+  green.SetProperty(Actor::Property::NAME, "Green");
+  green.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  green.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(0.4f, 0.4f, 0.5f));
+  green.SetProperty(Actor::Property::SIZE, actorSize);
+
+  // Add the actors to the view
+  stage.Add(blue);
+  stage.Add(green);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(0);
+  application.Render(10);
+
+  {
+    HitTestAlgorithm::Results results;
+    HitTest(stage, Vector2(240.0f, 400.0f), results, &DefaultIsActorTouchableFunction, true);
+    DALI_TEST_CHECK(results.actor == green);
+    DALI_TEST_EQUALS(results.actorCoordinates, actorSize * 0.6f, 0.01f, TEST_LOCATION);
+  }
+
+  {
+    HitTestAlgorithm::Results results;
+    HitTest(stage, Vector2(0.001f, 0.001f), results, &DefaultIsActorTouchableFunction, true);
+    DALI_TEST_CHECK(results.actor == blue);
+    DALI_TEST_EQUALS(results.actorCoordinates, Vector2(0.001f, 0.001f), 0.001f, TEST_LOCATION);
+  }
+
+  {
+    HitTestAlgorithm::Results results;
+    HitTest(stage, stageSize, results, &DefaultIsActorTouchableFunction, true);
+    DALI_TEST_CHECK(!results.actor);
+    DALI_TEST_EQUALS(results.actorCoordinates, Vector2::ZERO, TEST_LOCATION);
+  }
+
+  // Just inside green
+  {
+    HitTestAlgorithm::Results results;
+    HitTest(stage, stageSize * 0.69f, results, &DefaultIsActorTouchableFunction, true);
+    DALI_TEST_CHECK(results.actor == green);
+    DALI_TEST_EQUALS(results.actorCoordinates, actorSize * 0.98f, 0.01f, TEST_LOCATION);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliGeoHitTestAlgorithmClippingActor(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::HitTestAlgorithm with a stencil");
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Stage stage     = Stage::GetCurrent();
+  Actor rootLayer = stage.GetRootLayer();
+  rootLayer.SetProperty(Actor::Property::NAME, "RootLayer");
+
+  // Create a layer
+  Layer layer = Layer::New();
+  layer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  layer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  layer.SetProperty(Actor::Property::NAME, "layer");
+  stage.Add(layer);
+
+  // Create a clipping actor and add it to the layer.
+  Actor clippingActor = CreateRenderableActor();
+  clippingActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  clippingActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  clippingActor.SetProperty(Actor::Property::SIZE, Vector2(50.0f, 50.0f));
+  clippingActor.SetProperty(Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN);
+  clippingActor.SetProperty(Actor::Property::NAME, "clippingActor");
+  layer.Add(clippingActor);
+
+  // Create a renderable actor and add it to the clipping actor.
+  Actor childActor = CreateRenderableActor();
+  childActor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  childActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  childActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  childActor.SetProperty(Actor::Property::NAME, "childActor");
+  clippingActor.Add(childActor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Hit within clippingActor and childActor.
+  HitTestAlgorithm::Results results;
+  HitTest(stage, Vector2(10.0f, 10.0f), results, &DefaultIsActorTouchableFunction, true);
+  DALI_TEST_CHECK(results.actor == childActor);
+  tet_printf("Hit: %s\n", (results.actor ? results.actor.GetProperty<std::string>(Actor::Property::NAME).c_str() : "NULL"));
+
+  // Hit within childActor but outside of clippingActor, should hit the root-layer instead.
+  HitTest(stage, Vector2(60.0f, 60.0f), results, &DefaultIsActorTouchableFunction, true);
+  DALI_TEST_CHECK(results.actor == rootLayer);
+  tet_printf("Hit: %s\n", (results.actor ? results.actor.GetProperty<std::string>(Actor::Property::NAME).c_str() : "NULL"));
+
+  END_TEST;
+}
+
+int UtcDaliGeoHitTestAlgorithmClippingActorStress(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::HitTestAlgorithm with many many stencil");
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Stage stage     = Stage::GetCurrent();
+  Actor rootLayer = stage.GetRootLayer();
+  rootLayer.SetProperty(Actor::Property::NAME, "RootLayer");
+
+  // Create a layer
+  Layer layer = Layer::New();
+  layer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  layer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  layer.SetProperty(Actor::Property::NAME, "layer");
+  stage.Add(layer);
+
+  // Create a clipping actor and add it to the layer.
+  Actor clippingActor = CreateRenderableActor();
+  clippingActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  clippingActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  clippingActor.SetProperty(Actor::Property::SIZE, Vector2(220.0f, 220.0f));
+  clippingActor.SetProperty(Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_TO_BOUNDING_BOX);
+  clippingActor.SetProperty(Actor::Property::NAME, "clippingActor");
+  layer.Add(clippingActor);
+
+  // Create a renderable actor and add it to the clipping actor.
+  Actor     latestActor = clippingActor;
+  const int depthMax    = 100;
+  for(int i = 0; i < depthMax; i++)
+  {
+    char tmp[29];
+    sprintf(tmp, "depth%03d", i);
+
+    Actor childActor = CreateRenderableActor();
+    childActor.SetProperty(Actor::Property::SIZE, Vector2(220.0f, 220.0f));
+    childActor.SetProperty(Actor::Property::POSITION, Vector2(200.0f / depthMax, 200.0f / depthMax));
+    childActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+    childActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+    childActor.SetProperty(Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_TO_BOUNDING_BOX);
+    childActor.SetProperty(Actor::Property::NAME, tmp);
+
+    latestActor.Add(childActor);
+    latestActor = childActor;
+  }
+  // NOTE : latestActor's TOP_LEFT position become 200.f, 200.0f
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Hit within clippingActor and latestActor.
+  HitTestAlgorithm::Results results;
+  HitTest(stage, Vector2(201.0f, 201.0f), results, &DefaultIsActorTouchableFunction, true);
+  tet_printf("Hit: %s\n", (results.actor ? results.actor.GetProperty<std::string>(Actor::Property::NAME).c_str() : "NULL"));
+  DALI_TEST_CHECK(results.actor == latestActor);
+
+  // Hit within childActor but outside of clippingActor, should hit the root-layer instead.
+  HitTest(stage, Vector2(221.0f, 221.0f), results, &DefaultIsActorTouchableFunction, true);
+  tet_printf("Hit: %s\n", (results.actor ? results.actor.GetProperty<std::string>(Actor::Property::NAME).c_str() : "NULL"));
+  DALI_TEST_CHECK(results.actor == rootLayer);
+
+  END_TEST;
+}
+
+int UtcDaliGeoHitTestAlgorithmOverlay(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::HitTestAlgorithm with overlay actors");
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Stage             stage             = Stage::GetCurrent();
+  RenderTaskList    renderTaskList    = stage.GetRenderTaskList();
+  RenderTask        defaultRenderTask = renderTaskList.GetTask(0u);
+  Dali::CameraActor cameraActor       = defaultRenderTask.GetCameraActor();
+
+  Vector2 stageSize(stage.GetSize());
+  cameraActor.SetOrthographicProjection(stageSize);
+  cameraActor.SetProperty(Actor::Property::POSITION, Vector3(0.0f, 0.0f, 1600.0f));
+
+  Vector2 actorSize(stageSize * 0.5f);
+  // Create two actors with half the size of the stage and set them to be partially overlapping
+  Actor blue = Actor::New();
+  blue.SetProperty(Actor::Property::DRAW_MODE, DrawMode::OVERLAY_2D);
+  blue.SetProperty(Actor::Property::NAME, "Blue");
+  blue.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  blue.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(1.0f / 3.0f, 1.0f / 3.0f, 0.5f));
+  blue.SetProperty(Actor::Property::SIZE, actorSize);
+  blue.SetProperty(Actor::Property::POSITION_Z, 30.0f);
+
+  Actor green = Actor::New();
+  green.SetProperty(Actor::Property::NAME, "Green");
+  green.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  green.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(2.0f / 3.0f, 2.0f / 3.0f, 0.5f));
+  green.SetProperty(Actor::Property::SIZE, actorSize);
+
+  // Add the actors to the view
+  stage.Add(blue);
+  stage.Add(green);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(0);
+  application.Render(10);
+
+  HitTestAlgorithm::Results results;
+
+  //Hit in the intersection. Should pick the blue actor since it is an overlay.
+  HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction, true);
+  DALI_TEST_CHECK(results.actor == blue);
+  DALI_TEST_EQUALS(results.actorCoordinates, actorSize * 5.0f / 6.0f, TEST_LOCATION);
+
+  //Hit in the blue actor
+  HitTest(stage, stageSize / 3.0f, results, &DefaultIsActorTouchableFunction, true);
+  DALI_TEST_CHECK(results.actor == blue);
+  DALI_TEST_EQUALS(results.actorCoordinates, actorSize * 0.5f, TEST_LOCATION);
+
+  //Hit in the green actor
+  HitTest(stage, stageSize * 2.0f / 3.0f, results, &DefaultIsActorTouchableFunction, true);
+  DALI_TEST_CHECK(results.actor == green);
+  DALI_TEST_EQUALS(results.actorCoordinates, actorSize * 0.5f, TEST_LOCATION);
+
+  // Create new actor child as blue. It will be shown over the blue, and green.
+  Actor red = Actor::New();
+  red.SetProperty(Actor::Property::NAME, "Red");
+  red.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  red.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  red.SetProperty(Actor::Property::POSITION, Vector2(actorSize.x * 5.0f / 6.0f, -actorSize.y * 1.0f / 6.0f));
+  red.SetProperty(Actor::Property::SIZE, actorSize);
+
+  blue.Add(red);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(0);
+  application.Render(10);
+
+  //Hit in the intersection red, green, blue. Should pick the red actor since it is an child of overlay.
+  HitTest(stage, Vector2(stageSize.x * 13.0f / 24.0f, stageSize.y * 11.0f / 24.0f), results, &DefaultIsActorTouchableFunction, true);
+  tet_printf("%d %d %d , %f %f\n", results.actor == red ? 1 : 0, results.actor == green ? 1 : 0, results.actor == blue ? 1 : 0, results.actorCoordinates.x, results.actorCoordinates.y);
+  DALI_TEST_CHECK(results.actor == red);
+  DALI_TEST_EQUALS(results.actorCoordinates, Vector2(actorSize.x * 1.0f / 12.0f, actorSize.y * 11.0f / 12.0f), TEST_LOCATION);
+
+  //Hit in the intersection red, blue. Should pick the red actor since it is an child of blue.
+  HitTest(stage, Vector2(stageSize.x * 13.0f / 24.0f, stageSize.y * 9.0f / 24.0f), results, &DefaultIsActorTouchableFunction, true);
+  tet_printf("%d %d %d , %f %f\n", results.actor == red ? 1 : 0, results.actor == green ? 1 : 0, results.actor == blue ? 1 : 0, results.actorCoordinates.x, results.actorCoordinates.y);
+  DALI_TEST_CHECK(results.actor == red);
+  DALI_TEST_EQUALS(results.actorCoordinates, Vector2(actorSize.x * 1.0f / 12.0f, actorSize.y * 9.0f / 12.0f), TEST_LOCATION);
+
+  //Hit in the intersection red, green. Should pick the green actor since red is outside the scope of its parent.
+  HitTest(stage, Vector2(stageSize.x * 15.0f / 24.0f, stageSize.y * 11.0f / 24.0f), results, &DefaultIsActorTouchableFunction, true);
+  tet_printf("%d %d %d , %f %f\n", results.actor == red ? 1 : 0, results.actor == green ? 1 : 0, results.actor == blue ? 1 : 0, results.actorCoordinates.x, results.actorCoordinates.y);
+  DALI_TEST_CHECK(results.actor == green);
+  DALI_TEST_EQUALS(results.actorCoordinates, Vector2(actorSize.x * 5.0f / 12.0f, actorSize.y * 1.0f / 12.0f), TEST_LOCATION);
+
+  //Hit in the intersection blue, green. Should pick the blue actor since it is an overlay.
+  HitTest(stage, Vector2(stageSize.x * 11.0f / 24.0f, stageSize.y * 13.0f / 24.0f), results, &DefaultIsActorTouchableFunction, true);
+  tet_printf("%d %d %d , %f %f\n", results.actor == red ? 1 : 0, results.actor == green ? 1 : 0, results.actor == blue ? 1 : 0, results.actorCoordinates.x, results.actorCoordinates.y);
+  DALI_TEST_CHECK(results.actor == blue);
+  DALI_TEST_EQUALS(results.actorCoordinates, Vector2(actorSize.x * 9.0f / 12.0f, actorSize.y * 11.0f / 12.0f), TEST_LOCATION);
+
+  // Change blue's draw mode as normal. now blue < red < green
+  blue.SetProperty(Actor::Property::DRAW_MODE, DrawMode::NORMAL);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(0);
+  application.Render(10);
+
+  //Hit in the intersection red, green, blue. Should pick the green actor since it is latest ordered actor.
+  HitTest(stage, Vector2(stageSize.x * 13.0f / 24.0f, stageSize.y * 11.0f / 24.0f), results, &DefaultIsActorTouchableFunction, true);
+  tet_printf("%d %d %d , %f %f\n", results.actor == red ? 1 : 0, results.actor == green ? 1 : 0, results.actor == blue ? 1 : 0, results.actorCoordinates.x, results.actorCoordinates.y);
+  DALI_TEST_CHECK(results.actor == green);
+  DALI_TEST_EQUALS(results.actorCoordinates, Vector2(actorSize.x * 3.0f / 12.0f, actorSize.y * 1.0f / 12.0f), TEST_LOCATION);
+
+  //Hit in the intersection red, blue. Should pick the red actor since it is an child of blue.
+  HitTest(stage, Vector2(stageSize.x * 13.0f / 24.0f, stageSize.y * 9.0f / 24.0f), results, &DefaultIsActorTouchableFunction, true);
+  tet_printf("%d %d %d , %f %f\n", results.actor == red ? 1 : 0, results.actor == green ? 1 : 0, results.actor == blue ? 1 : 0, results.actorCoordinates.x, results.actorCoordinates.y);
+  DALI_TEST_CHECK(results.actor == red);
+  DALI_TEST_EQUALS(results.actorCoordinates, Vector2(actorSize.x * 1.0f / 12.0f, actorSize.y * 9.0f / 12.0f), TEST_LOCATION);
+
+  //Hit in the intersection red, green. Should pick the green actor since it is latest ordered actor.
+  HitTest(stage, Vector2(stageSize.x * 15.0f / 24.0f, stageSize.y * 11.0f / 24.0f), results, &DefaultIsActorTouchableFunction, true);
+  tet_printf("%d %d %d , %f %f\n", results.actor == red ? 1 : 0, results.actor == green ? 1 : 0, results.actor == blue ? 1 : 0, results.actorCoordinates.x, results.actorCoordinates.y);
+  DALI_TEST_CHECK(results.actor == green);
+  DALI_TEST_EQUALS(results.actorCoordinates, Vector2(actorSize.x * 5.0f / 12.0f, actorSize.y * 1.0f / 12.0f), TEST_LOCATION);
+
+  //Hit in the intersection blue, green. Should pick the green actor since it is latest ordered actor.
+  HitTest(stage, Vector2(stageSize.x * 11.0f / 24.0f, stageSize.y * 13.0f / 24.0f), results, &DefaultIsActorTouchableFunction, true);
+  tet_printf("%d %d %d , %f %f\n", results.actor == red ? 1 : 0, results.actor == green ? 1 : 0, results.actor == blue ? 1 : 0, results.actorCoordinates.x, results.actorCoordinates.y);
+  DALI_TEST_CHECK(results.actor == green);
+  DALI_TEST_EQUALS(results.actorCoordinates, Vector2(actorSize.x * 1.0f / 12.0f, actorSize.y * 3.0f / 12.0f), TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliGeoHitTestAlgorithmOrder(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::HitTestAlgorithm between On/Off render task");
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Stage   stage = Stage::GetCurrent();
+  Vector2 stageSize(stage.GetSize());
+
+  Actor blue                                        = Actor::New();
+  blue[Dali::Actor::Property::NAME]                 = "Blue";
+  blue[Dali::Actor::Property::ANCHOR_POINT]         = AnchorPoint::CENTER;
+  blue[Dali::Actor::Property::PARENT_ORIGIN]        = ParentOrigin::CENTER;
+  blue[Dali::Actor::Property::WIDTH_RESIZE_POLICY]  = ResizePolicy::FILL_TO_PARENT;
+  blue[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+  Actor green                                        = Actor::New();
+  green[Dali::Actor::Property::NAME]                 = "Green";
+  green[Dali::Actor::Property::ANCHOR_POINT]         = AnchorPoint::CENTER;
+  green[Dali::Actor::Property::PARENT_ORIGIN]        = ParentOrigin::CENTER;
+  green[Dali::Actor::Property::WIDTH_RESIZE_POLICY]  = ResizePolicy::FILL_TO_PARENT;
+  green[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+  stage.Add(blue);
+  stage.Add(green);
+
+  RenderTaskList renderTaskList = stage.GetRenderTaskList();
+  RenderTask     offRenderTask  = renderTaskList.CreateTask();
+
+  Dali::CameraActor cameraActor                     = Dali::CameraActor::New(stageSize);
+  cameraActor[Dali::Actor::Property::ANCHOR_POINT]  = AnchorPoint::CENTER;
+  cameraActor[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+  stage.Add(cameraActor);
+
+  offRenderTask.SetExclusive(true);
+  offRenderTask.SetInputEnabled(true);
+  offRenderTask.SetCameraActor(cameraActor);
+  offRenderTask.SetSourceActor(green);
+  offRenderTask.SetScreenToFrameBufferMappingActor(green);
+
+  Dali::Texture texture      = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGB888, unsigned(stageSize.width), unsigned(stageSize.height));
+  FrameBuffer   renderTarget = FrameBuffer::New(stageSize.width, stageSize.height, FrameBuffer::Attachment::DEPTH);
+  renderTarget.AttachColorTexture(texture);
+  offRenderTask.SetFrameBuffer(renderTarget);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(10);
+
+  HitTestAlgorithm::Results results;
+  HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction, true);
+  DALI_TEST_CHECK(results.actor == green);
+
+  END_TEST;
+}
+
+int UtcDaliGeoHitTestAlgorithmExclusiveMultiple(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::HitTestAlgorithm between On/Off render task with multiple exclusived");
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Stage   stage = Stage::GetCurrent();
+  Vector2 stageSize(stage.GetSize());
+
+  Actor blue                                        = Actor::New();
+  blue[Dali::Actor::Property::NAME]                 = "Blue";
+  blue[Dali::Actor::Property::ANCHOR_POINT]         = AnchorPoint::CENTER;
+  blue[Dali::Actor::Property::PARENT_ORIGIN]        = ParentOrigin::CENTER;
+  blue[Dali::Actor::Property::WIDTH_RESIZE_POLICY]  = ResizePolicy::FILL_TO_PARENT;
+  blue[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+  Actor green                                        = Actor::New();
+  green[Dali::Actor::Property::NAME]                 = "Green";
+  green[Dali::Actor::Property::ANCHOR_POINT]         = AnchorPoint::CENTER;
+  green[Dali::Actor::Property::PARENT_ORIGIN]        = ParentOrigin::CENTER;
+  green[Dali::Actor::Property::WIDTH_RESIZE_POLICY]  = ResizePolicy::FILL_TO_PARENT;
+  green[Dali::Actor::Property::HEIGHT_RESIZE_POLICY] = ResizePolicy::FILL_TO_PARENT;
+
+  stage.Add(blue);
+  stage.Add(green);
+
+  RenderTaskList renderTaskList = stage.GetRenderTaskList();
+  RenderTask     offRenderTask  = renderTaskList.CreateTask();
+  RenderTask     offRenderTask2 = renderTaskList.CreateTask();
+
+  Dali::CameraActor cameraActor                     = Dali::CameraActor::New(stageSize);
+  cameraActor[Dali::Actor::Property::ANCHOR_POINT]  = AnchorPoint::CENTER;
+  cameraActor[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+  stage.Add(cameraActor);
+
+  offRenderTask.SetExclusive(true);
+  offRenderTask.SetInputEnabled(true);
+  offRenderTask.SetCameraActor(cameraActor);
+  offRenderTask.SetSourceActor(green);
+  offRenderTask.SetScreenToFrameBufferMappingActor(green);
+
+  Dali::Texture texture      = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGB888, unsigned(stageSize.width), unsigned(stageSize.height));
+  FrameBuffer   renderTarget = FrameBuffer::New(stageSize.width, stageSize.height, FrameBuffer::Attachment::DEPTH);
+  renderTarget.AttachColorTexture(texture);
+  offRenderTask.SetFrameBuffer(renderTarget);
+
+  offRenderTask2.SetExclusive(true);
+  offRenderTask2.SetInputEnabled(true);
+  offRenderTask2.SetCameraActor(cameraActor);
+  offRenderTask2.SetSourceActor(green);
+  offRenderTask2.SetScreenToFrameBufferMappingActor(green);
+  offRenderTask2.SetFrameBuffer(renderTarget);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(10);
+
+  HitTestAlgorithm::Results results;
+  HitTest(stage, stageSize / 2.0f, results, &DefaultIsActorTouchableFunction, true);
+  DALI_TEST_CHECK(results.actor == green);
+
+  END_TEST;
+}
+
+int UtcDaliGeoHitTestAlgorithmBuildPickingRay01(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::HitTestAlgorithm::BuildPickingRay positive test");
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Stage             stage             = Stage::GetCurrent();
+  RenderTaskList    renderTaskList    = stage.GetRenderTaskList();
+  RenderTask        defaultRenderTask = renderTaskList.GetTask(0u);
+  Dali::CameraActor cameraActor       = defaultRenderTask.GetCameraActor();
+
+  Vector2 stageSize(stage.GetSize());
+
+  Vector2 actorSize(stageSize * 0.5f);
+  // Create two actors with half the size of the stage and set them to be overlapping
+  Actor blue = Actor::New();
+  blue.SetProperty(Actor::Property::NAME, "Blue");
+  blue.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  blue.SetProperty(Actor::Property::PARENT_ORIGIN, AnchorPoint::CENTER);
+  blue.SetProperty(Actor::Property::SIZE, actorSize);
+
+  Actor green = Actor::New();
+  green.SetProperty(Actor::Property::NAME, "Green");
+  green.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  green.SetProperty(Actor::Property::PARENT_ORIGIN, AnchorPoint::CENTER);
+  green.SetProperty(Actor::Property::SIZE, actorSize);
+
+  // Add the actors to the view
+  stage.Add(blue);
+  stage.Add(green);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(0);
+
+  Vector2 screenCoords(stageSize * 0.5f); // touch center of screen
+  Vector3 origin;
+  Vector3 direction;
+  bool    built = HitTestAlgorithm::BuildPickingRay(defaultRenderTask, screenCoords, origin, direction);
+
+  Vector3 camPos = cameraActor[Actor::Property::POSITION];
+  DALI_TEST_EQUALS(built, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(camPos, origin, TEST_LOCATION);
+  direction.Normalize();
+  DALI_TEST_EQUALS(direction, -Vector3::ZAXIS, 0.01f, TEST_LOCATION);
+
+  screenCoords.x = stageSize.width * 0.75f;
+  built          = HitTestAlgorithm::BuildPickingRay(defaultRenderTask, screenCoords, origin, direction);
+  DALI_TEST_EQUALS(built, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(camPos, origin, TEST_LOCATION);
+  direction.Normalize();
+  DALI_TEST_EQUALS(direction, Vector3(0.075f, 0.0f, -1.0f), 0.01f, TEST_LOCATION);
+
+  screenCoords.x = 0.0f;
+  screenCoords.y = 0.0f;
+  built          = HitTestAlgorithm::BuildPickingRay(defaultRenderTask, screenCoords, origin, direction);
+  DALI_TEST_EQUALS(built, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(camPos, origin, TEST_LOCATION);
+  direction.Normalize();
+  DALI_TEST_EQUALS(direction, Vector3(-0.144f, -0.24f, -0.96f), 0.01f, TEST_LOCATION);
+
+  screenCoords.x = stageSize.width;
+  screenCoords.y = stageSize.height;
+  built          = HitTestAlgorithm::BuildPickingRay(defaultRenderTask, screenCoords, origin, direction);
+  DALI_TEST_EQUALS(built, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(camPos, origin, TEST_LOCATION);
+  direction.Normalize();
+  DALI_TEST_EQUALS(direction, Vector3(0.144f, 0.24f, -0.96f), 0.01f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliGeoHitTestAlgorithmBuildPickingRay02(void)
+{
+  TestApplication application;
+  tet_infoline("Testing Dali::HitTestAlgorithm::BuildPickingRay positive test for offscreen");
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Stage          stage             = Stage::GetCurrent();
+  RenderTaskList renderTaskList    = stage.GetRenderTaskList();
+  RenderTask     defaultRenderTask = renderTaskList.GetTask(0u);
+  RenderTask     offRenderTask     = renderTaskList.CreateTask();
+
+  Dali::CameraActor defaultCameraActor = defaultRenderTask.GetCameraActor();
+
+  Vector2 stageSize(stage.GetSize());
+
+  Vector2 actorSize(stageSize * 0.5f);
+  Vector2 offscreenSize(1920.0f, 1080.0f); // Quit big size.
+
+  // Create two actors with half the size of the stage and set them to be partial-overlapping
+  Actor blue = Actor::New();
+  blue.SetProperty(Actor::Property::NAME, "Blue");
+  blue.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  blue.SetProperty(Actor::Property::PARENT_ORIGIN, AnchorPoint::CENTER);
+  blue.SetProperty(Actor::Property::SIZE, actorSize);
+  blue.SetProperty(Actor::Property::POSITION, -actorSize * 0.25f);
+
+  Actor green = Actor::New();
+  green.SetProperty(Actor::Property::NAME, "Green");
+  green.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  green.SetProperty(Actor::Property::PARENT_ORIGIN, AnchorPoint::CENTER);
+  green.SetProperty(Actor::Property::SIZE, actorSize);
+  green.SetProperty(Actor::Property::POSITION, actorSize * 0.25f);
+
+  Actor red = Actor::New();
+  red.SetProperty(Actor::Property::NAME, "Red");
+  red.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  red.SetProperty(Actor::Property::PARENT_ORIGIN, AnchorPoint::CENTER);
+  red.SetProperty(Actor::Property::SIZE, offscreenSize * 0.5f);
+
+  Dali::CameraActor offscreenCameraActor                     = Dali::CameraActor::New(offscreenSize);
+  offscreenCameraActor[Dali::Actor::Property::ANCHOR_POINT]  = AnchorPoint::CENTER;
+  offscreenCameraActor[Dali::Actor::Property::PARENT_ORIGIN] = ParentOrigin::CENTER;
+  stage.Add(offscreenCameraActor);
+
+  offRenderTask.SetExclusive(true);
+  offRenderTask.SetInputEnabled(true);
+  offRenderTask.SetCameraActor(offscreenCameraActor);
+  offRenderTask.SetSourceActor(red);
+  offRenderTask.SetScreenToFrameBufferMappingActor(green);
+
+  Dali::Texture texture      = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(actorSize.width), unsigned(actorSize.height));
+  FrameBuffer   renderTarget = FrameBuffer::New(actorSize.width, actorSize.height, FrameBuffer::Attachment::DEPTH_STENCIL);
+  renderTarget.AttachColorTexture(texture);
+  offRenderTask.SetFrameBuffer(renderTarget);
+
+  // Add the actors to the view
+  stage.Add(blue);
+  stage.Add(green);
+  stage.Add(red);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(0);
+
+  Vector2 screenCoords(stageSize * 0.5f); // touch center of screen
+  Vector3 origin;
+  Vector3 direction;
+  bool    built = HitTestAlgorithm::BuildPickingRay(defaultRenderTask, screenCoords, origin, direction);
+
+  Vector3 camPos = defaultCameraActor[Actor::Property::POSITION];
+  DALI_TEST_EQUALS(built, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(camPos, origin, TEST_LOCATION);
+  direction.Normalize();
+  DALI_TEST_EQUALS(direction, -Vector3::ZAXIS, 0.01f, TEST_LOCATION);
+
+  screenCoords.x = stageSize.width * 0.75f;
+  built          = HitTestAlgorithm::BuildPickingRay(defaultRenderTask, screenCoords, origin, direction);
+  DALI_TEST_EQUALS(built, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(camPos, origin, TEST_LOCATION);
+  direction.Normalize();
+  DALI_TEST_EQUALS(direction, Vector3(0.075f, 0.0f, -1.0f), 0.01f, TEST_LOCATION);
+
+  screenCoords.x = 0.0f;
+  screenCoords.y = 0.0f;
+  built          = HitTestAlgorithm::BuildPickingRay(defaultRenderTask, screenCoords, origin, direction);
+  DALI_TEST_EQUALS(built, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(camPos, origin, TEST_LOCATION);
+  direction.Normalize();
+  DALI_TEST_EQUALS(direction, Vector3(-0.144f, -0.24f, -0.96f), 0.01f, TEST_LOCATION);
+
+  screenCoords.x = stageSize.width;
+  screenCoords.y = stageSize.height;
+  built          = HitTestAlgorithm::BuildPickingRay(defaultRenderTask, screenCoords, origin, direction);
+  DALI_TEST_EQUALS(built, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(camPos, origin, TEST_LOCATION);
+  direction.Normalize();
+  DALI_TEST_EQUALS(direction, Vector3(0.144f, 0.24f, -0.96f), 0.01f, TEST_LOCATION);
+
+  // For offscreen picking ray
+  camPos = Vector3(offscreenCameraActor[Actor::Property::POSITION]);
+
+  const float ELLIPSION = 0.001f; ///< tiny margin to avoid non-hitting cases
+
+  // Center of green
+  screenCoords = stageSize * 0.5f + actorSize * 0.25f;
+  built        = HitTestAlgorithm::BuildPickingRay(offRenderTask, screenCoords, origin, direction);
+
+  DALI_TEST_EQUALS(built, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(camPos, origin, TEST_LOCATION);
+  direction.Normalize();
+  DALI_TEST_EQUALS(direction, -Vector3::ZAXIS, 0.01f, TEST_LOCATION);
+
+  // Center right of green
+  screenCoords.x = stageSize.width * 0.5f + actorSize.width * 0.75f - ELLIPSION;
+  built          = HitTestAlgorithm::BuildPickingRay(offRenderTask, screenCoords, origin, direction);
+  DALI_TEST_EQUALS(built, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(camPos, origin, TEST_LOCATION);
+  direction.Normalize();
+  DALI_TEST_EQUALS(direction, Vector3(0.242533f, 0.0f, -0.970143f), 0.01f, TEST_LOCATION);
+
+  // Top left of green
+  screenCoords = stageSize * 0.5f - actorSize * 0.25f + Vector2(ELLIPSION, ELLIPSION);
+  built        = HitTestAlgorithm::BuildPickingRay(offRenderTask, screenCoords, origin, direction);
+  DALI_TEST_EQUALS(built, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(camPos, origin, TEST_LOCATION);
+  direction.Normalize();
+  DALI_TEST_EQUALS(direction, Vector3(-0.240308f, -0.135174f, -0.961239f), 0.01f, TEST_LOCATION);
+
+  // Bottom right of green
+  screenCoords = stageSize * 0.5f + actorSize * 0.75f - Vector2(ELLIPSION, ELLIPSION);
+  built        = HitTestAlgorithm::BuildPickingRay(offRenderTask, screenCoords, origin, direction);
+  DALI_TEST_EQUALS(built, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(camPos, origin, TEST_LOCATION);
+  direction.Normalize();
+  DALI_TEST_EQUALS(direction, Vector3(0.240308f, 0.135174f, -0.961239f), 0.01f, TEST_LOCATION);
+
+  // Rotate green
+  green.SetProperty(Actor::Property::ORIENTATION, Quaternion(Radian(Degree(90.0f)), Vector3::ZAXIS));
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(0);
+
+  // Top left of green, but ray directoin is bottom left
+  screenCoords.x = stageSize.width * 0.5f + actorSize.width * 0.25f - actorSize.height * 0.5f + ELLIPSION;
+  screenCoords.y = stageSize.height * 0.5f + actorSize.height * 0.25f - actorSize.width * 0.5f + ELLIPSION;
+  built          = HitTestAlgorithm::BuildPickingRay(offRenderTask, screenCoords, origin, direction);
+  DALI_TEST_EQUALS(built, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(camPos, origin, TEST_LOCATION);
+  direction.Normalize();
+  DALI_TEST_EQUALS(direction, Vector3(-0.240308f, 0.135174f, -0.961239f), 0.01f, TEST_LOCATION);
+
+  // Bottom right of green, but ray direction is top right
+  screenCoords.x = stageSize.width * 0.5f + actorSize.width * 0.25f + actorSize.height * 0.5f - ELLIPSION;
+  screenCoords.y = stageSize.height * 0.5f + actorSize.height * 0.25f + actorSize.width * 0.5f - ELLIPSION;
+  built          = HitTestAlgorithm::BuildPickingRay(offRenderTask, screenCoords, origin, direction);
+  DALI_TEST_EQUALS(built, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(camPos, origin, TEST_LOCATION);
+  direction.Normalize();
+  DALI_TEST_EQUALS(direction, Vector3(0.240308f, -0.135174f, -0.961239f), 0.01f, TEST_LOCATION);
+
+  // Out of green. BuildPickingRay failed.
+  screenCoords = stageSize * 0.5f - actorSize * 0.5f;
+  built        = HitTestAlgorithm::BuildPickingRay(offRenderTask, screenCoords, origin, direction);
+  DALI_TEST_EQUALS(built, false, TEST_LOCATION);
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali/utc-Dali-GeoHoverProcessing.cpp b/automated-tests/src/dali/utc-Dali-GeoHoverProcessing.cpp
new file mode 100644 (file)
index 0000000..625788e
--- /dev/null
@@ -0,0 +1,1387 @@
+/*
+ * Copyright (c) 2023 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 <dali-test-suite-utils.h>
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/devel-api/events/hover-event-devel.h>
+#include <dali/integration-api/events/hover-event-integ.h>
+#include <dali/integration-api/events/touch-integ.h>
+#include <dali/integration-api/render-task-list-integ.h>
+#include <dali/public-api/dali-core.h>
+#include <stdlib.h>
+
+#include <iostream>
+
+using namespace Dali;
+
+void utc_dali_geo_hover_processing_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_geo_hover_processing_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+// Stores data that is populated in the callback and will be read by the TET cases
+struct SignalData
+{
+  SignalData()
+  : functorCalled(false),
+    hoverEvent(),
+    hoveredActor()
+  {
+  }
+
+  void Reset()
+  {
+    functorCalled = false;
+    hoverEvent.Reset();
+    hoveredActor.Reset();
+  }
+
+  bool       functorCalled;
+  HoverEvent hoverEvent;
+  Actor      hoveredActor;
+};
+
+// Functor that sets the data when called
+struct HoverEventFunctor
+{
+  /**
+   * Constructor.
+   * @param[in]  data         Reference to the data to store callback information.
+   * @param[in]  returnValue  What the functor should return.
+   */
+  HoverEventFunctor(SignalData& data, bool returnValue = true)
+  : signalData(data),
+    returnValue(returnValue)
+  {
+  }
+
+  bool operator()(Actor actor, const HoverEvent& hoverEvent)
+  {
+    signalData.functorCalled = true;
+    signalData.hoveredActor  = actor;
+    signalData.hoverEvent    = hoverEvent;
+
+    return returnValue;
+  }
+
+  SignalData& signalData;
+  bool        returnValue;
+};
+
+// Functor that removes the actor when called.
+struct RemoveActorFunctor : public HoverEventFunctor
+{
+  /**
+   * Constructor.
+   * @param[in]  data         Reference to the data to store callback information.
+   * @param[in]  returnValue  What the functor should return.
+   */
+  RemoveActorFunctor(SignalData& data, bool returnValue = true)
+  : HoverEventFunctor(data, returnValue)
+  {
+  }
+
+  bool operator()(Actor actor, const HoverEvent& hoverEvent)
+  {
+    Actor parent(actor.GetParent());
+    if(parent)
+    {
+      parent.Remove(actor);
+    }
+
+    return HoverEventFunctor::operator()(actor, hoverEvent);
+  }
+};
+
+Integration::HoverEvent GenerateSingleHover(PointState::Type state, const Vector2& screenPosition)
+{
+  Integration::HoverEvent hoverEvent;
+  Integration::Point      point;
+  point.SetState(state);
+  point.SetScreenPosition(screenPosition);
+  hoverEvent.points.push_back(point);
+  return hoverEvent;
+}
+
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+
+int UtcDaliGeoHoverNormalProcessing(void)
+{
+  TestApplication application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  Vector2 screenCoordinates(10.0f, 10.0f);
+  Vector2 localCoordinates;
+  actor.ScreenToLocal(localCoordinates.x, localCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, screenCoordinates));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, data.hoverEvent.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, data.hoverEvent.GetScreenPosition(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(localCoordinates, data.hoverEvent.GetLocalPosition(0), 0.1f, TEST_LOCATION);
+  DALI_TEST_EQUALS(0, data.hoverEvent.GetDeviceId(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(0u, data.hoverEvent.GetTime(), TEST_LOCATION);
+  DALI_TEST_EQUALS(actor, data.hoverEvent.GetHitActor(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(-1, data.hoverEvent.GetDeviceId(1), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::FINISHED, data.hoverEvent.GetState(1), TEST_LOCATION);
+  DALI_TEST_EQUALS(Vector2::ZERO, data.hoverEvent.GetScreenPosition(1), 0.1f, TEST_LOCATION);
+  DALI_TEST_EQUALS(Vector2::ZERO, data.hoverEvent.GetLocalPosition(1), 0.1f, TEST_LOCATION);
+  DALI_TEST_EQUALS(Dali::Actor(), data.hoverEvent.GetHitActor(1), TEST_LOCATION);
+  data.Reset();
+
+  // Emit a motion signal
+  screenCoordinates.x = screenCoordinates.y = 11.0f;
+  actor.ScreenToLocal(localCoordinates.x, localCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, screenCoordinates));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, data.hoverEvent.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::MOTION, data.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, data.hoverEvent.GetScreenPosition(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(localCoordinates, data.hoverEvent.GetLocalPosition(0), 0.1f, TEST_LOCATION);
+  DALI_TEST_EQUALS(0, data.hoverEvent.GetDeviceId(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(0u, data.hoverEvent.GetTime(), TEST_LOCATION);
+  DALI_TEST_EQUALS(actor, data.hoverEvent.GetHitActor(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(-1, data.hoverEvent.GetDeviceId(1), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::FINISHED, data.hoverEvent.GetState(1), TEST_LOCATION);
+  DALI_TEST_EQUALS(Vector2::ZERO, data.hoverEvent.GetScreenPosition(1), 0.1f, TEST_LOCATION);
+  DALI_TEST_EQUALS(Vector2::ZERO, data.hoverEvent.GetLocalPosition(1), 0.1f, TEST_LOCATION);
+  DALI_TEST_EQUALS(Dali::Actor(), data.hoverEvent.GetHitActor(1), TEST_LOCATION);
+  data.Reset();
+
+  // Emit a finished signal
+  screenCoordinates.x = screenCoordinates.y = 12.0f;
+  actor.ScreenToLocal(localCoordinates.x, localCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+  application.ProcessEvent(GenerateSingleHover(PointState::FINISHED, screenCoordinates));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, data.hoverEvent.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::FINISHED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, data.hoverEvent.GetScreenPosition(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(localCoordinates, data.hoverEvent.GetLocalPosition(0), 0.1f, TEST_LOCATION);
+  DALI_TEST_EQUALS(0, data.hoverEvent.GetDeviceId(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(0u, data.hoverEvent.GetTime(), TEST_LOCATION);
+  DALI_TEST_EQUALS(actor, data.hoverEvent.GetHitActor(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(-1, data.hoverEvent.GetDeviceId(1), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::FINISHED, data.hoverEvent.GetState(1), TEST_LOCATION);
+  DALI_TEST_EQUALS(Vector2::ZERO, data.hoverEvent.GetScreenPosition(1), 0.1f, TEST_LOCATION);
+  DALI_TEST_EQUALS(Vector2::ZERO, data.hoverEvent.GetLocalPosition(1), 0.1f, TEST_LOCATION);
+  DALI_TEST_EQUALS(Dali::Actor(), data.hoverEvent.GetHitActor(1), TEST_LOCATION);
+  data.Reset();
+
+  // Emit a started signal where the actor is not present
+  screenCoordinates.x = screenCoordinates.y = 200.0f;
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, screenCoordinates));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_CHECK(!data.hoverEvent);
+
+  END_TEST;
+}
+
+int UtcDaliGeoHoverOutsideCameraNearFarPlanes(void)
+{
+  TestApplication application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Integration::Scene stage     = application.GetScene();
+  Vector2            stageSize = stage.GetSize();
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  stage.Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Get the camera's near and far planes
+  RenderTaskList   taskList  = stage.GetRenderTaskList();
+  Dali::RenderTask task      = taskList.GetTask(0);
+  CameraActor      camera    = task.GetCameraActor();
+  float            nearPlane = camera.GetNearClippingPlane();
+  float            farPlane  = camera.GetFarClippingPlane();
+
+  // Calculate the current distance of the actor from the camera
+  float tanHalfFov = tanf(camera.GetFieldOfView() * 0.5f);
+  float distance   = (stageSize.y * 0.5f) / tanHalfFov;
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  Vector2 screenCoordinates(stageSize.x * 0.5f, stageSize.y * 0.5f);
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, screenCoordinates));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Emit a started signal where actor is just at the camera's near plane
+  actor.SetProperty(Actor::Property::POSITION_Z, distance - nearPlane);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, screenCoordinates));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Emit a started signal where actor is closer than the camera's near plane
+  actor.SetProperty(Actor::Property::POSITION_Z, (distance - nearPlane) + 1.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // When hover event leave outside of actor, the actor receive a Leave event
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, screenCoordinates));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::LEAVE, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+
+  // Emit a started signal where actor is just at the camera's far plane
+  actor.SetProperty(Actor::Property::POSITION_Z, distance - farPlane);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, screenCoordinates));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Emit a started signal where actor is further than the camera's far plane
+  actor.SetProperty(Actor::Property::POSITION_Z, (distance - farPlane) - 1.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // When hover event leave outside of actor, the actor receive a Leave event
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, screenCoordinates));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::LEAVE, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliGeoHoverEmitEmpty(void)
+{
+  TestApplication application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  try
+  {
+    // Emit an empty HoverEvent
+    Integration::HoverEvent event;
+    application.ProcessEvent(event);
+    tet_result(TET_FAIL);
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "!event.points.empty()", TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+int UtcDaliGeoHoverInterrupted(void)
+{
+  TestApplication application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+
+  // Emit an interrupted signal, we should be signalled regardless of whether there is a hit or not.
+  application.ProcessEvent(GenerateSingleHover(PointState::INTERRUPTED, Vector2(200.0f, 200.0f /* Outside actor */)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+
+  // Emit another interrupted signal, our signal handler should not be called.
+  application.ProcessEvent(GenerateSingleHover(PointState::INTERRUPTED, Vector2(200.0f, 200.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliGeoHoverParentConsumer(void)
+{
+  TestApplication application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+  Actor           rootActor(application.GetScene().GetRootLayer());
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data, false);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Connect to root actor's hovered signal
+  SignalData        rootData;
+  HoverEventFunctor rootFunctor(rootData); // Consumes signal
+  rootActor.HoveredSignal().Connect(&application, rootFunctor);
+
+  Vector2 screenCoordinates(10.0f, 10.0f);
+  Vector2 actorCoordinates, rootCoordinates;
+  actor.ScreenToLocal(actorCoordinates.x, actorCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+  rootActor.ScreenToLocal(rootCoordinates.x, rootCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, screenCoordinates));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, data.hoverEvent.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, rootData.hoverEvent.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, rootData.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, data.hoverEvent.GetScreenPosition(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, rootData.hoverEvent.GetScreenPosition(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(actorCoordinates, data.hoverEvent.GetLocalPosition(0), 0.1f, TEST_LOCATION);
+  DALI_TEST_EQUALS(rootCoordinates, rootData.hoverEvent.GetLocalPosition(0), 0.1f, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.hoverEvent.GetHitActor(0));
+  DALI_TEST_CHECK(actor == rootData.hoverEvent.GetHitActor(0));
+  data.Reset();
+  rootData.Reset();
+
+  // Emit a motion signal
+  screenCoordinates.x = screenCoordinates.y = 11.0f;
+  actor.ScreenToLocal(actorCoordinates.x, actorCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+  rootActor.ScreenToLocal(rootCoordinates.x, rootCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, screenCoordinates));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, data.hoverEvent.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, rootData.hoverEvent.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::MOTION, data.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::MOTION, rootData.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, data.hoverEvent.GetScreenPosition(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, rootData.hoverEvent.GetScreenPosition(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(actorCoordinates, data.hoverEvent.GetLocalPosition(0), 0.1f, TEST_LOCATION);
+  DALI_TEST_EQUALS(rootCoordinates, rootData.hoverEvent.GetLocalPosition(0), 0.1f, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.hoverEvent.GetHitActor(0));
+  DALI_TEST_CHECK(actor == rootData.hoverEvent.GetHitActor(0));
+  data.Reset();
+  rootData.Reset();
+
+  // Emit a finished signal
+  screenCoordinates.x = screenCoordinates.y = 12.0f;
+  actor.ScreenToLocal(actorCoordinates.x, actorCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+  rootActor.ScreenToLocal(rootCoordinates.x, rootCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+  application.ProcessEvent(GenerateSingleHover(PointState::FINISHED, screenCoordinates));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, data.hoverEvent.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, rootData.hoverEvent.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::FINISHED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::FINISHED, rootData.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, data.hoverEvent.GetScreenPosition(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, rootData.hoverEvent.GetScreenPosition(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(actorCoordinates, data.hoverEvent.GetLocalPosition(0), 0.1f, TEST_LOCATION);
+  DALI_TEST_EQUALS(rootCoordinates, rootData.hoverEvent.GetLocalPosition(0), 0.1f, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.hoverEvent.GetHitActor(0));
+  DALI_TEST_CHECK(actor == rootData.hoverEvent.GetHitActor(0));
+  data.Reset();
+  rootData.Reset();
+
+  // Emit a started signal where the actor is not present, will hit the root actor though
+  screenCoordinates.x = screenCoordinates.y = 200.0f;
+  rootActor.ScreenToLocal(rootCoordinates.x, rootCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, screenCoordinates));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, rootData.hoverEvent.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, rootData.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, rootData.hoverEvent.GetScreenPosition(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(rootCoordinates, rootData.hoverEvent.GetLocalPosition(0), 0.1f, TEST_LOCATION);
+  DALI_TEST_CHECK(rootActor == rootData.hoverEvent.GetHitActor(0));
+  END_TEST;
+}
+
+int UtcDaliGeoHoverInterruptedParentConsumer(void)
+{
+  TestApplication application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+  Actor           rootActor(application.GetScene().GetRootLayer());
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data, false);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Connect to root actor's hovered signal
+  SignalData        rootData;
+  HoverEventFunctor rootFunctor(rootData); // Consumes signal
+  rootActor.HoveredSignal().Connect(&application, rootFunctor);
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, rootData.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.hoverEvent.GetHitActor(0));
+  DALI_TEST_CHECK(actor == rootData.hoverEvent.GetHitActor(0));
+  data.Reset();
+  rootData.Reset();
+
+  // Emit an interrupted signal
+  application.ProcessEvent(GenerateSingleHover(PointState::INTERRUPTED, Vector2(200.0f, 200.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, rootData.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.hoverEvent.GetHitActor(0));
+  DALI_TEST_CHECK(actor == rootData.hoverEvent.GetHitActor(0));
+  data.Reset();
+  rootData.Reset();
+
+  // Emit another started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, rootData.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+  rootData.Reset();
+
+  // Remove actor from Stage
+  application.GetScene().Remove(actor);
+  data.Reset();
+  rootData.Reset();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit an interrupted signal, only root actor's signal should be called.
+  application.ProcessEvent(GenerateSingleHover(PointState::INTERRUPTED, Vector2(200.0f, 200.0f /* Outside actor */)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, rootData.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_CHECK(rootActor == rootData.hoverEvent.GetHitActor(0));
+  data.Reset();
+  rootData.Reset();
+
+  // Emit another interrupted state, none of the signal's should be called.
+  application.ProcessEvent(GenerateSingleHover(PointState::INTERRUPTED, Vector2(200.0f, 200.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(false, rootData.functorCalled, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliGeoHoverLeave(void)
+{
+  TestApplication application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+
+  // Emit a motion signal outside of actor, should be signalled with a Leave
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(200.0f, 200.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::LEAVE, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+
+  // Another motion outside of actor, no signalling
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(201.0f, 201.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Another motion event inside actor, signalled with start. This is because a new hover event was started on that actor.
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliGeoHoverLeaveParentConsumer(void)
+{
+  TestApplication application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+  Actor           rootActor(application.GetScene().GetRootLayer());
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data, false);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Connect to root actor's hovered signal
+  SignalData        rootData;
+  HoverEventFunctor rootFunctor(rootData); // Consumes signal
+  rootActor.HoveredSignal().Connect(&application, rootFunctor);
+
+  // Set actor to require leave events
+  actor.SetProperty(Actor::Property::LEAVE_REQUIRED, true);
+  rootActor.SetProperty(Actor::Property::LEAVE_REQUIRED, true);
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, rootData.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.hoverEvent.GetHitActor(0));
+  DALI_TEST_CHECK(actor == rootData.hoverEvent.GetHitActor(0));
+  data.Reset();
+  rootData.Reset();
+
+  // Emit a motion signal outside of actor, should be signalled with a Leave
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(200.0f, 200.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::LEAVE, data.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::MOTION, rootData.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.hoverEvent.GetHitActor(0));
+  DALI_TEST_CHECK(rootActor == rootData.hoverEvent.GetHitActor(0));
+  data.Reset();
+  rootData.Reset();
+
+  // Another motion outside of actor, only rootActor signalled
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(201.0f, 201.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::MOTION, rootData.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_CHECK(rootActor == rootData.hoverEvent.GetHitActor(0));
+  data.Reset();
+  rootData.Reset();
+
+  // Another motion event inside actor, signalled with start. This is because a new hover event was started on that actor.
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::MOTION, rootData.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.hoverEvent.GetHitActor(0));
+  DALI_TEST_CHECK(actor == rootData.hoverEvent.GetHitActor(0));
+  data.Reset();
+  rootData.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliGeoHoverActorBecomesInsensitive(void)
+{
+  TestApplication application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+
+  // Change actor to insensitive
+  actor.SetProperty(Actor::Property::SENSITIVE, false);
+
+  // Emit a motion signal, signalled with an interrupted
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(200.0f, 200.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliGeoHoverActorBecomesInsensitiveParentConsumer(void)
+{
+  TestApplication application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+  Actor           rootActor(application.GetScene().GetRootLayer());
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data, false);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Connect to root actor's hovered signal
+  SignalData        rootData;
+  HoverEventFunctor rootFunctor(rootData, false);
+  rootActor.HoveredSignal().Connect(&application, rootFunctor);
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, rootData.hoverEvent.GetState(0), TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.hoverEvent.GetHitActor(0));
+  DALI_TEST_CHECK(actor == rootData.hoverEvent.GetHitActor(0));
+  data.Reset();
+  rootData.Reset();
+
+  // Remove actor from Stage
+  application.GetScene().Remove(actor);
+
+  // Because it was removed, it gets interrupted.
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+  rootData.Reset();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Make root actor insensitive
+  rootActor.SetProperty(Actor::Property::SENSITIVE, false);
+
+  // Because it is insensitive, it does not receive the event.
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(200.0f, 200.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(false, rootData.functorCalled, TEST_LOCATION);
+  data.Reset();
+  rootData.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliGeoHoverActorBecomesUserInteractionDisabled(void)
+{
+  TestApplication application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::STARTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+
+  // Change actor to disable user interaction.
+  actor.SetProperty(DevelActor::Property::USER_INTERACTION_ENABLED, false);
+
+  // Emit a motion signal, signalled with an interrupted
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(200.0f, 200.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliGeoHoverMultipleLayers(void)
+{
+  TestApplication application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+  Actor           rootActor(application.GetScene().GetRootLayer());
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data);
+
+  Layer layer1(Layer::New());
+  layer1.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  layer1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  application.GetScene().Add(layer1);
+
+  Actor actor1(Actor::New());
+  actor1.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  actor1.SetProperty(Actor::Property::POSITION_Z, 1.0f); // Should hit actor1 in this layer
+  layer1.Add(actor1);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to layer1 and actor1
+  layer1.HoveredSignal().Connect(&application, functor);
+  actor1.HoveredSignal().Connect(&application, functor);
+
+  // Hit in hittable area, actor1 should be hit
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_CHECK(data.hoveredActor == actor1);
+  data.Reset();
+
+  // Make layer1 insensitive, nothing should be hit
+  layer1.SetProperty(Actor::Property::SENSITIVE, false);
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Make layer1 sensitive again, again actor1 will be hit
+  layer1.SetProperty(Actor::Property::SENSITIVE, true);
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_CHECK(data.hoveredActor == actor1);
+  data.Reset();
+
+  // Make rootActor insensitive, nothing should be hit
+  rootActor.SetProperty(Actor::Property::SENSITIVE, false);
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Make rootActor sensitive
+  rootActor.SetProperty(Actor::Property::SENSITIVE, true);
+
+  // Add another layer
+  Layer layer2(Layer::New());
+  layer2.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  layer2.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  layer2.SetProperty(Actor::Property::POSITION_Z, 10.0f); // Should hit layer2 in this layer rather than actor2
+  application.GetScene().Add(layer2);
+
+  Actor actor2(Actor::New());
+  actor2.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor2.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  layer2.Add(actor2);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to layer2 and actor2
+  layer2.HoveredSignal().Connect(&application, functor);
+  actor2.HoveredSignal().Connect(&application, functor);
+
+  // Emit an event, should hit layer2
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  //DALI_TEST_CHECK( data.hoveredActor == layer2 ); // TODO: Uncomment this after removing renderable hack!
+  data.Reset();
+
+  // Make layer2 insensitive, should hit actor1
+  layer2.SetProperty(Actor::Property::SENSITIVE, false);
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_CHECK(data.hoveredActor == actor1);
+  data.Reset();
+
+  // Make layer2 sensitive again, should hit layer2
+  layer2.SetProperty(Actor::Property::SENSITIVE, true);
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  //DALI_TEST_CHECK( data.hoveredActor == layer2 ); // TODO: Uncomment this after removing renderable hack!
+  data.Reset();
+
+  // Make layer2 invisible, render and notify
+  layer2.SetProperty(Actor::Property::VISIBLE, false);
+  application.SendNotification();
+  application.Render();
+
+  // Should hit actor1
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_CHECK(data.hoveredActor == actor1);
+  data.Reset();
+
+  // Make rootActor invisible, render and notify
+  rootActor.SetProperty(Actor::Property::VISIBLE, false);
+
+  // Because visible became false, we receive interrupted
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+
+  application.SendNotification();
+  application.Render();
+
+  // Should not hit anything
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliGeoHoverMultipleRenderTasks(void)
+{
+  TestApplication    application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+  Integration::Scene stage(application.GetScene());
+  Vector2            stageSize(stage.GetSize());
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  stage.Add(actor);
+
+  // Create render task
+  Viewport   viewport(stageSize.width * 0.5f, stageSize.height * 0.5f, stageSize.width * 0.5f, stageSize.height * 0.5f);
+  RenderTask renderTask(application.GetScene().GetRenderTaskList().CreateTask());
+  renderTask.SetViewport(viewport);
+  renderTask.SetInputEnabled(true);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Ensure renderTask actor can be hit too.
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(viewport.x + 5.0f, viewport.y + 5.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Disable input on renderTask, should not be hittable
+  renderTask.SetInputEnabled(false);
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(viewport.x + 5.0f, viewport.y + 5.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::LEAVE, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliGeoHoverMultipleRenderTasksWithChildLayer(void)
+{
+  TestApplication    application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+  Integration::Scene stage(application.GetScene());
+  Vector2            stageSize(stage.GetSize());
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  stage.Add(actor);
+
+  Layer layer = Layer::New();
+  layer.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  layer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  actor.Add(layer);
+
+  // Create render task
+  Viewport   viewport(stageSize.width * 0.5f, stageSize.height * 0.5f, stageSize.width * 0.5f, stageSize.height * 0.5f);
+  RenderTask renderTask(application.GetScene().GetRenderTaskList().CreateTask());
+  renderTask.SetViewport(viewport);
+  renderTask.SetInputEnabled(true);
+  renderTask.SetSourceActor(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to layer's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data);
+  actor.HoveredSignal().Connect(&application, functor);
+  layer.HoveredSignal().Connect(&application, functor);
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Ensure renderTask actor can be hit too.
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(viewport.x + 5.0f, viewport.y + 5.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Disable input on renderTask, should not be hittable
+  renderTask.SetInputEnabled(false);
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(viewport.x + 5.0f, viewport.y + 5.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::LEAVE, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliGeoHoverOffscreenRenderTasks(void)
+{
+  TestApplication    application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+  Integration::Scene stage(application.GetScene());
+  Vector2            stageSize(stage.GetSize());
+
+  // FrameBufferImage for offscreen RenderTask
+  FrameBuffer frameBuffer = FrameBuffer::New(stageSize.width, stageSize.height);
+
+  // Create a renderable actor to display the FrameBufferImage
+  Actor renderableActor = CreateRenderableActor(frameBuffer.GetColorTexture());
+  renderableActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  renderableActor.SetProperty(Actor::Property::SIZE, Vector2(stageSize.x, stageSize.y));
+  renderableActor.ScaleBy(Vector3(1.0f, -1.0f, 1.0f)); // FIXME
+  stage.Add(renderableActor);
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  stage.Add(actor);
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE); // Ensure framebuffer connects
+
+  stage.GetRenderTaskList().GetTask(0u).SetScreenToFrameBufferFunction(RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION);
+
+  // Create a RenderTask
+  RenderTask renderTask = stage.GetRenderTaskList().CreateTask();
+  renderTask.SetSourceActor(actor);
+  renderTask.SetFrameBuffer(frameBuffer);
+  renderTask.SetInputEnabled(true);
+
+  // Create another RenderTask
+  RenderTask renderTask2(stage.GetRenderTaskList().CreateTask());
+  renderTask2.SetInputEnabled(true);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliGeoHoverMultipleRenderableActors(void)
+{
+  TestApplication    application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+  Integration::Scene stage(application.GetScene());
+  Vector2            stageSize(stage.GetSize());
+
+  Actor parent = CreateRenderableActor();
+  parent.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  parent.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  stage.Add(parent);
+
+  Actor actor = CreateRenderableActor();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  parent.Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to layer's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data);
+  parent.HoveredSignal().Connect(&application, functor);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.hoveredActor);
+  END_TEST;
+}
+
+int UtcDaliGeoHoverActorRemovedInSignal(void)
+{
+  TestApplication application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData         data;
+  RemoveActorFunctor functor(data);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Register for leave events
+  actor.SetProperty(Actor::Property::LEAVE_REQUIRED, true);
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Re-add, render and notify
+  application.GetScene().Add(actor);
+  application.SendNotification();
+  application.Render();
+
+  // Emit another signal outside of actor's area, should not get anything as the scene has changed.
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(210.0f, 210.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit another signal outside of actor's area, should not get anything as the scene has changed.
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(210.0f, 210.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Re-add actor back to stage, render and notify
+  application.GetScene().Add(actor);
+  application.SendNotification();
+  application.Render();
+
+  // Emit another started event
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Completely delete the actor
+  actor.Reset();
+
+  // Emit event, should not crash and should not receive an event.
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(210.0f, 210.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliGeoHoverActorSignalNotConsumed(void)
+{
+  TestApplication application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data, false);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliGeoHoverActorUnStaged(void)
+{
+  TestApplication application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Emit a started signal
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Remove actor from stage
+  application.GetScene().Remove(actor);
+
+  // Interrupted is received because the actor receiving the event removed.
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit a move at the same point, we should not be signalled.
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliGeoHoverLeaveActorReadded(void)
+{
+  TestApplication    application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+  Integration::Scene stage = application.GetScene();
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  stage.Add(actor);
+
+  // Set actor to receive hover-events
+  actor.SetProperty(Actor::Property::LEAVE_REQUIRED, true);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Emit a started and motion
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(11.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Remove actor from stage and add again
+  stage.Remove(actor);
+  stage.Add(actor);
+
+  // Emit a motion within the actor's bounds
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(12.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Emit a motion outside the actor's bounds
+  application.ProcessEvent(GenerateSingleHover(PointState::MOTION, Vector2(200.0f, 200.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::LEAVE, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliGeoHoverClippingActor(void)
+{
+  TestApplication    application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+  Integration::Scene stage = application.GetScene();
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  stage.Add(actor);
+
+  Actor clippingActor = Actor::New();
+  clippingActor.SetProperty(Actor::Property::SIZE, Vector2(50.0f, 50.0f));
+  clippingActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  clippingActor.SetProperty(Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN);
+  stage.Add(clippingActor);
+
+  // Add a child to the clipped region.
+  Actor clippingChild = Actor::New();
+  clippingChild.SetProperty(Actor::Property::SIZE, Vector2(50.0f, 50.0f));
+  clippingChild.SetProperty(Actor::Property::POSITION, Vector2(25.0f, 25.0f));
+  clippingChild.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  clippingActor.Add(clippingChild);
+
+  // Render and notify.
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal.
+  SignalData        data;
+  HoverEventFunctor functor(data);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Emit an event within clipped area - we should have a hit.
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Emit an event outside the clipped area but within the actor area, we should have a hit.
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(60.0f, 60.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  clippingChild.HoveredSignal().Connect(&application, functor);
+
+  // Emit an event inside part of the child which is within the clipped area, we should have a hit.
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(30.0f, 30.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliGeoHoverActorHide(void)
+{
+  TestApplication    application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+  Integration::Scene stage = application.GetScene();
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  stage.Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's hovered signal
+  SignalData        data;
+  HoverEventFunctor functor(data);
+  actor.HoveredSignal().Connect(&application, functor);
+
+  // Emit a started
+  application.ProcessEvent(GenerateSingleHover(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  actor.SetProperty(Actor::Property::VISIBLE, false);
+
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  // Interrupted is received because the actor receiving the event hides.
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.hoverEvent.GetState(0), TEST_LOCATION);
+  data.Reset();
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali/utc-Dali-GeoTouchProcessing.cpp b/automated-tests/src/dali/utc-Dali-GeoTouchProcessing.cpp
new file mode 100644 (file)
index 0000000..51f22e8
--- /dev/null
@@ -0,0 +1,2378 @@
+/*
+ * Copyright (c) 2023 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 <dali-test-suite-utils.h>
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/touch-integ.h>
+#include <dali/integration-api/render-task-list-integ.h>
+#include <dali/public-api/dali-core.h>
+#include <stdlib.h>
+
+#include <iostream>
+
+using namespace Dali;
+
+void utc_dali_geo_touch_processing_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_geo_touch_processing_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+struct TestPoint
+{
+  int32_t                deviceId{-1};
+  PointState::Type       state{PointState::FINISHED};
+  Actor                  hitActor;
+  Vector2                local;
+  Vector2                screen;
+  float                  radius{0};
+  Vector2                ellipseRadius;
+  float                  pressure{0};
+  Degree                 angle;
+  Device::Class::Type    deviceClass{Device::Class::NONE};
+  Device::Subclass::Type deviceSubclass{Device::Subclass::NONE};
+
+  TestPoint() = default;
+  static const TestPoint ZERO;
+};
+
+const TestPoint TestPoint::ZERO;
+
+// Stores data that is populated in the callback and will be read by the TET cases
+struct SignalData
+{
+  SignalData()
+  : functorCalled(false),
+    receivedTouch(),
+    touchedActor()
+  {
+  }
+
+  struct TestTouchEvent
+  {
+    unsigned long          time;
+    std::vector<TestPoint> points;
+
+    const TestPoint& GetPoint(size_t i)
+    {
+      if(i < points.size())
+      {
+        return points[i];
+      }
+      return TestPoint::ZERO;
+    }
+    size_t GetPointCount()
+    {
+      return points.size();
+    }
+  };
+
+  void Reset()
+  {
+    functorCalled = false;
+
+    receivedTouch.time = 0u;
+    receivedTouch.points.clear();
+
+    touchedActor.Reset();
+  }
+
+  bool           functorCalled;
+  TestTouchEvent receivedTouch;
+  Actor          touchedActor;
+};
+
+// Functor that sets the data when called
+struct TouchEventFunctor
+{
+  /**
+   * Constructor.
+   * @param[in]  data         Reference to the data to store callback information.
+   * @param[in]  returnValue  What the functor should return.
+   */
+  TouchEventFunctor(SignalData& data, bool returnValue = true)
+  : signalData(data),
+    returnValue(returnValue)
+  {
+  }
+
+  bool operator()(Actor actor, const TouchEvent& touch)
+  {
+    signalData.functorCalled = true;
+    signalData.touchedActor  = actor;
+
+    signalData.receivedTouch.time = touch.GetTime();
+    signalData.receivedTouch.points.clear();
+
+    for(size_t i = 0; i < touch.GetPointCount(); ++i)
+    {
+      TestPoint p;
+      p.deviceId       = touch.GetDeviceId(i);
+      p.state          = touch.GetState(i);
+      p.hitActor       = touch.GetHitActor(i);
+      p.local          = touch.GetLocalPosition(i);
+      p.screen         = touch.GetScreenPosition(i);
+      p.radius         = touch.GetRadius(i);
+      p.ellipseRadius  = touch.GetEllipseRadius(i);
+      p.pressure       = touch.GetPressure(i);
+      p.angle          = touch.GetAngle(i);
+      p.deviceClass    = touch.GetDeviceClass(i);
+      p.deviceSubclass = touch.GetDeviceSubclass(i);
+      signalData.receivedTouch.points.push_back(p);
+    }
+
+    return returnValue;
+  }
+
+  SignalData& signalData;
+  bool        returnValue;
+};
+
+struct HandleData
+{
+  bool       signalReceived;
+  TouchEvent receivedTouchHandle;
+
+  HandleData()
+  : signalReceived(false)
+  {
+  }
+};
+
+struct TouchEventHandleFunctor
+{
+  /**
+   * Constructor.
+   * @param[in]  data         Reference to the data to store callback information.
+   * @param[in]  returnValue  What the functor should return.
+   */
+  TouchEventHandleFunctor(HandleData& handleData, bool returnValue = true)
+  : handleData(handleData),
+    returnValue(returnValue)
+  {
+  }
+
+  bool operator()(Actor actor, const TouchEvent& someTouchEvent)
+  {
+    handleData.signalReceived      = true;
+    handleData.receivedTouchHandle = someTouchEvent;
+    return returnValue;
+  }
+
+  HandleData& handleData;
+  bool        returnValue;
+};
+
+// Functor that removes the actor when called.
+struct RemoveActorFunctor : public TouchEventFunctor
+{
+  /**
+   * Constructor.
+   * @param[in]  data         Reference to the data to store callback information.
+   * @param[in]  returnValue  What the functor should return.
+   */
+  RemoveActorFunctor(SignalData& data, bool returnValue = true)
+  : TouchEventFunctor(data, returnValue)
+  {
+  }
+
+  bool operator()(Actor actor, const TouchEvent& touch)
+  {
+    Actor parent(actor.GetParent());
+    if(parent)
+    {
+      parent.Remove(actor);
+    }
+
+    return TouchEventFunctor::operator()(actor, touch);
+  }
+};
+
+struct OutOfBoundsData
+{
+  TestPoint point;
+  bool      functorCalled;
+
+  OutOfBoundsData()
+  : functorCalled(false)
+  {
+  }
+};
+
+// Functor that reads out of bounds data when called
+struct OutOfBoundsFunctor
+{
+  /**
+   * Constructor.
+   * @param[in]  data         Reference to the data to store callback information.
+   * @param[in]  returnValue  What the functor should return.
+   */
+  OutOfBoundsFunctor(OutOfBoundsData& data, bool returnValue = true)
+  : outOfBoundsData(data),
+    returnValue(returnValue)
+  {
+  }
+
+  bool operator()(Actor actor, const TouchEvent& touch)
+  {
+    outOfBoundsData.functorCalled = true;
+    size_t count                  = touch.GetPointCount();
+
+    // Read out of bounds data
+    outOfBoundsData.point.deviceId = touch.GetDeviceId(count + 1);
+    outOfBoundsData.point.state    = touch.GetState(count + 1);
+    outOfBoundsData.point.hitActor = touch.GetHitActor(count + 1);
+    outOfBoundsData.point.local    = touch.GetLocalPosition(count + 1);
+    outOfBoundsData.point.screen   = touch.GetScreenPosition(count + 1);
+
+    return returnValue;
+  }
+
+  OutOfBoundsData& outOfBoundsData;
+  bool             returnValue;
+};
+
+Integration::TouchEvent GenerateSingleTouch(PointState::Type state, const Vector2& screenPosition)
+{
+  Integration::TouchEvent touchEvent;
+  Integration::Point      point;
+  point.SetState(state);
+  point.SetScreenPosition(screenPosition);
+  point.SetDeviceClass(Device::Class::TOUCH);
+  point.SetDeviceSubclass(Device::Subclass::NONE);
+  touchEvent.points.push_back(point);
+  return touchEvent;
+}
+
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+
+int UtcDaliGeoTouchEventNormalProcessing01(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touch signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  Vector2 screenCoordinates(10.0f, 10.0f);
+  Vector2 localCoordinates;
+  actor.ScreenToLocal(localCoordinates.x, localCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, screenCoordinates));
+  const TestPoint* point1 = &data.receivedTouch.GetPoint(0);
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, data.receivedTouch.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, point1->state, TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, point1->screen, TEST_LOCATION);
+  DALI_TEST_EQUALS(localCoordinates, point1->local, 0.1f, TEST_LOCATION);
+  data.Reset();
+
+  // Emit a motion signal
+  screenCoordinates.x = screenCoordinates.y = 11.0f;
+  actor.ScreenToLocal(localCoordinates.x, localCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, screenCoordinates));
+  const TestPoint* point2 = &data.receivedTouch.GetPoint(0);
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, data.receivedTouch.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::MOTION, point2->state, TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, point2->screen, TEST_LOCATION);
+  DALI_TEST_EQUALS(localCoordinates, point2->local, 0.1f, TEST_LOCATION);
+  data.Reset();
+
+  // Emit an up signal
+  screenCoordinates.x = screenCoordinates.y = 12.0f;
+  actor.ScreenToLocal(localCoordinates.x, localCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, screenCoordinates));
+  const TestPoint* point3 = &data.receivedTouch.GetPoint(0);
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, data.receivedTouch.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::UP, point3->state, TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, point3->screen, TEST_LOCATION);
+  DALI_TEST_EQUALS(localCoordinates, point3->local, 0.1f, TEST_LOCATION);
+  data.Reset();
+
+  // Emit a down signal where the actor is not present
+  screenCoordinates.x = screenCoordinates.y = 200.0f;
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, screenCoordinates));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventNormalProcessing02(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  HandleData              handleData;
+  TouchEventHandleFunctor functor(handleData);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  Vector2 screenCoordinates(10.0f, 10.0f);
+  Vector2 localCoordinates;
+  actor.ScreenToLocal(localCoordinates.x, localCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, screenCoordinates));
+  DALI_TEST_EQUALS(true, handleData.signalReceived, TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, handleData.receivedTouchHandle.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, handleData.receivedTouchHandle.GetState(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, handleData.receivedTouchHandle.GetScreenPosition(0), TEST_LOCATION);
+  DALI_TEST_EQUALS(localCoordinates, handleData.receivedTouchHandle.GetLocalPosition(0), 0.1f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventAPINegative(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  OutOfBoundsData    data;
+  OutOfBoundsFunctor functor(data, true);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  Vector2 screenCoordinates(10.0f, 10.0f);
+  Vector2 localCoordinates;
+  actor.ScreenToLocal(localCoordinates.x, localCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, screenCoordinates));
+
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(-1, data.point.deviceId, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::FINISHED, data.point.state, TEST_LOCATION);
+  DALI_TEST_EQUALS(Vector2::ZERO, data.point.screen, TEST_LOCATION);
+  DALI_TEST_EQUALS(Vector2::ZERO, data.point.local, 0.1f, TEST_LOCATION);
+  DALI_TEST_CHECK(!data.point.hitActor);
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventOutsideCameraNearFarPlanes(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Integration::Scene scene     = application.GetScene();
+  Vector2            sceneSize = scene.GetSize();
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  scene.Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Get the camera's near and far planes
+  RenderTaskList   taskList  = scene.GetRenderTaskList();
+  Dali::RenderTask task      = taskList.GetTask(0);
+  CameraActor      camera    = task.GetCameraActor();
+  float            nearPlane = camera.GetNearClippingPlane();
+  float            farPlane  = camera.GetFarClippingPlane();
+
+  // Calculate the current distance of the actor from the camera
+  float tanHalfFov = tanf(camera.GetFieldOfView() * 0.5f);
+  float distance   = (sceneSize.y * 0.5f) / tanHalfFov;
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  Vector2 screenCoordinates(sceneSize.x * 0.5f, sceneSize.y * 0.5f);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, screenCoordinates));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, screenCoordinates));
+  data.Reset();
+
+  // Emit a down signal where actor is just at the camera's near plane
+  actor.SetProperty(Actor::Property::POSITION_Z, distance - nearPlane);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, screenCoordinates));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, screenCoordinates));
+  data.Reset();
+
+  // Emit a down signal where actor is closer than the camera's near plane
+  actor.SetProperty(Actor::Property::POSITION_Z, (distance - nearPlane) + 1.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, screenCoordinates));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, screenCoordinates));
+  data.Reset();
+
+  // Emit a down signal where actor is just at the camera's far plane
+  actor.SetProperty(Actor::Property::POSITION_Z, distance - farPlane);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, screenCoordinates));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, screenCoordinates));
+  data.Reset();
+
+  // Emit a down signal where actor is further than the camera's far plane
+  actor.SetProperty(Actor::Property::POSITION_Z, (distance - farPlane) - 1.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, screenCoordinates));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, screenCoordinates));
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventEmitEmpty(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  try
+  {
+    // Emit an empty TouchEvent
+    Integration::TouchEvent event;
+    application.ProcessEvent(event);
+    tet_result(TET_FAIL);
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "!event.points.empty()", TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventInterrupted(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  data.Reset();
+
+  // Emit an interrupted signal, we should be signalled regardless of whether there is a hit or not.
+  application.ProcessEvent(GenerateSingleTouch(PointState::INTERRUPTED, Vector2(200.0f, 200.0f /* Outside actor */)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.receivedTouch.points[0].state, TEST_LOCATION);
+  data.Reset();
+
+  // Emit another interrupted signal, our signal handler should not be called.
+  application.ProcessEvent(GenerateSingleTouch(PointState::INTERRUPTED, Vector2(200.0f, 200.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventParentConsumer(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Actor           rootActor(application.GetScene().GetRootLayer());
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data, false);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Connect to root actor's touched signal
+  SignalData        rootData;
+  TouchEventFunctor rootFunctor(rootData); // Consumes signal
+  rootActor.TouchedSignal().Connect(&application, rootFunctor);
+
+  Vector2 screenCoordinates(10.0f, 10.0f);
+  Vector2 actorCoordinates, rootCoordinates;
+  actor.ScreenToLocal(actorCoordinates.x, actorCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+  rootActor.ScreenToLocal(rootCoordinates.x, rootCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, screenCoordinates));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, data.receivedTouch.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, rootData.receivedTouch.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, rootData.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, data.receivedTouch.points[0].screen, TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, rootData.receivedTouch.points[0].screen, TEST_LOCATION);
+  DALI_TEST_EQUALS(actorCoordinates, data.receivedTouch.points[0].local, 0.1f, TEST_LOCATION);
+  DALI_TEST_EQUALS(rootCoordinates, rootData.receivedTouch.points[0].local, 0.1f, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.receivedTouch.points[0].hitActor);
+  DALI_TEST_CHECK(actor == rootData.receivedTouch.points[0].hitActor);
+  data.Reset();
+  rootData.Reset();
+
+  // Emit a motion signal
+  screenCoordinates.x = screenCoordinates.y = 11.0f;
+  actor.ScreenToLocal(actorCoordinates.x, actorCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+  rootActor.ScreenToLocal(rootCoordinates.x, rootCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, screenCoordinates));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, rootData.receivedTouch.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::MOTION, rootData.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, rootData.receivedTouch.points[0].screen, TEST_LOCATION);
+  DALI_TEST_EQUALS(rootCoordinates, rootData.receivedTouch.points[0].local, 0.1f, TEST_LOCATION);
+  DALI_TEST_CHECK(rootActor == rootData.receivedTouch.points[0].hitActor);
+  data.Reset();
+  rootData.Reset();
+
+  // Emit an up signal
+  screenCoordinates.x = screenCoordinates.y = 12.0f;
+  actor.ScreenToLocal(actorCoordinates.x, actorCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+  rootActor.ScreenToLocal(rootCoordinates.x, rootCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, screenCoordinates));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, rootData.receivedTouch.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::UP, rootData.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, rootData.receivedTouch.points[0].screen, TEST_LOCATION);
+  DALI_TEST_EQUALS(rootCoordinates, rootData.receivedTouch.points[0].local, 0.1f, TEST_LOCATION);
+  DALI_TEST_CHECK(rootActor == rootData.receivedTouch.points[0].hitActor);
+  data.Reset();
+  rootData.Reset();
+
+  // Emit a down signal where the actor is not present, will hit the root actor though
+  screenCoordinates.x = screenCoordinates.y = 200.0f;
+  rootActor.ScreenToLocal(rootCoordinates.x, rootCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, screenCoordinates));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(1u, rootData.receivedTouch.GetPointCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, rootData.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_EQUALS(screenCoordinates, rootData.receivedTouch.points[0].screen, TEST_LOCATION);
+  DALI_TEST_EQUALS(rootCoordinates, rootData.receivedTouch.points[0].local, 0.1f, TEST_LOCATION);
+  DALI_TEST_CHECK(rootActor == rootData.receivedTouch.points[0].hitActor);
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventInterruptedParentConsumer(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Actor           rootActor(application.GetScene().GetRootLayer());
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data, false);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Connect to root actor's touched signal
+  SignalData        rootData;
+  TouchEventFunctor rootFunctor(rootData); // Consumes signal
+  rootActor.TouchedSignal().Connect(&application, rootFunctor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, rootData.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.receivedTouch.points[0].hitActor);
+  DALI_TEST_CHECK(actor == rootData.receivedTouch.points[0].hitActor);
+  data.Reset();
+  rootData.Reset();
+
+  // Emit an interrupted signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::INTERRUPTED, Vector2(200.0f, 200.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, rootData.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(rootActor == rootData.receivedTouch.points[0].hitActor);
+  data.Reset();
+  rootData.Reset();
+
+  // Emit another down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, rootData.receivedTouch.points[0].state, TEST_LOCATION);
+  data.Reset();
+  rootData.Reset();
+
+  // Remove actor from scene
+  application.GetScene().Remove(actor);
+  data.Reset();
+  rootData.Reset();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit an interrupted signal, only root actor's signal should be called.
+  application.ProcessEvent(GenerateSingleTouch(PointState::INTERRUPTED, Vector2(200.0f, 200.0f /* Outside actor */)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, rootData.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(rootActor == rootData.receivedTouch.points[0].hitActor);
+  data.Reset();
+  rootData.Reset();
+
+  // Emit another interrupted state, none of the signal's should be called.
+  application.ProcessEvent(GenerateSingleTouch(PointState::INTERRUPTED, Vector2(200.0f, 200.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(false, rootData.functorCalled, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventActorBecomesInsensitive(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  data.Reset();
+
+  // Change actor to insensitive
+  actor.SetProperty(Actor::Property::SENSITIVE, false);
+
+  // Emit a motion signal, signalled with an interrupted
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(200.0f, 200.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.receivedTouch.points[0].state, TEST_LOCATION);
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventActorBecomesInsensitiveParentConsumer(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Actor           rootActor(application.GetScene().GetRootLayer());
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data, false);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Connect to root actor's touched signal
+  SignalData        rootData;
+  TouchEventFunctor rootFunctor(rootData); // Consumes signal
+  rootActor.TouchedSignal().Connect(&application, rootFunctor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, rootData.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.receivedTouch.points[0].hitActor);
+  DALI_TEST_CHECK(actor == rootData.receivedTouch.points[0].hitActor);
+  data.Reset();
+  rootData.Reset();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Make root actor insensitive
+  rootActor.SetProperty(Actor::Property::SENSITIVE, false);
+
+  // Emit a motion signal, signalled with an interrupted (should get interrupted even if within root actor)
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(200.0f, 200.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, rootData.receivedTouch.points[0].state, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventActorBecomesUserInteractionDisabled(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  data.Reset();
+
+  // Change actor to disable user interaction.
+  actor.SetProperty(DevelActor::Property::USER_INTERACTION_ENABLED, false);
+
+  // Emit a motion signal, signalled with an interrupted
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(200.0f, 200.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.receivedTouch.points[0].state, TEST_LOCATION);
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventMultipleLayers(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Actor           rootActor(application.GetScene().GetRootLayer());
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+
+  Layer layer1(Layer::New());
+  layer1.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  layer1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  application.GetScene().Add(layer1);
+
+  Actor actor1(Actor::New());
+  actor1.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor1.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  actor1.SetProperty(Actor::Property::POSITION_Z, 1.0f); // Should hit actor1 in this layer
+  layer1.Add(actor1);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to layer1 and actor1
+  layer1.TouchedSignal().Connect(&application, functor);
+  actor1.TouchedSignal().Connect(&application, functor);
+
+  // Hit in hittable area, actor1 should be hit
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_CHECK(data.touchedActor == actor1);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  data.Reset();
+
+  // Make layer1 insensitive, nothing should be hit
+  layer1.SetProperty(Actor::Property::SENSITIVE, false);
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  data.Reset();
+
+  // Make layer1 sensitive again, again actor1 will be hit
+  layer1.SetProperty(Actor::Property::SENSITIVE, true);
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_CHECK(data.touchedActor == actor1);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  data.Reset();
+
+  // Make rootActor insensitive, nothing should be hit
+  rootActor.SetProperty(Actor::Property::SENSITIVE, false);
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  data.Reset();
+
+  // Make rootActor sensitive
+  rootActor.SetProperty(Actor::Property::SENSITIVE, true);
+
+  // Add another layer
+  Layer layer2(Layer::New());
+  layer2.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  layer2.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  layer2.SetProperty(Actor::Property::POSITION_Z, 10.0f); // Should hit layer2 in this layer rather than actor2
+  application.GetScene().Add(layer2);
+
+  Actor actor2(Actor::New());
+  actor2.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor2.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  layer2.Add(actor2);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to layer2 and actor2
+  layer2.TouchedSignal().Connect(&application, functor);
+  actor2.TouchedSignal().Connect(&application, functor);
+
+  // Emit an event, should hit layer2
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  //DALI_TEST_CHECK( data.touchedActor == layer2 ); // TODO: Uncomment this after removing renderable hack!
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  data.Reset();
+
+  // Make layer2 insensitive, should hit actor1
+  layer2.SetProperty(Actor::Property::SENSITIVE, false);
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_CHECK(data.touchedActor == actor1);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  data.Reset();
+
+  // Make layer2 sensitive again, should hit layer2
+  layer2.SetProperty(Actor::Property::SENSITIVE, true);
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  //DALI_TEST_CHECK( data.touchedActor == layer2 ); // TODO: Uncomment this after removing renderable hack!
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  data.Reset();
+
+  // Make layer2 invisible, render and notify
+  layer2.SetProperty(Actor::Property::VISIBLE, false);
+  application.SendNotification();
+  application.Render();
+
+  // Should hit actor1
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_CHECK(data.touchedActor == actor1);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  data.Reset();
+
+  // Make rootActor invisible, render and notify
+  rootActor.SetProperty(Actor::Property::VISIBLE, false);
+  application.SendNotification();
+  application.Render();
+
+  // Should not hit anything
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventMultipleRenderTasks(void)
+{
+  TestApplication    application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+
+  Integration::Scene scene(application.GetScene());
+  Vector2            sceneSize(scene.GetSize());
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  scene.Add(actor);
+
+  // Create render task
+  Viewport   viewport(sceneSize.width * 0.5f, sceneSize.height * 0.5f, sceneSize.width * 0.5f, sceneSize.height * 0.5f);
+  RenderTask renderTask(application.GetScene().GetRenderTaskList().CreateTask());
+  renderTask.SetViewport(viewport);
+  renderTask.SetInputEnabled(true);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  data.Reset();
+
+  // Ensure renderTask actor can be hit too.
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(viewport.x + 5.0f, viewport.y + 5.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  data.Reset();
+
+  // Disable input on renderTask, should not be hittable
+  renderTask.SetInputEnabled(false);
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(viewport.x + 5.0f, viewport.y + 5.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventMultipleRenderTasksWithChildLayer(void)
+{
+  TestApplication    application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Integration::Scene scene(application.GetScene());
+  Vector2            sceneSize(scene.GetSize());
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  scene.Add(actor);
+
+  Layer layer = Layer::New();
+  layer.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  layer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  actor.Add(layer);
+
+  // Create render task
+  Viewport   viewport(sceneSize.width * 0.5f, sceneSize.height * 0.5f, sceneSize.width * 0.5f, sceneSize.height * 0.5f);
+  RenderTask renderTask(application.GetScene().GetRenderTaskList().CreateTask());
+  renderTask.SetViewport(viewport);
+  renderTask.SetInputEnabled(true);
+  renderTask.SetSourceActor(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to layer's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+  layer.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  data.Reset();
+
+  // Ensure renderTask actor can be hit too.
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(viewport.x + 5.0f, viewport.y + 5.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  data.Reset();
+
+  // Disable input on renderTask, should not be hittable
+  renderTask.SetInputEnabled(false);
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(viewport.x + 5.0f, viewport.y + 5.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventOffscreenRenderTasks(void)
+{
+  TestApplication    application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Integration::Scene scene(application.GetScene());
+  Vector2            sceneSize(scene.GetSize());
+
+  // FrameBufferImage for offscreen RenderTask
+  FrameBuffer frameBuffer = FrameBuffer::New(sceneSize.width, sceneSize.height);
+
+  // Create a renderable actor to display the FrameBufferImage
+  Actor renderableActor = CreateRenderableActor(frameBuffer.GetColorTexture());
+  renderableActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  renderableActor.SetProperty(Actor::Property::SIZE, Vector2(sceneSize.x, sceneSize.y));
+  renderableActor.ScaleBy(Vector3(1.0f, -1.0f, 1.0f)); // FIXME
+  scene.Add(renderableActor);
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  scene.Add(actor);
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE); // Ensure framebuffer connects
+
+  scene.GetRenderTaskList().GetTask(0u).SetScreenToFrameBufferFunction(RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION);
+
+  // Create a RenderTask
+  RenderTask renderTask = scene.GetRenderTaskList().CreateTask();
+  renderTask.SetSourceActor(actor);
+  renderTask.SetFrameBuffer(frameBuffer);
+  renderTask.SetInputEnabled(true);
+
+  // Create another RenderTask
+  RenderTask renderTask2(scene.GetRenderTaskList().CreateTask());
+  renderTask2.SetInputEnabled(true);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventMultipleRenderableActors(void)
+{
+  TestApplication    application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Integration::Scene scene(application.GetScene());
+  Vector2            sceneSize(scene.GetSize());
+
+  Actor parent = CreateRenderableActor();
+  parent.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  parent.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  scene.Add(parent);
+
+  Actor actor = CreateRenderableActor();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  parent.Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to layer's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  parent.TouchedSignal().Connect(&application, functor);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.touchedActor);
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventActorRemovedInSignal(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData         data;
+  RemoveActorFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Register for leave events
+  actor.SetProperty(Actor::Property::LEAVE_REQUIRED, true);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Re-add, render and notify
+  application.GetScene().Add(actor);
+  application.SendNotification();
+  application.Render();
+
+  // Emit another signal outside of actor's area, should not get anything as the scene has changed.
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(210.0f, 210.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit another signal outside of actor's area, should not get anything as the scene has changed.
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(210.0f, 210.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Re-add actor back to scene, render and notify
+  application.GetScene().Add(actor);
+  application.SendNotification();
+  application.Render();
+
+  // Emit another down event
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Completely delete the actor
+  actor.Reset();
+
+  // Emit event, should not crash and should not receive an event.
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(210.0f, 210.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventActorSignalNotConsumed(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data, false);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventActorRemovedFromScene(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Remove actor from scene
+  application.GetScene().Remove(actor);
+  data.Reset();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit a move at the same point, we should not be signalled.
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventLayerConsumesTouch(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Add a layer to overlap the actor
+  Layer layer = Layer::New();
+  layer.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  layer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  application.GetScene().Add(layer);
+  layer.RaiseToTop();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit a few touch signals
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Set layer to consume all touch
+  layer.SetProperty(Layer::Property::CONSUMES_TOUCH, true);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit the same signals again, should not receive
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventClippedActor(void)
+{
+  TestApplication    application;
+  Integration::Scene scene = application.GetScene();
+
+  scene.SetGeometryHittestEnabled(true);
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  scene.Add(actor);
+
+  Actor clippingActor = Actor::New();
+  clippingActor.SetProperty(Actor::Property::SIZE, Vector2(50.0f, 50.0f));
+  clippingActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  clippingActor.SetProperty(Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN);
+  scene.Add(clippingActor);
+
+  // Add a child to the clipped region.
+  Actor clippingChild = Actor::New();
+  clippingChild.SetProperty(Actor::Property::SIZE, Vector2(50.0f, 50.0f));
+  clippingChild.SetProperty(Actor::Property::POSITION, Vector2(25.0f, 25.0f));
+  clippingChild.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  clippingActor.Add(clippingChild);
+
+  // Render and notify.
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touch signal.
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit an event within clipped area - we should have a hit.
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(10.0f, 10.0f)));
+  data.Reset();
+
+  // Emit an event within clipped child area - we should still have a hit.
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(40.0f, 40.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(40.0f, 40.0f)));
+  data.Reset();
+
+  // Now connect to the clippingChild's touch signal
+  SignalData        clippingChildData;
+  TouchEventFunctor clippingChildFunctor(clippingChildData);
+  clippingChild.TouchedSignal().Connect(&application, clippingChildFunctor);
+
+  // Emit an event within clipped child area - no hit on actor, but hit on clipped child.
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(40.0f, 40.0f)));
+  DALI_TEST_EQUALS(true, clippingChildData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(40.0f, 40.0f)));
+  data.Reset();
+  clippingChildData.Reset();
+
+  // Emit an event outside the clipped area but within the actor area, we should have a hit.
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(60.0f, 60.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(60.0f, 60.0f)));
+  data.Reset();
+  clippingChildData.Reset();
+
+  // Emit an event inside part of the child which is within the clipped area, we should have a hit on the clipped child but not the actor.
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(30.0f, 30.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, clippingChildData.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(30.0f, 30.0f)));
+  data.Reset();
+  clippingChildData.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventActorUnparented(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.receivedTouch.points[0].hitActor);
+  data.Reset();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Unparent the actor
+  actor.Unparent();
+
+  // Should receive an interrupted event
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.receivedTouch.points[0].state, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventParentRemovedFromScene(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Actor parent = Actor::New();
+  parent.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  parent.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  application.GetScene().Add(parent);
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  parent.Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.receivedTouch.points[0].hitActor);
+  data.Reset();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Unparent the parent of the touchable actor
+  parent.Unparent();
+
+  // Should receive an interrupted event
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.receivedTouch.points[0].state, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventActorRemovedFromSceneDifferentConsumer(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Actor parent = Actor::New();
+  parent.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  parent.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  application.GetScene().Add(parent);
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  parent.Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data, false /* Do not consume */);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Connect to parent's touched signal
+  SignalData        parentData;
+  TouchEventFunctor parentFunctor(parentData);
+  parent.TouchedSignal().Connect(&application, parentFunctor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.receivedTouch.points[0].hitActor);
+  DALI_TEST_CHECK(actor == data.touchedActor);
+  DALI_TEST_EQUALS(true, parentData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, parentData.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == parentData.receivedTouch.points[0].hitActor);
+  DALI_TEST_CHECK(parent == parentData.touchedActor);
+  data.Reset();
+  parentData.Reset();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Unparent the actor
+  actor.Unparent();
+
+  // Should receive an interrupted event for both actor & parent
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(false, parentData.functorCalled, TEST_LOCATION);
+  data.Reset();
+  parentData.Reset();
+
+  // Readd actor to parent
+  parent.Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit a motion signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, parentData.functorCalled, TEST_LOCATION);
+  data.Reset();
+  parentData.Reset();
+
+  // Parent is now consumer, connect again to the touched signal of the actor so that it becomes the consumer
+  SignalData        secondData;
+  TouchEventFunctor secondFunctor(secondData /* Consume */);
+  actor.TouchedSignal().Connect(&application, secondFunctor);
+
+  // Unparent the actor
+  actor.Unparent();
+
+  // Should receive an interrupted event for both actor functors & the parent as well as it was last consumer
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(false, parentData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(false, secondData.functorCalled, TEST_LOCATION);
+  data.Reset();
+  parentData.Reset();
+  secondData.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventInterruptedDifferentConsumer(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Actor           rootActor(application.GetScene().GetRootLayer());
+
+  Actor parent = Actor::New();
+  parent.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  parent.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  application.GetScene().Add(parent);
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  parent.Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data, false /* Do not consume */);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Connect to parent's touched signal
+  SignalData        parentData;
+  TouchEventFunctor parentFunctor(parentData, false /* Do not consume */);
+  parent.TouchedSignal().Connect(&application, parentFunctor);
+
+  // Connect to root's touched signal and consume
+  SignalData        rootData;
+  TouchEventFunctor rootFunctor(rootData);
+  rootActor.TouchedSignal().Connect(&application, rootFunctor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.receivedTouch.points[0].hitActor);
+  DALI_TEST_CHECK(actor == data.touchedActor);
+  DALI_TEST_EQUALS(true, parentData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, parentData.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == parentData.receivedTouch.points[0].hitActor);
+  DALI_TEST_CHECK(parent == parentData.touchedActor);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, rootData.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == rootData.receivedTouch.points[0].hitActor);
+  DALI_TEST_CHECK(rootActor == rootData.touchedActor);
+  data.Reset();
+  parentData.Reset();
+  rootData.Reset();
+
+  // Root is now consumer, connect to the touched signal of the parent so that it becomes the consumer
+  SignalData        secondData;
+  TouchEventFunctor secondFunctor(secondData /* Consume */);
+  parent.TouchedSignal().Connect(&application, secondFunctor);
+
+  // Emit an interrupted signal, Since rootActor has already comsume, only rootActor gets INTERRUPTED.
+  application.ProcessEvent(GenerateSingleTouch(PointState::INTERRUPTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(false, parentData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, rootData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, rootData.receivedTouch.points[0].state, TEST_LOCATION);
+  data.Reset();
+  parentData.Reset();
+  rootData.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventGetRadius(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal with an angle
+  Integration::TouchEvent touchEvent = GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f));
+  touchEvent.points[0].SetRadius(100.0f);
+  application.ProcessEvent(touchEvent);
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_EQUALS(100.0f, data.receivedTouch.points[0].radius, TEST_LOCATION);
+  DALI_TEST_EQUALS(100.0f, data.receivedTouch.points[0].ellipseRadius.x, TEST_LOCATION);
+  DALI_TEST_EQUALS(100.0f, data.receivedTouch.points[0].ellipseRadius.y, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventGetEllipseRadius(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal with an angle
+  Integration::TouchEvent touchEvent = GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f));
+  touchEvent.points[0].SetRadius(100.0f, Vector2(20.0f, 10.0f));
+  application.ProcessEvent(touchEvent);
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_EQUALS(100.0f, data.receivedTouch.points[0].radius, TEST_LOCATION);
+  DALI_TEST_EQUALS(20.0f, data.receivedTouch.points[0].ellipseRadius.x, TEST_LOCATION);
+  DALI_TEST_EQUALS(10.0f, data.receivedTouch.points[0].ellipseRadius.y, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventGetAngle(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal with an angle
+  Integration::TouchEvent touchEvent = GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f));
+  touchEvent.points[0].SetAngle(Degree(90.0f));
+  application.ProcessEvent(touchEvent);
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_EQUALS(Degree(90.0f), data.receivedTouch.points[0].angle, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventGetPressure(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal with an angle
+  Integration::TouchEvent touchEvent = GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f));
+  touchEvent.points[0].SetPressure(10.0f);
+  application.ProcessEvent(touchEvent);
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_EQUALS(10.0f, data.receivedTouch.points[0].pressure, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventUsage(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal with an angle
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventGetDeviceAPINegative(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  HandleData              handleData;
+  TouchEventHandleFunctor functor(handleData);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  Vector2 screenCoordinates(10.0f, 10.0f);
+  Vector2 localCoordinates;
+  actor.ScreenToLocal(localCoordinates.x, localCoordinates.y, screenCoordinates.x, screenCoordinates.y);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, screenCoordinates));
+
+  TouchEvent data = handleData.receivedTouchHandle;
+  DALI_TEST_EQUALS(data.GetDeviceClass(-1), Device::Class::NONE, TEST_LOCATION);
+  DALI_TEST_EQUALS(data.GetDeviceSubclass(-1), Device::Subclass::NONE, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventGetMouseButtonPositive(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  HandleData              handleData;
+  TouchEventHandleFunctor functor(handleData);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal with MouseButton
+  Integration::TouchEvent touchEvent = GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f));
+  touchEvent.points[0].SetMouseButton(static_cast<MouseButton::Type>(3));
+  application.ProcessEvent(touchEvent);
+
+  TouchEvent data = handleData.receivedTouchHandle;
+  DALI_TEST_EQUALS(data.GetMouseButton(0), MouseButton::SECONDARY, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventGetMouseButtonNagative(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  HandleData              handleData;
+  TouchEventHandleFunctor functor(handleData);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal with MouseButton
+  Integration::TouchEvent touchEvent = GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f));
+  touchEvent.points[0].SetMouseButton(static_cast<MouseButton::Type>(2));
+  application.ProcessEvent(touchEvent);
+
+  TouchEvent data = handleData.receivedTouchHandle;
+  DALI_TEST_EQUALS(data.GetMouseButton(0), MouseButton::TERTIARY, TEST_LOCATION);
+  DALI_TEST_EQUALS(data.GetMouseButton(3), MouseButton::INVALID, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventCapturePropertySet(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Now motion outside of actor, we now SHOULD receive the event
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(110.0f, 110.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Up event, we should receive it again, but as ended rather than interrupted
+  application.ProcessEvent(GenerateSingleTouch(PointState::FINISHED, Vector2(110.0f, 110.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(data.receivedTouch.GetPoint(0).state, PointState::FINISHED, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventIntegNewTouchEvent(void)
+{
+  TestApplication application;
+  application.GetScene().SetGeometryHittestEnabled(true);
+  uint32_t         timestamp = 92858u;
+  TouchPoint       tp(1, PointState::STARTED, 34.4f, 123.89f, 5.0f, 7.0f);
+  Dali::TouchEvent touchEvent = Integration::NewTouchEvent(timestamp, tp);
+
+  DALI_TEST_EQUALS(touchEvent.GetPointCount(), 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(touchEvent.GetState(0), PointState::STARTED, TEST_LOCATION);
+  DALI_TEST_EQUALS(touchEvent.GetLocalPosition(0), Vector2(5.0f, 7.0f), TEST_LOCATION);
+  DALI_TEST_EQUALS(touchEvent.GetScreenPosition(0), Vector2(34.4f, 123.89f), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventIntercept01(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's intercept touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data, false /* Do not consume */);
+  Dali::DevelActor::InterceptTouchedSignal(actor).Connect(&application, functor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+
+  // It should be able to receive touch events by registering only InterceptTouchEvent.
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.receivedTouch.points[0].hitActor);
+  DALI_TEST_CHECK(actor == data.touchedActor);
+  data.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventIntercept02(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  Actor parent = Actor::New();
+  parent.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  parent.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  application.GetScene().Add(parent);
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  parent.Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data, false /* Do not consume */);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Connect to parent's touched signal
+  SignalData        parentData;
+  TouchEventFunctor parentFunctor(parentData, false /* Do not consume */);
+  parent.TouchedSignal().Connect(&application, parentFunctor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+
+  data.Reset();
+  parentData.Reset();
+
+  // Connect to parent's intercept touched signal
+  SignalData        interceptData;
+  TouchEventFunctor interceptFunctor(interceptData, true /* Do intercept */);
+  Dali::DevelActor::InterceptTouchedSignal(parent).Connect(&application, interceptFunctor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+
+  // The actor gets interrupted. Because touch is intercepted by parent.
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::INTERRUPTED, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, interceptData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, interceptData.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == interceptData.receivedTouch.points[0].hitActor);
+  DALI_TEST_CHECK(parent == interceptData.touchedActor);
+  DALI_TEST_EQUALS(true, parentData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, parentData.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == parentData.receivedTouch.points[0].hitActor);
+  DALI_TEST_CHECK(parent == parentData.touchedActor);
+  data.Reset();
+  interceptData.Reset();
+  parentData.Reset();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit a move signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(20.0f, 20.0f)));
+
+  // Since InterceptTouchEvent is not called because it has already been intercepted by the parent, only the parent will receive the touchEvent.
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(false, interceptData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(true, parentData.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::MOTION, parentData.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == parentData.receivedTouch.points[0].hitActor);
+  DALI_TEST_CHECK(parent == parentData.touchedActor);
+  data.Reset();
+  interceptData.Reset();
+  parentData.Reset();
+
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventIntercept03(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  // Add a layer to overlap the actor
+  Layer layer = Layer::New();
+  layer.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  layer.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  application.GetScene().Add(layer);
+  layer.RaiseToTop();
+
+  // Set layer to consume all touch
+  layer.SetProperty(Layer::Property::CONSUMES_TOUCH, true);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  layer.Add(actor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Actor           rootActor(application.GetScene().GetRootLayer());
+
+  // Connect to root actor's intercept touched signal
+  SignalData        sceneData;
+  TouchEventFunctor sceneFunctor(sceneData);
+  Dali::DevelActor::InterceptTouchedSignal(rootActor).Connect(&application, sceneFunctor);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(10.0f, 10.0f)));
+
+  // Even if the layer is touch consumed, the root actor must be able to intercept touch.
+  DALI_TEST_EQUALS(true, sceneData.functorCalled, TEST_LOCATION);
+  sceneData.Reset();
+
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchAreaOffset(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data, false /* Do not consume */);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(110.0f, 110.0f)));
+  // The actor touched signal is not called because the touch area is outside actor.
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(110.0f, 110.0f)));
+  data.Reset();
+
+  // set a bigger touch area
+  actor.SetProperty(DevelActor::Property::TOUCH_AREA_OFFSET, Rect<int>(-70, 70, 70, -70)); // left, right, bottom, top
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(150.0f, 150.0f)));
+  // The actor touched signal is called because the touch area is inside touchArea.
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.receivedTouch.points[0].hitActor);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(150.0f, 150.0f)));
+  data.Reset();
+
+  // set a offset touch area
+  actor.SetProperty(DevelActor::Property::TOUCH_AREA_OFFSET, Rect<int>(50, 100, -50, 0)); // left, right, bottom, top
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(190.0f, 25.0f)));
+  // The actor touched signal is called because the touch area is inside touchArea.
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.receivedTouch.points[0].hitActor);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(190.0f, 25.0f)));
+  data.Reset();
+
+  // set a smaller touch area
+  actor.SetProperty(DevelActor::Property::TOUCH_AREA_OFFSET, Rect<int>(50, 0, 0, 50));
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(40.0f, 40.0f)));
+  // The actor touched signal is not called because the touch area is outside touchArea.
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(40.0f, 40.0f)));
+  data.Reset();
+
+  // Emit a down signal
+  application.ProcessEvent(GenerateSingleTouch(PointState::DOWN, Vector2(90.0f, 90.0f)));
+  // The actor touched signal is called because the touch area is inside touchArea.
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(PointState::DOWN, data.receivedTouch.points[0].state, TEST_LOCATION);
+  DALI_TEST_CHECK(actor == data.receivedTouch.points[0].hitActor);
+  application.ProcessEvent(GenerateSingleTouch(PointState::UP, Vector2(90.0f, 90.0f)));
+  data.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventAllowOnlyOwnTouchPropertySet(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // AllowOnlyOwnTouch is default. We don't turn this on/off.
+  // Now set the only allow own touch property
+  // actor.SetProperty(DevelActor::Property::ALLOW_ONLY_OWN_TOUCH, true);
+
+  // Emit a down signal outside of actor, we should not receive the event
+  application.ProcessEvent(GenerateSingleTouch(PointState::STARTED, Vector2(110.0f, 110.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Now motion inside of actor, we should NOT receive the event
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(80.0f, 80.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Up event, should not receive the event
+  application.ProcessEvent(GenerateSingleTouch(PointState::FINISHED, Vector2(110.0f, 110.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Emit a down signal inside of actor, we should receive the event
+  application.ProcessEvent(GenerateSingleTouch(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Now motion inside of actor, we should receive the event
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(80.0f, 80.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Now motion outsize of actor, we should receive the event
+  // CAPTURE_ALL_TOUCH_AFTER_START is now the default policy. We don't turn this on/off.
+  // So, even though it is outside the actor, it receives the event.
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(110.0f, 110.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Up event, should receive an finished
+  application.ProcessEvent(GenerateSingleTouch(PointState::FINISHED, Vector2(110.0f, 110.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(data.receivedTouch.GetPoint(0).state, PointState::FINISHED, TEST_LOCATION);
+  data.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliGeoTouchEventDispatchTouchMotionPropertySet(void)
+{
+  TestApplication application;
+
+  application.GetScene().SetGeometryHittestEnabled(true);
+
+  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);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Connect to actor's touched signal
+  SignalData        data;
+  TouchEventFunctor functor(data);
+  actor.TouchedSignal().Connect(&application, functor);
+
+  // Emit a down signal actor, we should receive the event
+  application.ProcessEvent(GenerateSingleTouch(PointState::STARTED, Vector2(10.0f, 10.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(data.receivedTouch.GetPoint(0).state, PointState::STARTED, TEST_LOCATION);
+  data.Reset();
+
+  // Emit a motion signal actor, we should receive the event
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(20.0f, 20.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(data.receivedTouch.GetPoint(0).state, PointState::MOTION, TEST_LOCATION);
+  data.Reset();
+
+  // Now set the dispatch touch motion property
+  actor.SetProperty(DevelActor::Property::DISPATCH_TOUCH_MOTION, false);
+
+  // Emit a motion signal actor, we should not receive the event
+  application.ProcessEvent(GenerateSingleTouch(PointState::MOTION, Vector2(30.0f, 30.0f)));
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+  data.Reset();
+
+  // Up event, should receive the event
+  application.ProcessEvent(GenerateSingleTouch(PointState::FINISHED, Vector2(40.0f, 40.0f)));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(data.receivedTouch.GetPoint(0).state, PointState::FINISHED, TEST_LOCATION);
+  data.Reset();
+
+  data.Reset();
+
+  END_TEST;
+}
index 98bc7b0..3e6df52 100644 (file)
@@ -2931,3 +2931,105 @@ int UtcDaliSceneEnableDisablePartialUpdate(void)
 
   END_TEST;
 }
+
+int UtcDaliSceneGeoTouchedEnabledDisabled(void)
+{
+  TestApplication          application;
+  Dali::Integration::Scene scene = application.GetScene();
+  DALI_TEST_EQUALS(scene.IsGeometryHittestEnabled(), false, TEST_LOCATION);
+
+  TouchedSignalData data;
+  TouchFunctor      functor(data);
+  scene.TouchedSignal().Connect(&application, functor);
+
+  // Render and notify.
+  application.SendNotification();
+  application.Render();
+
+  // Confirm functor not called before there has been any touch event.
+  DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+
+  // No actors, single touch, down, motion then up.
+  {
+    GenerateTouch(application, PointState::DOWN, Vector2(10.0f, 10.0f));
+
+    DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+    DALI_TEST_CHECK(data.receivedTouchEvent.GetPointCount() != 0u);
+    DALI_TEST_CHECK(!data.receivedTouchEvent.GetHitActor(0));
+
+    data.Reset();
+
+    // Confirm there is no signal when the touchpoint is only moved.
+    GenerateTouch(application, PointState::MOTION, Vector2(1200.0f, 10.0f)); // Some motion
+
+    DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+    data.Reset();
+
+    // Confirm a following up event generates a signal.
+    GenerateTouch(application, PointState::UP, Vector2(1200.0f, 10.0f));
+
+    DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+    DALI_TEST_CHECK(data.receivedTouchEvent.GetPointCount() != 0u);
+    DALI_TEST_CHECK(!data.receivedTouchEvent.GetHitActor(0));
+    data.Reset();
+  }
+
+  // Add an actor to the scene.
+  Actor actor = Actor::New();
+  actor.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f));
+  actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+  actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+  actor.TouchedSignal().Connect(&DummyTouchCallback);
+  scene.Add(actor);
+
+  // Render and notify.
+  application.SendNotification();
+  application.Render();
+
+  // Actor on scene, single touch, down in actor, motion, then up outside actor.
+  {
+    GenerateTouch(application, PointState::DOWN, Vector2(10.0f, 10.0f));
+
+    DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+    DALI_TEST_CHECK(data.receivedTouchEvent.GetPointCount() != 0u);
+    DALI_TEST_CHECK(data.receivedTouchEvent.GetHitActor(0) == actor);
+    data.Reset();
+
+    GenerateTouch(application, PointState::MOTION, Vector2(150.0f, 10.0f)); // Some motion
+
+    DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+    data.Reset();
+
+    GenerateTouch(application, PointState::UP, Vector2(150.0f, 10.0f)); // Some motion
+
+    DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+    DALI_TEST_CHECK(data.receivedTouchEvent.GetPointCount() != 0u);
+    DALI_TEST_CHECK(!data.receivedTouchEvent.GetHitActor(0));
+    data.Reset();
+  }
+
+  scene.SetGeometryHittestEnabled(true);
+  DALI_TEST_EQUALS(scene.IsGeometryHittestEnabled(), true, TEST_LOCATION);
+  {
+    GenerateTouch(application, PointState::DOWN, Vector2(10.0f, 10.0f));
+
+    DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+    DALI_TEST_CHECK(data.receivedTouchEvent.GetPointCount() != 0u);
+    DALI_TEST_CHECK(data.receivedTouchEvent.GetHitActor(0) == actor);
+    data.Reset();
+
+    GenerateTouch(application, PointState::MOTION, Vector2(150.0f, 10.0f)); // Some motion
+
+    DALI_TEST_EQUALS(false, data.functorCalled, TEST_LOCATION);
+    data.Reset();
+
+    GenerateTouch(application, PointState::UP, Vector2(150.0f, 10.0f)); // Some motion
+
+    DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+    DALI_TEST_CHECK(data.receivedTouchEvent.GetPointCount() != 0u);
+    DALI_TEST_CHECK(data.receivedTouchEvent.GetHitActor(0) == actor);
+    data.Reset();
+  }
+
+  END_TEST;
+}
index b8714de..9609a1b 100644 (file)
@@ -29,10 +29,10 @@ namespace Dali
 {
 namespace HitTestAlgorithm
 {
-bool HitTest(Stage stage, const Vector2& screenCoordinates, Results& results, HitTestFunction func)
+bool HitTest(Stage stage, const Vector2& screenCoordinates, Results& results, HitTestFunction func, bool isGeometry)
 {
   Internal::Stage& stageImpl = GetImplementation(stage);
-  return Internal::HitTestAlgorithm::HitTest(stageImpl.GetSize(), stageImpl.GetRenderTaskList(), stageImpl.GetLayerList(), screenCoordinates, results, func);
+  return Internal::HitTestAlgorithm::HitTest(stageImpl.GetSize(), stageImpl.GetRenderTaskList(), stageImpl.GetLayerList(), screenCoordinates, results, func, isGeometry);
 }
 
 bool BuildPickingRay(RenderTask renderTask, const Vector2& screenCoordinates, Vector3& origin, Vector3& direction)
index cc7aad9..6481e9e 100644 (file)
@@ -139,9 +139,10 @@ using HitTestFunction = bool (*)(Actor, TraverseType);
  * @param[in] screenCoordinates The screen coordinates.
  * @param[out] results The results of the hit-test, only modified if something is hit
  * @param[in] func The function to use in the hit-test algorithm.
+ * @param[in] isGeometry If true, hittest works in a geometry way.
  * @return true if something was hit
  */
-DALI_CORE_API bool HitTest(Stage stage, const Vector2& screenCoordinates, Results& results, HitTestFunction func);
+DALI_CORE_API bool HitTest(Stage stage, const Vector2& screenCoordinates, Results& results, HitTestFunction func, bool isGeometry = false);
 
 /**
  * @brief Given screen coordinates, this method returns the camera origin in world coordinates and the direction of the picking ray in world-space.
index 960c2a7..5bf411f 100644 (file)
@@ -228,6 +228,16 @@ bool Scene::IsPartialUpdateEnabled() const
   return GetImplementation(*this).IsPartialUpdateEnabled();
 }
 
+void Scene::SetGeometryHittestEnabled(bool enabled)
+{
+  GetImplementation(*this).SetGeometryHittestEnabled(enabled);
+}
+
+bool Scene::IsGeometryHittestEnabled()
+{
+  return GetImplementation(*this).IsGeometryHittestEnabled();
+}
+
 Scene::EventProcessingFinishedSignalType& Scene::EventProcessingFinishedSignal()
 {
   return GetImplementation(*this).EventProcessingFinishedSignal();
index e0ec85f..e0205e3 100644 (file)
@@ -416,6 +416,20 @@ public:
   bool IsPartialUpdateEnabled() const;
 
   /**
+   * @brief Sets whether the processes using geometry event propagation touch and hover events.
+   *
+   * @param[in] enabled True if the processes using geometry event propagation touch and hover events.
+   */
+  void SetGeometryHittestEnabled(bool enabled);
+
+  /**
+   * @brief Queries whether the scene using geometry event propagation touch and hover events.
+   *
+   * @return True if the scene using geometry event propagation touch and hover events.
+   */
+  bool IsGeometryHittestEnabled();
+
+  /**
    * @brief This signal is emitted just after the event processing is finished.
    *
    * @return The signal to connect to
index 1574f07..ea5cb70 100644 (file)
@@ -1116,6 +1116,7 @@ Actor::Actor(DerivedType derivedType, const SceneGraph::Node& node)
   mDrawMode(DrawMode::NORMAL),
   mColorMode(Node::DEFAULT_COLOR_MODE),
   mClippingMode(ClippingMode::DISABLED),
+  mHoverState(PointState::FINISHED),
   mBlendEquation(DevelBlendEquation::ADD)
 {
 }
index f60e531..cd71a09 100644 (file)
@@ -1350,6 +1350,23 @@ public:
     return mDispatchHoverMotion;
   }
 
+  /**
+   * @brief Sets the hover state of actor
+   * @param state The PointState
+   */
+  void SetHoverState(PointState::Type state)
+  {
+    mHoverState = state;
+  }
+
+  /**
+   * @brief Gets the hover state of actor
+   * @return PointState::Type
+   */
+  PointState::Type GetHoverState() const
+  {
+    return mHoverState;
+  }
   // Gestures
 
   /**
@@ -1978,6 +1995,7 @@ protected:
   DrawMode::Type           mDrawMode : 3;                  ///< Cached: How the actor and its children should be drawn
   ColorMode                mColorMode : 3;                 ///< Cached: Determines whether mWorldColor is inherited
   ClippingMode::Type       mClippingMode : 3;              ///< Cached: Determines which clipping mode (if any) to use.
+  PointState::Type         mHoverState : 3;                ///< Stores the HoverEvent state of actor.
   DevelBlendEquation::Type mBlendEquation : 16;            ///< Cached: Determines which blend equation will be used to render renderers.
 
 private:
index 9b34b5f..8808e2f 100644 (file)
@@ -58,6 +58,7 @@ Scene::Scene()
   mBackgroundColor(DEFAULT_BACKGROUND_COLOR),
   mDepthTreeDirty(false),
   mPartialUpdateEnabled(true),
+  mGeometryHittest(false),
   mEventProcessor(*this, ThreadLocalStorage::GetInternal()->GetGestureEventProcessor()),
   mSurfaceOrientation(0),
   mScreenOrientation(0)
@@ -499,6 +500,16 @@ bool Scene::IsPartialUpdateEnabled() const
   return mPartialUpdateEnabled;
 }
 
+void Scene::SetGeometryHittestEnabled(bool enabled)
+{
+  mGeometryHittest = enabled;
+}
+
+bool Scene::IsGeometryHittestEnabled() const
+{
+  return mGeometryHittest;
+}
+
 Integration::Scene::KeyEventSignalType& Scene::KeyEventSignal()
 {
   return mKeyEventSignal;
index 12f377a..56b2f7b 100644 (file)
@@ -243,6 +243,16 @@ public:
   void SetSurfaceRenderTarget(const Graphics::RenderTargetCreateInfo& renderTargetCreateInfo);
 
   /**
+   * @copydoc Dali::Integration::Scene::SetGeometryHittestEnabled
+   */
+  void SetGeometryHittestEnabled(bool enabled);
+
+  /**
+   * @copydoc Dali::Integration::Scene::IsGeometryHittestEnabled
+   */
+  bool IsGeometryHittestEnabled() const;
+
+  /**
    * Used by the EventProcessor to emit key event signals.
    * @param[in] event The key event.
    */
@@ -423,6 +433,7 @@ private:
 
   bool mDepthTreeDirty : 1;       ///< True if the depth tree needs recalculating
   bool mPartialUpdateEnabled : 1; ///< True if the partial update is enabled
+  bool mGeometryHittest : 1;      ///< True if the geometry hittest is enabled
 
   EventProcessor mEventProcessor;
 
index 1cf4b26..a2d581c 100644 (file)
@@ -61,7 +61,7 @@ struct GestureHitTestCheck : public HitTestAlgorithm::HitTestInterface
     return layer->IsTouchConsumed();
   }
 
-  bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp) override
+  bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp, bool isGeometry) override
   {
     return actor->EmitHitTestResultSignal(point, hitPointLocal, timeStamp);
   }
index ef398e2..e441aeb 100644 (file)
@@ -89,9 +89,14 @@ struct HitTestFunctionWrapper : public HitTestInterface
     return false;
   }
 
-  bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp) override
+  bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp, bool isGeometry) override
   {
-    return actor->EmitHitTestResultSignal(point, hitPointLocal, timeStamp);
+    // Geometry way does not require Hittest from the client.
+    if(!isGeometry)
+    {
+      return actor->EmitHitTestResultSignal(point, hitPointLocal, timeStamp);
+    }
+    return true;
   }
 
   Dali::HitTestAlgorithm::HitTestFunction mFunc;
@@ -120,13 +125,19 @@ struct ActorTouchableCheck : public HitTestInterface
     return layer->IsTouchConsumed();
   }
 
-  bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp) override
+  bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp, bool isGeometry) override
   {
-    if(point.GetState() != PointState::STARTED && actor->IsAllowedOnlyOwnTouch() && ownActor != actor)
+    // The Geometry way behaves like AllowedOnlyOwnTouch is enabled.
+    if(point.GetState() != PointState::STARTED && (isGeometry || actor->IsAllowedOnlyOwnTouch()) && ownActor != actor)
     {
       return false;
     }
-    return actor->EmitHitTestResultSignal(point, hitPointLocal, timeStamp);
+    // Geometry way does not require Hittest from the client.
+    if(!isGeometry)
+    {
+      return actor->EmitHitTestResultSignal(point, hitPointLocal, timeStamp);
+    }
+    return true;
   }
 
   void SetOwnActor(const Actor* actor)
@@ -182,7 +193,8 @@ void HitTestActor(const RenderTask&         renderTask,
                   bool                      overlayedActor,
                   Actor&                    actor,
                   bool&                     overlayHit,
-                  HitActor&                 hit)
+                  HitActor&                 hit,
+                  bool                      isGeometry)
 {
   if(clippingActor || hitCheck.IsActorHittable(&actor))
   {
@@ -218,7 +230,7 @@ void HitTestActor(const RenderTask&         renderTask,
             }
 
             // If the hit actor does not want to hit, the hit-test continues.
-            if(hitCheck.ActorRequiresHitResultCheck(&actor, point, hitPointLocal, eventTime))
+            if(hitCheck.ActorRequiresHitResultCheck(&actor, point, hitPointLocal, eventTime, isGeometry))
             {
               hit.actor       = &actor;
               hit.hitPosition = hitPointLocal;
@@ -298,7 +310,9 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
                             bool                                       layerIs3d,
                             const RayTest&                             rayTest,
                             const Integration::Point&                  point,
-                            const uint32_t                             eventTime)
+                            const uint32_t                             eventTime,
+                            std::list<Dali::Internal::Actor*>&         actorLists,
+                            bool                                       isGeometry)
 {
   HitActor hit;
 
@@ -314,18 +328,35 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
   bool overlayedActor = overlayed || actor.IsOverlay();
 
   // If we are a clipping actor or hittable...
-  HitTestActor(renderTask, rayOrigin, rayDir, nearClippingPlane, farClippingPlane, hitCheck, rayTest, point, eventTime, clippingActor, overlayedActor, actor, overlayHit, hit);
+  HitTestActor(renderTask, rayOrigin, rayDir, nearClippingPlane, farClippingPlane, hitCheck, rayTest, point, eventTime, clippingActor, overlayedActor, actor, overlayHit, hit, isGeometry);
 
   // If current actor is clipping, and hit failed, We should not checkup child actors. Fast return
   if(clippingActor && !(hit.actor))
   {
     return hit;
   }
+  else if (isGeometry && hit.actor)
+  {
+    // Saves the actors that can be hit as a list
+    actorLists.push_back(hit.actor);
+  }
 
   // Find a child hit, until we run out of actors in the current layer.
   HitActor childHit;
   if(actor.GetChildCount() > 0)
   {
+    // If the child touches outside the parent's size boundary, it should not be hit.
+    if(isGeometry && !actor.IsLayer())
+    {
+      Vector2 hitPointLocal;
+      float   distance;
+      if(!(rayTest.SphereTest(actor, rayOrigin, rayDir) &&
+            rayTest.ActorTest(actor, rayOrigin, rayDir, hitPointLocal, distance)))
+      {
+        return hit;
+      }
+    }
+
     childHit.distance        = std::numeric_limits<float>::max();
     childHit.depth           = std::numeric_limits<int32_t>::min();
     ActorContainer& children = actor.GetChildrenInternal();
@@ -340,20 +371,21 @@ HitActor HitTestWithinLayer(Actor&                                     actor,
          (hitCheck.DescendActorHierarchy((*iter).Get()))) // We can descend into child hierarchy
       {
         HitActor currentHit(HitTestWithinLayer((*iter->Get()),
-                                               renderTask,
-                                               exclusives,
-                                               rayOrigin,
-                                               rayDir,
-                                               nearClippingPlane,
-                                               farClippingPlane,
-                                               hitCheck,
-                                               overlayedActor,
-                                               overlayHit,
-                                               layerIs3d,
-                                               rayTest,
-                                               point,
-                                               eventTime));
-
+                                              renderTask,
+                                              exclusives,
+                                              rayOrigin,
+                                              rayDir,
+                                              nearClippingPlane,
+                                              farClippingPlane,
+                                              hitCheck,
+                                              overlayedActor,
+                                              overlayHit,
+                                              layerIs3d,
+                                              rayTest,
+                                              point,
+                                              eventTime,
+                                              actorLists,
+                                              isGeometry));
         // Make sure the set hit actor is actually hittable. This is usually required when we have some
         // clipping as we need to hit-test all actors as we descend the tree regardless of whether they
         // are hittable or not.
@@ -440,6 +472,118 @@ void GetCameraClippingPlane(RenderTask& renderTask, float& nearClippingPlane, fl
   farClippingPlane         = cameraActor->GetFarClippingPlane();
 }
 
+void GeoHitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
+                       const Vector2&                             sceneSize,
+                       LayerList&                                 layers,
+                       RenderTask&                                renderTask,
+                       Vector2                                    screenCoordinates,
+                       Results&                                   results,
+                       HitTestInterface&                          hitCheck,
+                       const RayTest&                             rayTest)
+{
+  if(renderTask.IsHittable(screenCoordinates))
+  {
+    Viewport viewport;
+    renderTask.GetHittableViewport(viewport);
+
+    if(screenCoordinates.x < static_cast<float>(viewport.x) ||
+       screenCoordinates.x > static_cast<float>(viewport.x + viewport.width) ||
+       screenCoordinates.y < static_cast<float>(viewport.y) ||
+       screenCoordinates.y > static_cast<float>(viewport.y + viewport.height))
+    {
+      // The screen coordinate is outside the viewport of render task. The viewport clips all layers.
+      return;
+    }
+
+    float nearClippingPlane, farClippingPlane;
+    GetCameraClippingPlane(renderTask, nearClippingPlane, farClippingPlane);
+
+    // Determine the layer depth of the source actor
+    Actor* sourceActor(renderTask.GetSourceActor());
+    if(sourceActor)
+    {
+      Dali::Layer sourceLayer(sourceActor->GetLayer());
+      if(sourceLayer)
+      {
+        const uint32_t sourceActorDepth(sourceLayer.GetProperty<bool>(Dali::Layer::Property::DEPTH));
+        CameraActor* cameraActor     = renderTask.GetCameraActor();
+        bool         pickingPossible = cameraActor->BuildPickingRay(screenCoordinates,
+                                                                    viewport,
+                                                                    results.rayOrigin,
+                                                                    results.rayDirection);
+        if(!pickingPossible)
+        {
+          return;
+        }
+
+        // Hit test starting with the top layer, working towards the bottom layer.
+        bool     overlayHit           = false;
+
+        for(uint32_t i = 0; i < layers.GetLayerCount(); ++i)
+        {
+          Layer* layer(layers.GetLayer(i));
+          overlayHit = false;
+          HitActor hit;
+
+          // Ensure layer is touchable (also checks whether ancestors are also touchable)
+          if(IsActuallyHittable(*layer, screenCoordinates, sceneSize, hitCheck))
+          {
+            // Always hit-test the source actor; otherwise test whether the layer is below the source actor in the hierarchy
+            if(sourceActorDepth == i)
+            {
+              // Recursively hit test the source actor & children, without crossing into other layers.
+              hit = HitTestWithinLayer(*sourceActor,
+                                      renderTask,
+                                      exclusives,
+                                      results.rayOrigin,
+                                      results.rayDirection,
+                                      nearClippingPlane,
+                                      farClippingPlane,
+                                      hitCheck,
+                                      overlayHit,
+                                      overlayHit,
+                                      layer->GetBehavior() == Dali::Layer::LAYER_3D,
+                                      rayTest,
+                                      results.point,
+                                      results.eventTime,
+                                      results.actorLists,
+                                      true);
+            }
+            else if(IsWithinSourceActors(*sourceActor, *layer))
+            {
+              // Recursively hit test all the actors, without crossing into other layers.
+              hit = HitTestWithinLayer(*layer,
+                                      renderTask,
+                                      exclusives,
+                                      results.rayOrigin,
+                                      results.rayDirection,
+                                      nearClippingPlane,
+                                      farClippingPlane,
+                                      hitCheck,
+                                      overlayHit,
+                                      overlayHit,
+                                      layer->GetBehavior() == Dali::Layer::LAYER_3D,
+                                      rayTest,
+                                      results.point,
+                                      results.eventTime,
+                                      results.actorLists,
+                                      true);
+            }
+          }
+
+          if(hit.actor)
+          {
+            results.renderTask       = RenderTaskPtr(&renderTask);
+            results.actor            = Dali::Actor(hit.actor);
+            results.actorCoordinates = hit.hitPosition;
+          }
+        }
+      }
+    }
+  }
+  return;
+}
+
 /**
  * Hit test a RenderTask
  */
@@ -536,7 +680,9 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
                                        layer->GetBehavior() == Dali::Layer::LAYER_3D,
                                        rayTest,
                                        results.point,
-                                       results.eventTime);
+                                       results.eventTime,
+                                       results.actorLists,
+                                       false);
             }
             else if(IsWithinSourceActors(*sourceActor, *layer))
             {
@@ -555,7 +701,9 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
                                        layer->GetBehavior() == Dali::Layer::LAYER_3D,
                                        rayTest,
                                        results.point,
-                                       results.eventTime);
+                                       results.eventTime,
+                                       results.actorLists,
+                                       false);
             }
 
             // If this layer is set to consume the hit, then do not check any layers behind it
@@ -603,6 +751,7 @@ bool HitTestRenderTask(const RenderTaskList::ExclusivesContainer& exclusives,
  * @param[in] taskList The list of render tasks
  * @param[out] results Ray information calculated by the camera
  * @param[in] hitCheck The hit testing interface object to use
+ * @param[in] isGeometry Whether the scene using geometry event propagation touch and hover events.
  * @return True if we have a hit, false otherwise
  */
 bool HitTestRenderTaskList(const Vector2&    sceneSize,
@@ -610,25 +759,44 @@ bool HitTestRenderTaskList(const Vector2&    sceneSize,
                            RenderTaskList&   taskList,
                            const Vector2&    screenCoordinates,
                            Results&          results,
-                           HitTestInterface& hitCheck)
+                           HitTestInterface& hitCheck,
+                           bool isGeometry)
 {
-  RenderTaskList::RenderTaskContainer&                  tasks      = taskList.GetTasks();
-  RenderTaskList::RenderTaskContainer::reverse_iterator endIter    = tasks.rend();
-  const auto&                                           exclusives = taskList.GetExclusivesList();
-  RayTest                                               rayTest;
-
-  // Hit test order should be reverse of draw order
-  for(RenderTaskList::RenderTaskContainer::reverse_iterator iter = tasks.rbegin(); endIter != iter; ++iter)
+  if(isGeometry)
   {
-    RenderTask& renderTask = *iter->Get();
-    if(HitTestRenderTask(exclusives, sceneSize, layers, renderTask, screenCoordinates, results, hitCheck, rayTest))
+    RenderTaskList::RenderTaskContainer&                  tasks      = taskList.GetTasks();
+    RenderTaskList::RenderTaskContainer::iterator endIter            = tasks.end();
+    const auto&                                           exclusives = taskList.GetExclusivesList();
+    RayTest                                               rayTest;
+
+    // Hit test order should be of draw order
+    for(RenderTaskList::RenderTaskContainer::iterator iter = tasks.begin(); endIter != iter; ++iter)
     {
-      // Return true when an actor is hit (or layer in our render-task consumes the hit)
-      return true;
+      RenderTask& renderTask = *iter->Get();
+      GeoHitTestRenderTask(exclusives, sceneSize, layers, renderTask, screenCoordinates, results, hitCheck, rayTest);
     }
+
+    return !results.actorLists.empty();
   }
+  else
+  {
+    RenderTaskList::RenderTaskContainer&                  tasks      = taskList.GetTasks();
+    RenderTaskList::RenderTaskContainer::reverse_iterator endIter    = tasks.rend();
+    const auto&                                           exclusives = taskList.GetExclusivesList();
+    RayTest                                               rayTest;
 
-  return false;
+    // Hit test order should be reverse of draw order
+    for(RenderTaskList::RenderTaskContainer::reverse_iterator iter = tasks.rbegin(); endIter != iter; ++iter)
+    {
+      RenderTask& renderTask = *iter->Get();
+      if(HitTestRenderTask(exclusives, sceneSize, layers, renderTask, screenCoordinates, results, hitCheck, rayTest))
+      {
+        // Return true when an actor is hit (or layer in our render-task consumes the hit)
+        return true;
+      }
+    }
+    return false;
+  }
 }
 
 /**
@@ -639,6 +807,7 @@ bool HitTestRenderTaskList(const Vector2&    sceneSize,
  * @param[in] taskList The list of render tasks
  * @param[out] results Ray information calculated by the camera
  * @param[in] hitCheck The hit testing interface object to use
+ * @param[in] isGeometry Whether the scene using geometry event propagation touch and hover events.
  * @return True if we have a hit, false otherwise
  */
 bool HitTestForEachRenderTask(const Vector2&    sceneSize,
@@ -646,11 +815,12 @@ bool HitTestForEachRenderTask(const Vector2&    sceneSize,
                               RenderTaskList&   taskList,
                               const Vector2&    screenCoordinates,
                               Results&          results,
-                              HitTestInterface& hitCheck)
+                              HitTestInterface& hitCheck,
+                              bool isGeometry)
 {
   bool result = false;
 
-  if(HitTestRenderTaskList(sceneSize, layers, taskList, screenCoordinates, results, hitCheck))
+  if(HitTestRenderTaskList(sceneSize, layers, taskList, screenCoordinates, results, hitCheck, isGeometry))
   {
     // Found hit.
     result = true;
@@ -663,13 +833,13 @@ bool HitTestForEachRenderTask(const Vector2&    sceneSize,
 
 HitTestInterface::~HitTestInterface() = default;
 
-bool HitTest(const Vector2& sceneSize, RenderTaskList& taskList, LayerList& layerList, const Vector2& screenCoordinates, Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func)
+bool HitTest(const Vector2& sceneSize, RenderTaskList& taskList, LayerList& layerList, const Vector2& screenCoordinates, Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func, bool isGeometry)
 {
   bool wasHit(false);
   // Hit-test the regular on-scene actors
   Results                hitTestResults;
   HitTestFunctionWrapper hitTestFunctionWrapper(func);
-  if(HitTestForEachRenderTask(sceneSize, layerList, taskList, screenCoordinates, hitTestResults, hitTestFunctionWrapper))
+  if(HitTestForEachRenderTask(sceneSize, layerList, taskList, screenCoordinates, hitTestResults, hitTestFunctionWrapper, isGeometry))
   {
     results.actor            = hitTestResults.actor;
     results.actorCoordinates = hitTestResults.actorCoordinates;
@@ -678,23 +848,23 @@ bool HitTest(const Vector2& sceneSize, RenderTaskList& taskList, LayerList& laye
   return wasHit;
 }
 
-bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results, HitTestInterface& hitTestInterface)
+bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results, HitTestInterface& hitTestInterface, bool isGeometry)
 {
   bool wasHit(false);
 
   // Hit-test the regular on-scene actors
   if(!wasHit)
   {
-    wasHit = HitTestForEachRenderTask(sceneSize, layerList, renderTaskList, screenCoordinates, results, hitTestInterface);
+    wasHit = HitTestForEachRenderTask(sceneSize, layerList, renderTaskList, screenCoordinates, results, hitTestInterface, isGeometry);
   }
   return wasHit;
 }
 
-bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results, const Actor* ownActor)
+bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results, const Actor* ownActor, bool isGeometry)
 {
   ActorTouchableCheck actorTouchableCheck;
   actorTouchableCheck.SetOwnActor(ownActor);
-  return HitTest(sceneSize, renderTaskList, layerList, screenCoordinates, results, actorTouchableCheck);
+  return HitTest(sceneSize, renderTaskList, layerList, screenCoordinates, results, actorTouchableCheck, isGeometry);
 }
 
 } // namespace HitTestAlgorithm
index 5a4c2fc..7a37204 100644 (file)
@@ -38,13 +38,14 @@ namespace HitTestAlgorithm
 {
 struct Results
 {
-  RenderTaskPtr      renderTask;       ///< The render-task displaying the actor.
-  Dali::Actor        actor;            ///< The hit actor.
-  Vector2            actorCoordinates; ///< The actor coordinates.
-  Vector4            rayOrigin;        ///< The point of origin of the ray.
-  Vector4            rayDirection;     ///< The direction vector of the ray.
-  Integration::Point point;            ///< The point of event touched.
-  uint32_t           eventTime;        ///< The time the event occurred.
+  RenderTaskPtr      renderTask;                ///< The render-task displaying the actor.
+  Dali::Actor        actor;                     ///< The hit actor.
+  Vector2            actorCoordinates;          ///< The actor coordinates.
+  Vector4            rayOrigin;                 ///< The point of origin of the ray.
+  Vector4            rayDirection;              ///< The direction vector of the ray.
+  Integration::Point point;                     ///< The point of event touched.
+  uint32_t           eventTime;                 ///< The time the event occurred.
+  std::list<Dali::Internal::Actor*> actorLists; ///< If the geometry hittest way is used, a list of actors that can be hit is stored.
 };
 
 /**
@@ -94,10 +95,11 @@ struct HitTestInterface
    * @param[in] point The point of event touched.
    * @param[in] hitPointLocal The hit point in the Actor's local reference system.
    * @param[in] timeStamp The time the event occurred.
+   * @param[in] isGeometry If true, hittest works in a geometry way.
    *
    * @return true if the actor should be the hit, false otherwise.
    */
-  virtual bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp) = 0;
+  virtual bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp, bool isGeometry) = 0;
 
 protected:
   /**
@@ -115,11 +117,12 @@ protected:
  * @param[in] screenCoordinates The screen coordinates.
  * @param[out] results The results of the hit-test.
  * @param[in] func The function to use in the hit-test algorithm.
+ * @param[in] isGeometry If true, hittest works in a geometry way.
  * @return true if something was hit
  *
  * @see HitTest(Stage&, const Vector2&, Results&, HitTestInterface&)
  */
-bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func);
+bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Dali::HitTestAlgorithm::Results& results, Dali::HitTestAlgorithm::HitTestFunction func, bool isGeometry = false);
 
 /**
  * Given screen coordinates, this method returns the hit actor & the local coordinates relative to the actor etc.
@@ -129,6 +132,7 @@ bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList
  * @param[in] screenCoordinates The screen coordinates.
  * @param[out] results The results of the hit-test.
  * @param[in] hitTestInterface Used to determine whether the actor is hit or whether we walk down its hierarchy
+ * @param[in] isGeometry If true, hittest works in a geometry way.
  * @return true if something was hit
  *
  * <h3>Hit Test Algorithm:</h3>
@@ -145,7 +149,7 @@ bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList
  * @note Currently, we prefer a child hit over a parent (regardless of the distance from the
  *       camera) unless the parent is a RenderableActor but this is subject to change.
  */
-bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results, HitTestInterface& hitTestInterface);
+bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results, HitTestInterface& hitTestInterface, bool isGeometry = false);
 
 /**
  * Default HitTest where we check if a touch is required.
@@ -156,11 +160,12 @@ bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList
  * @param[in] screenCoordinates The screen coordinates.
  * @param[out] results The results of the hit-test.
  * @param[in] ownActor The actor from which the touch down was started.
+ * @param[in] isGeometry If true, hittest works in a geometry way.
  * @return true if something was hit
  *
  * @see HitTest(Stage&, const Vector2&, Results&, HitTestInterface&)
  */
-bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results, const Actor* ownActor = nullptr);
+bool HitTest(const Vector2& sceneSize, RenderTaskList& renderTaskList, LayerList& layerList, const Vector2& screenCoordinates, Results& results, const Actor* ownActor = nullptr, bool isGeometry = false);
 
 } // namespace HitTestAlgorithm
 
index 0b4ae9e..ba824c6 100644 (file)
@@ -109,6 +109,49 @@ Dali::Actor EmitHoverSignals(Dali::Actor actor, const Dali::HoverEvent& event)
   return consumedActor;
 }
 
+/**
+ *  Recursively deliver events to the actor and its below actor, until the event is consumed or the stage is reached.
+ */
+Dali::Actor EmitGeoHoverSignals(std::list<Dali::Internal::Actor*>& actorLists, const Dali::HoverEvent& hoverEvent)
+{
+  Dali::Actor consumedActor;
+
+  std::list<Dali::Internal::Actor*>::reverse_iterator rIter = actorLists.rbegin();
+  for (; rIter != actorLists.rend(); rIter++)
+  {
+    Actor* actorImpl(*rIter);
+    // Only emit the signal if the actor's hover signal has connections (or derived actor implementation requires hover).
+    if(ShouldEmitHoverEvent(*actorImpl, hoverEvent))
+    {
+      DALI_TRACE_SCOPE(gTraceFilter, "DALI_EMIT_HOVER_EVENT_SIGNAL");
+      PointState::Type currentState = actorImpl->GetHoverState();
+      actorImpl->SetHoverState(hoverEvent.GetState(0));
+      // If hover event is newly entering the actor, update it to the started state.
+      if(hoverEvent.GetState(0) == PointState::MOTION &&
+        (currentState == PointState::FINISHED || currentState == PointState::INTERRUPTED || currentState == PointState::LEAVE))
+      {
+        HoverEventPtr newHoverEvent = HoverEvent::Clone(GetImplementation(hoverEvent));
+        newHoverEvent->GetPoint(0).SetState(PointState::STARTED);
+        actorImpl->SetHoverState(PointState::STARTED); //update state
+        if(actorImpl->EmitHoverEventSignal(Dali::HoverEvent(newHoverEvent.Get())))
+        {
+          // One of this actor's listeners has consumed the event so set this actor as the consumed actor.
+          consumedActor = Dali::Actor(actorImpl);
+          break;
+        }
+      }
+      else if(actorImpl->EmitHoverEventSignal(hoverEvent))
+      {
+        // One of this actor's listeners has consumed the event so set this actor as the consumed actor.
+        consumedActor = Dali::Actor(actorImpl);
+        break;
+      }
+    }
+  }
+  return consumedActor;
+}
+
+
 Dali::Actor AllocAndEmitHoverSignals(unsigned long time, Dali::Actor actor, const Integration::Point& point)
 {
   HoverEventPtr    hoverEvent(new HoverEvent(time));
@@ -119,14 +162,26 @@ Dali::Actor AllocAndEmitHoverSignals(unsigned long time, Dali::Actor actor, cons
   return EmitHoverSignals(actor, hoverEventHandle);
 }
 
+Dali::Actor GeoAllocAndEmitHoverSignals(std::list<Dali::Internal::Actor*>& actorLists, unsigned long time, const Integration::Point& point)
+{
+  HoverEventPtr    hoverEvent(new HoverEvent(time));
+  Dali::HoverEvent hoverEventHandle(hoverEvent.Get());
+
+  hoverEvent->AddPoint(point);
+
+  return EmitGeoHoverSignals(actorLists, hoverEventHandle);
+}
+
+
 /**
  * Changes the state of the primary point to leave and emits the hover signals
  */
-Dali::Actor EmitHoverSignals(Actor* actor, RenderTask& renderTask, const HoverEventPtr& originalEvent, PointState::Type state)
+Dali::Actor EmitHoverSignals(Actor* actor, RenderTask& renderTask, const HoverEventPtr& originalEvent, PointState::Type state, bool isGeometry)
 {
   HoverEventPtr hoverEvent = HoverEvent::Clone(*originalEvent.Get());
 
   DALI_ASSERT_DEBUG(NULL != actor && "NULL actor pointer");
+  Dali::Actor consumingActor;
   if(actor)
   {
     Integration::Point& primaryPoint = hoverEvent->GetPoint(0);
@@ -140,7 +195,17 @@ Dali::Actor EmitHoverSignals(Actor* actor, RenderTask& renderTask, const HoverEv
     primaryPoint.SetState(state);
   }
 
-  return EmitHoverSignals(Dali::Actor(actor), Dali::HoverEvent(hoverEvent.Get()));
+  if(isGeometry)
+  {
+    std::list<Dali::Internal::Actor*> actorLists;
+    actorLists.push_back(actor);
+    consumingActor = EmitGeoHoverSignals(actorLists, Dali::HoverEvent(hoverEvent.Get()));
+  }
+  else
+  {
+    consumingActor = EmitHoverSignals(Dali::Actor(actor), Dali::HoverEvent(hoverEvent.Get()));
+  }
+  return consumingActor;
 }
 
 /**
@@ -165,7 +230,7 @@ struct ActorHoverableCheck : public HitTestAlgorithm::HitTestInterface
     return layer->IsHoverConsumed();
   }
 
-  bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp) override
+  bool ActorRequiresHitResultCheck(Actor* actor, Integration::Point point, Vector2 hitPointLocal, uint32_t timeStamp, bool isGeometry) override
   {
     // Hover event is always hit.
     return true;
@@ -204,7 +269,16 @@ void HoverEventProcessor::SendInterruptedHoverEvent(Dali::Internal::Actor* actor
     Integration::Point point;
     point.SetState(PointState::INTERRUPTED);
     point.SetHitActor(Dali::Actor(actor));
-    AllocAndEmitHoverSignals(GetMilliSeconds(), point.GetHitActor(), point);
+    if(mScene.IsGeometryHittestEnabled())
+    {
+      std::list<Dali::Internal::Actor*> actorLists;
+      actorLists.push_back(actor);
+      GeoAllocAndEmitHoverSignals(actorLists, 0, point);
+    }
+    else
+    {
+      AllocAndEmitHoverSignals(GetMilliSeconds(), point.GetHitActor(), point);
+    }
     Clear();
   }
 }
@@ -220,6 +294,8 @@ void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event
 
   DALI_TRACE_SCOPE(gTraceFilter, "DALI_PROCESS_HOVER_EVENT");
 
+  bool isGeometry = mScene.IsGeometryHittestEnabled();
+
   // Copy so we can add the results of a hit-test.
   HoverEventPtr hoverEvent(new HoverEvent(event.time));
 
@@ -236,30 +312,55 @@ void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event
     {
       Dali::Actor lastPrimaryHitActorHandle(lastPrimaryHitActor);
       currentPoint.SetHitActor(lastPrimaryHitActorHandle);
-      consumingActor = AllocAndEmitHoverSignals(event.time, lastPrimaryHitActorHandle, currentPoint);
+      if(isGeometry)
+      {
+        consumingActor = GeoAllocAndEmitHoverSignals(mCandidateActorLists, event.time, currentPoint);
+      }
+      else
+      {
+        consumingActor = AllocAndEmitHoverSignals(event.time, lastPrimaryHitActorHandle, currentPoint);
+      }
     }
 
     // If the last consumed actor was different to the primary hit actor then inform it as well (if it has not already been informed).
     Actor* lastConsumedActor(mLastConsumedActor.GetActor());
     if(lastConsumedActor &&
-       lastConsumedActor != lastPrimaryHitActor &&
-       lastConsumedActor != consumingActor)
+      lastConsumedActor != lastPrimaryHitActor &&
+      lastConsumedActor != consumingActor)
     {
       Dali::Actor lastConsumedActorHandle(lastConsumedActor);
       currentPoint.SetHitActor(lastConsumedActorHandle);
-      AllocAndEmitHoverSignals(event.time, lastConsumedActorHandle, currentPoint);
+      if(isGeometry)
+      {
+        std::list<Dali::Internal::Actor*> actorLists;
+        actorLists.push_back(lastConsumedActor);
+        GeoAllocAndEmitHoverSignals(actorLists, event.time, currentPoint);
+      }
+      else
+      {
+        AllocAndEmitHoverSignals(event.time, lastConsumedActorHandle, currentPoint);
+      }
     }
 
     // Tell the hover-start consuming actor as well, if required
     Actor* hoverStartConsumedActor(mHoverStartConsumedActor.GetActor());
     if(hoverStartConsumedActor &&
-       hoverStartConsumedActor != lastPrimaryHitActor &&
-       hoverStartConsumedActor != lastConsumedActor &&
-       hoverStartConsumedActor != consumingActor)
+      hoverStartConsumedActor != lastPrimaryHitActor &&
+      hoverStartConsumedActor != lastConsumedActor &&
+      hoverStartConsumedActor != consumingActor)
     {
       Dali::Actor hoverStartConsumedActorHandle(hoverStartConsumedActor);
       currentPoint.SetHitActor(hoverStartConsumedActorHandle);
-      AllocAndEmitHoverSignals(event.time, hoverStartConsumedActorHandle, currentPoint);
+      if(isGeometry)
+      {
+        std::list<Dali::Internal::Actor*> actorLists;
+        actorLists.push_back(hoverStartConsumedActor);
+        GeoAllocAndEmitHoverSignals(actorLists, event.time, currentPoint);
+      }
+      else
+      {
+        AllocAndEmitHoverSignals(event.time, hoverStartConsumedActorHandle, currentPoint);
+      }
     }
 
     Clear();
@@ -281,7 +382,7 @@ void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event
   {
     HitTestAlgorithm::Results hitTestResults;
     ActorHoverableCheck       actorHoverableCheck;
-    HitTestAlgorithm::HitTest(mScene.GetSize(), mScene.GetRenderTaskList(), mScene.GetLayerList(), currentPoint.GetScreenPosition(), hitTestResults, actorHoverableCheck);
+    HitTestAlgorithm::HitTest(mScene.GetSize(), mScene.GetRenderTaskList(), mScene.GetLayerList(), currentPoint.GetScreenPosition(), hitTestResults, actorHoverableCheck, isGeometry);
 
     Integration::Point newPoint(currentPoint);
     newPoint.SetHitActor(hitTestResults.actor);
@@ -296,6 +397,7 @@ void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event
     {
       firstPointParsed  = true;
       currentRenderTask = hitTestResults.renderTask;
+      mCandidateActorLists = hitTestResults.actorLists;
     }
   }
 
@@ -310,18 +412,26 @@ void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event
   if(currentRenderTask)
   {
     Dali::Actor hitActor = hoverEvent->GetHitActor(0);
-    // If the actor is hit first, the hover is started.
-    if(hitActor &&
-       mLastPrimaryHitActor.GetActor() != hitActor &&
-       state == PointState::MOTION)
+
+    if(isGeometry)
+    {
+      consumedActor = EmitGeoHoverSignals(mCandidateActorLists, hoverEventHandle);
+    }
+    else
     {
-      Actor* hitActorImpl = &GetImplementation(hitActor);
-      if(hitActorImpl->GetLeaveRequired())
+      // If the actor is hit first, the hover is started.
+      if(hitActor &&
+        mLastPrimaryHitActor.GetActor() != hitActor &&
+        state == PointState::MOTION)
       {
-        hoverEvent->GetPoint(0).SetState(PointState::STARTED);
+        Actor* hitActorImpl = &GetImplementation(hitActor);
+        if(hitActorImpl->GetLeaveRequired())
+        {
+          hoverEvent->GetPoint(0).SetState(PointState::STARTED);
+        }
       }
+      consumedActor = EmitHoverSignals(hitActor, hoverEventHandle);
     }
-    consumedActor = EmitHoverSignals(hitActor, hoverEventHandle);
 
     if(hoverEvent->GetPoint(0).GetState() != PointState::MOTION)
     {
@@ -350,15 +460,46 @@ void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event
       RenderTask& lastRenderTaskImpl = *mLastRenderTask.Get();
 
       if(lastPrimaryHitActor &&
-         lastPrimaryHitActor != primaryHitActor &&
-         lastPrimaryHitActor != consumedActor)
+        lastPrimaryHitActor != primaryHitActor &&
+        lastPrimaryHitActor != consumedActor)
       {
         if(lastPrimaryHitActor->IsHittable() && IsActuallySensitive(lastPrimaryHitActor))
         {
-          if(lastPrimaryHitActor->GetLeaveRequired())
+          if(isGeometry)
+          {
+            // This is a situation where actors who received a hover event must leave.
+            // Compare the lastActorList that received the hover event and the CandidateActorList that can receive the new hover event
+            // If the hover event can no longer be received, Leave is sent.
+            std::list<Dali::Internal::Actor*>::reverse_iterator rLastIter = mLastActorLists.rbegin();
+            for(; rLastIter != mLastActorLists.rend(); rLastIter++)
+            {
+              bool find = false;
+              std::list<Dali::Internal::Actor*>::reverse_iterator rCandidateIter = mCandidateActorLists.rbegin();
+              for(; rCandidateIter != mCandidateActorLists.rend(); rCandidateIter++)
+              {
+                if(*rCandidateIter == *rLastIter)
+                {
+                  find = true;
+                  break;
+                }
+              }
+              if(!find)
+              {
+                DALI_LOG_RELEASE_INFO("LeaveActor(Hit): (%p) %d %s\n", reinterpret_cast<void*>(*rLastIter), (*rLastIter)->GetId(), (*rLastIter)->GetName().data());
+                leaveEventConsumer = EmitHoverSignals(*rLastIter, lastRenderTaskImpl, hoverEvent, PointState::LEAVE, isGeometry);
+              }
+              // If the actor has been consumed, you do not need to proceed.
+              if(*rLastIter == lastConsumedActor)
+              {
+                break;
+              }
+            }
+          }
+          else if(lastPrimaryHitActor->GetLeaveRequired())
           {
+            // In the case of isGeometry, it is not propagated but only sent to actors who are not hittable.
             DALI_LOG_RELEASE_INFO("LeaveActor(Hit): (%p) %d %s\n", reinterpret_cast<void*>(lastPrimaryHitActor), lastPrimaryHitActor->GetId(), lastPrimaryHitActor->GetName().data());
-            leaveEventConsumer = EmitHoverSignals(mLastPrimaryHitActor.GetActor(), lastRenderTaskImpl, hoverEvent, PointState::LEAVE);
+            leaveEventConsumer = EmitHoverSignals(mLastPrimaryHitActor.GetActor(), lastRenderTaskImpl, hoverEvent, PointState::LEAVE, isGeometry);
           }
         }
         else if(primaryPointState != PointState::STARTED)
@@ -366,7 +507,7 @@ void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event
           // At this point mLastPrimaryHitActor was touchable and sensitive in the previous touch event process but is not in the current one.
           // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls)
           DALI_LOG_RELEASE_INFO("InterruptedActor(Hit): (%p) %d %s\n", reinterpret_cast<void*>(lastPrimaryHitActor), lastPrimaryHitActor->GetId(), lastPrimaryHitActor->GetName().data());
-          leaveEventConsumer = EmitHoverSignals(mLastPrimaryHitActor.GetActor(), lastRenderTaskImpl, hoverEvent, PointState::INTERRUPTED);
+          leaveEventConsumer = EmitHoverSignals(mLastPrimaryHitActor.GetActor(), lastRenderTaskImpl, hoverEvent, PointState::INTERRUPTED, isGeometry);
         }
       }
 
@@ -374,17 +515,17 @@ void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event
       // 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.
       if(lastConsumedActor &&
-         lastConsumedActor != consumedActor &&
-         lastConsumedActor != lastPrimaryHitActor &&
-         lastConsumedActor != primaryHitActor &&
-         lastConsumedActor != leaveEventConsumer)
+        lastConsumedActor != consumedActor &&
+        lastConsumedActor != lastPrimaryHitActor &&
+        lastConsumedActor != primaryHitActor &&
+        lastConsumedActor != leaveEventConsumer)
       {
         if(lastConsumedActor->IsHittable() && IsActuallySensitive(lastConsumedActor))
         {
-          if(lastConsumedActor->GetLeaveRequired())
+          if(lastConsumedActor->GetLeaveRequired() && !isGeometry) // For geometry, we have already sent leave. There is no need to send leave repeatedly.
           {
             DALI_LOG_RELEASE_INFO("LeaveActor(Consume): (%p) %d %s\n", reinterpret_cast<void*>(lastConsumedActor), lastConsumedActor->GetId(), lastConsumedActor->GetName().data());
-            EmitHoverSignals(lastConsumedActor, lastRenderTaskImpl, hoverEvent, PointState::LEAVE);
+            EmitHoverSignals(lastConsumedActor, lastRenderTaskImpl, hoverEvent, PointState::LEAVE, isGeometry);
           }
         }
         else if(primaryPointState != PointState::STARTED)
@@ -392,7 +533,7 @@ void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event
           // At this point mLastConsumedActor was touchable and sensitive in the previous touch event process but is not in the current one.
           // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls)
           DALI_LOG_RELEASE_INFO("InterruptedActor(Consume): (%p) %d %s\n", reinterpret_cast<void*>(lastConsumedActor), lastConsumedActor->GetId(), lastConsumedActor->GetName().data());
-          EmitHoverSignals(mLastConsumedActor.GetActor(), lastRenderTaskImpl, hoverEvent, PointState::INTERRUPTED);
+          EmitHoverSignals(mLastConsumedActor.GetActor(), lastRenderTaskImpl, hoverEvent, PointState::INTERRUPTED, isGeometry);
         }
       }
     }
@@ -422,6 +563,7 @@ void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event
       }
 
       mLastRenderTask = currentRenderTask;
+      mLastActorLists = mCandidateActorLists;
     }
     else
     {
@@ -447,7 +589,16 @@ void HoverEventProcessor::ProcessHoverEvent(const Integration::HoverEvent& event
           Integration::Point primaryPoint = hoverEvent->GetPoint(0);
           primaryPoint.SetHitActor(hoverStartConsumedActorHandle);
           primaryPoint.SetState(PointState::INTERRUPTED);
-          AllocAndEmitHoverSignals(event.time, hoverStartConsumedActorHandle, primaryPoint);
+          if(isGeometry)
+          {
+            std::list<Dali::Internal::Actor*> actorLists;
+            actorLists.push_back(hoverStartConsumedActor);
+            GeoAllocAndEmitHoverSignals(actorLists, event.time, primaryPoint);
+          }
+          else
+          {
+            AllocAndEmitHoverSignals(event.time, hoverStartConsumedActorHandle, primaryPoint);
+          }
 
           // Restore hover-event to original state
           primaryPoint.SetHitActor(primaryHitActor);
@@ -476,6 +627,7 @@ void HoverEventProcessor::Clear()
   mLastPrimaryHitActor.SetActor(nullptr);
   mLastConsumedActor.SetActor(nullptr);
   mLastRenderTask.Reset();
+  mLastActorLists.clear();
 }
 
 void HoverEventProcessor::OnObservedActorDisconnected(Dali::Internal::Actor* actor)
index 94c75ad..5ec5002 100644 (file)
@@ -90,11 +90,13 @@ private:
    */
   void OnObservedActorDisconnected(Dali::Internal::Actor* actor);
 
-  Scene&        mScene;                   ///< Reference to the scene
-  ActorObserver mLastPrimaryHitActor;     ///< Stores the last primary point hit actor
-  ActorObserver mLastConsumedActor;       ///< Stores the last consumed actor
-  ActorObserver mHoverStartConsumedActor; ///< Stores the hover-start consumed actor
-  RenderTaskPtr mLastRenderTask;          ///< The RenderTask used for the last hit actor
+  Scene&        mScene;                                       ///< Reference to the scene
+  ActorObserver mLastPrimaryHitActor;                         ///< Stores the last primary point hit actor
+  ActorObserver mLastConsumedActor;                           ///< Stores the last consumed actor
+  ActorObserver mHoverStartConsumedActor;                     ///< Stores the hover-start consumed actor
+  RenderTaskPtr mLastRenderTask;                              ///< The RenderTask used for the last hit actor
+  std::list<Dali::Internal::Actor*> mCandidateActorLists;     ///< Stores a list of actors that can be touched, from leaf actor to root.
+  std::list<Dali::Internal::Actor*> mLastActorLists;     ///< Stores a list of actors that can be touched, from leaf actor to root.
 };
 
 } // namespace Internal
index 1e86b4c..9a139f5 100644 (file)
@@ -70,6 +70,7 @@ bool ShouldEmitTouchEvent(const Actor& actorImpl, const Dali::TouchEvent& event)
   return actorImpl.GetTouchRequired() && (state != PointState::MOTION || actorImpl.IsDispatchTouchMotion());
 }
 
+// child -> parent
 Dali::Actor EmitInterceptTouchSignals(Dali::Actor actor, const Dali::TouchEvent& touchEvent)
 {
   Dali::Actor interceptedActor;
@@ -98,7 +99,28 @@ Dali::Actor EmitInterceptTouchSignals(Dali::Actor actor, const Dali::TouchEvent&
       }
     }
   }
+  return interceptedActor;
+}
 
+// geometry
+// child -> below
+Dali::Actor EmitGeoInterceptTouchSignals(std::list<Dali::Internal::Actor*>& actorLists, std::list<Dali::Internal::Actor*>& interceptActorList, const Dali::TouchEvent& touchEvent)
+{
+  interceptActorList.clear();
+  Dali::Actor interceptedActor;
+  for(auto&& actor : actorLists)
+  {
+    interceptActorList.push_back(actor);
+    if(ShouldEmitInterceptTouchEvent(*actor, touchEvent))
+    {
+      DALI_TRACE_SCOPE(gTraceFilter, "DALI_EMIT_INTERCEPT_TOUCH_EVENT_SIGNAL");
+      if(actor->EmitInterceptTouchEventSignal(touchEvent))
+      {
+        interceptedActor = Dali::Actor(actor);
+        break;
+      }
+    }
+  }
   return interceptedActor;
 }
 
@@ -146,6 +168,32 @@ Dali::Actor EmitTouchSignals(Dali::Actor actor, const Dali::TouchEvent& touchEve
   return consumedActor;
 }
 
+/**
+ *  Recursively deliver events to the actor and its below actor, until the event is consumed or the stage is reached.
+ */
+Dali::Actor EmitGeoTouchSignals(std::list<Dali::Internal::Actor*>& actorLists, const Dali::TouchEvent& touchEvent)
+{
+  Dali::Actor consumedActor;
+
+  std::list<Dali::Internal::Actor*>::reverse_iterator rIter = actorLists.rbegin();
+  for (; rIter != actorLists.rend(); rIter++)
+  {
+    Actor* actorImpl(*rIter);
+    // Only emit the signal if the actor's touch signal has connections (or derived actor implementation requires touch).
+    if(ShouldEmitTouchEvent(*actorImpl, touchEvent))
+    {
+      DALI_TRACE_SCOPE(gTraceFilter, "DALI_EMIT_TOUCH_EVENT_SIGNAL");
+      if(actorImpl->EmitTouchEventSignal(touchEvent))
+      {
+        // One of this actor's listeners has consumed the event so set this actor as the consumed actor.
+        consumedActor = Dali::Actor(actorImpl);
+        break;
+      }
+    }
+  }
+  return consumedActor;
+}
+
 Dali::Actor AllocAndEmitTouchSignals(unsigned long time, Dali::Actor actor, const Integration::Point& point, RenderTaskPtr renderTask)
 {
   TouchEventPtr    touchEvent(new TouchEvent(time));
@@ -157,10 +205,21 @@ Dali::Actor AllocAndEmitTouchSignals(unsigned long time, Dali::Actor actor, cons
   return EmitTouchSignals(actor, touchEventHandle);
 }
 
+Dali::Actor GeoAllocAndEmitTouchSignals(std::list<Dali::Internal::Actor*>& actorLists, unsigned long time, const Integration::Point& point, RenderTaskPtr renderTask)
+{
+  TouchEventPtr    touchEvent(new TouchEvent(time));
+  Dali::TouchEvent touchEventHandle(touchEvent.Get());
+
+  touchEvent->AddPoint(point);
+  touchEvent->SetRenderTask(Dali::RenderTask(renderTask.Get()));
+
+  return EmitGeoTouchSignals(actorLists, touchEventHandle);
+}
+
 /**
  * Changes the state of the primary point to leave and emits the touch signals
  */
-Dali::Actor EmitTouchSignals(Actor* actor, RenderTask& renderTask, const TouchEventPtr& originalTouchEvent, PointState::Type state)
+Dali::Actor EmitTouchSignals(Actor* actor, RenderTask& renderTask, const TouchEventPtr& originalTouchEvent, PointState::Type state, bool isGeometry)
 {
   Dali::Actor consumingActor;
 
@@ -179,7 +238,16 @@ Dali::Actor EmitTouchSignals(Actor* actor, RenderTask& renderTask, const TouchEv
     primaryPoint.SetHitActor(Dali::Actor(actor));
     primaryPoint.SetState(state);
 
-    consumingActor = EmitTouchSignals(Dali::Actor(actor), Dali::TouchEvent(touchEventImpl.Get()));
+    if(isGeometry)
+    {
+      std::list<Dali::Internal::Actor*> actorLists;
+      actorLists.push_back(actor);
+      consumingActor = EmitGeoTouchSignals(actorLists, Dali::TouchEvent(touchEventImpl.Get()));
+    }
+    else
+    {
+      consumingActor = EmitTouchSignals(Dali::Actor(actor), Dali::TouchEvent(touchEventImpl.Get()));
+    }
   }
 
   return consumingActor;
@@ -193,6 +261,7 @@ Dali::Actor EmitTouchSignals(Actor* actor, RenderTask& renderTask, const TouchEv
  * @param[in] lastRenderTask The last render task member
  * @param[in] currentPoint The current point information
  * @param[in] scene The scene that this touch is related to
+ * @param[in] actorLists The list of actors that can be touched, from leaf actor to root.
  */
 void ParsePrimaryTouchPoint(
   HitTestAlgorithm::Results& hitTestResults,
@@ -200,7 +269,8 @@ void ParsePrimaryTouchPoint(
   ActorObserver&             ownTouchActorObserver,
   const RenderTaskPtr&       lastRenderTask,
   const Integration::Point&  currentPoint,
-  const Internal::Scene&     scene)
+  const Internal::Scene&     scene,
+  std::list<Dali::Internal::Actor*>& actorLists)
 {
   Actor* capturingTouchActor = capturingTouchActorObserver.GetActor();
 
@@ -215,20 +285,25 @@ void ParsePrimaryTouchPoint(
   else
   {
     Actor* ownTouchActor = ownTouchActorObserver.GetActor();
-    HitTestAlgorithm::HitTest(scene.GetSize(), scene.GetRenderTaskList(), scene.GetLayerList(), currentPoint.GetScreenPosition(), hitTestResults, ownTouchActor);
+    HitTestAlgorithm::HitTest(scene.GetSize(), scene.GetRenderTaskList(), scene.GetLayerList(), currentPoint.GetScreenPosition(), hitTestResults, ownTouchActor, scene.IsGeometryHittestEnabled());
 
     if(currentPoint.GetState() == PointState::STARTED && hitTestResults.actor)
     {
+      bool isGeometry = scene.IsGeometryHittestEnabled();
       // If we've just started touch, then check whether the actor has requested to capture all touch events
       Actor* hitActor = &GetImplementation(hitTestResults.actor);
-      if(hitActor->CapturesAllTouchAfterStart())
+      if(hitActor->CapturesAllTouchAfterStart() || isGeometry)
       {
         capturingTouchActorObserver.SetActor(hitActor);
       }
-      if(hitActor->IsAllowedOnlyOwnTouch())
+      if(hitActor->IsAllowedOnlyOwnTouch() || isGeometry)
       {
         ownTouchActorObserver.SetActor(hitActor);
       }
+      if(isGeometry)
+      {
+        actorLists = hitTestResults.actorLists;
+      }
     }
   }
 }
@@ -274,6 +349,8 @@ bool TouchEventProcessor::ProcessTouchEvent(const Integration::TouchEvent& event
 
   DALI_TRACE_SCOPE(gTraceFilter, "DALI_PROCESS_TOUCH_EVENT");
 
+  bool isGeometry = mScene.IsGeometryHittestEnabled();
+
   // 1) Check if it is an interrupted event - we should inform our last primary hit actor about this
   //    and emit the stage signal as well.
 
@@ -282,37 +359,71 @@ bool TouchEventProcessor::ProcessTouchEvent(const Integration::TouchEvent& event
     Dali::Actor        consumingActor;
     Integration::Point currentPoint(event.points[0]);
 
-    Actor* lastPrimaryHitActor(mLastPrimaryHitActor.GetActor());
-    if(lastPrimaryHitActor)
+    if(isGeometry)
     {
-      Dali::Actor lastPrimaryHitActorHandle(lastPrimaryHitActor);
-      currentPoint.SetHitActor(lastPrimaryHitActorHandle);
+      // Since the geometry way only receives touch events from the consumed actor,
+      // it first searches for whether there is a consumed actor and then sends the event
+      Actor* touchConsumedActor(mLastConsumedActor.GetActor());
+      Actor* touchDownConsumedActor(mTouchDownConsumedActor.GetActor());
+      Actor* lastPrimaryHitActor(mLastPrimaryHitActor.GetActor());
+      if(touchConsumedActor)
+      {
+        Dali::Actor touchConsumedActorHandle(touchConsumedActor);
+        currentPoint.SetHitActor(touchConsumedActorHandle);
+        std::list<Dali::Internal::Actor*> actorLists;
+        actorLists.push_back(touchConsumedActor);
+        GeoAllocAndEmitTouchSignals(actorLists, event.time, currentPoint, mLastRenderTask);
+      }
+      else if(touchDownConsumedActor)
+      {
+        Dali::Actor touchDownConsumedActorHandle(touchDownConsumedActor);
+        currentPoint.SetHitActor(touchDownConsumedActorHandle);
+        std::list<Dali::Internal::Actor*> actorLists;
+        actorLists.push_back(touchDownConsumedActor);
+        GeoAllocAndEmitTouchSignals(actorLists, event.time, currentPoint, mLastRenderTask);
+      }
+      else if(lastPrimaryHitActor)
+      {
+        Dali::Actor lastPrimaryHitActorHandle(lastPrimaryHitActor);
+        currentPoint.SetHitActor(lastPrimaryHitActorHandle);
 
-      consumingActor = AllocAndEmitTouchSignals(event.time, lastPrimaryHitActorHandle, currentPoint, mLastRenderTask);
+        GeoAllocAndEmitTouchSignals(mCandidateActorLists, event.time, currentPoint, mLastRenderTask);
+      }
     }
-
-    // If the last consumed actor was different to the primary hit actor then inform it as well (if it has not already been informed).
-    Actor* lastConsumedActor(mLastConsumedActor.GetActor());
-    if(lastConsumedActor &&
-       lastConsumedActor != lastPrimaryHitActor &&
-       lastConsumedActor != consumingActor)
+    else
     {
-      Dali::Actor lastConsumedActorHandle(lastConsumedActor);
-      currentPoint.SetHitActor(lastConsumedActorHandle);
-      AllocAndEmitTouchSignals(event.time, lastConsumedActorHandle, currentPoint, mLastRenderTask);
-    }
+      Actor* lastPrimaryHitActor(mLastPrimaryHitActor.GetActor());
+      if(lastPrimaryHitActor)
+      {
+        Dali::Actor lastPrimaryHitActorHandle(lastPrimaryHitActor);
+        currentPoint.SetHitActor(lastPrimaryHitActorHandle);
 
-    // Tell the touch-down consuming actor as well, if required
-    Actor* touchDownConsumedActor(mTouchDownConsumedActor.GetActor());
-    if(touchDownConsumedActor &&
-       touchDownConsumedActor != lastPrimaryHitActor &&
-       touchDownConsumedActor != lastConsumedActor &&
-       touchDownConsumedActor != consumingActor)
-    {
-      Dali::Actor touchDownConsumedActorHandle(touchDownConsumedActor);
+        consumingActor = AllocAndEmitTouchSignals(event.time, lastPrimaryHitActorHandle, currentPoint, mLastRenderTask);
+      }
+
+      // If the last consumed actor was different to the primary hit actor then inform it as well (if it has not already been informed).
+      Actor* lastConsumedActor(mLastConsumedActor.GetActor());
+      if(lastConsumedActor &&
+        lastConsumedActor != lastPrimaryHitActor &&
+        lastConsumedActor != consumingActor)
+      {
+        Dali::Actor lastConsumedActorHandle(lastConsumedActor);
+        currentPoint.SetHitActor(lastConsumedActorHandle);
+        AllocAndEmitTouchSignals(event.time, lastConsumedActorHandle, currentPoint, mLastRenderTask);
+      }
 
-      currentPoint.SetHitActor(touchDownConsumedActorHandle);
-      AllocAndEmitTouchSignals(event.time, touchDownConsumedActorHandle, currentPoint, mLastRenderTask);
+      // Tell the touch-down consuming actor as well, if required
+      Actor* touchDownConsumedActor(mTouchDownConsumedActor.GetActor());
+      if(touchDownConsumedActor &&
+        touchDownConsumedActor != lastPrimaryHitActor &&
+        touchDownConsumedActor != lastConsumedActor &&
+        touchDownConsumedActor != consumingActor)
+      {
+        Dali::Actor touchDownConsumedActorHandle(touchDownConsumedActor);
+
+        currentPoint.SetHitActor(touchDownConsumedActorHandle);
+        AllocAndEmitTouchSignals(event.time, touchDownConsumedActorHandle, currentPoint, mLastRenderTask);
+      }
     }
 
     Clear();
@@ -347,7 +458,7 @@ bool TouchEventProcessor::ProcessTouchEvent(const Integration::TouchEvent& event
     if(!firstPointParsed)
     {
       firstPointParsed = true;
-      ParsePrimaryTouchPoint(hitTestResults, mCapturingTouchActor, mOwnTouchActor, mLastRenderTask, currentPoint, mScene);
+      ParsePrimaryTouchPoint(hitTestResults, mCapturingTouchActor, mOwnTouchActor, mLastRenderTask, currentPoint, mScene, mCandidateActorLists);
 
       // Only set the currentRenderTask for the primary hit actor.
       currentRenderTask = hitTestResults.renderTask;
@@ -355,7 +466,7 @@ bool TouchEventProcessor::ProcessTouchEvent(const Integration::TouchEvent& event
     }
     else
     {
-      HitTestAlgorithm::HitTest(mScene.GetSize(), mScene.GetRenderTaskList(), mScene.GetLayerList(), currentPoint.GetScreenPosition(), hitTestResults);
+      HitTestAlgorithm::HitTest(mScene.GetSize(), mScene.GetRenderTaskList(), mScene.GetLayerList(), currentPoint.GetScreenPosition(), hitTestResults, nullptr, isGeometry);
     }
 
     Integration::Point newPoint(currentPoint);
@@ -380,46 +491,107 @@ bool TouchEventProcessor::ProcessTouchEvent(const Integration::TouchEvent& event
 
   if(currentRenderTask)
   {
-    Actor* interceptedTouchActor(mInterceptedTouchActor.GetActor());
-    if(interceptedTouchActor)
+    if(isGeometry)
     {
-      Dali::Actor interceptedTouchActorHandle(interceptedTouchActor);
-      consumedActor = EmitTouchSignals(interceptedTouchActorHandle, touchEventHandle);
+      Actor* touchConsumedActor(mLastConsumedActor.GetActor());
+      Actor* interceptedTouchActor(mInterceptedTouchActor.GetActor());
+      if(touchConsumedActor) // If there is a consultative actor, send events only to the consultative actor.
+      {
+        RenderTask& currentRenderTaskImpl = *currentRenderTask.Get();
+        consumedActor = EmitTouchSignals(touchConsumedActor, currentRenderTaskImpl, touchEventImpl, primaryPointState, isGeometry);
+      }
+      else if(interceptedTouchActor) // If there is an intercepted actor, send a touch event starting from the intercepted actor.
+      {
+        Dali::Actor interceptedTouchActorHandle(interceptedTouchActor);
+        std::list<Dali::Internal::Actor*> interceptActorLists = mInterceptedActorLists;
+        consumedActor = EmitGeoTouchSignals(interceptActorLists, touchEventHandle);
+      }
+      else
+      {
+        Dali::Actor interceptedActor;
+        // Let's find out if there is an intercept actor.
+        interceptedActor = EmitGeoInterceptTouchSignals(mCandidateActorLists, mInterceptedActorLists, touchEventHandle);
+        if(interceptedActor)
+        {
+          mInterceptedTouchActor.SetActor(&GetImplementation(interceptedActor));
+
+          // If there is an interception, send an interrupted event to the last consumed actor or to the actor that hit previously.
+          if(mLastConsumedActor.GetActor() &&
+              mLastConsumedActor.GetActor() != interceptedActor &&
+              mLastRenderTask &&
+              mLastPrimaryPointState != PointState::FINISHED)
+          {
+            EmitTouchSignals(mLastConsumedActor.GetActor(), *mLastRenderTask.Get(), touchEventImpl, PointState::INTERRUPTED, isGeometry);
+            mTouchDownConsumedActor.SetActor(nullptr);
+            mLastConsumedActor.SetActor(nullptr);
+          }
+          else if(mLastPrimaryHitActor.GetActor() &&
+                  mLastPrimaryHitActor.GetActor() != interceptedActor &&
+                  mLastRenderTask &&
+                  mLastPrimaryPointState != PointState::FINISHED)
+          {
+            std::list<Dali::Internal::Actor*> internalActorLists = mCandidateActorLists;
+            while(!internalActorLists.empty())
+            {
+              Actor* actorImpl = internalActorLists.back();
+              // Only emit the signal if the actor's touch signal has connections (or derived actor implementation requires touch).
+              if(actorImpl->GetTouchRequired())
+              {
+                EmitTouchSignals(actorImpl, *mLastRenderTask.Get(), touchEventImpl, PointState::INTERRUPTED, isGeometry);
+              }
+              internalActorLists.pop_back();
+            }
+          }
+        }
+
+        // Let's propagate touch events from the intercepted actor or start propagating touch events from the leaf actor.
+        consumedActor = EmitGeoTouchSignals(interceptedActor ? mInterceptedActorLists : mCandidateActorLists, touchEventHandle);
+      }
     }
     else
     {
-      // Emit the intercept touch signal
-      Dali::Actor interceptedActor = EmitInterceptTouchSignals(primaryHitActor, touchEventHandle);
-      if(interceptedActor)
+      Actor* interceptedTouchActor(mInterceptedTouchActor.GetActor());
+      if(interceptedTouchActor)
       {
-        mInterceptedTouchActor.SetActor(&GetImplementation(interceptedActor));
-        // If the child is being touched, INTERRUPTED is sent.
-        if(mLastPrimaryHitActor.GetActor() &&
-           mLastPrimaryHitActor.GetActor() != interceptedActor &&
-           mLastRenderTask &&
-           mLastPrimaryPointState != PointState::FINISHED)
-        {
-          EmitTouchSignals(mLastPrimaryHitActor.GetActor(), *mLastRenderTask.Get(), touchEventImpl, PointState::INTERRUPTED);
-          mTouchDownConsumedActor.SetActor(nullptr);
-        }
-        consumedActor = EmitTouchSignals(interceptedActor, touchEventHandle);
+        Dali::Actor interceptedTouchActorHandle(interceptedTouchActor);
+        consumedActor = EmitTouchSignals(interceptedTouchActorHandle, touchEventHandle);
       }
       else
       {
-        consumedActor = EmitTouchSignals(primaryHitActor, touchEventHandle);
+        // Emit the intercept touch signal
+        Dali::Actor interceptedActor = EmitInterceptTouchSignals(primaryHitActor, touchEventHandle);
+        if(interceptedActor)
+        {
+          mInterceptedTouchActor.SetActor(&GetImplementation(interceptedActor));
+          // If the child is being touched, INTERRUPTED is sent.
+          if(mLastPrimaryHitActor.GetActor() &&
+            mLastPrimaryHitActor.GetActor() != interceptedActor &&
+            mLastRenderTask &&
+            mLastPrimaryPointState != PointState::FINISHED)
+          {
+            EmitTouchSignals(mLastPrimaryHitActor.GetActor(), *mLastRenderTask.Get(), touchEventImpl, PointState::INTERRUPTED, isGeometry);
+            mTouchDownConsumedActor.SetActor(nullptr);
+          }
+          consumedActor = EmitTouchSignals(interceptedActor, touchEventHandle);
+        }
+        else
+        {
+          consumedActor = EmitTouchSignals(primaryHitActor, touchEventHandle);
+        }
       }
     }
+
     consumed = consumedActor ? true : false;
 
     if(primaryPointState == PointState::MOTION)
     {
-      DALI_LOG_INFO(gLogFilter, Debug::Concise, "PrimaryHitActor: (%p) id(%d), name(%s), state(%s), screenPosition(%f, %f)\n", primaryHitActor ? reinterpret_cast<void*>(&primaryHitActor.GetBaseObject()) : NULL, primaryHitActor ? primaryHitActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1, primaryHitActor ? primaryHitActor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : "", TOUCH_POINT_STATE[primaryPointState], primaryPoint.GetScreenPosition().x, primaryPoint.GetScreenPosition().y);
-      DALI_LOG_INFO(gLogFilter, Debug::Concise, "ConsumedActor:   (%p) id(%d), name(%s), state(%s)\n", consumedActor ? reinterpret_cast<void*>(&consumedActor.GetBaseObject()) : NULL, consumedActor ? consumedActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1, consumedActor ? consumedActor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : "", TOUCH_POINT_STATE[primaryPointState]);
+      DALI_LOG_INFO(gLogFilter, Debug::Concise, "PrimaryHitActor: (%p) id(%d), name(%s), state(%s), screenPosition(%f, %f), isGeo : %d \n", primaryHitActor ? reinterpret_cast<void*>(&primaryHitActor.GetBaseObject()) : NULL, primaryHitActor ? primaryHitActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1, primaryHitActor ? primaryHitActor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : "", TOUCH_POINT_STATE[primaryPointState], primaryPoint.GetScreenPosition().x, primaryPoint.GetScreenPosition().y, isGeometry);
+      DALI_LOG_INFO(gLogFilter, Debug::Concise, "ConsumedActor:   (%p) id(%d), name(%s), state(%s), isGeo : %d \n", consumedActor ? reinterpret_cast<void*>(&consumedActor.GetBaseObject()) : NULL, consumedActor ? consumedActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1, consumedActor ? consumedActor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : "", TOUCH_POINT_STATE[primaryPointState], isGeometry);
     }
     else
     {
-      DALI_LOG_RELEASE_INFO("PrimaryHitActor:(%p), id(%d), name(%s), state(%s), screenPosition(%f, %f)\n", primaryHitActor ? reinterpret_cast<void*>(&primaryHitActor.GetBaseObject()) : NULL, primaryHitActor ? primaryHitActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1, primaryHitActor ? primaryHitActor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : "", TOUCH_POINT_STATE[primaryPointState], primaryPoint.GetScreenPosition().x, primaryPoint.GetScreenPosition().y);
-      DALI_LOG_RELEASE_INFO("ConsumedActor:  (%p), id(%d), name(%s), state(%s)\n", consumedActor ? reinterpret_cast<void*>(&consumedActor.GetBaseObject()) : NULL, consumedActor ? consumedActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1, consumedActor ? consumedActor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : "", TOUCH_POINT_STATE[primaryPointState]);
+      DALI_LOG_RELEASE_INFO("PrimaryHitActor:(%p), id(%d), name(%s), state(%s), screenPosition(%f, %f), isGeo : %d \n", primaryHitActor ? reinterpret_cast<void*>(&primaryHitActor.GetBaseObject()) : NULL, primaryHitActor ? primaryHitActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1, primaryHitActor ? primaryHitActor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : "", TOUCH_POINT_STATE[primaryPointState], primaryPoint.GetScreenPosition().x, primaryPoint.GetScreenPosition().y, isGeometry);
+      DALI_LOG_RELEASE_INFO("ConsumedActor:  (%p), id(%d), name(%s), state(%s), isGeo : %d \n", consumedActor ? reinterpret_cast<void*>(&consumedActor.GetBaseObject()) : NULL, consumedActor ? consumedActor.GetProperty<int32_t>(Dali::Actor::Property::ID) : -1, consumedActor ? consumedActor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str() : "", TOUCH_POINT_STATE[primaryPointState], isGeometry);
     }
   }
 
@@ -449,52 +621,86 @@ bool TouchEventProcessor::ProcessTouchEvent(const Integration::TouchEvent& event
       Dali::Actor leaveEventConsumer;
       RenderTask& lastRenderTaskImpl = *mLastRenderTask.Get();
 
-      if(lastPrimaryHitActor &&
-         lastPrimaryHitActor != primaryHitActor &&
-         lastPrimaryHitActor != consumedActor)
+      if(isGeometry)
       {
-        if(lastPrimaryHitActor->IsHittable() && IsActuallySensitive(lastPrimaryHitActor))
+        if(lastPrimaryHitActor)
         {
-          if(lastPrimaryHitActor->GetLeaveRequired())
+          if(!lastPrimaryHitActor->IsHittable() || !IsActuallySensitive(lastPrimaryHitActor))
           {
-            DALI_LOG_RELEASE_INFO("LeaveActor(Hit): (%p) %d %s\n", reinterpret_cast<void*>(lastPrimaryHitActor), lastPrimaryHitActor->GetId(), lastPrimaryHitActor->GetName().data());
-            leaveEventConsumer = EmitTouchSignals(lastPrimaryHitActor, lastRenderTaskImpl, touchEventImpl, PointState::LEAVE);
+            // At this point mLastPrimaryHitActor was touchable and sensitive in the previous touch event process but is not in the current one.
+            // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls)
+            DALI_LOG_RELEASE_INFO("InterruptedActor(Hit):     (%p) %s\n", reinterpret_cast<void*>(lastPrimaryHitActor), lastPrimaryHitActor->GetName().data());
+            leaveEventConsumer = EmitTouchSignals(lastPrimaryHitActor, lastRenderTaskImpl, touchEventImpl, PointState::INTERRUPTED, isGeometry);
           }
         }
-        else
+
+        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.
+        if(lastConsumedActor &&
+           lastConsumedActor != lastPrimaryHitActor &&
+           lastConsumedActor != leaveEventConsumer)
         {
-          // At this point mLastPrimaryHitActor was touchable and sensitive in the previous touch event process but is not in the current one.
-          // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls)
-          DALI_LOG_RELEASE_INFO("InterruptedActor(Hit): (%p) %d %s\n", reinterpret_cast<void*>(lastPrimaryHitActor), lastPrimaryHitActor->GetId(), lastPrimaryHitActor->GetName().data());
-          leaveEventConsumer = EmitTouchSignals(lastPrimaryHitActor, lastRenderTaskImpl, touchEventImpl, PointState::INTERRUPTED);
+          if(!lastConsumedActor->IsHittable() || !IsActuallySensitive(lastConsumedActor))
+          {
+            // At this point mLastConsumedActor was touchable and sensitive in the previous touch event process but is not in the current one.
+            // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls)
+            DALI_LOG_RELEASE_INFO("InterruptedActor(Consume):     (%p) %s\n", reinterpret_cast<void*>(lastConsumedActor), lastConsumedActor->GetName().data());
+            EmitTouchSignals(mLastConsumedActor.GetActor(), lastRenderTaskImpl, touchEventImpl, PointState::INTERRUPTED, isGeometry);
+          }
         }
       }
-
-      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.
-      if(lastConsumedActor &&
-         lastConsumedActor != consumedActor &&
-         lastConsumedActor != lastPrimaryHitActor &&
-         lastConsumedActor != primaryHitActor &&
-         lastConsumedActor != leaveEventConsumer)
+      else
       {
-        if(lastConsumedActor->IsHittable() && IsActuallySensitive(lastConsumedActor))
+        if(lastPrimaryHitActor &&
+           lastPrimaryHitActor != primaryHitActor &&
+           lastPrimaryHitActor != consumedActor)
         {
-          if(lastConsumedActor->GetLeaveRequired())
+          if(lastPrimaryHitActor->IsHittable() && IsActuallySensitive(lastPrimaryHitActor))
+          {
+            if(lastPrimaryHitActor->GetLeaveRequired())
+            {
+              DALI_LOG_RELEASE_INFO("LeaveActor(Hit): (%p) %d %s\n", reinterpret_cast<void*>(lastPrimaryHitActor), lastPrimaryHitActor->GetId(), lastPrimaryHitActor->GetName().data());
+              leaveEventConsumer = EmitTouchSignals(lastPrimaryHitActor, lastRenderTaskImpl, touchEventImpl, PointState::LEAVE, isGeometry);
+            }
+          }
+          else
           {
-            DALI_LOG_RELEASE_INFO("LeaveActor(Consume): (%p) %d %s\n", reinterpret_cast<void*>(lastConsumedActor), lastConsumedActor->GetId(), lastConsumedActor->GetName().data());
-            EmitTouchSignals(lastConsumedActor, lastRenderTaskImpl, touchEventImpl, PointState::LEAVE);
+            // At this point mLastPrimaryHitActor was touchable and sensitive in the previous touch event process but is not in the current one.
+            // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls)
+            DALI_LOG_RELEASE_INFO("InterruptedActor(Hit): (%p) %d %s\n", reinterpret_cast<void*>(lastPrimaryHitActor), lastPrimaryHitActor->GetId(), lastPrimaryHitActor->GetName().data());
+            leaveEventConsumer = EmitTouchSignals(lastPrimaryHitActor, lastRenderTaskImpl, touchEventImpl, PointState::INTERRUPTED, isGeometry);
           }
         }
-        else
+
+        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.
+        if(lastConsumedActor &&
+          lastConsumedActor != consumedActor &&
+          lastConsumedActor != lastPrimaryHitActor &&
+          lastConsumedActor != primaryHitActor &&
+          lastConsumedActor != leaveEventConsumer)
         {
-          // At this point mLastConsumedActor was touchable and sensitive in the previous touch event process but is not in the current one.
-          // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls)
-          DALI_LOG_RELEASE_INFO("InterruptedActor(Consume): (%p) %d %s\n", reinterpret_cast<void*>(lastConsumedActor), lastConsumedActor->GetId(), lastConsumedActor->GetName().data());
-          EmitTouchSignals(mLastConsumedActor.GetActor(), lastRenderTaskImpl, touchEventImpl, PointState::INTERRUPTED);
+          if(lastConsumedActor->IsHittable() && IsActuallySensitive(lastConsumedActor))
+          {
+            if(lastConsumedActor->GetLeaveRequired())
+            {
+              DALI_LOG_RELEASE_INFO("LeaveActor(Consume): (%p) %d %s\n", reinterpret_cast<void*>(lastConsumedActor), lastConsumedActor->GetId(), lastConsumedActor->GetName().data());
+              EmitTouchSignals(lastConsumedActor, lastRenderTaskImpl, touchEventImpl, PointState::LEAVE, isGeometry);
+            }
+          }
+          else
+          {
+            // At this point mLastConsumedActor was touchable and sensitive in the previous touch event process but is not in the current one.
+            // An interrupted event is send to allow some actors to go back to their original state (i.e. Button controls)
+            DALI_LOG_RELEASE_INFO("InterruptedActor(Consume): (%p) %d %s\n", reinterpret_cast<void*>(lastConsumedActor), lastConsumedActor->GetId(), lastConsumedActor->GetName().data());
+            EmitTouchSignals(mLastConsumedActor.GetActor(), lastRenderTaskImpl, touchEventImpl, PointState::INTERRUPTED, isGeometry);
+          }
         }
       }
     }
@@ -520,7 +726,17 @@ bool TouchEventProcessor::ProcessTouchEvent(const Integration::TouchEvent& event
       }
       else
       {
-        mLastConsumedActor.SetActor(nullptr);
+        if(isGeometry)
+        {
+          if(lastConsumedActor && !lastConsumedActor->OnScene())
+          {
+            mLastConsumedActor.SetActor(nullptr);
+          }
+        }
+        else
+        {
+          mLastConsumedActor.SetActor(nullptr);
+        }
       }
 
       mLastRenderTask        = currentRenderTask;
@@ -553,7 +769,16 @@ bool TouchEventProcessor::ProcessTouchEvent(const Integration::TouchEvent& event
           currentPoint.SetHitActor(touchDownConsumedActorHandle);
           currentPoint.SetState(PointState::INTERRUPTED);
 
-          AllocAndEmitTouchSignals(event.time, touchDownConsumedActorHandle, currentPoint, nullptr /* Not Required for this use case */);
+          if(isGeometry)
+          {
+            std::list<Dali::Internal::Actor*> actorLists;
+            actorLists.push_back(touchDownConsumedActor);
+            GeoAllocAndEmitTouchSignals(actorLists, event.time, currentPoint, nullptr /* Not Required for this use case */);
+          }
+          else
+          {
+            AllocAndEmitTouchSignals(event.time, touchDownConsumedActorHandle, currentPoint, nullptr /* Not Required for this use case */);
+          }
         }
 
         mTouchDownConsumedActor.SetActor(nullptr);
@@ -584,31 +809,53 @@ bool TouchEventProcessor::ProcessTouchEvent(const Integration::TouchEvent& event
 
 void TouchEventProcessor::OnObservedActorDisconnected(Actor* actor)
 {
-  if(actor == mLastPrimaryHitActor.GetActor())
+  if(mScene.IsGeometryHittestEnabled() && (actor == mLastConsumedActor.GetActor() || actor == mLastPrimaryHitActor.GetActor()))
   {
     Dali::Actor actorHandle(actor);
-
     Integration::Point point;
     point.SetState(PointState::INTERRUPTED);
     point.SetHitActor(actorHandle);
-
-    TouchEventPtr touchEventImpl(new TouchEvent);
-    touchEventImpl->AddPoint(point);
-    Dali::TouchEvent touchEventHandle(touchEventImpl.Get());
-
-    Dali::Actor eventConsumer = EmitTouchSignals(actorHandle, touchEventHandle);
-
-    if(mLastConsumedActor.GetActor() != eventConsumer)
+    if(actor == mLastConsumedActor.GetActor())
     {
-      EmitTouchSignals(Dali::Actor(mLastConsumedActor.GetActor()), touchEventHandle);
+      std::list<Dali::Internal::Actor*> actorLists;
+      actorLists.push_back(mLastConsumedActor.GetActor());
+      GeoAllocAndEmitTouchSignals(actorLists, 0, point, mLastRenderTask);
+    }
+    else if(!mLastConsumedActor.GetActor())
+    {
+      GeoAllocAndEmitTouchSignals(mCandidateActorLists, 0, point, mLastRenderTask);
     }
-
     // Do not set mLastPrimaryHitActor to NULL we may be iterating through its observers
-
     mLastConsumedActor.SetActor(nullptr);
     mLastRenderTask.Reset();
     mLastPrimaryPointState = PointState::FINISHED;
   }
+  else
+  {
+    if(actor == mLastPrimaryHitActor.GetActor())
+    {
+      Dali::Actor actorHandle(actor);
+      Integration::Point point;
+      point.SetState(PointState::INTERRUPTED);
+      point.SetHitActor(actorHandle);
+
+      TouchEventPtr touchEventImpl(new TouchEvent);
+      touchEventImpl->AddPoint(point);
+      Dali::TouchEvent touchEventHandle(touchEventImpl.Get());
+
+      Dali::Actor eventConsumer = EmitTouchSignals(actorHandle, touchEventHandle);
+      if(mLastConsumedActor.GetActor() != eventConsumer)
+      {
+        EmitTouchSignals(Dali::Actor(mLastConsumedActor.GetActor()), touchEventHandle);
+      }
+
+      // Do not set mLastPrimaryHitActor to NULL we may be iterating through its observers
+      mLastConsumedActor.SetActor(nullptr);
+      mLastRenderTask.Reset();
+      mLastPrimaryPointState = PointState::FINISHED;
+    }
+  }
+
 }
 
 } // namespace Internal
index a2ed681..6ecc67b 100644 (file)
@@ -99,6 +99,8 @@ private:
   ActorObserver    mInterceptedTouchActor;  ///< Stores the intercepted actor
   RenderTaskPtr    mLastRenderTask;         ///< The RenderTask used for the last hit actor
   PointState::Type mLastPrimaryPointState;  ///< Stores the last primary point state
+  std::list<Dali::Internal::Actor*> mInterceptedActorLists;   ///< Stores the list from root to intercepted actors.
+  std::list<Dali::Internal::Actor*> mCandidateActorLists;     ///< Stores a list of actors that can be touched, from leaf actor to root.
 };
 
 } // namespace Internal