uifw/AvKon/aknphysics/src/aknphysics.cpp
changeset 0 2f259fa3e83a
child 14 3320e4e6e8bb
child 16 71dd06cfe933
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uifw/AvKon/aknphysics/src/aknphysics.cpp	Tue Feb 02 01:00:49 2010 +0200
@@ -0,0 +1,1224 @@
+/*
+* 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:  CAknPhysics
+*
+*/
+
+
+#include <aknphysics.h>
+#include <aknphysicsobserveriface.h>
+#include <e32debug.h>
+
+#include "aknphysicsconstants.h"
+#include "aknphysicsengine.h"
+#include "aknphysicsparameterprovider.h"
+#include "aknphysicsrestrictor.h"
+#include "aknphysicsconeobserver.h"
+#include <touchfeedback.h>
+
+const TInt KSamePositionStopCount( 3 );
+
+_LIT( KNullThreadProcessName, "ekern.exe*" );
+_LIT( KNullThreadName, "::Null" );
+
+#undef AKNHIGHRESPERIODIC_PROFILE
+
+/**
+ * Opens a handle to the null thread.
+ */
+static TBool FindNullThread( RThread& aThread )
+    {
+    TFindProcess fp( KNullThreadProcessName );
+    TFullName kernelName;
+    if ( fp.Next( kernelName ) == KErrNone )
+        {
+        kernelName.Append( KNullThreadName );
+        
+        TFindThread ft( kernelName );
+        TFullName threadName;
+        if ( ft.Next( threadName ) == KErrNone )
+            {
+            if ( aThread.Open( threadName ) != KErrNone )
+                {
+                return EFalse;
+                }
+            }
+        }        
+
+    return ( aThread.Handle() != 0 );
+    }
+
+
+/**
+ * Periodic timer using CTimer::HighRes.
+ */
+NONSHARABLE_CLASS( CAknHighResPeriodic ) : public CTimer
+    {
+public:
+
+    /**
+     * Creates new timer instance.
+     * 
+     * @param  aPriority    Priority of the timer.
+     * @param  aNullThread  Open thread handle to the null thread,
+     *                      ownership is not transferred.
+     */
+    static CAknHighResPeriodic* NewL( TInt aPriority,
+                                      RThread* aNullThread );
+
+    /**
+     * Destructor.
+     */
+    ~CAknHighResPeriodic();
+
+    /**
+     * Starts periodic timer.
+     * 
+     * @param  aDelay      Initial delay.
+     * @param  anInterval  Minimum interval between callback.
+     * @param  aCallBack   Callback to invoke.
+     */
+    void Start( TTimeIntervalMicroSeconds32 aDelay,
+                TTimeIntervalMicroSeconds32 anInterval,
+                TCallBack aCallBack );
+
+    /**
+     * Sets minimum time between end of callback to beginning of next one.
+     *
+     * This is one approach to try to make sure that there is some time for
+     * other processes. If this process can handle callback quickly,
+     * this won't slow down frame rate.
+     * 
+     * @param  aDelay  Minimum time between callbacks.
+     */
+    void SetMinCallBackPeriod( TTimeIntervalMicroSeconds32 aDelay );
+
+protected:
+
+    /**
+     * C++ constructor.
+     * 
+     * @param  aPriority    Priority of the timer.
+     * @param  aNullThread  Open thread handle to the null thread,
+     *                      ownership is not transferred.
+     */
+    CAknHighResPeriodic( TInt aPriority, RThread* aNullThread );
+    
+    /**
+     * Called upon timer completion.
+     */
+    void RunL();
+
+private:
+
+    /**
+     * Prints out the CPU time given to the null thread between this and
+     * the previous call to this method.
+     */
+    void DumpNull();
+    
+private:
+
+    /** Timer interval. */
+    TTimeIntervalMicroSeconds32 iInterval;
+    
+    /** Callback of the timer. */
+    TCallBack iCallBack;
+    
+    /** Is the end time valid, i.e. has the timer been completed at least once. */
+    TBool iEndTimeValid;
+    
+    /** Time after the execution of the last timer callback. */
+    TTime iEndTime;
+    
+    /** Minimum interval between callbacks. */
+    TInt64 iMinCallBackPeriod;
+    
+    TBool iWaiting;
+    
+    /** Pointer to the null thread handle, not own. */
+    RThread* iDebugNullThread;
+    
+    /** Null thread CPU time after the last callback. */ 
+    TInt64 iDebugPreviousTime;
+    };
+
+
+// ---------------------------------------------------------------------------
+// Creates new timer instance
+// ---------------------------------------------------------------------------
+//
+CAknHighResPeriodic* CAknHighResPeriodic::NewL( TInt aPriority,
+                                                RThread* aNullThread )
+    {
+    CAknHighResPeriodic* self =
+        new (ELeave) CAknHighResPeriodic( aPriority, aNullThread );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CAknHighResPeriodic::~CAknHighResPeriodic()
+    {
+    }
+
+
+// ---------------------------------------------------------------------------
+// Starts the periodic timer.
+// ---------------------------------------------------------------------------
+//
+void CAknHighResPeriodic::Start( TTimeIntervalMicroSeconds32 aDelay,
+                                 TTimeIntervalMicroSeconds32 anInterval,
+                                 TCallBack aCallBack)
+    {
+    iInterval = anInterval.Int();
+    iCallBack = aCallBack;
+    iEndTimeValid = EFalse;
+    iWaiting = EFalse;
+    HighRes( aDelay );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Sets minimum time between end of callback to beginning of next one.
+// ---------------------------------------------------------------------------
+//
+void CAknHighResPeriodic::SetMinCallBackPeriod(
+    TTimeIntervalMicroSeconds32 aDelay )
+    {
+    if ( aDelay.Int() >= 0 )
+        {
+        iMinCallBackPeriod = aDelay.Int();
+        }
+    else
+        {
+        iMinCallBackPeriod = 0;
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// C++ constructor.
+// ---------------------------------------------------------------------------
+//
+CAknHighResPeriodic::CAknHighResPeriodic( TInt aPriority,
+                                          RThread* aNullThread )
+    : CTimer( aPriority ), iDebugNullThread( aNullThread )
+    {
+    CActiveScheduler::Add( this );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Prints out the CPU time given to the null thread between this and previous
+// call to this method.
+// ---------------------------------------------------------------------------
+//
+void CAknHighResPeriodic::DumpNull()
+    {
+    TTimeIntervalMicroSeconds time;
+    TInt err = iDebugNullThread->GetCpuTime( time );
+
+    if ( !err )
+        {
+        if ( !iEndTimeValid )
+            {
+            iDebugPreviousTime = time.Int64();
+            }
+        else
+            {
+            TInt64 delta = time.Int64() - iDebugPreviousTime; 
+            iDebugPreviousTime = time.Int64();
+#ifdef AKNHIGHRESPERIODIC_PROFILE
+            _LIT( KDMsg1, "[AKNPHYSICS] Null thread CPU time between frames: %d microseconds" );
+            RDebug::Print( KDMsg1, TInt( delta ) );
+#endif // AKNHIGHRESPERIODIC_PROFILE
+            }
+        }
+    else
+        {
+#ifdef AKNHIGHRESPERIODIC_PROFILE
+        _LIT( KDMsg2, "[AKNPHYSICS] Error %d in getting null thread CPU time" );
+        RDebug::Print( KDMsg2, err );
+#endif // AKNHIGHRESPERIODIC_PROFILE
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// Handles timer completion.
+// ---------------------------------------------------------------------------
+//
+void CAknHighResPeriodic::RunL()
+    {
+    if ( iEndTimeValid && !iWaiting ) 
+        {
+        TTime now;
+        now.UniversalTime();
+        
+        TInt64 delta = now.MicroSecondsFrom( iEndTime ).Int64();
+        if ( delta < 0 )
+            {
+            delta = 0;
+            }
+
+        TInt64 waitTime = iMinCallBackPeriod - delta; 
+        
+        if ( waitTime >= 0 )
+            {
+            // Restrict to some sensible min-max period.
+            if ( waitTime < KAknHighResMinWait )
+                {
+                waitTime = KAknHighResMinWait;
+                }
+
+            if ( waitTime > KAknHighResMaxWait )
+                {
+                waitTime = KAknHighResMaxWait;
+                }
+
+            TInt timeToWait( waitTime );
+
+#ifdef AKNHIGHRESPERIODIC_PROFILE
+            _LIT( KDmsg, "[AKNPHYSICS] - CAknHighResPeriodic::RunL : waiting for %d microseconds" );
+            RDebug::Print( KDmsg, timeToWait );
+#endif            
+            iWaiting = ETrue;
+            HighRes( timeToWait );
+            return;
+            }
+        }
+    
+    HighRes( iInterval );
+    iCallBack.CallBack();
+    
+#ifdef AKNHIGHRESPERIODIC_PROFILE
+
+    if ( iDebugNullThread && iDebugNullThread->Handle() )
+        {
+        DumpNull();
+        }
+
+#endif // AKNHIGHRESPERIODIC_PROFILE
+    
+    iWaiting = EFalse;
+    iEndTime.UniversalTime();
+    iEndTimeValid = ETrue;
+    }
+
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::NewL()
+// ---------------------------------------------------------------------------
+//
+EXPORT_C CAknPhysics* CAknPhysics::NewL( MAknPhysicsObserver& aObserver,
+                                         CCoeControl* aViewControl )
+    {
+    CAknPhysics* self = new ( ELeave ) CAknPhysics( aObserver );
+    CleanupStack::PushL( self );
+    self->ConstructL( aViewControl );
+    CleanupStack::Pop( self );
+    return self;
+    }
+    
+// ---------------------------------------------------------------------------
+// CAknPhysics::~CAknPhysics()
+// ---------------------------------------------------------------------------
+//
+CAknPhysics::~CAknPhysics()
+    {
+    delete iPhysics;
+    delete iEngine;
+    delete iParamProvider;
+    delete iRestrictor;
+    delete iConeObserver;
+
+    iNullThread.Close();
+    }
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::InitPhysicsL()
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CAknPhysics::InitPhysicsL( const TSize& aWorldSize, 
+                                         const TSize& aViewSize, 
+                                         TBool aLandscape )
+    {
+    if ( iRestrictor )
+        {
+        // Update always the restrictor parameters.
+        iRestrictor->UpdatePhysicsEnvironment( aWorldSize,
+                                               aViewSize,
+                                               aLandscape );
+        }
+    
+    // Do not initialize if all parameters match with old ones
+    if ( aWorldSize == iWorldSize && aViewSize == iViewSize 
+        && ( ( aLandscape && iLandscape ) || ( !aLandscape && !iLandscape ) ) )
+        {
+        return;    
+        }
+
+    StopPhysics();
+    iEngine->DeletePhysics();
+
+    iLandscape = aLandscape;
+
+    iWorldSize = aWorldSize;
+    iViewSize = aViewSize;
+    if( (iLandscape && aWorldSize.iWidth < aViewSize.iWidth) 
+            || (!iLandscape && aWorldSize.iHeight < aViewSize.iHeight) )
+        {
+        iWorldSize = aViewSize;
+        }
+
+    TInt64 ih, x, y, w, h, r;
+    if(iLandscape)
+        {
+        ih = iWorldSize.iWidth;
+        x = 1;
+        y = 0;
+        r = iViewSize.iHeight;
+        }
+    else
+        {
+        ih = iWorldSize.iHeight;
+        x = 0;
+        y = 1;
+        r = iViewSize.iWidth;
+        }
+
+    w = iViewSize.iWidth;
+    h = iViewSize.iHeight;
+    
+    if ( iEngine )
+        {
+        iEngine->CreateWorld( iParamProvider->Gravity() );
+        iEngine->CreatePlanes( ih, x, y, r );
+        iEngine->CreateViewBody( w, h, iParamProvider->ViewMass() );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::StartPhysics
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TBool CAknPhysics::StartPhysics( TPoint& aDrag, 
+                                          const TTime& aStartTime )
+    {
+    // Check that world really exists
+    if ( !iEngine || !iEngine->WorldExists() )
+        {
+        return EFalse;
+        }
+    
+    iSuspended = EFalse;
+
+    TTime now;
+    now.HomeTime();
+    TInt moveTime( now.MicroSecondsFrom( aStartTime ).Int64() );
+
+    TBool startPhysics( EFalse );
+    iFlickTimeExceeded = EFalse;
+
+    // Check if drag direction has changed during drag event
+    // and receive the changed parameters
+    if ( iConeObserver )
+        {
+        iConeObserver->DragChanged( iLandscape, aDrag, moveTime );
+        }
+
+    // Start physics if drag threshold is exceeded
+    startPhysics = 
+        ( iLandscape && Abs( aDrag.iX ) > DragThreshold() )
+        || ( !iLandscape && Abs( aDrag.iY ) > DragThreshold() );
+        
+    // Check if movetime threshold is exceeded
+    if ( startPhysics && moveTime > KFlickMaxDuration )
+        {
+        iFlickTimeExceeded = ETrue;
+        }
+
+    // Start physics always if position reveals empty space
+    if ( !startPhysics && iRestrictor )
+        {
+        TPoint viewPosition( iObserver.ViewPosition() );
+        startPhysics = 
+            iRestrictor->PositionRevealsEmptySpace( viewPosition );
+        }
+        
+    // Stop FPS logging here so that panning gets logged correctly. Each
+    // panning always ends with a flick attempt.
+    if ( iParamProvider->FpsLoggingEnabled() )
+        {
+        iEngine->StopFpsLogging();
+        }
+
+    if ( startPhysics && iEngine )
+        {
+        iEngine->SetViewBodyPosition( iObserver.ViewPosition() );
+        StartPhysics();
+        ApplyDrag( aDrag, moveTime ); 
+        
+        if ( iParamProvider->FpsLoggingEnabled() )
+            {
+            iEngine->StartFpsLogging();
+            }
+            
+        return ETrue;
+        }
+    return EFalse;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::StopPhysics()
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CAknPhysics::StopPhysics()
+    {
+    // Check that world really exists
+    if ( !iEngine || !iEngine->WorldExists() )
+        {
+        return;
+        }
+    
+    iSuspended = EFalse;
+
+    iSamePositionCounter = 0;
+    
+    if ( iPhysics && iPhysics->IsActive() )
+        {
+        if ( iParamProvider->FpsLoggingEnabled() )
+            {
+            iEngine->StopFpsLogging();
+            }
+
+        CancelPhysicsTimer();
+    
+        if ( iEngine )
+            {
+            iEngine->ResetViewBodyForceAndVelocity();
+            }
+        iObserver.PhysicEmulationEnded();
+        }
+    else
+        {
+        UpdateActionState();
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::OngoingPhysicsAction
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TInt CAknPhysics::OngoingPhysicsAction() const
+    {
+    return iOngoingAction;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::RegisterPanningPosition
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CAknPhysics::RegisterPanningPosition( const TPoint& aDelta )
+    {
+    TTimeIntervalMicroSeconds time;
+    TInt err( KErrNone );
+    if ( iNullThread.Handle() )
+        {
+        err = iNullThread.GetCpuTime( time );
+        }
+    else
+        {
+        err = KErrBadHandle;
+        }
+    
+    TInt64 nullDelta = !err ? time.Int64() - iNullThreadTime : KMaxTInt64;
+    
+    TTime now;
+    now.UniversalTime();
+    
+    TInt64 delta = Max( 0, now.MicroSecondsFrom( iTimeOfLastDraw ).Int64() );
+    
+#ifdef AKNHIGHRESPERIODIC_PROFILE
+
+    _LIT( KDMsg1, "[AKNPHYSICS] - RegisterPanningPosition : Null thread CPU time between frames: %d microseconds" );
+    _LIT( KDMsg2, "[AKNPHYSICS] - RegisterPanningPosition : Last draw %d microseconds ago");
+    RDebug::Print( KDMsg1, TInt( nullDelta ) );
+    RDebug::Print( KDMsg2, TInt( delta ) );
+    
+    if ( err )
+        {
+        _LIT( KDMsg3, "[AKNPHYSICS] Error %d in getting null thread CPU time" );
+        RDebug::Print( KDMsg3, err );
+        }
+    
+#endif // AKNHIGHRESPERIODIC_PROFILE
+    
+    TBool drawNow = EFalse;
+    if ( nullDelta > FrameDelay() * 1000 ||       // There has been enough idle time.
+         delta > MinFrameInterval() * 1000 ||     // Enough time since last draw.
+         iTimeOfLastDraw.Int64() == Int64( 0 ) || // First draw.
+         nullDelta < 0 )                          // Null thread CPU time not valid.
+        {
+        drawNow = ETrue;
+        }
+
+    iPanningDrawOmitted = !drawNow;
+    
+    TPoint position( iObserver.ViewPosition() );
+    position += aDelta;
+
+    if ( iRestrictor && iRestrictor->AllowedViewPosition( position ) )
+        {
+        if ( OngoingPhysicsAction() == EAknPhysicsActionNone )
+            {
+            iOngoingAction = EAknPhysicsActionDragging;
+            
+            if ( iParamProvider->FpsLoggingEnabled() )
+                {
+                iEngine->StartFpsLogging();
+                }
+            }
+        
+        NotifyViewPositionChanged( position, drawNow );
+        
+        if ( drawNow )
+            {
+            // Update the CPU time that the null thread has gotten.
+            iNullThreadTime = time.Int64();
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::SetFriction()
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CAknPhysics::SetFriction( TReal aFriction )
+    {
+    if ( iEngine )
+        {
+        iEngine->SetFriction( aFriction );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::ResetFriction()
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CAknPhysics::ResetFriction()
+    {
+    if ( iEngine )
+        {
+        iEngine->ResetFriction();
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::HighlightTimeOut
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TInt CAknPhysics::HighlightTimeout() const
+    {
+    if ( iParamProvider )
+        {
+        return iParamProvider->HighlightTimeout();
+        }
+    return 0;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::DragThreshold
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TInt CAknPhysics::DragThreshold() const
+    {
+    if ( iParamProvider )
+        {
+        return iParamProvider->DragThreshold();
+        }
+    return 0;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::FeatureEnabled
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TBool CAknPhysics::FeatureEnabled()
+    {
+    return CAknPhysicsParameterProvider::FeatureEnabled();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::EventHandlingAllowed
+// ---------------------------------------------------------------------------
+//
+EXPORT_C TBool CAknPhysics::EventHandlingAllowed() const
+    {
+    if ( iConeObserver )
+        {
+        return iConeObserver->EventHandlingAllowed();
+        }
+    return ETrue;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::UpdateViewWindowControl
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CAknPhysics::UpdateViewWindowControl( CCoeControl* aControl )
+    {
+    if ( iConeObserver )
+        {
+        iConeObserver->UpdateViewWindowControl( aControl );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::SuspendPhysics
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CAknPhysics::SuspendPhysics()
+    {
+    // Check that world really exists
+    if ( !iEngine || !iEngine->WorldExists() )
+        {
+        return;
+        }
+    
+    if ( iSuspended )
+        {
+        // Already suspended
+        return;
+        }
+    iSuspended = ETrue;
+    
+    iSamePositionCounter = 0;
+    if ( iPhysics && iPhysics->IsActive() )
+        {
+        if ( iParamProvider->FpsLoggingEnabled() )
+            {
+            iEngine->StopFpsLogging();
+            }
+        CancelPhysicsTimer();
+        }
+    else
+        {
+        UpdateActionState();
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::ResumePhysics
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CAknPhysics::ResumePhysics()
+    {
+    if ( !iEngine || !iEngine->WorldExists() )
+        {
+        return;
+        }
+    
+    if ( !iSuspended )
+        {
+        // Not suspended
+        return;
+        }
+    iSuspended = EFalse;
+    
+    if ( iParamProvider->FpsLoggingEnabled() )
+        {
+        iEngine->StopFpsLogging();
+        }
+
+    iEngine->SetViewBodyPosition( iObserver.ViewPosition() );
+    StartPhysics();         
+            
+    if ( iParamProvider->FpsLoggingEnabled() )
+        {
+        iEngine->StartFpsLogging();
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::UpdateViewPosition
+// ---------------------------------------------------------------------------
+//
+void CAknPhysics::UpdateViewPosition()
+    {
+    if ( iOngoingAction == CAknPhysics::EAknPhysicsActionNone
+         || iOngoingAction == CAknPhysics::EAknPhysicsActionDragging )
+        {
+        TPoint viewPosition( iObserver.ViewPosition() );
+        if ( iRestrictor 
+            && iRestrictor->PositionRevealsEmptySpace( viewPosition ) )
+            {
+            NotifyViewPositionChanged( viewPosition );            
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::Landscape
+// ---------------------------------------------------------------------------
+//
+const TBool& CAknPhysics::Landscape()
+    {
+    return iLandscape;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::ViewSize
+// ---------------------------------------------------------------------------
+//
+const TSize& CAknPhysics::ViewSize()
+    {
+    return iViewSize;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::WorldSize
+// ---------------------------------------------------------------------------
+//
+const TSize& CAknPhysics::WorldSize()
+    {
+    return iWorldSize;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::SurfaceErp
+// ---------------------------------------------------------------------------
+//
+TInt CAknPhysics::SurfaceErp() const
+    {
+    if ( iParamProvider )
+        {
+        return iParamProvider->SurfaceErp();
+        }
+    return 0;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::SurfaceCfm
+// ---------------------------------------------------------------------------
+//
+TInt CAknPhysics::SurfaceCfm() const
+    {
+    if ( iParamProvider )
+        {
+        return iParamProvider->SurfaceCfm();
+        }
+    return 0;
+    }
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::IsPanningDrawIgnored
+// ---------------------------------------------------------------------------
+//
+TBool CAknPhysics::IsPanningDrawOmitted() const
+    {
+    return iPanningDrawOmitted;
+    }
+
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::FrameDelay
+// ---------------------------------------------------------------------------
+//
+TInt CAknPhysics::FrameDelay() const
+    {
+    if ( iParamProvider )
+        {
+        return iParamProvider->FrameDelay();
+        }
+
+    return KPhysicsMinTime / 1000;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::MinFrameInterval
+// ---------------------------------------------------------------------------
+//
+TInt CAknPhysics::MinFrameInterval() const
+    {
+    if ( iParamProvider )
+        {
+        return iParamProvider->MinFrameInterval();
+        }
+
+    return KPhysicsTime / 1000;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::DrawViewInCurrentPosition
+// ---------------------------------------------------------------------------
+//
+void CAknPhysics::DrawViewInCurrentPosition()
+    {
+    NotifyViewPositionChanged( iObserver.ViewPosition(), ETrue );
+    }
+
+// --------------------------------------------------------------------------
+// CAknPhysics::SetBounceTactileFeedback
+// --------------------------------------------------------------------------
+//
+void CAknPhysics::SetBounceTactileFeedback( TBool aBounceTactileFeedback )
+    {
+    iBounceTactileFeedback = aBounceTactileFeedback;
+    }
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::CAknPhysics
+// ---------------------------------------------------------------------------
+//
+CAknPhysics::CAknPhysics( MAknPhysicsObserver& aObserver )
+    : iObserver( aObserver ),
+    iOngoingAction( EAknPhysicsActionNone ),
+    iParamProvider( NULL ),
+    iRestrictor( NULL ),
+    iConeObserver( NULL ),
+    iEngine( NULL ),
+    iNullThreadTime( 0 ),
+    iTimeOfLastDraw( 0 ), 
+    iBounceTactileFeedback( ETrue ),
+    iPanningDrawOmitted( EFalse )
+    {
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::ConstructL()
+// ---------------------------------------------------------------------------
+//
+void CAknPhysics::ConstructL( CCoeControl* aViewControl )
+    {
+    // Open the handle to the null thread.
+    TBool nullThreadOpen = FindNullThread( iNullThread );
+    
+    // Create Physics timer to step physics emulation
+    iPhysics = CAknHighResPeriodic::NewL(
+        CActive::EPriorityStandard, nullThreadOpen ? &iNullThread : NULL );
+    iPhysics->SetMinCallBackPeriod( FrameDelay() * 1000 );
+    
+    iEngine = CAknPhysicsEngine::NewL( this );
+    iParamProvider = CAknPhysicsParameterProvider::NewL();
+    iRestrictor = CAknPhysicsRestrictor::NewL( iParamProvider );
+    iConeObserver = CAknPhysicsConeObserver::NewL( this, iRestrictor );
+    iConeObserver->SetViewWindowControl( aViewControl );
+    iFeedback = MTouchFeedback::Instance();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::StartPhysics()
+// ---------------------------------------------------------------------------
+//
+void CAknPhysics::StartPhysics()
+    {
+    // Check that world really exists
+    if ( !iEngine || !iEngine->WorldExists() )
+        {
+        return;
+        }
+
+    iEngine->ResetCollisionState();
+    iEngine->EnableViewBody();
+    CancelPhysicsTimer();
+    if ( iPhysics && !iPhysics->IsActive() )
+        {
+        iPhysics->Start(
+                0, KPhysicsTime, TCallBack( CAknPhysics::Simulate, this ) );
+		UpdateActionState();
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::ApplyDrag()
+// ---------------------------------------------------------------------------
+//
+void CAknPhysics::ApplyDrag( TPoint aDrag, TInt aMoveTime )
+    {
+    // Check that world really exists
+    if ( !iEngine || !iEngine->WorldExists() )
+        {
+        return;
+        }
+    
+    if ( iRestrictor )
+        {
+        iRestrictor->AdjustDragPoint( aDrag );
+        }
+
+    iEngine->ResetCollisionState();
+
+    if(iLandscape)
+        {
+        if(aDrag.iY > iViewSize.iHeight/2 || aDrag.iY < -iViewSize.iHeight/2)
+            aDrag.iX = 0;
+        else
+            aDrag.iY = 0;
+        }
+    else
+        {
+        if(aDrag.iX > iViewSize.iWidth/2 || aDrag.iX < -iViewSize.iWidth/2)
+            aDrag.iY = 0;
+        else
+            aDrag.iX = 0;
+        }
+
+    if( aMoveTime < KSwipeDuration )
+        {
+        iEngine->ApplyDragForce( aDrag, aMoveTime );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::Simulate()
+// ---------------------------------------------------------------------------
+//
+TInt CAknPhysics::Simulate(TAny* aSelf)
+    {
+    CAknPhysics* self = (CAknPhysics*) aSelf;
+    self->DoSimulation();
+    return KErrNone;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::DoSimulation()
+// ---------------------------------------------------------------------------
+//
+void CAknPhysics::DoSimulation()
+    {
+    if ( iFlickTimeExceeded && iOngoingAction != EAknPhysicsActionBouncing  )
+        {
+        iFlickTimeExceeded = EFalse;
+        StopPhysics();
+        return;
+        }
+
+    TPoint previousViewPosition;
+    TPoint currentViewPosition;
+
+    // get position before step
+    iEngine->GetViewBodyPosition( previousViewPosition );
+    
+    CAknPhysicsEngine::TAknPhysicsCollision prevState = iEngine->CollisionState();
+
+    iEngine->TakePhysicsStep();
+
+    // get position after step
+    iEngine->GetViewBodyPosition( currentViewPosition );
+    
+    // Signal physics stop only after a possible view position change has been 
+    // communicated.
+    TBool stopPhysics = EFalse;
+    
+    // if iViewBody gets auto disabled, it's safe to stop physics emulation 
+    if( !iEngine->IsViewBodyEnabled() )
+        {
+        stopPhysics = ETrue;
+        }
+    else if ( prevState != CAknPhysicsEngine::EAknPhysicsNoCollision )
+        {
+
+        TBool collisionChanged( 
+            iEngine->CollisionState() != CAknPhysicsEngine::EAknPhysicsNoCollision 
+            && iEngine->CollisionState() != prevState );
+        TBool topCollision( prevState == CAknPhysicsEngine::EAknPhysicsTopCollision );
+        TBool previousOut( EFalse );
+        TBool currentOut( EFalse );
+
+        // Check if positions are out of boundaries
+        if ( iRestrictor )
+            {
+            previousOut = iRestrictor->PositionIsOutOfBoundaries( 
+                previousViewPosition, topCollision );
+            currentOut = iRestrictor->PositionIsOutOfBoundaries( 
+                currentViewPosition, topCollision );
+            }
+
+        // Stop bounce if
+        // 1) Collision has changed from top to bottom or bottom to top
+        // 2) Current view position is out of boundaries (and previous was not)
+        // -> prevent view flicking when bounce ends
+        // 3) Collision type has changed to no collision and both of the view
+        // positions are inside view boundaries.
+        if ( collisionChanged 
+            || currentOut && !previousOut
+            || !currentOut && !previousOut 
+            && iEngine->CollisionState() == CAknPhysicsEngine::EAknPhysicsNoCollision )
+            {
+            if ( topCollision || collisionChanged )
+                {
+                iRestrictor->PositionToViewTop( currentViewPosition );
+                }
+            else
+                {
+                iRestrictor->PositionToViewBottom( currentViewPosition );
+                }
+            stopPhysics = ETrue;
+            iEngine->ResetCollisionState();
+            // boundary effect                       
+            if ( iBounceTactileFeedback && iFeedback )
+                {
+                iFeedback->InstantFeedback( NULL,
+                                            ETouchFeedbackBoundaryList,
+                                            ETouchFeedbackVibra,
+                                            TPointerEvent() );
+                }
+            }
+
+        // Previous view position and current view position are out of view
+        // boundaries -> bounce has changed to flick
+        else if ( currentOut && previousOut )
+            {
+            iEngine->ResetCollisionState();
+            }
+        }
+
+    UpdateActionState();
+
+    if ( currentViewPosition == previousViewPosition )
+        {
+        iSamePositionCounter++;
+        // Never stop physics while bouncing even though
+        // same position count has been exceeded
+        if ( iOngoingAction != EAknPhysicsActionBouncing 
+            && iSamePositionCounter >= KSamePositionStopCount )
+            {
+            stopPhysics = ETrue;
+            }
+        }
+
+    NotifyViewPositionChanged( currentViewPosition );
+       
+    if ( stopPhysics )
+        {
+        StopPhysics();
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::CancelPhysicsTimer()
+// ---------------------------------------------------------------------------
+//
+void CAknPhysics::CancelPhysicsTimer()
+    {
+    if ( iPhysics )
+        {
+        iPhysics->Cancel();
+        UpdateActionState();
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::UpdateActionState()
+// ---------------------------------------------------------------------------
+//
+void CAknPhysics::UpdateActionState()
+    {
+    if ( iPhysics && iPhysics->IsActive() )
+        {
+        // If we are colliding or physics timer is active and view is about
+        // to bounce -> action to bouncing
+        if ( iEngine->CollisionState() != CAknPhysicsEngine::EAknPhysicsNoCollision
+            || ( iOngoingAction == EAknPhysicsActionNone && ViewAboutToBounce() ) )
+            {
+            iOngoingAction = EAknPhysicsActionBouncing;
+            }
+        // Otherwise we are flicking
+        else
+            {
+            iOngoingAction = EAknPhysicsActionFlicking;
+            }
+        }
+    else
+        {
+        iOngoingAction = EAknPhysicsActionNone;
+        }
+
+    if ( iConeObserver )
+        {
+        iConeObserver->PhysicsStateChanged();
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::ViewAboutToBounce()
+// ---------------------------------------------------------------------------
+//
+TBool CAknPhysics::ViewAboutToBounce()
+    {
+    TPoint viewPosition( iObserver.ViewPosition() );
+    if ( iRestrictor && iRestrictor->PositionRevealsEmptySpace( viewPosition ) )
+        {
+        return ETrue;
+        }
+    return EFalse;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CAknPhysics::NotifyViewPositionChanged
+// ---------------------------------------------------------------------------
+//
+void CAknPhysics::NotifyViewPositionChanged( const TPoint& aPosition,
+                                             TBool aDrawNow )
+    {
+    iObserver.ViewPositionChanged( aPosition, aDrawNow, 0 );
+    
+    if ( aDrawNow )
+        {
+        // Update the time of the last draw.
+        iTimeOfLastDraw.UniversalTime();
+        }
+    }
+
+// End of File