akntouchgesturefw/src/akntouchgesturefwimpl.cpp
author William Roberts <williamr@symbian.org>
Mon, 21 Jun 2010 22:36:19 +0100
branchGCC_SURGE
changeset 32 512f698a535d
parent 0 2f259fa3e83a
permissions -rw-r--r--
Mark extraneous symbols as ABSENT (bug 3065)

/*
* 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:  Touch gesture framework implementation.
*
*/

#include <aknappui.h>
#include <e32base.h>

#include "akntouchgesturefwimpl.h"
#include "akntouchgesturefwdefs.h"
#include "akntouchgesturefwevent.h"
#include "akntouchgesturefwrecognitionengine.h"

using namespace AknTouchGestureFw;

// ---------------------------------------------------------------------------
// Two-phased constructor.
// ---------------------------------------------------------------------------
//
CAknTouchGestureFwImpl* CAknTouchGestureFwImpl::NewL(
    MAknTouchGestureFwObserver& aObserver,
    CCoeControl* aControl )
    {
    CAknTouchGestureFwImpl* self =
        CAknTouchGestureFwImpl::NewLC( aObserver, aControl );
    CleanupStack::Pop( self );
    return self;
    }


// ---------------------------------------------------------------------------
// Two-phased constructor.
// ---------------------------------------------------------------------------
//
CAknTouchGestureFwImpl* CAknTouchGestureFwImpl::NewLC(
    MAknTouchGestureFwObserver& aObserver,
    CCoeControl* aControl )
    {
    CAknTouchGestureFwImpl* self =
        new ( ELeave ) CAknTouchGestureFwImpl( aControl );
    CleanupStack::PushL( self );
    self->ConstructL( aObserver );
    return self;
    }


// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CAknTouchGestureFwImpl::~CAknTouchGestureFwImpl()
    {
    if ( iCoeEnv )
        {
        iCoeEnv->RemoveForegroundObserver( *this );
        iCoeEnv->RemoveMessageMonitorObserver( *this );
        }

    delete iRecognitionEngine;
    }


// ---------------------------------------------------------------------------
// Handles simulated pointer events.
// Used only for testing purposes.
// ---------------------------------------------------------------------------
//
void CAknTouchGestureFwImpl::HandleSimulatedPointerEventL(
    const TPointerEventData& pointerData )
    {
    HandlePointerEventL( pointerData );

    iSubscriberControl->HandlePointerEventL( pointerData.iPointerEvent );
    }


// ---------------------------------------------------------------------------
// Sets target control for window server events.
// ---------------------------------------------------------------------------
//
void CAknTouchGestureFwImpl::SetSubscriberControlL( CCoeControl* aControl )
    {
    CCoeControl* subsControl = aControl;

    CCoeControl* windowControl( subsControl );

    while ( windowControl && !windowControl->OwnsWindow() )
        {
        windowControl = windowControl->Parent();
        }

    if ( windowControl )
        {
        iWindowControl = windowControl;
        }
    else
        {
        // The subscriber control or it's parents have no window,
        // so there's no point to continue.
        User::Leave( KErrNotFound );
        }

    iSubscriberControl = subsControl;

    EnableAdditionalEvents();
    }


// ---------------------------------------------------------------------------
// Sets the gesture interest.
// ---------------------------------------------------------------------------
//
void CAknTouchGestureFwImpl::SetGestureInterestL( TUint aGestureGroups )
    {
    TUint gestureInterest( EAknTouchGestureFwNoGroup );
    if ( aGestureGroups )
        {
        gestureInterest = aGestureGroups;
        }

    if ( !iMonitoringWs &&
         gestureInterest != EAknTouchGestureFwNoGroup )
        {
        iCoeEnv->AddMessageMonitorObserverL( *this );
        iMonitoringWs = ETrue;
        }
    else if ( iMonitoringWs &&
              gestureInterest == EAknTouchGestureFwNoGroup )
        {
        iCoeEnv->RemoveMessageMonitorObserver( *this );
        iMonitoringWs = EFalse;
        }

    TRAPD( err,
           iRecognitionEngine->SetGestureInterestL( gestureInterest ) );

    // If setting the gesture interes fails then there's no need to
    // monitor the WS events.
    if ( err != KErrNone && iMonitoringWs )
        {
        iCoeEnv->RemoveMessageMonitorObserver( *this );
        iMonitoringWs = EFalse;

        User::Leave( err );
        }

    EnableAdditionalEvents();
    }


// ---------------------------------------------------------------------------
// Returns the gesture groups which should be recognized.
// ---------------------------------------------------------------------------
//
TUint CAknTouchGestureFwImpl::GestureInterest() const
    {
    TUint gestureInterest( EAknTouchGestureFwNoGroup );
    if ( iRecognitionEngine )
        {
        gestureInterest = iRecognitionEngine->GestureInterest();
        }
    return gestureInterest;
    }


// ---------------------------------------------------------------------------
// Defines gesture groups, which trigger tactile feedback automatically.
// ---------------------------------------------------------------------------
//
void CAknTouchGestureFwImpl::SetFeedbackForGroupsL( TUint aGestureGroups )
    {
    iRecognitionEngine->SetFeedbackForGroupsL( aGestureGroups );
    }


// ---------------------------------------------------------------------------
// Defines gesture types, which trigger tactile feedback automatically.
// ---------------------------------------------------------------------------
//
void CAknTouchGestureFwImpl::SetFeedbackForTypesL(
    TAknTouchGestureFwGroup aGestureGroup,
    TUint aGestureTypesForTactile,
    TUint aGestureTypesForAudio )
    {
    iRecognitionEngine->SetFeedbackForTypesL( aGestureGroup,
        aGestureTypesForTactile, aGestureTypesForAudio );
    }


// ---------------------------------------------------------------------------
// EnableTestingFeatures
// ---------------------------------------------------------------------------
//    
void CAknTouchGestureFwImpl::EnableTestingFeatures()
    {
    iRecognitionEngine->EnableTestingFeatures();
    }


// ----------------------------------------------------------------------------
// C++ Constructor
// ---------------------------------------------------------------------------
//
CAknTouchGestureFwImpl::CAknTouchGestureFwImpl( CCoeControl* aControl )
    :
    iMonitoringWs( EFalse ),
    iCoeEnv( CCoeEnv::Static() ),
    iSubscriberControl( aControl ),
    iWindowControl( NULL ),
    iRecognitionEngine( NULL )
    {
    }


// ---------------------------------------------------------------------------
// Symbian second-phase constructor.
// ---------------------------------------------------------------------------
//
void CAknTouchGestureFwImpl::ConstructL(
    MAknTouchGestureFwObserver& aObserver )
    {
    SetSubscriberControlL( iSubscriberControl );

    iRecognitionEngine =
        CAknTouchGestureFwRecognitionEngine::NewL( aObserver,
            iSubscriberControl );

    iCoeEnv->AddForegroundObserverL( *this );
    }


// ---------------------------------------------------------------------------
// Handles pointer events.
// ---------------------------------------------------------------------------
//
void CAknTouchGestureFwImpl::HandlePointerEventL(
    const TPointerEventData& aPointerData )
    {
#ifdef GFW_DEBUG_TRACE_INPUTOUTPUT
    AknTouchGestureFwUtils::DumpPointerEvent( aEvent, aPointerData.iSimulated );
#endif // GFW_DEBUG_TRACE_INPUTOUTPUT
    
    const TPointerEvent event = aPointerData.iPointerEvent;
    TInt pointerNumber = 0;
    if ( event.IsAdvancedPointerEvent() )
        {
        pointerNumber = event.AdvancedPointerEvent()->PointerNumber();
        }

    __ASSERT_ALWAYS( pointerNumber >= 0, User::Invariant() );
    __ASSERT_ALWAYS( pointerNumber <= 1, User::Invariant() );

    iRecognitionEngine->HandlePointerEventL( aPointerData );
   }


// ---------------------------------------------------------------------------
// Cancels ongoing recognition.
// ---------------------------------------------------------------------------
//
void CAknTouchGestureFwImpl::CancelRecognition()
    {
    iRecognitionEngine->CancelRecognizing();
    }


// ---------------------------------------------------------------------------
// Enables the necessary events for the subscriber control's window.
// ---------------------------------------------------------------------------
//
void CAknTouchGestureFwImpl::EnableAdditionalEvents()
    {
    // Additional pointer events are needed for the following gesture groups
    TUint gestureInterest( GestureInterest() );
    TBool multiEventsNeeded = gestureInterest & EAknTouchGestureFwGroupPinch;
    TBool dragEventsNeeded =
        gestureInterest & ( EAknTouchGestureFwGroupFlick |
                            EAknTouchGestureFwGroupDrag |
                            EAknTouchGestureFwGroupPinch );

    // Enables drag events and advanced pointer events for window if needed
    if ( iWindowControl )
        {
        RDrawableWindow* window = iWindowControl->DrawableWindow();
        if ( window )
            {
            if ( dragEventsNeeded )
                {
                window->PointerFilter( EPointerFilterDrag, 0 );
                }
            if ( multiEventsNeeded )
                {
                window->EnableAdvancedPointers();
                }
            if ( dragEventsNeeded || multiEventsNeeded )
			    {
                // Set pointer grab when drag or multi pointer events are
                // needed to enable gesture recognition outside gesture control.
                window->SetPointerGrab( ETrue );
				}
            }
        }
    }


// ---------------------------------------------------------------------------
// Checks if pointer event is targeted to the gesture control.
// ---------------------------------------------------------------------------
//
TBool CAknTouchGestureFwImpl::PointerEventTargetedToControl(
    CCoeControl* aTargetControl,
    TPointerEvent& aEvent ) const
    {
    if ( !aTargetControl )
        {
        return EFalse;
        }

    TBool targetedToControl( EFalse );
    TBool eventInControl(
            iSubscriberControl->Rect().Contains( aEvent.iPosition ) );

    // Check if target control is gesture control's window control.
    targetedToControl = aTargetControl == iWindowControl;

    // Check that pointer is in gesture control area.
    if ( targetedToControl &&
         aEvent.iType == TPointerEvent::EButton1Down )
        {
        targetedToControl = eventInControl;
        }

    // Check if pointer is targeted to child window that is on gesture
    // control area.
    else if ( !targetedToControl && eventInControl )
        {
        CCoeControl* windowControl( aTargetControl );
        while ( windowControl )
            {
            windowControl = windowControl->Parent();
            if ( windowControl == iWindowControl )
                {
                targetedToControl = ETrue;
                ConvertPositionToControlWindow(
                        aTargetControl->DrawableWindow(),
                        aEvent.iPosition );
                break;
                }
            }
        }

    return targetedToControl;
    }


// ---------------------------------------------------------------------------
// Converts position in window area according to control window coordinates.
// ---------------------------------------------------------------------------
//
void CAknTouchGestureFwImpl::ConvertPositionToControlWindow(
    RDrawableWindow* aWindow,
    TPoint& aPosition ) const
    {
    if ( aWindow )
        {
        TPoint targetPosition( aWindow->AbsPosition() );
        TPoint windowPosition(
                iWindowControl->DrawableWindow()->AbsPosition() );
        aPosition.iX = aPosition.iX + targetPosition.iX - windowPosition.iX;
        aPosition.iY = aPosition.iY + targetPosition.iY - windowPosition.iY;
        }
    }


// ---------------------------------------------------------------------------
// Called when the application gains foreground.
// ---------------------------------------------------------------------------
//
void CAknTouchGestureFwImpl::HandleGainingForeground()
    {
#ifdef GFW_DEBUG_TRACE_INPUTOUTPUT
    _LIT( KAknTouchGainForeground, "[GFW] IN GAIN FOREGROUND" );
    RDebug::Print( KAknTouchGainForeground );
#endif

    if ( !iMonitoringWs && GestureInterest() != EAknTouchGestureFwNoGroup )
        {
        TRAP_IGNORE( iCoeEnv->AddMessageMonitorObserverL( *this ) );
        iMonitoringWs = ETrue;
        }
    }


// ---------------------------------------------------------------------------
// Called when the application loses foreground.
// ---------------------------------------------------------------------------
//
void CAknTouchGestureFwImpl::HandleLosingForeground()
    {
#ifdef GFW_DEBUG_TRACE_INPUTOUTPUT
    _LIT( KAknTouchLostForeground, "[GFW] IN LOST FOREGROUND" );
    RDebug::Print( KAknTouchLostForeground );
#endif

    // Reset framework state because it might be possible that
    // pointer is down when framework loses background.
    // In this situation corresponding up-event is never received
    // and framework stays to wrong state (assuming pointer is still down)
    // without resetting it.
    CancelRecognition();

    if ( iMonitoringWs )
        {
        iCoeEnv->RemoveMessageMonitorObserver( *this );
        iMonitoringWs = EFalse;
        }
    }


// ---------------------------------------------------------------------------
// Handles window server messages.
// ---------------------------------------------------------------------------
//
void CAknTouchGestureFwImpl::MonitorWsMessage( const TWsEvent& aEvent )
    {
    if ( aEvent.Type() == EEventPointer )
        {
        CCoeControl* targetControl =
            reinterpret_cast<CCoeControl*>( aEvent.Handle() );
        TAdvancedPointerEvent event( *aEvent.Pointer() );
        TBool targetedToControl( PointerEventTargetedToControl(
                targetControl, event ) );
        
        TPointerEventData pointerData( event, 
                                       event.PointerNumber(), 
                                       aEvent.Time(), 
                                       EFalse, 
                                       targetedToControl );
        
        TRAP_IGNORE( HandlePointerEventL( pointerData ) );
        }
    else if ( aEvent.Type() == EEventScreenDeviceChanged )
        {
        // Cancel recognition if layout changes
        CancelRecognition();
        }
    }

// End of File