akntouchgesturefw/src/akntouchgesturefwflickrecognizer.cpp
changeset 0 2f259fa3e83a
child 14 3320e4e6e8bb
equal deleted inserted replaced
-1:000000000000 0:2f259fa3e83a
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Flick touch gesture recognizer.
       
    15 *
       
    16 */
       
    17 
       
    18 #include "akntouchgesturefwdefs.h"
       
    19 #include "akntouchgesturefwdragtracer.h"
       
    20 #include "akntouchgesturefwevent.h"
       
    21 #include "akntouchgesturefwflickrecognizer.h"
       
    22 #include "akntouchgesturefwsettings.h"
       
    23 
       
    24 using namespace AknTouchGestureFw;
       
    25 
       
    26 
       
    27 // ======== MEMBER FUNCTIONS ========
       
    28 
       
    29 // ---------------------------------------------------------------------------
       
    30 // Two-phased constructor.
       
    31 // ---------------------------------------------------------------------------
       
    32 //
       
    33 CAknTouchGestureFwFlickRecognizer* CAknTouchGestureFwFlickRecognizer::NewL(
       
    34     CAknTouchGestureFwRecognitionEngine& aEngine )
       
    35     {
       
    36     CAknTouchGestureFwFlickRecognizer* self =
       
    37         CAknTouchGestureFwFlickRecognizer::NewLC( aEngine );
       
    38     CleanupStack::Pop( self );
       
    39     return self;
       
    40     }
       
    41 
       
    42 
       
    43 // ---------------------------------------------------------------------------
       
    44 // Two-phased constructor.
       
    45 // ---------------------------------------------------------------------------
       
    46 //
       
    47 CAknTouchGestureFwFlickRecognizer* CAknTouchGestureFwFlickRecognizer::NewLC(
       
    48     CAknTouchGestureFwRecognitionEngine& aEngine )
       
    49     {
       
    50     CAknTouchGestureFwFlickRecognizer* self
       
    51         = new ( ELeave ) CAknTouchGestureFwFlickRecognizer( aEngine );
       
    52     CleanupStack::PushL( self );
       
    53     self->ConstructL();
       
    54     return self;
       
    55     }
       
    56 
       
    57 
       
    58 // ---------------------------------------------------------------------------
       
    59 // Destructor
       
    60 // ---------------------------------------------------------------------------
       
    61 //
       
    62 CAknTouchGestureFwFlickRecognizer::~CAknTouchGestureFwFlickRecognizer()
       
    63     {
       
    64     delete iDragTracer;
       
    65     iPoints.Close();
       
    66     }
       
    67 
       
    68 
       
    69 // ---------------------------------------------------------------------------
       
    70 // Returns the flick gesture group.
       
    71 // ---------------------------------------------------------------------------
       
    72 //
       
    73 TAknTouchGestureFwGroup CAknTouchGestureFwFlickRecognizer::GestureGroup() const
       
    74     {
       
    75     return EAknTouchGestureFwGroupFlick;
       
    76     }
       
    77 
       
    78 
       
    79 // ---------------------------------------------------------------------------
       
    80 // Cancels gesture recognition.
       
    81 // ---------------------------------------------------------------------------
       
    82 //
       
    83 void CAknTouchGestureFwFlickRecognizer::CancelRecognizing()
       
    84     {
       
    85     Reset();
       
    86     }
       
    87 
       
    88 
       
    89 // ---------------------------------------------------------------------------
       
    90 // Handles single-touch pointer events.
       
    91 // ---------------------------------------------------------------------------
       
    92 //
       
    93 void CAknTouchGestureFwFlickRecognizer::HandleSinglePointerEventL(
       
    94     const TPointerEventData& aPointerData )
       
    95     {
       
    96     switch ( aPointerData.iPointerEvent.iType )
       
    97         {
       
    98         case TPointerEvent::EButton1Down:
       
    99             {
       
   100             StartSingleRecognizing( 
       
   101                     aPointerData.iPointerEvent.iPosition,
       
   102                     aPointerData.iTimeStamp );
       
   103             break;
       
   104             }
       
   105         case TPointerEvent::EDrag:
       
   106             {
       
   107             if ( iStartOnSingleTouchDrag )
       
   108                 {
       
   109                 // Start (via Reset) clears iStartOnSingleTouchDrag.
       
   110                 StartSingleRecognizing( 
       
   111                     aPointerData.iPointerEvent.iPosition,
       
   112                     aPointerData.iTimeStamp );                
       
   113                 }
       
   114             else
       
   115                 {
       
   116                 SingleRecognizeL( 
       
   117                     aPointerData.iPointerEvent.iPosition,
       
   118                     aPointerData.iTimeStamp );
       
   119                 }
       
   120             break;
       
   121             }
       
   122         case TPointerEvent::EButton1Up:
       
   123             {
       
   124             CompleteSingleRecognizingL( 
       
   125                     aPointerData.iPointerEvent.iPosition,
       
   126                     aPointerData.iTimeStamp,
       
   127                     EFalse );
       
   128             break;
       
   129             }
       
   130         default:
       
   131             {
       
   132             break;
       
   133             }
       
   134         }
       
   135     }
       
   136 
       
   137 
       
   138 // ---------------------------------------------------------------------------
       
   139 // Handles multi-touch pointer events.
       
   140 // ---------------------------------------------------------------------------
       
   141 //
       
   142 void CAknTouchGestureFwFlickRecognizer::HandleMultiPointerEventL(
       
   143     const TPointerEventData& aPointerData,
       
   144     const TPoint& aFirstPointerPosition,
       
   145     const TPoint& /*aSecondPointerPosition*/ )
       
   146     {
       
   147     switch ( aPointerData.iPointerEvent.iType )
       
   148         {
       
   149         case TPointerEvent::EButton1Down:
       
   150             {
       
   151             // Completes single recognizing but does not check if
       
   152             // flick is detected
       
   153             CompleteSingleRecognizingL( 
       
   154                     aFirstPointerPosition,
       
   155                     aPointerData.iTimeStamp,
       
   156                     ETrue );
       
   157             break;
       
   158             }
       
   159         case TPointerEvent::EDrag:
       
   160             {
       
   161             break;
       
   162             }
       
   163         case TPointerEvent::EButton1Up:
       
   164             {
       
   165             // Upon next single touch drag, start recognition.
       
   166             // Current position is not necessarily accurate.
       
   167             iStartOnSingleTouchDrag = ETrue;
       
   168             break;
       
   169             }
       
   170         default:
       
   171             {
       
   172             break;
       
   173             }
       
   174         }
       
   175     }
       
   176 
       
   177 
       
   178 // ---------------------------------------------------------------------------
       
   179 // C++ constructor.
       
   180 // ---------------------------------------------------------------------------
       
   181 //
       
   182 CAknTouchGestureFwFlickRecognizer::CAknTouchGestureFwFlickRecognizer(
       
   183         CAknTouchGestureFwRecognitionEngine& aEngine )
       
   184     : CAknTouchGestureFwBaseRecognizer( aEngine )
       
   185     {
       
   186     }
       
   187 
       
   188 
       
   189 // ---------------------------------------------------------------------------
       
   190 // Second-phase constructor.
       
   191 // ---------------------------------------------------------------------------
       
   192 //
       
   193 void CAknTouchGestureFwFlickRecognizer::ConstructL()
       
   194     {
       
   195     iDragTracer = CAknTouchGestureFwDragTracer::NewL();
       
   196     }
       
   197 
       
   198 
       
   199 // ---------------------------------------------------------------------------
       
   200 // Starts recognizing the flick gesture.
       
   201 // ---------------------------------------------------------------------------
       
   202 //
       
   203 void CAknTouchGestureFwFlickRecognizer::StartSingleRecognizing(
       
   204     const TPoint& aPointerPos,
       
   205     const TTime& aTimeStamp )
       
   206     {
       
   207     Reset();
       
   208     iDragTracer->Initialize( aPointerPos );
       
   209     AddPoint( aPointerPos, aTimeStamp );
       
   210     iDragArea.Start( aPointerPos );
       
   211     }
       
   212 
       
   213 
       
   214 // ---------------------------------------------------------------------------
       
   215 // Continues recognizing the flick gesture, called on drag events.
       
   216 // ---------------------------------------------------------------------------
       
   217 //
       
   218 void CAknTouchGestureFwFlickRecognizer::SingleRecognizeL(
       
   219     const TPoint& aPointerPos,
       
   220     const TTime& aTimeStamp )
       
   221     {
       
   222     AddPoint( aPointerPos, aTimeStamp );
       
   223     iThresholdExceeded =
       
   224         iThresholdExceeded || iDragArea.Check( aPointerPos, DragThreshold() );
       
   225     }
       
   226 
       
   227 
       
   228 // ---------------------------------------------------------------------------
       
   229 // Ends the flick gesture recognition.
       
   230 // ---------------------------------------------------------------------------
       
   231 //
       
   232 void CAknTouchGestureFwFlickRecognizer::CompleteSingleRecognizingL(
       
   233     const TPoint& aPointerPos,
       
   234     const TTime& aTimeStamp,
       
   235     TBool aStartMultiTouch )
       
   236     {
       
   237     // Try to detect flick if multi touch was not started
       
   238     if ( !aStartMultiTouch )
       
   239         {
       
   240         AddPoint( aPointerPos, aTimeStamp );
       
   241         }
       
   242 
       
   243     // Try to detect flick only if drag already detected and
       
   244     // caller wants to detect flick.
       
   245     if ( iThresholdExceeded && !aStartMultiTouch )
       
   246         {
       
   247         TAknTouchGestureFwType flickGestureType( EAknTouchGestureFwUnknown );
       
   248         TPoint flickSpeed( 0, 0 );
       
   249         TBool flickDetected = DetermineFlickTypeAndSpeed( flickGestureType,
       
   250                 flickSpeed );
       
   251 
       
   252         // Send flick event if speed threshold is exceeded
       
   253         if( flickDetected )
       
   254             {
       
   255             TPoint flickPosition( iPoints[ iPoints.Count() - 1 ].iPos );
       
   256             iPoints.Reset();
       
   257             SendFlickEventL( flickGestureType, flickPosition, flickSpeed );
       
   258             iFlickSpeed = TPoint( 0, 0 );
       
   259             }
       
   260         }
       
   261 
       
   262     Reset();
       
   263     }
       
   264 
       
   265 
       
   266 // ---------------------------------------------------------------------------
       
   267 // Sends a flick gesture event to the observer.
       
   268 // ---------------------------------------------------------------------------
       
   269 //
       
   270 void CAknTouchGestureFwFlickRecognizer::SendFlickEventL(
       
   271     TAknTouchGestureFwType aGestureType,
       
   272     const TPoint& aPosition,
       
   273     const TPoint& aSpeed )
       
   274     {
       
   275     TTouchFeedbackType feedbackType( FeedbackType( aGestureType ) );
       
   276     if ( feedbackType )
       
   277         {
       
   278         switch ( aGestureType )
       
   279             {
       
   280             case EAknTouchGestureFwFlickLeft:
       
   281             case EAknTouchGestureFwFlickRight:
       
   282             case EAknTouchGestureFwFlickUp:
       
   283             case EAknTouchGestureFwFlickDown:
       
   284                 {
       
   285                 ImmediateFeedback( ETouchFeedbackFlick, feedbackType );
       
   286                 break;
       
   287                 }
       
   288             default:
       
   289                 {
       
   290                 break;
       
   291                 }
       
   292             }
       
   293         }
       
   294     
       
   295     TAknTouchGestureFwFlickEvent flick;
       
   296     flick.SetType( aGestureType );
       
   297     flick.SetPosition( aPosition );
       
   298     flick.SetSpeed( aSpeed );
       
   299     SendGestureEventL( flick );
       
   300     }
       
   301 
       
   302 
       
   303 // ---------------------------------------------------------------------------
       
   304 // Resets recognizer's state.
       
   305 // ---------------------------------------------------------------------------
       
   306 //
       
   307 void CAknTouchGestureFwFlickRecognizer::Reset()
       
   308     {
       
   309     iStartOnSingleTouchDrag = EFalse;
       
   310     iPoints.Reset();
       
   311     iDragArea.Reset();
       
   312     iThresholdExceeded = EFalse;
       
   313     }
       
   314 
       
   315 
       
   316 // ---------------------------------------------------------------------------
       
   317 // Adds a point to the sequences of points that forms the gesture.
       
   318 // ---------------------------------------------------------------------------
       
   319 //
       
   320 void CAknTouchGestureFwFlickRecognizer::AddPoint( const TPoint& aPoint,
       
   321     const TTime& aTimeStamp )
       
   322     {
       
   323     // Don't add duplicate points, but update time of latest point
       
   324     if ( iPoints.Count() > 0 &&
       
   325          iPoints[ iPoints.Count() - 1 ].iPos == aPoint )
       
   326         {
       
   327         iPoints[ iPoints.Count() - 1 ].iTime = aTimeStamp;
       
   328         return;
       
   329         }
       
   330 
       
   331     TInt err = iPoints.Append( TPointEntry( aPoint, aTimeStamp ) );
       
   332     if ( err == KErrNone )
       
   333         {
       
   334         // if buffer is full, remove oldest points
       
   335         if ( iPoints.Count() > MaximumBufferLength() )
       
   336             {
       
   337             iPoints.Remove( 0 );
       
   338             }
       
   339         // Handle changes in direction.
       
   340         // In practice, removes unnecessary points if direction changes
       
   341         HandleDirectionChanges( aPoint );
       
   342         }
       
   343     }
       
   344 
       
   345 
       
   346 // ---------------------------------------------------------------------------
       
   347 // Checks if the point array is empty.
       
   348 // ---------------------------------------------------------------------------
       
   349 //
       
   350 TBool CAknTouchGestureFwFlickRecognizer::IsEmpty() const
       
   351     {
       
   352     return iPoints.Count() == 0;
       
   353     }
       
   354 
       
   355 
       
   356 // ---------------------------------------------------------------------------
       
   357 // Determines the direction and speed of a flick gesture.
       
   358 // ---------------------------------------------------------------------------
       
   359 //
       
   360 TBool CAknTouchGestureFwFlickRecognizer::DetermineFlickTypeAndSpeed(
       
   361     TAknTouchGestureFwType& aFlickGestureType,
       
   362     TPoint& aSpeed )
       
   363     {
       
   364     // Calculate distance and speed based on first and last
       
   365     // point in the pointer array.
       
   366 
       
   367     TPoint distance;
       
   368     TPoint speed;
       
   369     if ( !CalculateFlickParameters( distance, speed ) )
       
   370         {
       
   371         return EFalse;
       
   372         }
       
   373 
       
   374     // If speed is over threshold, this movement is assumed to be flick
       
   375     TInt speedThreshold( FlickSpeedThreshold() );
       
   376     if ( Abs( speed.iX ) >= speedThreshold ||
       
   377          Abs ( speed.iY ) >= speedThreshold )
       
   378         {
       
   379         aFlickGestureType = EAknTouchGestureFwUnknown;
       
   380 
       
   381         // Flick detected - determine its direction.
       
   382         if ( Abs( distance.iX ) > Abs( distance. iY ) )
       
   383             {
       
   384             // Right or left
       
   385             if ( distance.iX > 0 )
       
   386                 {
       
   387                 aFlickGestureType = EAknTouchGestureFwFlickRight;
       
   388                 }
       
   389             else
       
   390                 {
       
   391                 aFlickGestureType = EAknTouchGestureFwFlickLeft;
       
   392                 }
       
   393             }
       
   394         else
       
   395             {
       
   396             // Up or down
       
   397             if ( distance.iY > 0 )
       
   398                 {
       
   399                 aFlickGestureType = EAknTouchGestureFwFlickDown;
       
   400                 }
       
   401             else
       
   402                 {
       
   403                 aFlickGestureType = EAknTouchGestureFwFlickUp;
       
   404                 }
       
   405             }
       
   406 
       
   407         // Set flick speed.
       
   408         aSpeed = speed;
       
   409 
       
   410         return ETrue;
       
   411         }
       
   412 
       
   413     return EFalse;
       
   414     }
       
   415 
       
   416 
       
   417 // ---------------------------------------------------------------------------
       
   418 // Calculates the flick distance and speed.
       
   419 // ---------------------------------------------------------------------------
       
   420 //
       
   421 TBool CAknTouchGestureFwFlickRecognizer::CalculateFlickParameters(
       
   422     TPoint& aDistance,
       
   423     TPoint& aSpeed )
       
   424     {
       
   425     // Check that there are at least 2 points to calculate parameters.
       
   426     TInt count = iPoints.Count();
       
   427     if ( count < 2 )
       
   428         {
       
   429         return EFalse;
       
   430         }
       
   431 
       
   432     // Flick detection is done using latest points added during last
       
   433     // n seconds.
       
   434     // Ignore all points that are older than n seconds
       
   435     TTime endTime = iPoints[ count - 1 ].iTime;
       
   436     TInt startIndex = -1;
       
   437 
       
   438     for ( TInt i = 0; i < count - 1; i++ )
       
   439         {
       
   440         TInt elapsedTime = Elapsed( iPoints[ i ].iTime, endTime ).Int();
       
   441 
       
   442         if ( elapsedTime < FlickDetectionTime() )
       
   443             {
       
   444             startIndex = i;
       
   445             break;
       
   446             }
       
   447         }
       
   448 
       
   449     // If there is no new start point (within n seconds) found,
       
   450     // it means that time between two latest points have been over this time
       
   451     // and movement can't be flick
       
   452     if ( startIndex == -1 )
       
   453         {
       
   454         return EFalse;
       
   455         }
       
   456 
       
   457     // Calculate distance and speed based on new start- and endpoints
       
   458     aDistance = iPoints[ count - 1 ].iPos - iPoints[ startIndex ].iPos;
       
   459 
       
   460     TInt elapsedTime = Elapsed( iPoints[ startIndex ].iTime,
       
   461                                 iPoints[ count - 1 ].iTime ).Int();
       
   462 
       
   463     if ( elapsedTime <= 0 )
       
   464         {
       
   465         return EFalse;
       
   466         }
       
   467 
       
   468     aSpeed.iX = KMicroSecondsInSecond * aDistance.iX / elapsedTime;
       
   469     aSpeed.iY = KMicroSecondsInSecond * aDistance.iY / elapsedTime;
       
   470 
       
   471     return ETrue;
       
   472     }
       
   473 
       
   474 
       
   475 // ---------------------------------------------------------------------------
       
   476 // Called when drag direction changes to clear the previous points.
       
   477 // ---------------------------------------------------------------------------
       
   478 //
       
   479 void CAknTouchGestureFwFlickRecognizer::HandleDirectionChanges(
       
   480     const TPoint& aPosition )
       
   481     {
       
   482     // Sensitivity tells how many points are needed to reversed direction
       
   483     // to detect change in direction.
       
   484     TInt sensitivity( DirectionChangeSensitivity() );
       
   485 
       
   486     if ( iDragTracer->IsDirectionChanged( aPosition, sensitivity ) )
       
   487         {
       
   488         // Remove all previous points so that latest points which
       
   489         // are to reversed direction + point where direction changes are left.
       
   490         RemovePreviousPoints( sensitivity + 1 );
       
   491         }
       
   492     }
       
   493 
       
   494 
       
   495 // ---------------------------------------------------------------------------
       
   496 // Calculates the elapsed time from the specified start time and end time.
       
   497 // static
       
   498 // ---------------------------------------------------------------------------
       
   499 //
       
   500 TTimeIntervalMicroSeconds32 CAknTouchGestureFwFlickRecognizer::Elapsed(
       
   501     const TTime& aStartTime,
       
   502     const TTime& aEndTime )
       
   503     {
       
   504     return aEndTime.MicroSecondsFrom( aStartTime ).Int64();
       
   505     }
       
   506 
       
   507 
       
   508 // ---------------------------------------------------------------------------
       
   509 // Removes the specified amount of stored points from the array.
       
   510 // ---------------------------------------------------------------------------
       
   511 //
       
   512 void CAknTouchGestureFwFlickRecognizer::RemovePreviousPoints(
       
   513     TInt aNumberOfPoints )
       
   514     {
       
   515     TInt count = iPoints.Count();
       
   516     if ( count - aNumberOfPoints > 0 )
       
   517         {
       
   518         for ( TInt i = 0; i < count - aNumberOfPoints; i++ )
       
   519             {
       
   520             iPoints.Remove( 0 );
       
   521             }
       
   522         }
       
   523     }
       
   524 
       
   525 
       
   526 // ---------------------------------------------------------------------------
       
   527 // CAknTouchGestureFwFlickRecognizer::MaximumBufferLength
       
   528 // ---------------------------------------------------------------------------
       
   529 //
       
   530 TInt CAknTouchGestureFwFlickRecognizer::MaximumBufferLength() const
       
   531     {
       
   532     return Settings().FlickBuffer();
       
   533     }
       
   534 
       
   535 
       
   536 // ---------------------------------------------------------------------------
       
   537 // Returns the current value of flick speed threshold setting.
       
   538 // ---------------------------------------------------------------------------
       
   539 //
       
   540 TInt CAknTouchGestureFwFlickRecognizer::FlickSpeedThreshold() const
       
   541     {
       
   542     return Settings().FlickSpeedThreshold();
       
   543     }
       
   544 
       
   545 
       
   546 // ---------------------------------------------------------------------------
       
   547 // Returns the current value of flick detection time setting.
       
   548 // ---------------------------------------------------------------------------
       
   549 //
       
   550 TInt CAknTouchGestureFwFlickRecognizer::FlickDetectionTime() const
       
   551     {
       
   552     return Settings().FlickDetectionTime() * KMicroSecondsInMilliSecond;
       
   553     }
       
   554 
       
   555 
       
   556 // ---------------------------------------------------------------------------
       
   557 // Returns the current value of direction change sensitivity setting.
       
   558 // ---------------------------------------------------------------------------
       
   559 //
       
   560 TInt CAknTouchGestureFwFlickRecognizer::DirectionChangeSensitivity() const
       
   561     {
       
   562     return Settings().FlickChangeSensitivity();
       
   563     }
       
   564 
       
   565 // End of File