tactilefeedback/tactilefeedbackresolver/plugins/tactilehapticsplugin/src/tactilehapticsplayer.cpp
/*
* 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: Class for producing haptics feedback.
* Part of: Tactile Feedback.
*
*/
#include <f32file.h>
#include <e32debug.h>
#include <hwrmhaptics.h>
#include <centralrepository.h>
#include <ecom/implementationproxy.h>
#include <MProfileEngine.h>
#include <MProfile.h>
#include <MProfileExtraSettings.h>
#include <MProfileFeedbackSettings.h>
#include <CProfileChangeNotifyHandler.h>
#include "tactilefeedbackprivatecrkeys.h"
#include "tactilefeedbacktrace.h"
#include "tactilehapticsplayer.h"
#include "OstTraceDefinitions.h"
#ifdef OST_TRACE_COMPILER_IN_USE
#include "tactilehapticsplayerTraces.h"
#endif
// ======== MEMBER FUNCTIONS ========
const TInt KMaxEffectNameLen = 128;
// Pulse feedback's names
_LIT8( KTFBasic, "TFBasic");
_LIT8( KTFSensitive, "TFSensitive");
_LIT8( KTFBasicButton, "TFBasicButton");
_LIT8( KTFSensitiveButton, "TFSensitiveButton");
_LIT8( KTFList, "TFList");
_LIT8( KTFSensitiveList, "TFSensitiveList");
_LIT8( KTFBoundaryList, "TFBoundaryList");
_LIT8( KTFSlider, "TFSlider");
_LIT8( KTFEdit, "TFEdit");
_LIT8( KTFLineSelection, "TFLineSelection");
_LIT8( KTFBlankSelection, "TFBlankSelection");
_LIT8( KTFTextSelection, "TFTextSelection");
_LIT8( KTFEmptyLineSelection, "TFEmptyLineSelection");
_LIT8( KTFTab, "TFTab");
_LIT8( KTFPopUp, "TFPopUp");
_LIT8( KTFIncreasingPopUp, "TFIncreasingPopUp");
_LIT8( KTFDecreasingPopUp, "TFDecreasingPopUp");
_LIT8( KTFFlick, "TFFlick");
_LIT8( KTFCheckbox, "TFCheckbox");
_LIT8( KTFSensitiveInput, "TFSensitiveInput");
_LIT8( KTFCharacterInputButton, "TFCharacterInputButton");
_LIT8( KTFOptionsMenuOpened, "TFOptionsMenuOpened");
_LIT8( KTFOptionsMenuClosed, "TFOptionsMenuClosed");
_LIT8( KTFSubMenuOpened, "TFSubMenuOpened");
_LIT8( KTFSubMenuClosed, "TFSubMenuClosed");
_LIT8( KTFLongTap, "TFLongTap");
_LIT8( KTFMultiTouchRecognized, "TFMultiTouchRecognized");
// Continuous feedback's names
_LIT8( KTFContinuousSmooth, "TFContinuousSmooth");
_LIT8( KTFContinuousSlider, "TFContinuousSlider");
_LIT8( KTFContinuousInput, "TFContinuousInput");
_LIT8( KTFContinuousFlick, "TFContinuousFlick");
_LIT8( KTFDynamicSlider, "TFDynamicSlider");
// ---------------------------------------------------------------------------
// Constructor.
// ---------------------------------------------------------------------------
//
CTactileHapticsPlayer::CTactileHapticsPlayer( CRepository& aRepository ) :
iRepository(aRepository)
{
}
// ---------------------------------------------------------------------------
// 2nd phase constructor.
// ---------------------------------------------------------------------------
//
void CTactileHapticsPlayer::ConstructL()
{
TRACE("CTactileHapticsPlayer::ConstructL - Begin");
iHaptics = CHWRMHaptics::NewL(NULL, NULL);
TUint32 suppMask( 0 );
User::LeaveIfError( iHaptics->SupportedActuators( suppMask ) );
TInt actuatorType( EHWRMLogicalActuatorAny );
iRepository.Get( KTactileFeedbackHapticsActuator, actuatorType );
if ( actuatorType & suppMask )
{
iHaptics->OpenActuatorL( static_cast<THWRMLogicalActuators>(actuatorType) );
}
User::LeaveIfError( iHaptics->SetDeviceProperty(
CHWRMHaptics::EHWRMHapticsLicensekey,
KNullDesC8() ) );
TInt strength(0);
iRepository.Get( KTactileFeedbackHapticsStrength, strength );
// Strength value in settings is multiplied by 100 to scale value
// suitable for haptics (0-10000).
iStrength = strength * 100;
// As a temporary fix to EAKH-7LKANT, the strength is (over)read from
// profiles engine
InitializeProfilesEngineL();
if ( iVibraLevel > EProfileTactileFeedbackLevel3 )
{
User::Leave( KErrGeneral );
}
User::LeaveIfError( iHaptics->SetDeviceProperty(
CHWRMHaptics::EHWRMHapticsStrength,
iStrength ) );
TFileName ivtFile;
if ( iVibraLevel != EProfileTactileFeedbackOff )
{
iRepository.Get( IVTFileId(), ivtFile );
}
else
{
// Load KTactileHapticsLevel1IVTFile as default IVT file
// to start up if vibra level is EProfileTactileFeedbackOff.
iRepository.Get( KTactileHapticsLevel1IVTFile, ivtFile );
}
HBufC8* ivtBuf = IVTBufAllocL( ivtFile );
CleanupStack::PushL( ivtBuf );
User::LeaveIfError( iHaptics->LoadEffectData( *ivtBuf, iIVTHandle ) );
CleanupStack::PopAndDestroy( ivtBuf );
iCenRepNotifier = CCenRepNotifyHandler::NewL( *this,
iRepository );
iCenRepNotifier->StartListeningL();
TRACE("CTactileHapticsPlayer::ConstructL - End");
}
// ---------------------------------------------------------------------------
// 2-phased constructor.
// ---------------------------------------------------------------------------
//
CTactileHapticsPlayer* CTactileHapticsPlayer::NewL( CRepository& aRepository )
{
CTactileHapticsPlayer* self =
new ( ELeave ) CTactileHapticsPlayer( aRepository );
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop( self );
return self;
}
// ---------------------------------------------------------------------------
// Destructor.
// ---------------------------------------------------------------------------
//
CTactileHapticsPlayer::~CTactileHapticsPlayer()
{
if( iProfileEng )
{
iProfileEng->Release();
iProfileEng = NULL;
}
delete iProfileHandler;
delete iCenRepNotifier;
delete iHaptics;
}
// ---------------------------------------------------------------------------
// From class CTactilePlayer
//
// ---------------------------------------------------------------------------
//
TInt CTactileHapticsPlayer::PlayFeedback( TTouchLogicalFeedback aFeedback )
{
// TRACE("CTactileHapticsPlayer::PlayFeedback - Start");
TRACE2("CTactileHapticsPlayer::PlayFeedback type: %d", aFeedback );
TRAPD( err, DoPlayFeedbackL( aFeedback ));
if ( err != KErrNone )
{
TRACE2("CTactileHapticsPlayer::PlayFeedback error: %d", err );
}
// TRACE("CTactileHapticsPlayer::PlayFeedback - End");
return err;
}
// ---------------------------------------------------------------------------
// Actually play feedback.
// ---------------------------------------------------------------------------
//
void CTactileHapticsPlayer::DoPlayFeedbackL( TTouchLogicalFeedback aFeedback )
{
// Check if hapticts strength is set to zero or
// vibra level is EProfileTactileFeedbackOff.
if ( !iStrength || iVibraLevel == EProfileTactileFeedbackOff)
{
User::Leave(KErrNotReady);
}
TBuf8<KMaxEffectNameLen> name;
switch( aFeedback )
{
case ETouchFeedbackBasic:
name = KTFBasic;
break;
case ETouchFeedbackSensitive:
name = KTFSensitive;
break;
case ETouchFeedbackBasicButton:
name = KTFBasicButton;
break;
case ETouchFeedbackSensitiveButton:
name = KTFSensitiveButton;
break;
case ETouchFeedbackList:
name = KTFList;
break;
case ETouchFeedbackSensitiveList:
name = KTFSensitiveList;
break;
case ETouchFeedbackBoundaryList:
name = KTFBoundaryList;
break;
case ETouchFeedbackSlider:
name = KTFSlider;
break;
case ETouchFeedbackEdit:
name = KTFEdit;
break;
case ETouchFeedbackLineSelection:
name = KTFLineSelection;
break;
case ETouchFeedbackBlankSelection:
name = KTFBlankSelection;
break;
case ETouchFeedbackTextSelection:
name = KTFTextSelection;
break;
case ETouchFeedbackEmptyLineSelection:
name = KTFEmptyLineSelection;
break;
case ETouchFeedbackTab:
name = KTFTab;
break;
case ETouchFeedbackPopUp:
name = KTFPopUp;
break;
case ETouchFeedbackIncreasingPopUp:
name = KTFIncreasingPopUp;
break;
case ETouchFeedbackDecreasingPopUp:
name = KTFDecreasingPopUp;
break;
case ETouchFeedbackFlick:
name = KTFFlick;
break;
case ETouchFeedbackCheckbox:
name = KTFCheckbox;
break;
case ETouchFeedbackSensitiveInput:
name = KTFSensitiveInput;
break;
case ETouchFeedbackCharacterInputButton:
name = KTFCharacterInputButton;
break;
case ETouchFeedbackOptionsMenuOpened:
name = KTFOptionsMenuOpened;
break;
case ETouchFeedbackOptionsMenuClosed:
name = KTFOptionsMenuClosed;
break;
case ETouchFeedbackSubMenuOpened:
name = KTFSubMenuOpened;
break;
case ETouchFeedbackSubMenuClosed:
name = KTFSubMenuClosed;
break;
case ETouchFeedbackLongTap:
name = KTFLongTap;
break;
case ETouchFeedbackMultiTouchRecognized:
name = KTFMultiTouchRecognized;
break;
default:
User::Leave( KErrArgument );
break;
}
TInt effectIndex(0);
User::LeaveIfError( iHaptics->GetEffectIndexFromName( iIVTHandle,
name,
effectIndex ) );
TInt effectHandle(0);
OstTrace0( TACTILE_PERFORMANCE, TACTILE_PLAY_HAPTICS_FEEDBACK_1, "e_TACTILE_PLAY_HAPTICS_FEEDBACK 1");
User::LeaveIfError( iHaptics->PlayEffect( iIVTHandle,
effectIndex,
effectHandle ) );
OstTrace0( TACTILE_PERFORMANCE, TACTILE_PLAY_HAPTICS_FEEDBACK_0, "e_TACTILE_PLAY_HAPTICS_FEEDBACK 0");
}
// ---------------------------------------------------------------------------
// Get IVT file Id via vibra level.
// ---------------------------------------------------------------------------
//
TUint32 CTactileHapticsPlayer::IVTFileId()
{
TUint32 fileId = 0;
switch ( iVibraLevel )
{
case EProfileTactileFeedbackLevel1:
fileId = KTactileHapticsLevel1IVTFile;
break;
case EProfileTactileFeedbackLevel2:
fileId = KTactileHapticsLevel2IVTFile;
break;
case EProfileTactileFeedbackLevel3:
fileId = KTactileHapticsLevel3IVTFile;
break;
}
return fileId;
}
// ---------------------------------------------------------------------------
// Load IVT file.
// ---------------------------------------------------------------------------
//
HBufC8* CTactileHapticsPlayer::IVTBufAllocL( const TDesC& aFileName )
{
TRACE("CTactileHapticsPlayer::IVTBufAllocL - Begin");
RFs fs;
User::LeaveIfError( fs.Connect() );
CleanupClosePushL( fs );
RFile file;
User::LeaveIfError( file.Open( fs, aFileName, EFileRead ) );
CleanupClosePushL( file );
TInt fileSize( 0 );
file.Size( fileSize );
HBufC8* ivtFileBuf = HBufC8::NewLC( fileSize );
TPtr8 dataBufPtr = ivtFileBuf->Des();
User::LeaveIfError( file.Read( dataBufPtr ) );
CleanupStack::Pop( ivtFileBuf );
CleanupStack::PopAndDestroy( &file );
CleanupStack::PopAndDestroy( &fs );
TRACE("CTactileHapticsPlayer::IVTBufAllocL - End");
return ivtFileBuf;
}
// ---------------------------------------------------------------------------
// Start feedback.
// ---------------------------------------------------------------------------
//
TInt CTactileHapticsPlayer::StartFeedback( TTouchContinuousFeedback aFeedback,
TInt aIntensity )
{
TRACE("CTactileHapticsPlayer::StartFeedback - Start");
TInt ret(KErrNone);
// If there's an ongoing feedback, stop it first.
if ( iEffectHandle )
{
StopFeedback();
}
TBuf8<KMaxEffectNameLen> name;
switch( aFeedback )
{
case ETouchContinuousSmooth:
name = KTFContinuousSmooth;
break;
case ETouchContinuousSlider:
name = KTFContinuousSlider;
break;
case ETouchContinuousInput:
name = KTFContinuousInput;
break;
case ETouchContinuousFlick:
name = KTFContinuousFlick;
break;
case ETouchDynamicSlider:
name = KTFDynamicSlider;
break;
default:
ret = KErrArgument;
break;
}
if ( ret == KErrNone )
{
ret = iHaptics->GetEffectIndexFromName( iIVTHandle,
name,
iEffectIndex );
}
TInt effectType(0);
if ( ret == KErrNone )
{
ret = iHaptics->GetEffectType( iIVTHandle,
iEffectIndex,
effectType );
}
if ( ret == KErrNone )
{
switch ( effectType )
{
case CHWRMHaptics::EHWRMHapticsTypePeriodic:
{
CHWRMHaptics::THWRMHapticsPeriodicEffect periodicDef;
ret = iHaptics->GetPeriodicEffectDefinition( iIVTHandle,
iEffectIndex,
periodicDef );
// Effect's magnitude value in IVT file is used as max value for
// continuous effects and Attack level is used as minimum value
iMultiplier = ( periodicDef.iMagnitude - periodicDef.iAttackLevel ) / 100;
periodicDef.iMagnitude = aIntensity * iMultiplier + periodicDef.iAttackLevel;
if ( ret == KErrNone )
{
ret = iHaptics->PlayPeriodicEffect( periodicDef,
iEffectHandle );
}
}
break;
case CHWRMHaptics::EHWRMHapticsTypeMagSweep:
{
CHWRMHaptics::THWRMHapticsMagSweepEffect magSweepDef;
ret =iHaptics->GetMagSweepEffectDefinition( iIVTHandle,
iEffectIndex,
magSweepDef );
// Effect's magnitude value in IVT file is used as max value for
// continuous effects and Attack level is used as minimum value
iMultiplier = ( magSweepDef.iMagnitude - magSweepDef.iAttackLevel ) / 100;
magSweepDef.iMagnitude = aIntensity * iMultiplier + magSweepDef.iAttackLevel;
if ( ret == KErrNone )
{
ret =iHaptics->PlayMagSweepEffect( magSweepDef,
iEffectHandle );
}
}
break;
default:
TRACE("CTactileHapticsPlayer::StartFeedback - Playing effect not found");
ret = KErrArgument;
break;
}
}
TRACE("CTactileHapticsPlayer::StartFeedback - End");
return ret;
}
// ---------------------------------------------------------------------------
// Modify feedback.
// ---------------------------------------------------------------------------
//
TInt CTactileHapticsPlayer::ModifyFeedback( TInt aIntensity )
{
TRACE("CTactileHapticsPlayer::ModifyFeedback - Start");
TInt ret(KErrNotReady);
// Check if there's feedback started, do nothing if not.
if ( iEffectHandle )
{
TInt effectType(0);
ret = iHaptics->GetEffectType( iIVTHandle,
iEffectIndex,
effectType );
TRACE2("CTactileHapticsPlayer::ModifyFeedback - effect type %d", effectType );
if ( ret == KErrNone )
{
TInt intensity = aIntensity * iMultiplier;
switch ( effectType )
{
case CHWRMHaptics::EHWRMHapticsTypePeriodic:
{
CHWRMHaptics::THWRMHapticsPeriodicEffect periodicDef;
iHaptics->GetPeriodicEffectDefinition( iIVTHandle,
iEffectIndex,
periodicDef );
periodicDef.iMagnitude = intensity + periodicDef.iAttackLevel;
iHaptics->ModifyPlayingPeriodicEffect( iEffectHandle,
periodicDef );
}
break;
case CHWRMHaptics::EHWRMHapticsTypeMagSweep:
{
CHWRMHaptics::THWRMHapticsMagSweepEffect magSweepDef;
iHaptics->GetMagSweepEffectDefinition( iIVTHandle,
iEffectIndex,
magSweepDef );
magSweepDef.iMagnitude = intensity + magSweepDef.iAttackLevel;
iHaptics->ModifyPlayingMagSweepEffect( iEffectHandle,
magSweepDef );
}
break;
default:
ret = KErrArgument;
break;
}
}
}
TRACE("CTactileHapticsPlayer::ModifyFeedback - End");
return ret;
}
// ---------------------------------------------------------------------------
// Stop feedback.
// ---------------------------------------------------------------------------
//
void CTactileHapticsPlayer::StopFeedback()
{
TRACE("CTactileHapticsPlayer::StopFeedback - Start");
iHaptics->StopAllPlayingEffects();
iEffectHandle = 0;
TRACE("CTactileHapticsPlayer::StopFeedback - End");
}
// ---------------------------------------------------------------------------
// Check if there's a change in haptics settings and set new values if needed.
// ---------------------------------------------------------------------------
//
void CTactileHapticsPlayer::DoHandleNotifyGenericL( TUint32 aId )
{
TRACE("CTactileHapticsPlayer::DoHandleNotifyGenericL - Begin");
switch ( aId )
{
case KTactileFeedbackHapticsStrength:
{
// Strength value in settings is multiplied by 100 to scale value
// suitable for haptics.
TInt strength(0);
iRepository.Get( KTactileFeedbackHapticsStrength, strength );
iStrength = strength * 100;
iHaptics->SetDeviceProperty( CHWRMHaptics::EHWRMHapticsStrength,
iStrength );
}
break;
case KTactileHapticsLevel1IVTFile:
case KTactileHapticsLevel2IVTFile:
case KTactileHapticsLevel3IVTFile:
{
TFileName ivtFile;
iRepository.Get( aId, ivtFile );
HBufC8* ivtBuf = IVTBufAllocL( ivtFile );
if ( ivtBuf )
{
TInt ret = iHaptics->DeleteEffectData( iIVTHandle );
if ( ret == KErrNone )
{
iHaptics->LoadEffectData( *ivtBuf, iIVTHandle );
}
delete ivtBuf;
}
}
break;
default:
break;
}
TRACE("CTactileHapticsPlayer::DoHandleNotifyGenericL - End");
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TInt CTactileHapticsPlayer::PlayPreviewFeedback( TInt aLevel,
TTouchLogicalFeedback aFeedback )
{
TRACE("CTactileHapticsPlayer::PlayPreviewFeedback - Begin");
// Set preview level (scaled to haptics - multiplied by 100).
TInt ret = iHaptics->SetDeviceProperty( CHWRMHaptics::EHWRMHapticsStrength,
aLevel * 100 );
if ( ret == KErrNone )
{
ret = PlayFeedback( aFeedback );
}
iHaptics->SetDeviceProperty( CHWRMHaptics::EHWRMHapticsStrength,
iStrength );
TRACE("CTactileHapticsPlayer::PlayPreviewFeedback - End");
return ret;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
TInt CTactileHapticsPlayer::StartPreviewFeedback( TInt aLevel,
TTouchContinuousFeedback aFeedback,
TInt aIntensity )
{
TRACE("CTactileHapticsPlayer::StartPreviewFeedback - Begin");
// Set preview level (scaled to haptics - multiplied by 100).
TInt ret = iHaptics->SetDeviceProperty( CHWRMHaptics::EHWRMHapticsStrength,
aLevel * 100 );
if ( ret == KErrNone )
{
ret = StartFeedback( aFeedback, aIntensity );
}
TRACE("CTactileHapticsPlayer::StartPreviewFeedback - End");
return ret;
}
// ---------------------------------------------------------------------------
//
// ---------------------------------------------------------------------------
//
void CTactileHapticsPlayer::StopPreviewFeedback()
{
TRACE("CTactileHapticsPlayer::StopPreviewFeedback - Begin");
StopFeedback();
iHaptics->SetDeviceProperty( CHWRMHaptics::EHWRMHapticsStrength,
iStrength );
TRACE("CTactileHapticsPlayer::StopPreviewFeedback - Begin");
}
// ---------------------------------------------------------------------------
// From MCenRepNotifyHandlerCallback.
// ---------------------------------------------------------------------------
//
void CTactileHapticsPlayer::HandleNotifyGeneric( TUint32 aId )
{
TRACE("CTactileHapticsPlayer::HandleNotifyGeneric - Begin");
TRAP_IGNORE( DoHandleNotifyGenericL( aId ) );
TRACE("CTactileHapticsPlayer::HandleNotifyGeneric - End");
}
// ---------------------------------------------------------------------------
// From MProfileChangeObserver.
// ---------------------------------------------------------------------------
//
void CTactileHapticsPlayer::HandleActiveProfileEventL(
TProfileEvent /*aProfileEvent*/,
TInt /*aProfileId*/ )
{
TInt oldVibraLevel = iVibraLevel;
InitializeProfilesEngineL();
iHaptics->SetDeviceProperty( CHWRMHaptics::EHWRMHapticsStrength, iStrength );
if ( iVibraLevel != oldVibraLevel &&
iVibraLevel != EProfileTactileFeedbackOff )
{
HandleNotifyGeneric( IVTFileId() );
}
}
// ---------------------------------------------------------------------------
// Profiles engine -related initializations
// ---------------------------------------------------------------------------
//
void CTactileHapticsPlayer::InitializeProfilesEngineL()
{
// Create profiles engine, if it does not yet exist
if ( !iProfileEng )
{
iProfileEng = CreateProfileEngineL();
}
MProfile* activeProfile = iProfileEng->ActiveProfileL();
const MProfileExtraSettings& extraSettings =
activeProfile->ProfileExtraSettings();
const MProfileFeedbackSettings& feedbackSettings =
extraSettings.ProfileFeedbackSettings();
iVibraLevel = feedbackSettings.TactileFeedback();
iStrength = 100 * ( EProfileTactileFeedbackOff != iVibraLevel ? 100 : 0 );
activeProfile->Release();
// Create listener for profiles changes, if it does not yet exist
if ( !iProfileHandler )
{
iProfileHandler = CProfileChangeNotifyHandler::NewL( this );
}
}
//---------------------------------------------------------------------------
// ImplementationTable[]
//
//---------------------------------------------------------------------------
//
const TImplementationProxy ImplementationTable[] =
{
IMPLEMENTATION_PROXY_ENTRY( 0x2001CB99, CTactileHapticsPlayer::NewL )
};
//---------------------------------------------------------------------------
// TImplementationProxy* ImplementationGroupProxy()
//
//---------------------------------------------------------------------------
//
EXPORT_C const TImplementationProxy* ImplementationGroupProxy( TInt& aTableCount )
{
aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
return ImplementationTable;
}
// End of file