akntouchgesturefw/src/akntouchgesturefwflickrecognizer.cpp
changeset 0 2f259fa3e83a
child 14 3320e4e6e8bb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/akntouchgesturefw/src/akntouchgesturefwflickrecognizer.cpp	Tue Feb 02 01:00:49 2010 +0200
@@ -0,0 +1,565 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  Flick touch gesture recognizer.
+*
+*/
+
+#include "akntouchgesturefwdefs.h"
+#include "akntouchgesturefwdragtracer.h"
+#include "akntouchgesturefwevent.h"
+#include "akntouchgesturefwflickrecognizer.h"
+#include "akntouchgesturefwsettings.h"
+
+using namespace AknTouchGestureFw;
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Two-phased constructor.
+// ---------------------------------------------------------------------------
+//
+CAknTouchGestureFwFlickRecognizer* CAknTouchGestureFwFlickRecognizer::NewL(
+    CAknTouchGestureFwRecognitionEngine& aEngine )
+    {
+    CAknTouchGestureFwFlickRecognizer* self =
+        CAknTouchGestureFwFlickRecognizer::NewLC( aEngine );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Two-phased constructor.
+// ---------------------------------------------------------------------------
+//
+CAknTouchGestureFwFlickRecognizer* CAknTouchGestureFwFlickRecognizer::NewLC(
+    CAknTouchGestureFwRecognitionEngine& aEngine )
+    {
+    CAknTouchGestureFwFlickRecognizer* self
+        = new ( ELeave ) CAknTouchGestureFwFlickRecognizer( aEngine );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CAknTouchGestureFwFlickRecognizer::~CAknTouchGestureFwFlickRecognizer()
+    {
+    delete iDragTracer;
+    iPoints.Close();
+    }
+
+
+// ---------------------------------------------------------------------------
+// Returns the flick gesture group.
+// ---------------------------------------------------------------------------
+//
+TAknTouchGestureFwGroup CAknTouchGestureFwFlickRecognizer::GestureGroup() const
+    {
+    return EAknTouchGestureFwGroupFlick;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Cancels gesture recognition.
+// ---------------------------------------------------------------------------
+//
+void CAknTouchGestureFwFlickRecognizer::CancelRecognizing()
+    {
+    Reset();
+    }
+
+
+// ---------------------------------------------------------------------------
+// Handles single-touch pointer events.
+// ---------------------------------------------------------------------------
+//
+void CAknTouchGestureFwFlickRecognizer::HandleSinglePointerEventL(
+    const TPointerEventData& aPointerData )
+    {
+    switch ( aPointerData.iPointerEvent.iType )
+        {
+        case TPointerEvent::EButton1Down:
+            {
+            StartSingleRecognizing( 
+                    aPointerData.iPointerEvent.iPosition,
+                    aPointerData.iTimeStamp );
+            break;
+            }
+        case TPointerEvent::EDrag:
+            {
+            if ( iStartOnSingleTouchDrag )
+                {
+                // Start (via Reset) clears iStartOnSingleTouchDrag.
+                StartSingleRecognizing( 
+                    aPointerData.iPointerEvent.iPosition,
+                    aPointerData.iTimeStamp );                
+                }
+            else
+                {
+                SingleRecognizeL( 
+                    aPointerData.iPointerEvent.iPosition,
+                    aPointerData.iTimeStamp );
+                }
+            break;
+            }
+        case TPointerEvent::EButton1Up:
+            {
+            CompleteSingleRecognizingL( 
+                    aPointerData.iPointerEvent.iPosition,
+                    aPointerData.iTimeStamp,
+                    EFalse );
+            break;
+            }
+        default:
+            {
+            break;
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// Handles multi-touch pointer events.
+// ---------------------------------------------------------------------------
+//
+void CAknTouchGestureFwFlickRecognizer::HandleMultiPointerEventL(
+    const TPointerEventData& aPointerData,
+    const TPoint& aFirstPointerPosition,
+    const TPoint& /*aSecondPointerPosition*/ )
+    {
+    switch ( aPointerData.iPointerEvent.iType )
+        {
+        case TPointerEvent::EButton1Down:
+            {
+            // Completes single recognizing but does not check if
+            // flick is detected
+            CompleteSingleRecognizingL( 
+                    aFirstPointerPosition,
+                    aPointerData.iTimeStamp,
+                    ETrue );
+            break;
+            }
+        case TPointerEvent::EDrag:
+            {
+            break;
+            }
+        case TPointerEvent::EButton1Up:
+            {
+            // Upon next single touch drag, start recognition.
+            // Current position is not necessarily accurate.
+            iStartOnSingleTouchDrag = ETrue;
+            break;
+            }
+        default:
+            {
+            break;
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// C++ constructor.
+// ---------------------------------------------------------------------------
+//
+CAknTouchGestureFwFlickRecognizer::CAknTouchGestureFwFlickRecognizer(
+        CAknTouchGestureFwRecognitionEngine& aEngine )
+    : CAknTouchGestureFwBaseRecognizer( aEngine )
+    {
+    }
+
+
+// ---------------------------------------------------------------------------
+// Second-phase constructor.
+// ---------------------------------------------------------------------------
+//
+void CAknTouchGestureFwFlickRecognizer::ConstructL()
+    {
+    iDragTracer = CAknTouchGestureFwDragTracer::NewL();
+    }
+
+
+// ---------------------------------------------------------------------------
+// Starts recognizing the flick gesture.
+// ---------------------------------------------------------------------------
+//
+void CAknTouchGestureFwFlickRecognizer::StartSingleRecognizing(
+    const TPoint& aPointerPos,
+    const TTime& aTimeStamp )
+    {
+    Reset();
+    iDragTracer->Initialize( aPointerPos );
+    AddPoint( aPointerPos, aTimeStamp );
+    iDragArea.Start( aPointerPos );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Continues recognizing the flick gesture, called on drag events.
+// ---------------------------------------------------------------------------
+//
+void CAknTouchGestureFwFlickRecognizer::SingleRecognizeL(
+    const TPoint& aPointerPos,
+    const TTime& aTimeStamp )
+    {
+    AddPoint( aPointerPos, aTimeStamp );
+    iThresholdExceeded =
+        iThresholdExceeded || iDragArea.Check( aPointerPos, DragThreshold() );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Ends the flick gesture recognition.
+// ---------------------------------------------------------------------------
+//
+void CAknTouchGestureFwFlickRecognizer::CompleteSingleRecognizingL(
+    const TPoint& aPointerPos,
+    const TTime& aTimeStamp,
+    TBool aStartMultiTouch )
+    {
+    // Try to detect flick if multi touch was not started
+    if ( !aStartMultiTouch )
+        {
+        AddPoint( aPointerPos, aTimeStamp );
+        }
+
+    // Try to detect flick only if drag already detected and
+    // caller wants to detect flick.
+    if ( iThresholdExceeded && !aStartMultiTouch )
+        {
+        TAknTouchGestureFwType flickGestureType( EAknTouchGestureFwUnknown );
+        TPoint flickSpeed( 0, 0 );
+        TBool flickDetected = DetermineFlickTypeAndSpeed( flickGestureType,
+                flickSpeed );
+
+        // Send flick event if speed threshold is exceeded
+        if( flickDetected )
+            {
+            TPoint flickPosition( iPoints[ iPoints.Count() - 1 ].iPos );
+            iPoints.Reset();
+            SendFlickEventL( flickGestureType, flickPosition, flickSpeed );
+            iFlickSpeed = TPoint( 0, 0 );
+            }
+        }
+
+    Reset();
+    }
+
+
+// ---------------------------------------------------------------------------
+// Sends a flick gesture event to the observer.
+// ---------------------------------------------------------------------------
+//
+void CAknTouchGestureFwFlickRecognizer::SendFlickEventL(
+    TAknTouchGestureFwType aGestureType,
+    const TPoint& aPosition,
+    const TPoint& aSpeed )
+    {
+    TTouchFeedbackType feedbackType( FeedbackType( aGestureType ) );
+    if ( feedbackType )
+        {
+        switch ( aGestureType )
+            {
+            case EAknTouchGestureFwFlickLeft:
+            case EAknTouchGestureFwFlickRight:
+            case EAknTouchGestureFwFlickUp:
+            case EAknTouchGestureFwFlickDown:
+                {
+                ImmediateFeedback( ETouchFeedbackFlick, feedbackType );
+                break;
+                }
+            default:
+                {
+                break;
+                }
+            }
+        }
+    
+    TAknTouchGestureFwFlickEvent flick;
+    flick.SetType( aGestureType );
+    flick.SetPosition( aPosition );
+    flick.SetSpeed( aSpeed );
+    SendGestureEventL( flick );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Resets recognizer's state.
+// ---------------------------------------------------------------------------
+//
+void CAknTouchGestureFwFlickRecognizer::Reset()
+    {
+    iStartOnSingleTouchDrag = EFalse;
+    iPoints.Reset();
+    iDragArea.Reset();
+    iThresholdExceeded = EFalse;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Adds a point to the sequences of points that forms the gesture.
+// ---------------------------------------------------------------------------
+//
+void CAknTouchGestureFwFlickRecognizer::AddPoint( const TPoint& aPoint,
+    const TTime& aTimeStamp )
+    {
+    // Don't add duplicate points, but update time of latest point
+    if ( iPoints.Count() > 0 &&
+         iPoints[ iPoints.Count() - 1 ].iPos == aPoint )
+        {
+        iPoints[ iPoints.Count() - 1 ].iTime = aTimeStamp;
+        return;
+        }
+
+    TInt err = iPoints.Append( TPointEntry( aPoint, aTimeStamp ) );
+    if ( err == KErrNone )
+        {
+        // if buffer is full, remove oldest points
+        if ( iPoints.Count() > MaximumBufferLength() )
+            {
+            iPoints.Remove( 0 );
+            }
+        // Handle changes in direction.
+        // In practice, removes unnecessary points if direction changes
+        HandleDirectionChanges( aPoint );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// Checks if the point array is empty.
+// ---------------------------------------------------------------------------
+//
+TBool CAknTouchGestureFwFlickRecognizer::IsEmpty() const
+    {
+    return iPoints.Count() == 0;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Determines the direction and speed of a flick gesture.
+// ---------------------------------------------------------------------------
+//
+TBool CAknTouchGestureFwFlickRecognizer::DetermineFlickTypeAndSpeed(
+    TAknTouchGestureFwType& aFlickGestureType,
+    TPoint& aSpeed )
+    {
+    // Calculate distance and speed based on first and last
+    // point in the pointer array.
+
+    TPoint distance;
+    TPoint speed;
+    if ( !CalculateFlickParameters( distance, speed ) )
+        {
+        return EFalse;
+        }
+
+    // If speed is over threshold, this movement is assumed to be flick
+    TInt speedThreshold( FlickSpeedThreshold() );
+    if ( Abs( speed.iX ) >= speedThreshold ||
+         Abs ( speed.iY ) >= speedThreshold )
+        {
+        aFlickGestureType = EAknTouchGestureFwUnknown;
+
+        // Flick detected - determine its direction.
+        if ( Abs( distance.iX ) > Abs( distance. iY ) )
+            {
+            // Right or left
+            if ( distance.iX > 0 )
+                {
+                aFlickGestureType = EAknTouchGestureFwFlickRight;
+                }
+            else
+                {
+                aFlickGestureType = EAknTouchGestureFwFlickLeft;
+                }
+            }
+        else
+            {
+            // Up or down
+            if ( distance.iY > 0 )
+                {
+                aFlickGestureType = EAknTouchGestureFwFlickDown;
+                }
+            else
+                {
+                aFlickGestureType = EAknTouchGestureFwFlickUp;
+                }
+            }
+
+        // Set flick speed.
+        aSpeed = speed;
+
+        return ETrue;
+        }
+
+    return EFalse;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Calculates the flick distance and speed.
+// ---------------------------------------------------------------------------
+//
+TBool CAknTouchGestureFwFlickRecognizer::CalculateFlickParameters(
+    TPoint& aDistance,
+    TPoint& aSpeed )
+    {
+    // Check that there are at least 2 points to calculate parameters.
+    TInt count = iPoints.Count();
+    if ( count < 2 )
+        {
+        return EFalse;
+        }
+
+    // Flick detection is done using latest points added during last
+    // n seconds.
+    // Ignore all points that are older than n seconds
+    TTime endTime = iPoints[ count - 1 ].iTime;
+    TInt startIndex = -1;
+
+    for ( TInt i = 0; i < count - 1; i++ )
+        {
+        TInt elapsedTime = Elapsed( iPoints[ i ].iTime, endTime ).Int();
+
+        if ( elapsedTime < FlickDetectionTime() )
+            {
+            startIndex = i;
+            break;
+            }
+        }
+
+    // If there is no new start point (within n seconds) found,
+    // it means that time between two latest points have been over this time
+    // and movement can't be flick
+    if ( startIndex == -1 )
+        {
+        return EFalse;
+        }
+
+    // Calculate distance and speed based on new start- and endpoints
+    aDistance = iPoints[ count - 1 ].iPos - iPoints[ startIndex ].iPos;
+
+    TInt elapsedTime = Elapsed( iPoints[ startIndex ].iTime,
+                                iPoints[ count - 1 ].iTime ).Int();
+
+    if ( elapsedTime <= 0 )
+        {
+        return EFalse;
+        }
+
+    aSpeed.iX = KMicroSecondsInSecond * aDistance.iX / elapsedTime;
+    aSpeed.iY = KMicroSecondsInSecond * aDistance.iY / elapsedTime;
+
+    return ETrue;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Called when drag direction changes to clear the previous points.
+// ---------------------------------------------------------------------------
+//
+void CAknTouchGestureFwFlickRecognizer::HandleDirectionChanges(
+    const TPoint& aPosition )
+    {
+    // Sensitivity tells how many points are needed to reversed direction
+    // to detect change in direction.
+    TInt sensitivity( DirectionChangeSensitivity() );
+
+    if ( iDragTracer->IsDirectionChanged( aPosition, sensitivity ) )
+        {
+        // Remove all previous points so that latest points which
+        // are to reversed direction + point where direction changes are left.
+        RemovePreviousPoints( sensitivity + 1 );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// Calculates the elapsed time from the specified start time and end time.
+// static
+// ---------------------------------------------------------------------------
+//
+TTimeIntervalMicroSeconds32 CAknTouchGestureFwFlickRecognizer::Elapsed(
+    const TTime& aStartTime,
+    const TTime& aEndTime )
+    {
+    return aEndTime.MicroSecondsFrom( aStartTime ).Int64();
+    }
+
+
+// ---------------------------------------------------------------------------
+// Removes the specified amount of stored points from the array.
+// ---------------------------------------------------------------------------
+//
+void CAknTouchGestureFwFlickRecognizer::RemovePreviousPoints(
+    TInt aNumberOfPoints )
+    {
+    TInt count = iPoints.Count();
+    if ( count - aNumberOfPoints > 0 )
+        {
+        for ( TInt i = 0; i < count - aNumberOfPoints; i++ )
+            {
+            iPoints.Remove( 0 );
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknTouchGestureFwFlickRecognizer::MaximumBufferLength
+// ---------------------------------------------------------------------------
+//
+TInt CAknTouchGestureFwFlickRecognizer::MaximumBufferLength() const
+    {
+    return Settings().FlickBuffer();
+    }
+
+
+// ---------------------------------------------------------------------------
+// Returns the current value of flick speed threshold setting.
+// ---------------------------------------------------------------------------
+//
+TInt CAknTouchGestureFwFlickRecognizer::FlickSpeedThreshold() const
+    {
+    return Settings().FlickSpeedThreshold();
+    }
+
+
+// ---------------------------------------------------------------------------
+// Returns the current value of flick detection time setting.
+// ---------------------------------------------------------------------------
+//
+TInt CAknTouchGestureFwFlickRecognizer::FlickDetectionTime() const
+    {
+    return Settings().FlickDetectionTime() * KMicroSecondsInMilliSecond;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Returns the current value of direction change sensitivity setting.
+// ---------------------------------------------------------------------------
+//
+TInt CAknTouchGestureFwFlickRecognizer::DirectionChangeSensitivity() const
+    {
+    return Settings().FlickChangeSensitivity();
+    }
+
+// End of File