hwrmhaptics/hapticspluginmanager/src/hwrmhapticsservice.cpp
author William Roberts <williamr@symbian.org>
Thu, 06 May 2010 14:58:25 +0100
branchRCL_3
changeset 18 36a7e6c28b62
parent 0 4e1aa6a622a0
permissions -rw-r--r--
Remove references to deleted bld.inf files, to fix Bug 2631

/*
* Copyright (c) 2008 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:  Haptic service implementation.
*
*/


#include <s32mem.h>              // RDesReadStream
#include <hwrmhaptics.h>
#include <hwrmhapticsobserver.h>
#include <hwrmlogicalactuators.h>
#include <hwrmhapticscommands.h> // adaptation interface
#include <hwrmhapticspacketizer.h>

#include "hwrmhapticsclientserver.h" // panic codes, service ID
#include "hwrmhapticsserver.h" // default case in ExecuteMessageL
#include "hwrmhapticsservice.h"
#include "hwrmhapticspluginmanager.h"
#include "hwrmhapticsreservationhandler.h"
#include "hwrmhapticscommondata.h"
#include "hwrmhapticstrace.h"
#include "hwrmhapticspluginrequestdata.h"

_LIT( KPanicCategory, "HWRMHapticsSService" );

// ---------------------------------------------------------------------------
// Two-phased constructor.
// ---------------------------------------------------------------------------
//
EXPORT_C CHWRMHapticsService* CHWRMHapticsService::NewL(
        CHWRMHapticsPluginManager* aPluginHandler,
        CHWRMHapticsReservationHandler* aReservationHandler,
        CHWRMHapticsCommonData& aHapticsCommonData,
        const RMessage2& aMessage )
    {
    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::NewL()" ) ) );

    CHWRMHapticsService* self = 
        new ( ELeave ) CHWRMHapticsService( aHapticsCommonData, aMessage );
    
    CleanupStack::PushL( self );
    self->ConstructL( aPluginHandler, aReservationHandler );
    CleanupStack::Pop( self );

    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::NewL - return 0x%x" ), self ) );
    
    return self;
    }
   
// ---------------------------------------------------------------------------
// Destructor.
// ---------------------------------------------------------------------------
//
CHWRMHapticsService::~CHWRMHapticsService()
    {
    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::~CHWRMHapticsService()" ) ) );

    // Cleanup haptics just in case regular cleanup failed
    CleanupHaptics();

    if ( iPacketizer )
        {
        delete iPacketizer;
        iPacketizer = NULL;
        }
    
    // Complete any pending requests
    while ( iTransactionList->FirstItem() )
        {
        COMPONENT_TRACE( ( _L( "CHWRMHapticsService::~CHWRMHapticsService() - Deleting request %d" ), iTransactionList->FirstItem()->TransactionId() ) );
        CHWRMHapticsPluginRequestData* data = 
            static_cast<CHWRMHapticsPluginRequestData*>(
                iTransactionList->RemoveFirstItem() );

        if ( data->RequestMessage().Handle() )
            {
            // Check that this request is not first one of a split request
            if ( !data->CommandSplit() || 
                 !CheckForMessage(data->RequestMessage().Handle()) )
                {
                COMPONENT_TRACE( ( _L( "CHWRMHapticsService::~CHWRMHapticsService() - Canceling pending message" ) ) );
                data->RequestMessage().Complete( KErrCancel );
                }
            else
                {
                COMPONENT_TRACE( ( _L( "CHWRMHapticsService::~CHWRMHapticsService() - Split request, not canceling message yet" ) ) );
                }
            }

        TRAPD ( err, iPluginManager->CancelCommandL( data->TransactionId() ) );
        
        if ( err != KErrNone )
            {
            COMPONENT_TRACE( ( _L( "CHWRMHapticsService::~CHWRMHapticsService() - Cancelling Command (transid: %d) failed: %d" ), data->TransactionId(), err ) );
            }

        delete data;
        }
        
    // Destroy transaction list
    delete iTransactionList;

    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::~CHWRMHapticsService() - return" ) ) );
    }

// ---------------------------------------------------------------------------
// Handles Haptics requests. 
// ---------------------------------------------------------------------------
//
EXPORT_C TBool CHWRMHapticsService::ExecuteMessageL( 
                                                const RMessage2& aMessage )
    {
    COMPONENT_TRACE( ( _L( "e_HWRMHAPTICS_SERVICE_EXECUTEMESSAGEL 1" ) ) );
    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ExecuteMessageL(0x%x)" ), aMessage.Function() ) );
    __ASSERT_ALWAYS( iPluginManager,
                     User::Panic( KPanicCategory, EPanicBadHandle ) );
    __ASSERT_ALWAYS( iReservationHandler,
                     User::Panic( KPanicCategory, EPanicBadHandle ) );
    
    if ( aMessage.IsNull() )
        {
        COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ExecuteMessageL - NULL message!" ) ) );
        User::Leave( KErrBadHandle );
        }

    TBool completeMessage( EFalse );
    
    switch( aMessage.Function() )
        {
        case RMessage2::EDisConnect:
            {
            // send command to close actuator, if actuator has 
            // been opened (i.e. packetizer exists)
            if ( iPacketizer )
                {
                SendMsgToPluginManagerL( aMessage );
                }

            CleanupHaptics();
            break;
            }
        case EHWRMHaptics:
        case EHWRMHapticsBridgeCommand: // flow through
            {
            // send haptics message
            SendMsgToPluginManagerL( aMessage );
            break;
            }
        case EHWRMHapticsPlayEffect:
            {
            // check if suspended
            if ( iSuspended )
                {
                // no effect playing, just complete the message
                COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ExecuteMessageL - Haptics suspended; Play not executed." ) )  );
                aMessage.Complete( KErrNone );
                }
            else if ( iReservationHandler->IsReserved( this ) &&
                      iReservationHandler->ReservedPriorityHigher( iSid ) )
                {
                // haptics has not been reserved for some other client with
                // higher (or equal) priority, notify caller with an error code
                COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ExecuteMessageL - Haptics Reserved!" ) ) );
                User::Leave( KErrInUse );
                }
            else
                {
                // send play effect -command forwards to plugin manager
                SendMsgToPluginManagerL( aMessage );
                }
            
            break;
            }
        case EHWRMHapticsOpenActuator:
            {
            // get actuator type
            THWRMLogicalActuators actuator = 
                    static_cast<THWRMLogicalActuators>( aMessage.Int2() );
            
            // open the plugin to send the message to appropriate actuator;
            TBool created = iPluginManager->OpenPluginToActuatorL( actuator );

            // reset packetizer instance
            if ( iPacketizer )
                {
                delete iPacketizer;
                iPacketizer = NULL;
                }
            
            iPacketizer = CHWRMHapticsPacketizer::NewL( actuator );

            // if plugin was not created, it already exists. Inform client 
            // about the last status of the plugin.
            if ( !created )
                {
                iHapticsCommonData.NotifyActuatorEvent( actuator, iSession );
                }
            
            // send the open device message;
            SendMsgToPluginManagerL( aMessage );

            break;
            }
        case EHWRMHapticsCleanup:
            {
            CleanupHaptics();

            // complete as there is no ProcessResponse for this
            aMessage.Complete( KErrNone );
            break;
            }
        case EHWRMHapticsReserve:
            {
            COMPONENT_TRACE( ( _L("CHWRMHapticsService::ExecuteMessageL - EHWRMReserveHaptics") ) );
            
            ReserveHapticsL( aMessage );

            // Since using dummy messages for freeze state restores, need complete always.
            completeMessage = ETrue;
            
            break;
            }           
        case EHWRMHapticsRelease:
            {
            COMPONENT_TRACE( ( _L("CHWRMHapticsService::ExecuteMessageL - EHWRMReleaseHaptics") ) );

            ReleaseHaptics();
            
            // Since using dummy messages for default state restores, need complete always.
            completeMessage = ETrue;

            break;
            }           
        case EHWRMHapticsSuppActuators:
            {
            // get the supported logical actuator types from 
            // the plugin manager
            TUint32 types = iPluginManager->GetSupportedActuatorInfo();
            
            // write the supported types to aMessage
            TPckg<TUint32> actuatorInfoRetPckg( types );
            TInt err = aMessage.Write( 0, actuatorInfoRetPckg, 0 );
            
            // complete the message
            aMessage.Complete( err );
            break;
            }

        case EHWRMHapticsSetLicenseProp:
            {
            // The license key is set automatically if it is given as empty
            // string and if LicenseAutoSettingAllowed check succeeds.
            // The actual license key setting occures in lower layer,
            // here it is enough to create new command message.
            
            // check license key length
            if ( aMessage.Int1() == 0 )
                {
                // check if automatic license key setting is allowed
                // for the calling client
                if ( iPluginManager->LicenseAutoSettingAllowed( aMessage ) &&
                     iPacketizer )
                    {
                    // create buffer for new request data
                    HWRMHapticsCommand::RHWRMHapticsReqData reqData;
                    
                    // client is allowed to get automatic license key setting,
                    // create new command package
                    TInt err = iPacketizer->EncSetPlatformLicenseKeyReq(
                                        iPacketizer->DeviceHandle(),
                                        reqData );
                    
                    // write new request data to request message, if creating
                    // it succeeded
                    if ( err == KErrNone )
                        {
                        aMessage.Write( 0, reqData, 0 );
                        }
                    
                    reqData.Close();
                    }
                }
            
            // send message to plugin manager
            SendMsgToPluginManagerL( aMessage );
            break;
            }
        case EHWRMHapticsStatusNotification:
            {
            // store the message. It will be completed only
            // when the haptics/actuator status for this client changes
            // (thus the command should always be asynchronous on the 
            // client side)
            iHapticsCommonData.AddStatusObserver( aMessage );
            
            break;
            }
        case EHWRMHapticsGetStatus:
            {
            // get the current status value for this client
            MHWRMHapticsObserver::THWRMHapticsStatus status =
                iHapticsCommonData.CurrentStatus( aMessage.Session() );

            // write the status to message
            TPckg<MHWRMHapticsObserver::THWRMHapticsStatus> statusPckg( status );
            TInt err = aMessage.Write( 0, statusPckg, 0 );
            
            // complete message
            aMessage.Complete( err );

            break;
            }
        default:
            {
            // Cannot identify the message, panic the client
            aMessage.Panic( KPanicCategory, EPanicIllegalFunction );
            break;
            }

        }//switch

    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ExecuteMessageL - return 0x%x" ), completeMessage ) );
    COMPONENT_TRACE( ( _L( "e_HWRMHAPTICS_SERVICE_EXECUTEMESSAGEL 0" ) ) );
    
    return completeMessage;
    }
    
// ---------------------------------------------------------------------------
// Handles Haptics requests responses.
// ---------------------------------------------------------------------------
//
void CHWRMHapticsService::ProcessResponseL( TInt aCommandId,  
                                                     TUint8 aTransId,
                                                     const TDesC8& aData )
    {
    COMPONENT_TRACE( ( _L( "e_HWRMHAPTICS_SERVICE_PROCESSRESPONSEL 1" ) ) );
    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ProcessResponseL(0x%x, 0x%x, <data>)" ), aCommandId, aTransId ) );

    if( aCommandId == HWRMHapticsCommand::EHapticsCmdId )
        {
        TInt contextErr = CompleteRequestL( aTransId, aData );
        COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ProcessResponseL - CompleteRequestL ret = %d" ), contextErr ) );

        // Leave if there is error in context
        User::LeaveIfError( contextErr );
        }
             
    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ProcessResponseL - return" ) ) );
    COMPONENT_TRACE( ( _L( "e_HWRMHAPTICS_SERVICE_PROCESSRESPONSEL 0" ) ) );
    }

// ---------------------------------------------------------------------------
// Suspends haptics.
// ---------------------------------------------------------------------------
//
void CHWRMHapticsService::SuspendResource()
    {
    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::SuspendSubResource()" ) ) );
    
    iSuspended = ETrue;

    // notify client that haptics for it has been suspended
    iHapticsCommonData.NotifyStatus( 
        MHWRMHapticsObserver::EHWRMHapticsStatusSuspended, iSession );
    
    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::SuspendSubResource - return" ) ) );
    }
    
// ---------------------------------------------------------------------------
// Resumes haptics.
// ---------------------------------------------------------------------------
//
void CHWRMHapticsService::ResumeResource()
    {
    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ResumeSubResource()" ) ) );

    iSuspended = EFalse;

    // notify client that haptics for it is now available
    iHapticsCommonData.NotifyStatus( 
        MHWRMHapticsObserver::EHWRMHapticsStatusAvailable, iSession );
    
    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ResumeSubResource - return" ) ) );
    }

// ---------------------------------------------------------------------------
// Cancels outstanding request by completing the RMessage2 and removing data
// from transaction list.
// ---------------------------------------------------------------------------
//
void CHWRMHapticsService::CancelRequest( TUint8 aTransId )
    {
    CHWRMHapticsPluginRequestData* data = 
        static_cast<CHWRMHapticsPluginRequestData*>(
        iTransactionList->FindTransaction( aTransId, ETrue ) );
    
    if ( data && data->RequestMessage().Handle() )
        {
        data->RequestMessage().Complete( KErrTimedOut );
        }
    }

// ---------------------------------------------------------------------------
// Constructor.
// ---------------------------------------------------------------------------
//
CHWRMHapticsService::CHWRMHapticsService(
                CHWRMHapticsCommonData& aHapticsCommonData, 
                const RMessage2& aMessage )
    : iHapticsCommonData( aHapticsCommonData ), iSid( aMessage.SecureId() ),
      iSession( aMessage.Session() )
    {
    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CHWRMHapticsService()" ) ) );
    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CHWRMHapticsService - return" ) ) );
    }

// ---------------------------------------------------------------------------
// Symbian 2nd phase constructor.
// ---------------------------------------------------------------------------
//
void CHWRMHapticsService::ConstructL(
        CHWRMHapticsPluginManager* aPluginManager,
        CHWRMHapticsReservationHandler* aReservationHandler )
    {    
    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ConstructL(0x%x)" ), aPluginManager ) );

    if ( !aPluginManager )
        {
        User::Leave( KErrBadHandle );
        }
        
    iPluginManager = aPluginManager;
    iReservationHandler = aReservationHandler;

    iTransactionList = new( ELeave ) CHWRMHapticsPluginTransactionList();
   
    // set this session to the common data for storing the client 
    // specific status information
    iHapticsCommonData.AddSessionL( iSession );

    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ConstructL - return " ) ) );
    }

// ---------------------------------------------------------------------------
// Completes request. Subclass calls this from ProcessResponseL
// ---------------------------------------------------------------------------
//
TInt CHWRMHapticsService::CompleteRequestL( TUint8 aTransId, 
                                            const TDesC8& aData )
    {
    // return value
    TInt contextErr( KErrNone );

    // find transaction data
    CHWRMHapticsPluginRequestData* data = 
        static_cast<CHWRMHapticsPluginRequestData*>(
        iTransactionList->FindTransaction( aTransId, ETrue ) );
    
    CleanupStack::PushL( data );

    if ( data && data->RequestMessage().Handle() )
        {
        COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CompleteRequestL - iRequestMessage.Handle() ok." ) ) );

        // data storage for the protocol version and error code
        CHWRMHapticsRespData* respData = 
            CHWRMHapticsRespData::NewLC( KErrNone, KNullDesC8 );

        // internalize data using stream reader
        RDesReadStream reader( aData );
        CleanupClosePushL( reader );
        reader >> *respData;
        CleanupStack::PopAndDestroy( &reader );
        
        // status filled in message decoding
        TInt vibeStatus = KErrNone;
        
        // decode data, if no error
        if ( respData->ErrorCode() == KErrNone )
            {
            if ( data->RequestMessage().Function() == EHWRMHapticsBridgeCommand )
                {
                // bridge command handling
                COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CompleteRequest - inside EHWRMHapticsBridgeCommand case:" ) ) );
                DATADUMP_TRACE( _L("CHWRMHapticsService::CompleteRequest - (EHWRMHapticsBridgeCommand case) - data dump "), respData->Data() );

                // write error code and response data
                TPckg<TInt> vibeDummyCodePckg( KErrNone );
                data->RequestMessage().Write( 1, vibeDummyCodePckg, 0 );
                data->RequestMessage().Write( 2, respData->Data(), 0 );
                }
            else
                {
                // decode the message and send it to the callback service
                CDesC8ArraySeg* decodeArray = NULL;
                TRAPD( err, decodeArray = iPacketizer->DecodeMessageL(
                                            respData->Data(), vibeStatus ) );

                COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CompleteRequestL - Return msg decoding, err = %d" ), err ) );

                for ( TInt i = 0; err == KErrNone && 
                      i < decodeArray->MdcaCount(); ++i )
                    {
                    // write data back to client
                    err = data->RequestMessage().Write(
                                KHapticsMessageResponseArgsOffset + i,
                                decodeArray->MdcaPoint( i ), 0 );
                    }

                COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CompleteRequestL - Data writing err = %d" ), err ) );
                }
            }
        
        CleanupStack::PopAndDestroy( respData );
        
        COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CompleteRequestL - calling iRequestMessage.Complete()") ) ) ;
        data->RequestMessage().Complete( vibeStatus );
        }
    else
        {
        // transaction data not found
        COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CompleteRequest - No transaction data found!" ) ) );
        contextErr = KErrBadHandle;
        }    

    // cleanup data
    CleanupStack::PopAndDestroy( data );
    
    return contextErr;
    }

// ---------------------------------------------------------------------------
// Checks transaction list if specified message is in any transaction.
// ---------------------------------------------------------------------------
//
TBool CHWRMHapticsService::CheckForMessage( TInt aHandle )
    {
    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CheckForMessage - Checking for message: 0x%x" ), aHandle ) );
    
    CHWRMHapticsPluginRequestData* data = 
        static_cast<CHWRMHapticsPluginRequestData*>(
            iTransactionList->FirstItem() );
    
    TBool retval( EFalse );
    
    while ( !retval && data )
        {
        if ( data->RequestMessage().Handle() == aHandle )
            {
            retval = ETrue;
            }
        
        data = static_cast<CHWRMHapticsPluginRequestData*>( data->NextItem() );
        }
        
    return retval;
    }
        
// ---------------------------------------------------------------------------
// Cleans up haptics. 
// ---------------------------------------------------------------------------
//
void CHWRMHapticsService::CleanupHaptics()
    {
    if ( !iCleanupDone )
        {
        COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CleanupHaptics()" ) ) );

        // release haptics in case this client has made the reservation
        ReleaseHaptics();

        iSuspended = EFalse;
        
        // remove priority of the client from reservation handler
        iReservationHandler->RemovePriority( iSid );

        // remove this session from the common data
        iHapticsCommonData.RemoveSession( iSession );

        iCleanupDone = ETrue;
        
        COMPONENT_TRACE( ( _L( "CHWRMHapticsService::CleanupHaptics - return" ) ) );
        }
    }

// ---------------------------------------------------------------------------
// Handles Haptics requests. 
// ---------------------------------------------------------------------------
//
void CHWRMHapticsService::SendMsgToPluginManagerL( const RMessage2& aMessage )
    {
    // Create new data (TransId is updated later, commandId is not important)
    CHWRMHapticsPluginRequestData* data( NULL );
    if ( aMessage.Function() == RMessage2::EDisConnect )
        {
        data = new ( ELeave ) 
            CHWRMHapticsPluginRequestData( RMessage2(), 0, 0, EFalse );
        }
    else 
        {
        data = new ( ELeave ) 
            CHWRMHapticsPluginRequestData( aMessage, 0, 0, EFalse );
        }
    
    CleanupStack::PushL( data );

    if ( aMessage.Function() == RMessage2::EDisConnect )
        {
        // form from Disconnect message actuator closing request
        RBuf8 closeBuf;
        CleanupClosePushL( closeBuf );
        
        User::LeaveIfError( iPacketizer->EncCloseDeviceReq( 
                            iPacketizer->DeviceHandle(), closeBuf ) );
        
        HBufC8* reqData = closeBuf.AllocL();
        
        CleanupStack::PopAndDestroy( &closeBuf );
        
        COMPONENT_TRACE( ( _L( "CHWRMHapticsService::SendMsgToPluginManagerL - Disconnect actuator") ) );
        
        // created buffer is deleted in the request data object
        data->SetRequestData( reqData );

        // command to plugin manager
        TUint8 transId = iPluginManager->ProcessCommandL( 
                                            HWRMHapticsCommand::EHapticsCmdId, 
                                            *reqData, this );
        data->SetTransactionId( transId );
        }
    else        
        {
        // read message data into a heap buffer
        HBufC8* reqData = HBufC8::NewL( aMessage.GetDesLength( 0 ) );
        TPtr8 dataPtr = reqData->Des();
        TInt err = aMessage.Read( 0, dataPtr, 0 );
        
        COMPONENT_TRACE( ( _L( "CHWRMHapticsService::SendMsgToPluginManagerL - aMessageRead err = %d"), err ) );
        
        // created buffer is deleted in the request data object
        data->SetRequestData( reqData );

        // command to plugin manager
        TUint8 transId = iPluginManager->ProcessCommandL( 
                                            HWRMHapticsCommand::EHapticsCmdId, 
                                            *reqData, this);
        data->SetTransactionId( transId );
        }
    
    // data still needed, do not destroy, just pop
    CleanupStack::Pop( data );
    
    // Add data to list
    iTransactionList->AddTransaction( data );
    }

// ---------------------------------------------------------------------------
// Reserves haptics.
// ---------------------------------------------------------------------------
//
void CHWRMHapticsService::ReserveHapticsL( const RMessage2& aMessage )
    {
    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ReserveHapticsL()" ) ) );
    
    // Reserve the haptics
    TBool noCoeEnv = aMessage.Int0();
    TBool suspended = iReservationHandler->ReserveL( iSid, noCoeEnv, this );
    
    // if reservation became the affective reservation, inform all other 
    // clients that haptics is reserved
    if ( !suspended )
        {
        iHapticsCommonData.BroadcastStatus( 
            MHWRMHapticsObserver::EHWRMHapticsStatusReserved, iSession );
        }
    
    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ReserveHapticsL() return" ) ) );
    }

// ---------------------------------------------------------------------------
// Releases haptics.
// ---------------------------------------------------------------------------
//
void CHWRMHapticsService::ReleaseHaptics()
    {
    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ReleaseHaptics()" ) ) );

    // get info is haptics currently reserved for this client
    TBool activeReservation = iReservationHandler->ActiveReservation( this );

    // release reservation (removes, if this has a reservation)
    TBool reserved = iReservationHandler->Release( this );

    // if haptics is still reserved for another client, notify client
    if ( reserved )
        {
        iHapticsCommonData.NotifyStatus( 
            MHWRMHapticsObserver::EHWRMHapticsStatusReserved, iSession );
        }
    else if ( activeReservation )
        {
        // haptics was reserved for this client, but there are no more 
        // reservations --> inform all clients, which have been blocked
        iHapticsCommonData.BroadcastStatus( 
            MHWRMHapticsObserver::EHWRMHapticsStatusAvailable, iSession );
        }
           
    COMPONENT_TRACE( ( _L( "CHWRMHapticsService::ReleaseHaptics() return" ) ) );
    }


//  End of File