diff -r 000000000000 -r 2f259fa3e83a uifw/AvKon/aknphysics/src/aknphysics.cpp --- /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 +#include +#include + +#include "aknphysicsconstants.h" +#include "aknphysicsengine.h" +#include "aknphysicsparameterprovider.h" +#include "aknphysicsrestrictor.h" +#include "aknphysicsconeobserver.h" +#include + +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