X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Faccessibility%2Fcommon%2Faccessibility-gesture-detector.cpp;h=b87207743ca4705dd31ba53aa15ae97bfddb01c0;hb=5b648302d22f4373c4993e9daa35e2ea7de1d758;hp=80103482d3c334853cab741aa819e244c7e482fe;hpb=761f75cd51351b7a4e072130f4a2ad0b3e3231bb;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git diff --git a/dali/internal/accessibility/common/accessibility-gesture-detector.cpp b/dali/internal/accessibility/common/accessibility-gesture-detector.cpp old mode 100644 new mode 100755 index 8010348..b872077 --- a/dali/internal/accessibility/common/accessibility-gesture-detector.cpp +++ b/dali/internal/accessibility/common/accessibility-gesture-detector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -19,7 +19,12 @@ #include // EXTERNAL INCLUDES -#include +#include + +#include + +#include + namespace Dali { @@ -30,10 +35,32 @@ namespace Internal namespace Adaptor { +namespace +{ + const float MINIMUM_MOTION_DISTANCE_BEFORE_PAN( 15.0f ); + const float MINIMUM_MOTION_DISTANCE_BEFORE_PAN_SQUARED( MINIMUM_MOTION_DISTANCE_BEFORE_PAN * MINIMUM_MOTION_DISTANCE_BEFORE_PAN ); + const float MINIMUM_MOTION_DISTANCE_TO_THRESHOLD_ADJUSTMENTS_RATIO( 2.0f / 3.0f ); + const unsigned long MAXIMUM_TIME_DIFF_ALLOWED( 500 ); + const unsigned long MINIMUM_TIME_BEFORE_THRESHOLD_ADJUSTMENTS( 100 ); + const unsigned int MINIMUM_MOTION_EVENTS_BEFORE_PAN(2); + const unsigned int MINIMUM_TOUCHES_BEFORE_PAN(1); + const unsigned int MAXIMUM_TOUCHES_BEFORE_PAN(1); +} // unnamed namespace + + AccessibilityGestureDetector::AccessibilityGestureDetector() -: PanGestureDetectorBase(Vector2::ZERO, Integration::PanGestureRequest(), NULL), - mGestureHandler(NULL), - mPanning(false) +: mState( Clear ), + mScene(nullptr), + mGestureHandler(nullptr), + mPanning(false), + mThresholdAdjustmentsRemaining( 0 ), + mThresholdTotalAdjustments( MINIMUM_MOTION_DISTANCE_BEFORE_PAN * MINIMUM_MOTION_DISTANCE_TO_THRESHOLD_ADJUSTMENTS_RATIO ), + mPrimaryTouchDownTime( 0 ), + mMinimumTouchesRequired( MINIMUM_TOUCHES_BEFORE_PAN ), + mMaximumTouchesRequired( MAXIMUM_TOUCHES_BEFORE_PAN ), + mMinimumDistanceSquared( MINIMUM_MOTION_DISTANCE_BEFORE_PAN_SQUARED ), + mMinimumMotionEvents( MINIMUM_MOTION_EVENTS_BEFORE_PAN ), + mMotionEvents( 0 ) { } @@ -46,11 +73,11 @@ void AccessibilityGestureDetector::SetGestureHandler(AccessibilityGestureHandler mGestureHandler = &handler; } -void AccessibilityGestureDetector::EmitPan(const Integration::PanGestureEvent gesture) +void AccessibilityGestureDetector::EmitPan(const AccessibilityGestureEvent gesture) { if( mGestureHandler ) { - if(gesture.state == Gesture::Started) + if(gesture.state == AccessibilityGestureEvent::Started) { mPanning = true; } @@ -59,8 +86,8 @@ void AccessibilityGestureDetector::EmitPan(const Integration::PanGestureEvent ge { mGestureHandler->HandlePanGesture(gesture); - if( (gesture.state == Gesture::Finished) || - (gesture.state == Gesture::Cancelled) ) + if( (gesture.state == AccessibilityGestureEvent::Finished) || + (gesture.state == AccessibilityGestureEvent::Cancelled) ) { mPanning = false; } @@ -68,6 +95,236 @@ void AccessibilityGestureDetector::EmitPan(const Integration::PanGestureEvent ge } } +void AccessibilityGestureDetector::SendEvent(const Integration::TouchEvent& event) +{ + PointState::Type primaryPointState(event.points[0].GetState()); + + if (primaryPointState == PointState::INTERRUPTED) + { + if ( ( mState == Started ) || ( mState == Possible ) ) + { + // If our pan had started and we are interrupted, then tell Core that pan is cancelled. + mTouchEvents.push_back(event); + SendPan(AccessibilityGestureEvent::Cancelled, event); + } + mState = Clear; // We should change our state to Clear. + mTouchEvents.clear(); + } + else + { + switch (mState) + { + case Clear: + { + if ( ( primaryPointState == PointState::DOWN ) || ( primaryPointState == PointState::STATIONARY ) ) + { + mPrimaryTouchDownLocation = event.points[0].GetScreenPosition(); + mPrimaryTouchDownTime = event.time; + mMotionEvents = 0; + if (event.GetPointCount() == mMinimumTouchesRequired) + { + // We have satisfied the minimum touches required for a pan, tell core that a gesture may be possible and change our state accordingly. + mState = Possible; + SendPan(AccessibilityGestureEvent::Possible, event); + } + + mTouchEvents.push_back(event); + } + break; + } + + case Possible: + { + unsigned int pointCount(event.GetPointCount()); + if ( (pointCount >= mMinimumTouchesRequired)&&(pointCount <= mMaximumTouchesRequired) ) + { + if (primaryPointState == PointState::MOTION) + { + mTouchEvents.push_back(event); + mMotionEvents++; + + Vector2 delta(event.points[0].GetScreenPosition() - mPrimaryTouchDownLocation); + + if ( ( mMotionEvents >= mMinimumMotionEvents ) && + ( delta.LengthSquared() >= static_cast( mMinimumDistanceSquared ) ) ) + { + // If the touch point(s) have moved enough distance to be considered a pan, then tell Core that the pan gesture has started and change our state accordingly. + mState = Started; + SendPan(AccessibilityGestureEvent::Started, event); + } + } + else if (primaryPointState == PointState::UP) + { + Vector2 delta(event.points[0].GetScreenPosition() - mPrimaryTouchDownLocation); + if (delta.LengthSquared() >= static_cast( mMinimumDistanceSquared ) ) + { + SendPan(AccessibilityGestureEvent::Started, event); + mTouchEvents.push_back(event); + SendPan(AccessibilityGestureEvent::Finished, event); + } + else + { + // If we have lifted the primary touch point then tell core the pan is cancelled and change our state to Clear. + SendPan(AccessibilityGestureEvent::Cancelled, event); + } + mState = Clear; + mTouchEvents.clear(); + } + } + else + { + // We do not satisfy pan conditions, tell Core our Gesture has been cancelled. + SendPan(AccessibilityGestureEvent::Cancelled, event); + + if (pointCount == 1 && primaryPointState == PointState::UP) + { + // If we have lifted the primary touch point, then change our state to Clear... + mState = Clear; + mTouchEvents.clear(); + } + else + { + // ...otherwise change it to Failed. + mState = Failed; + } + } + break; + } + + case Started: + { + mTouchEvents.push_back(event); + + unsigned int pointCount(event.GetPointCount()); + if ( (pointCount >= mMinimumTouchesRequired)&&(pointCount <= mMaximumTouchesRequired) ) + { + switch (primaryPointState) + { + case PointState::MOTION: + // Pan is continuing, tell Core. + SendPan(AccessibilityGestureEvent::Continuing, event); + break; + + case PointState::UP: + // Pan is finally finished when our primary point is lifted, tell Core and change our state to Clear. + SendPan(AccessibilityGestureEvent::Finished, event); + mState = Clear; + mTouchEvents.clear(); + break; + + case PointState::STATIONARY: + if (pointCount == mMinimumTouchesRequired) + { + Integration::PointContainerConstIterator iter = event.points.begin() + 1; // We already know the state of the first point + for(; iter != event.points.end(); ++iter) + { + if(iter->GetState() == PointState::UP) + { + // The number of touch points will be less than the minimum required. Inform core and change our state to Finished. + SendPan(AccessibilityGestureEvent::Finished, event); + mState = Finished; + break; + } + } + } + break; + + default: + break; + } + } + else + { + // We have gone outside of the pan requirements, inform Core that the gesture is finished. + SendPan(AccessibilityGestureEvent::Finished, event); + + if (pointCount == 1 && primaryPointState == PointState::UP) + { + // If this was the primary point being released, then we change our state back to Clear... + mState = Clear; + mTouchEvents.clear(); + } + else + { + // ...otherwise we change it to Finished. + mState = Finished; + } + } + break; + } + + case Finished: + case Failed: + { + if (primaryPointState == PointState::UP) + { + // Change our state back to clear when the primary touch point is released. + mState = Clear; + mTouchEvents.clear(); + } + break; + } + } + } +} + +void AccessibilityGestureDetector::SendPan(AccessibilityGestureEvent::State state, const Integration::TouchEvent& currentEvent) +{ + AccessibilityGestureEvent gesture(state); + gesture.currentPosition = currentEvent.points[0].GetScreenPosition(); + gesture.numberOfTouches = currentEvent.GetPointCount(); + + if ( mTouchEvents.size() > 1 ) + { + // Get the second last event in the queue, the last one is the current event + const Integration::TouchEvent& previousEvent( *( mTouchEvents.rbegin() + 1 ) ); + + Vector2 previousPosition( mPreviousPosition ); + uint32_t previousTime( previousEvent.time ); + + // If we've just started then we want to remove the threshold from Core calculations. + if ( state == AccessibilityGestureEvent::Started ) + { + previousPosition = mPrimaryTouchDownLocation; + previousTime = mPrimaryTouchDownTime; + + // If it's a slow pan, we do not want to phase in the threshold over the first few pan-events + // A slow pan is defined as one that starts the specified number of milliseconds after the down-event + if ( ( currentEvent.time - previousTime ) > MINIMUM_TIME_BEFORE_THRESHOLD_ADJUSTMENTS ) + { + mThresholdAdjustmentsRemaining = mThresholdTotalAdjustments; + mThresholdAdjustmentPerFrame = ( gesture.currentPosition - previousPosition ) / static_cast( mThresholdTotalAdjustments ); + } + else + { + mThresholdAdjustmentsRemaining = 0; + mThresholdAdjustmentPerFrame = Vector2::ZERO; + } + } + + gesture.previousPosition = previousPosition; + gesture.timeDelta = currentEvent.time - previousTime; + + // Apply the threshold with a phased approach + if ( mThresholdAdjustmentsRemaining > 0 ) + { + --mThresholdAdjustmentsRemaining; + gesture.currentPosition -= mThresholdAdjustmentPerFrame * static_cast( mThresholdAdjustmentsRemaining ); + } + + mPreviousPosition = gesture.currentPosition; + } + else + { + gesture.previousPosition = gesture.currentPosition; + gesture.timeDelta = 0; + } + + gesture.time = currentEvent.time; + + EmitPan(gesture); +} + } // namespace Adaptor } // namespace Internal