tactilefeedback/tactilefeedbackclient/src/touchfeedbackimpl.cpp
changeset 0 d54f32e146dd
child 3 1b74118366fe
equal deleted inserted replaced
-1:000000000000 0:d54f32e146dd
       
     1 /*
       
     2 * Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  This is the actual Client API implementation.
       
    15 * Part of:      Tactile Feedback.
       
    16 *
       
    17 */
       
    18 
       
    19 #include <eikenv.h>
       
    20 #include <coecntrl.h>
       
    21 #include <featmgr.h>
       
    22 #include <aknutils.h> 
       
    23 #include <tactilefeedbacktrace.h>
       
    24 #include <touchfeedbackspec.h>
       
    25 
       
    26 #include "touchfeedbackimpl.h"
       
    27 #include "touchfeedbackclient.h"
       
    28 #include "touchfeedbackregistry.h"
       
    29 #include "touchfeedbackclientpanic.h"
       
    30 
       
    31 /**
       
    32  * This is the maximum number that can be used as feedback area identifier.
       
    33  * after this the values starting from 1 are taken into use again when
       
    34  * new areas are added. This also defines the maximum number of feedback
       
    35  * areas that one application can have.
       
    36  */
       
    37 const TInt KTouchMaxFeedbackAreaIdentifier = 5000;
       
    38 
       
    39 
       
    40 // ======== LOCAL FUNCTIONS ========
       
    41 
       
    42 // ---------------------------------------------------------------------------
       
    43 // Cleanup items for removing latest item from the given array. These are used
       
    44 // for cleanup in case something leaves when we are adding new area
       
    45 // to the registry.
       
    46 // ---------------------------------------------------------------------------
       
    47 //
       
    48 void CleanupCacheArray( TAny* aPtr )
       
    49     {
       
    50     RArray<TControlCacheEntry>* array = 
       
    51         static_cast<RArray<TControlCacheEntry>*> ( aPtr );
       
    52         
       
    53     TInt index = array->Count() - 1;
       
    54     
       
    55     // If we are removing control from cache, then we have to clean the
       
    56     // associated area array also, or otherwise there will be a memory leak.
       
    57     (*array)[index].iAreaArray.Reset();
       
    58     (*array)[index].iAreaArray.Close();
       
    59     
       
    60     array->Remove( array->Count()-1 );        
       
    61     }
       
    62 
       
    63 // ---------------------------------------------------------------------------
       
    64 //
       
    65 // ---------------------------------------------------------------------------
       
    66 //
       
    67 void CleanupAreaArray( TAny* aPtr )
       
    68     {
       
    69     RArray<TAreaIndexEntry>* array = 
       
    70         static_cast<RArray<TAreaIndexEntry>*> ( aPtr );
       
    71         
       
    72     array->Remove( array->Count()-1 );    
       
    73     }
       
    74 
       
    75 
       
    76 // ======== MEMBER FUNCTIONS ========
       
    77 
       
    78 // ---------------------------------------------------------------------------
       
    79 // Constructor.
       
    80 // ---------------------------------------------------------------------------
       
    81 //
       
    82 CTouchFeedbackImpl::CTouchFeedbackImpl() :
       
    83     iAudioEnabledForThisApp( ETrue ), 
       
    84     iVibraEnabledForThisApp( ETrue )
       
    85     {
       
    86     }
       
    87 
       
    88 // ---------------------------------------------------------------------------
       
    89 // We check first if Tactile Feedback feature is supported in this device
       
    90 // and only construct the iClient -member in case needed. We thus use 
       
    91 // the existence of iClient as feature check in other API functions.
       
    92 //
       
    93 // This also means that iClient member needs to be checked in all the API
       
    94 // functions, so that we won't cause a KERN-EXEC 3 by trying to access
       
    95 // a NULL pointer in case the feature is disabled.
       
    96 // ---------------------------------------------------------------------------
       
    97 //
       
    98 void CTouchFeedbackImpl::ConstructL()
       
    99     { 
       
   100     TRACE("CTouchFeedbackImpl::ConstructL - Begin");
       
   101 
       
   102     // Check if the whole Tactile Feedback feature is supported or not
       
   103     
       
   104     // Initialize feature manager, just in case we happen to be the first
       
   105     // one using it in this thread.
       
   106     FeatureManager::InitializeLibL();
       
   107     
       
   108     TBool featureSupported =
       
   109         FeatureManager::FeatureSupported( KFeatureIdTactileFeedback );
       
   110 
       
   111     // We don't need feature manager anymore, as it is not possible
       
   112     // to change this feature on/off at run-time
       
   113     FeatureManager::UnInitializeLib();
       
   114     
       
   115     // Only create client in case feature is supported
       
   116     if ( featureSupported )
       
   117         {
       
   118         iClient = CTouchFeedbackClient::NewL( *this );
       
   119         }
       
   120     else
       
   121         {
       
   122         TRACE("Tactile Feedback feature is not supported");
       
   123         }
       
   124     
       
   125     // Check if pen usage is enabled. We use this information later for
       
   126     // disabling area registry -based feedback in case pen usage is not
       
   127     // enabled.    
       
   128     iPenEnabled = AknLayoutUtils::PenEnabled();
       
   129     
       
   130     TRACE3("CTouchFeedbackImpl::ConstructL - End, feature supported = %d, pen Enabled: %d", featureSupported, iPenEnabled);
       
   131     }
       
   132 
       
   133 // ---------------------------------------------------------------------------
       
   134 // We cannot afford to leave here (at least for the moment), because
       
   135 // in that case the whole system won't boot up. Constructing of the
       
   136 // client (in ConstructL) will fail if click plugin is not configured in
       
   137 // WSINI.INI file, and that can happen very easily at least in the beginning
       
   138 // when this is a new feature. Thus we TRAP any leaves here.
       
   139 //
       
   140 // This also means that iClient member needs to be checked in all the API
       
   141 // functions. We will also use this for recognizing the situation when
       
   142 // touch feedback is not supported (in that case we won't even try to
       
   143 // instantiate the client).
       
   144 // ---------------------------------------------------------------------------
       
   145 //
       
   146 CTouchFeedbackImpl* CTouchFeedbackImpl::New()
       
   147     {
       
   148     CTouchFeedbackImpl* self = new CTouchFeedbackImpl;
       
   149     if ( self )
       
   150         {
       
   151         TRAP_IGNORE( self->ConstructL() );    
       
   152         }    
       
   153     return self;
       
   154     }
       
   155 
       
   156 // ---------------------------------------------------------------------------
       
   157 // Destructor.
       
   158 // ---------------------------------------------------------------------------
       
   159 //
       
   160 CTouchFeedbackImpl::~CTouchFeedbackImpl()
       
   161     {
       
   162     TRACE("CTouchFeedbackImpl::~CTouchFeedbackImpl");
       
   163 
       
   164     delete iClient;
       
   165     
       
   166     TInt i = 0;
       
   167     
       
   168     for ( i=0; i < iRegistryArray.Count(); i++ )
       
   169         {
       
   170         delete iRegistryArray[i];
       
   171         }
       
   172         
       
   173     for ( i=iControlCache.Count()-1; i >= 0; i-- )
       
   174         {
       
   175         RemoveControlFromCache( i );
       
   176         }
       
   177         
       
   178     iRegistryArray.Close();
       
   179     iControlCache.Close();
       
   180     }
       
   181 
       
   182 // ---------------------------------------------------------------------------
       
   183 // We return ETrue if iClient exist, because instantiation of the client is
       
   184 // not done in case the feature is not enabled. And on the other hand if 
       
   185 // instantiation of client fails, then using of feedback is not possible
       
   186 // anyway.
       
   187 // ---------------------------------------------------------------------------
       
   188 //
       
   189 TBool CTouchFeedbackImpl::TouchFeedbackSupported()
       
   190     {
       
   191     if ( iClient )
       
   192         {
       
   193         return ETrue;        
       
   194         }
       
   195     else
       
   196         {
       
   197         return EFalse;
       
   198         }
       
   199     }
       
   200     
       
   201 // ---------------------------------------------------------------------------
       
   202 // Store the current status of feedback for this application, and
       
   203 // notify server of the change.
       
   204 // ---------------------------------------------------------------------------
       
   205 //
       
   206 void CTouchFeedbackImpl::SetFeedbackEnabledForThisApp( TBool aEnabled )
       
   207     {
       
   208     TRACE2( "CTouchFeedbackImpl::SetFeedbackEnabledForThisApp %d", aEnabled );
       
   209     
       
   210     // Only notify server when enabled value really changes.
       
   211     if ( iClient && 
       
   212        (( aEnabled != iAudioEnabledForThisApp ) || 
       
   213          (aEnabled != iVibraEnabledForThisApp ) ))
       
   214         {
       
   215         iClient->RegistryChanged();        
       
   216         }
       
   217         
       
   218     iAudioEnabledForThisApp = aEnabled;      
       
   219     iVibraEnabledForThisApp = aEnabled;      
       
   220     }
       
   221 
       
   222 // ---------------------------------------------------------------------------
       
   223 // Here we just return the current status.
       
   224 // ---------------------------------------------------------------------------
       
   225 //
       
   226 TBool CTouchFeedbackImpl::FeedbackEnabledForThisApp() 
       
   227     {
       
   228     return iAudioEnabledForThisApp || iVibraEnabledForThisApp;
       
   229     }
       
   230         
       
   231 // ---------------------------------------------------------------------------
       
   232 // This functions main purpose is to do all possible parameter checks to
       
   233 // the arguments before actually setting the area.
       
   234 // 
       
   235 // #1 Check that feedback is enabled
       
   236 // #2 Check that we weren't given a NULL pointer as control.
       
   237 // #3 Check that feedback type and pointer event are supported
       
   238 // #4 Check that we can generate a client handle from the control
       
   239 //    (if not, then there is something wrong with given control)
       
   240 // #5 Call overridden method SetFeedbackArea for actually setting the 
       
   241 //    feedback area.
       
   242 // ---------------------------------------------------------------------------
       
   243 //
       
   244 TInt CTouchFeedbackImpl::SetFeedbackArea( 
       
   245     const CCoeControl* aControl, 
       
   246     TUint32 aIndex, 
       
   247     TRect aRect, 
       
   248     TTouchLogicalFeedback aFeedbackType, 
       
   249     TTouchEventType aEventType )
       
   250     {
       
   251     TRACE("CTouchFeedbackImpl::SetFeedbackArea - Begin");
       
   252     
       
   253     // #1
       
   254     if ( !iClient )
       
   255         {
       
   256         return KErrNone;
       
   257         }
       
   258     
       
   259     // #2
       
   260     if ( !aControl )
       
   261         {
       
   262         TRACE("CTouchFeedbackImpl::SetFeedbackArea - Err: NULL Control");
       
   263         return KErrArgument;
       
   264         }
       
   265         
       
   266     // #3    
       
   267     if ( aFeedbackType > ETouchFeedbackSensitive || 
       
   268         ( aEventType!= ETouchEventStylusDown ) )
       
   269         {
       
   270         TRACE("CTouchFeedbackImpl::SetFeedbackArea - Err: Unsupported params");
       
   271         return KErrNotSupported;
       
   272         }
       
   273       
       
   274     // #4        
       
   275     TUint32 clientHandle = ClientHandle( aControl );
       
   276     
       
   277     if ( !clientHandle )
       
   278         {
       
   279         TRACE("CTouchFeedbackImpl::SetFeedbackArea - Err: Invalid Control");        
       
   280         return KErrArgument;
       
   281         }
       
   282     
       
   283     // #5    
       
   284     TInt err(KErrGeneral);
       
   285     CFeedbackSpec* spec = CFeedbackSpec::New();
       
   286     if (spec)
       
   287         {
       
   288         spec->AddFeedback(aEventType, aFeedbackType);
       
   289         err = SetFeedbackArea(aControl, aIndex, aRect, spec);
       
   290         delete spec;
       
   291         spec = NULL;
       
   292         }
       
   293         
       
   294     TRACE2("CTouchFeedbackImpl::SetFeedbackArea - End, err = %d", err );
       
   295     return err;    
       
   296     }
       
   297       
       
   298 // ---------------------------------------------------------------------------
       
   299 // Here we remove the given area from registry. 
       
   300 //
       
   301 // We still keep the control in the registry even if would have no areas,
       
   302 // because otherwise we'll lose feedback disabled/enabled information.
       
   303 //
       
   304 // #1 First check that given area is actually found
       
   305 // #2 Find corresponsing registry entry
       
   306 // #3 Remove feedback area entry from control cache
       
   307 // #4 Finally remove the actual area from registry, and notify server
       
   308 // ---------------------------------------------------------------------------
       
   309 //
       
   310 void CTouchFeedbackImpl::RemoveFeedbackArea( 
       
   311     const CCoeControl* aControl, 
       
   312     TUint32 aIndex )
       
   313     {
       
   314     TRACE3( "CTouchFeedbackImpl::RemoveFeedbackArea: 0x%x, %d", aControl, aIndex );
       
   315 
       
   316     if ( iClient )
       
   317         {
       
   318         TInt cacheIndex = KErrNotFound;
       
   319         TInt areaIndex = KErrNotFound;
       
   320         
       
   321         FindAreaFromCache( aControl, aIndex, cacheIndex, areaIndex );
       
   322         
       
   323         // #1 Only do something in case the area was found
       
   324         if ( cacheIndex >=0 && areaIndex >= 0 )
       
   325             {
       
   326             // #2
       
   327             TInt registryIndex = FindWindowFromRegistry ( 
       
   328                 iControlCache[cacheIndex].iClientHandle );
       
   329 
       
   330             TInt areaId = 
       
   331                 iControlCache[cacheIndex].iAreaArray[areaIndex].iAreaId;
       
   332             
       
   333             // #3 Remove this feedback area entry
       
   334             iControlCache[cacheIndex].iAreaArray.Remove( areaIndex );
       
   335             
       
   336             iNbOfFeedbackAreas--;
       
   337             
       
   338             // #4 Remove the area from registry
       
   339             if ( registryIndex != KErrNotFound )
       
   340                 {
       
   341                 iRegistryArray[registryIndex]->RemoveFeedbackArea( areaId );
       
   342                 
       
   343                 iClient->RegistryChanged();
       
   344                 }        
       
   345             }
       
   346         }
       
   347     }
       
   348 
       
   349 // ---------------------------------------------------------------------------
       
   350 // Here we return all areas related to given control.
       
   351 //
       
   352 // #1 Only do something in case the control is found from cache
       
   353 // #2 Find corresponding registry index.
       
   354 // #3 Remove all feedback areas from the registry.
       
   355 // #4 Remove the control from cache
       
   356 // #5 Notify server, if some areas were really removed.
       
   357 // ---------------------------------------------------------------------------
       
   358 //
       
   359 void CTouchFeedbackImpl::RemoveFeedbackForControl( 
       
   360     const CCoeControl* aControl )
       
   361     {
       
   362     TRACE2("CTouchFeedbackImpl::RemoveFeedbackForControl: 0x%x", aControl);
       
   363     
       
   364     if ( iClient )
       
   365         {
       
   366         TInt controlIndex = FindControlFromCache( aControl );
       
   367         
       
   368         // #1
       
   369         if ( controlIndex >= 0 ) // If control was found
       
   370             {
       
   371             TBool changesMade = EFalse;
       
   372 
       
   373             TControlCacheEntry& entry( iControlCache[controlIndex] );
       
   374             
       
   375             // #2
       
   376             TInt registryIndex = 
       
   377                 FindWindowFromRegistry( entry.iClientHandle );
       
   378             
       
   379             // #3 If registry entry was found, then remove all feedback
       
   380             // areas.
       
   381             if ( registryIndex >= 0) 
       
   382                 {
       
   383                 for ( TInt i=0; i < entry.iAreaArray.Count(); i++ )
       
   384                     {
       
   385                     iRegistryArray[registryIndex]->
       
   386                             RemoveFeedbackArea( 
       
   387                             entry.iAreaArray[i].iAreaId );
       
   388                             
       
   389                     changesMade = ETrue;   
       
   390                     
       
   391                     iNbOfFeedbackAreas--;     
       
   392                     }
       
   393                 }
       
   394             
       
   395             // #4 Anyway remove controls feedback areas from cache
       
   396             RemoveControlFromCache( controlIndex );
       
   397            
       
   398             // #5 Notify server of changes
       
   399             if ( changesMade )
       
   400                 {
       
   401                 iClient->RegistryChanged();
       
   402                 }
       
   403             }        
       
   404         }
       
   405     }
       
   406     
       
   407 // ---------------------------------------------------------------------------
       
   408 // Here we change the rectangle of existing feedback area.
       
   409 //
       
   410 // #1 Only do something in case the area is really found.
       
   411 // #2 Find corresponding registry entry
       
   412 // #3 If the entry was found, then change the feedback area
       
   413 // #4 Only notify the server when the area really changed
       
   414 // ---------------------------------------------------------------------------
       
   415 //
       
   416 void CTouchFeedbackImpl::ChangeFeedbackArea( const CCoeControl* aControl,
       
   417                                              TUint32 aIndex, 
       
   418                                              TRect aNewRect )
       
   419     {
       
   420     TRACE( "CTouchFeedbackImpl::ChangeFeedbackArea: 0x%x" );
       
   421 
       
   422     if ( iClient )
       
   423         {
       
   424         TInt cacheIndex = KErrNotFound;
       
   425         TInt areaIndex  = KErrNotFound;
       
   426 
       
   427         FindAreaFromCache( aControl, aIndex, cacheIndex, areaIndex );
       
   428         
       
   429         // #1
       
   430         if ( cacheIndex >= 0 && areaIndex >= 0 )
       
   431             {
       
   432             TInt id = 
       
   433                 iControlCache[cacheIndex].iAreaArray[areaIndex].iAreaId;
       
   434             
       
   435             // #2 
       
   436             TInt registryIndex = 
       
   437                 FindWindowFromRegistry ( 
       
   438                     iControlCache[cacheIndex].iClientHandle );
       
   439 
       
   440             // #3
       
   441             if ( registryIndex != KErrNotFound )
       
   442                 {
       
   443                 TBool changed = 
       
   444                     iRegistryArray[registryIndex]->ChangeFeedbackArea( 
       
   445                         id, 
       
   446                         aNewRect );
       
   447 
       
   448                 // #4 Only send upates to server when something 
       
   449                 //    really changed.
       
   450                 if ( changed )
       
   451                     {
       
   452                     iClient->RegistryChanged();                
       
   453                     }
       
   454                 }           
       
   455             }        
       
   456         }
       
   457     }
       
   458 
       
   459 // ---------------------------------------------------------------------------
       
   460 // Here we change the feedback type of existing feedback area.
       
   461 //
       
   462 // #1 Only do something in case the area is really found.
       
   463 // #2 Find corresponding registry entry
       
   464 // #3 If the entry was found, then change the feedback area
       
   465 // #4 Only notify the server when the feedback type really changed
       
   466 // ---------------------------------------------------------------------------
       
   467 //
       
   468 void CTouchFeedbackImpl::ChangeFeedbackType( const CCoeControl* aControl,
       
   469                                              TUint32 aIndex, 
       
   470                                              TTouchLogicalFeedback aNewType )
       
   471     {
       
   472     TRACE4("CTouchFeedbackImpl::ChangeFeedbackType: 0x%x, %d, %d", aControl, aIndex, aNewType);
       
   473 
       
   474     if ( iClient )
       
   475         {
       
   476         TInt cacheIndex = KErrNotFound;
       
   477         TInt areaIndex  = KErrNotFound;
       
   478 
       
   479         FindAreaFromCache( aControl, aIndex, cacheIndex, areaIndex );
       
   480         
       
   481         // #1
       
   482         if ( cacheIndex >= 0 && areaIndex >= 0 )
       
   483             {
       
   484             TInt id = iControlCache[cacheIndex].iAreaArray[areaIndex].iAreaId;
       
   485             
       
   486             // #2
       
   487             TInt registryIndex = 
       
   488                 FindWindowFromRegistry ( 
       
   489                     iControlCache[cacheIndex].iClientHandle );
       
   490 
       
   491             // #3
       
   492             if ( registryIndex != KErrNotFound )
       
   493                 {
       
   494                 TBool changed = 
       
   495                     iRegistryArray[registryIndex]->ChangeFeedbackType( 
       
   496                         id, 
       
   497                         aNewType,
       
   498                         // Feedback type change for up event is not supported 
       
   499                         // by this function.
       
   500                         static_cast<TTouchLogicalFeedback>( 0xFFFFFFFF ) );
       
   501 
       
   502                 // #4 Only send upates to server when something 
       
   503                 //    really changed.
       
   504                 if ( changed )
       
   505                     {
       
   506                     iClient->RegistryChanged();                
       
   507                     }
       
   508                 }           
       
   509             }        
       
   510         }
       
   511     }    
       
   512    
       
   513 // ---------------------------------------------------------------------------
       
   514 // Here we change move the given feedback area to first priority, so that
       
   515 // it will be the topmost in its window.
       
   516 //
       
   517 // #1 Only do something in case the area is really found.
       
   518 // #2 Find corresponding registry entry
       
   519 // #3 If the entry was found, then change the feedback area
       
   520 // #4 Only notify the server when the move was successfull
       
   521 // ---------------------------------------------------------------------------
       
   522 //
       
   523 void CTouchFeedbackImpl::MoveFeedbackAreaToFirstPriority( 
       
   524     const CCoeControl* aControl, 
       
   525     TUint32 aIndex )
       
   526     {
       
   527     if ( iClient )
       
   528         {
       
   529         TInt cacheIndex = KErrNotFound;
       
   530         TInt areaIndex  = KErrNotFound;
       
   531 
       
   532         FindAreaFromCache( aControl, aIndex, cacheIndex, areaIndex );
       
   533         
       
   534         // #1
       
   535         if ( cacheIndex >= 0 && areaIndex >= 0 )
       
   536             {
       
   537             TInt id = iControlCache[cacheIndex].iAreaArray[areaIndex].iAreaId;
       
   538             
       
   539             // #2
       
   540             TInt registryIndex = 
       
   541                 FindWindowFromRegistry ( 
       
   542                     iControlCache[cacheIndex].iClientHandle );
       
   543 
       
   544             // #3
       
   545             if ( registryIndex != KErrNotFound )
       
   546                 {
       
   547                 TInt err = 
       
   548                     iRegistryArray[registryIndex]->
       
   549                         MoveFeedbackAreaToFirstPriority( id );
       
   550 
       
   551                 // #4
       
   552                 if ( err == KErrNone )
       
   553                     {
       
   554                     TRACE3("CTouchFeedbackImpl::MoveFeedbackAreaToFirstPriority 0x%x, %d", aControl, aIndex);
       
   555                     iClient->RegistryChanged();
       
   556                     }
       
   557                 }  
       
   558             }
       
   559         }
       
   560     }   
       
   561 
       
   562 // ---------------------------------------------------------------------------
       
   563 // Pass request to server in case feedback is enabled for this 
       
   564 // application.
       
   565 // ---------------------------------------------------------------------------
       
   566 //
       
   567 void CTouchFeedbackImpl::InstantFeedback( TTouchLogicalFeedback aType )
       
   568     {
       
   569     if ( iClient && ( iAudioEnabledForThisApp || iVibraEnabledForThisApp ) )
       
   570         {
       
   571         TRACE2("CTouchFeedbackImpl::InstantFeedback %d", aType);
       
   572         iClient->ImmediateFeedback( 
       
   573             aType, 
       
   574             iVibraEnabledForThisApp, 
       
   575             iAudioEnabledForThisApp );        
       
   576         }
       
   577     }
       
   578     
       
   579 // ---------------------------------------------------------------------------
       
   580 // In this overload we only play direct feedback if the feedback has
       
   581 // not been disabled for this control.
       
   582 // ---------------------------------------------------------------------------
       
   583 //
       
   584 void CTouchFeedbackImpl::InstantFeedback( 
       
   585     const CCoeControl* aControl,
       
   586     TTouchLogicalFeedback aType )
       
   587     {
       
   588     if ( iClient && ( iAudioEnabledForThisApp || iVibraEnabledForThisApp ) )
       
   589         {
       
   590         
       
   591         // First take application level vibra and audio enablers
       
   592         // as default
       
   593         TBool vibraEnabled = iVibraEnabledForThisApp;
       
   594         TBool audioEnabled = iAudioEnabledForThisApp;
       
   595 
       
   596         TInt cacheIndex = FindControlFromCache( aControl );
       
   597         
       
   598         
       
   599         // Check control level disablers for vibra and audio.
       
   600         // (These can only prevent vibra or audio effect playback,
       
   601         //  but not to force it on)
       
   602         if ( cacheIndex >=0 && vibraEnabled ) 
       
   603             {
       
   604             vibraEnabled = !iControlCache[cacheIndex].iVibraDisabled;
       
   605             }
       
   606             
       
   607         if ( cacheIndex >=0 && audioEnabled ) 
       
   608             {
       
   609             audioEnabled = !iControlCache[cacheIndex].iAudioDisabled;
       
   610             }
       
   611             
       
   612         TRACE3("CTouchFeedbackImpl::InstantFeedback 0x%x, %d", aControl, aType);
       
   613         iClient->ImmediateFeedback( aType, vibraEnabled, audioEnabled );   
       
   614         }
       
   615     }    
       
   616 
       
   617 // ---------------------------------------------------------------------------
       
   618 // It is not enough to check that the control exists in the cache, we
       
   619 // also need to check that it actually has some areas registered.
       
   620 // ---------------------------------------------------------------------------
       
   621 //
       
   622 TBool CTouchFeedbackImpl::ControlHasFeedback( const CCoeControl* aControl )
       
   623     {
       
   624     TBool hasFeedback = EFalse;
       
   625     
       
   626     if ( iClient )
       
   627         {
       
   628         for ( TInt i=0; i < iControlCache.Count(); i++ )
       
   629             {
       
   630             if ( iControlCache[i].iControl == aControl )
       
   631                 {
       
   632                 if ( iControlCache[i].iAreaArray.Count() > 0 )
       
   633                     {
       
   634                     hasFeedback =  ETrue;                    
       
   635                     }
       
   636                     
       
   637                 // Break out from loop anyway, since we found the
       
   638                 // control
       
   639                 break;
       
   640                 }
       
   641             }        
       
   642         }
       
   643         
       
   644     return hasFeedback;
       
   645     }
       
   646 
       
   647 // ---------------------------------------------------------------------------
       
   648 // Control has feedback if it has a feedback identifier with given index
       
   649 // number.
       
   650 // ---------------------------------------------------------------------------
       
   651 //
       
   652 TBool CTouchFeedbackImpl::ControlHasFeedback( 
       
   653     const CCoeControl* aControl, 
       
   654     TUint32 aIndex )
       
   655     {
       
   656     TBool hasArea = EFalse;
       
   657     
       
   658     if ( iClient )
       
   659         {
       
   660         TInt cacheIndex = KErrNotFound;
       
   661         TInt areaIndex  = KErrNotFound;
       
   662         
       
   663         FindAreaFromCache( aControl, aIndex, cacheIndex, areaIndex );
       
   664         
       
   665         if ( cacheIndex >= 0 && areaIndex >= 0 )
       
   666             {
       
   667             hasArea = ETrue;
       
   668             }
       
   669         }
       
   670 
       
   671     return hasArea;
       
   672     }  
       
   673   
       
   674 // ---------------------------------------------------------------------------
       
   675 // This overload is only wrapper to the real function
       
   676 // ---------------------------------------------------------------------------
       
   677 //
       
   678 void CTouchFeedbackImpl::EnableFeedbackForControl( 
       
   679     const CCoeControl* aControl, 
       
   680     TBool aEnable )
       
   681     {
       
   682     EnableFeedbackForControl( aControl, aEnable, aEnable );
       
   683     }    
       
   684 
       
   685 // ---------------------------------------------------------------------------
       
   686 // #1 Find control from the cache
       
   687 // #2 In case control was found, disable/enable it's registry entries, and
       
   688 //    also take into accound it's dimming status
       
   689 // #3 If control was not found, then add it to cache
       
   690 // ---------------------------------------------------------------------------
       
   691 //
       
   692 void CTouchFeedbackImpl::EnableFeedbackForControl( 
       
   693     const CCoeControl* aControl,
       
   694     TBool aEnableVibra,
       
   695     TBool aEnableAudio )
       
   696     {
       
   697     TRACE4( "CTouchFeedbackImpl::EnableFeedbackForControl - 0x%x Vibra:%d Audio:=%d", 
       
   698            aControl, aEnableVibra, aEnableAudio );
       
   699 
       
   700     if ( aControl )
       
   701         {
       
   702         // #1
       
   703         TInt cacheIndex = FindControlFromCache( aControl );
       
   704 
       
   705         if ( cacheIndex >= 0 )
       
   706             {
       
   707             // #2
       
   708             TControlCacheEntry& entry ( iControlCache[cacheIndex] );
       
   709             
       
   710             entry.iVibraDisabled = !aEnableVibra;
       
   711             entry.iAudioDisabled = !aEnableAudio;
       
   712             
       
   713             // Let's update visibility and dimming information also now
       
   714             // that we have the pointer to control (due to broken object
       
   715             // provider chain we might not have the correct information on 
       
   716             // the moment).
       
   717             entry.iDimmed  = aControl->IsDimmed();
       
   718             entry.iVisible = aControl->IsVisible();
       
   719             
       
   720             if ( ControlsAreasActive( cacheIndex ) )
       
   721                 {
       
   722                 // If control is active (undimmed and visible), then we 
       
   723                 // set the areas according to parameters.
       
   724                 DoEnableControlsAreasInRegistry( cacheIndex, 
       
   725                                                  aEnableVibra, 
       
   726                                                  aEnableAudio,
       
   727                                                  aControl->IsVisible() );
       
   728                 }
       
   729             else
       
   730                 {
       
   731                 // If control is not active, then we disable all feedback.
       
   732                 DoEnableControlsAreasInRegistry( cacheIndex, 
       
   733                                                  EFalse, 
       
   734                                                  EFalse, 
       
   735                                                  aControl->IsVisible() );
       
   736                 }
       
   737             }
       
   738         else if ( !aEnableVibra || !aEnableAudio  )
       
   739             {
       
   740             // #3 We have to add control to the cache in case
       
   741             // it is not there yet (and disabling is wanted), because
       
   742             // otherwise it will be impossible to block feedback
       
   743             TUint32 clientHandle = ClientHandle( aControl );
       
   744             
       
   745             // We need to rely elsewhere that client handle exist if control
       
   746             // is found in the cache --> Only make new entry if client
       
   747             // handle can be aquired.
       
   748             if ( clientHandle > 0 )
       
   749                 {
       
   750                 TControlCacheEntry newCacheEntry;
       
   751                 
       
   752                 newCacheEntry.iControl        = aControl;
       
   753                 newCacheEntry.iClientHandle   = clientHandle;
       
   754                 newCacheEntry.iVibraDisabled  = !aEnableVibra;
       
   755                 newCacheEntry.iAudioDisabled  = !aEnableAudio;
       
   756                 newCacheEntry.iVisible        = aControl->IsVisible();
       
   757                 newCacheEntry.iDimmed         = aControl->IsDimmed();
       
   758                         
       
   759                 iControlCache.Append( newCacheEntry );                        
       
   760                 }
       
   761             }        
       
   762         }
       
   763     }
       
   764 
       
   765 // ---------------------------------------------------------------------------
       
   766 // Store the current status of audio and vibra feedbacks for this 
       
   767 // application, and notify server of the change.
       
   768 // ---------------------------------------------------------------------------
       
   769 //
       
   770 void CTouchFeedbackImpl::SetFeedbackEnabledForThisApp( 
       
   771     TBool aVibraEnabled, 
       
   772     TBool aAudioEnabled )
       
   773     {
       
   774     TRACE3( "CTouchFeedbackImpl::SetFeedbackEnabledForThisApp %d %d", aVibraEnabled, aAudioEnabled );
       
   775     
       
   776     // Only notify server when enabled value really changes.
       
   777     if ( iClient && 
       
   778        (( aAudioEnabled != iAudioEnabledForThisApp ) || 
       
   779          (aVibraEnabled != iVibraEnabledForThisApp ) ))
       
   780         {
       
   781         iClient->RegistryChanged();        
       
   782         }
       
   783         
       
   784     iAudioEnabledForThisApp = aAudioEnabled;      
       
   785     iVibraEnabledForThisApp = aVibraEnabled;      
       
   786     }
       
   787 
       
   788 // ---------------------------------------------------------------------------
       
   789 // Simple utility for CTouchFeedbackClient
       
   790 // ---------------------------------------------------------------------------
       
   791 //
       
   792 RPointerArray<CTouchFeedbackRegistry>* CTouchFeedbackImpl::RegistryArray()
       
   793     {
       
   794     return &iRegistryArray;
       
   795     }
       
   796         
       
   797 // ---------------------------------------------------------------------------
       
   798 // Simple utility for CTouchFeedbackClient
       
   799 //
       
   800 // We return zero in case pen is not supported in current layout. This way
       
   801 // area registry is disabled in non-touch powered layouts, but feedback areas
       
   802 // are still kept in memory so that feedback can be enabled again in case 
       
   803 // layout changes.
       
   804 // ---------------------------------------------------------------------------
       
   805 //
       
   806 void CTouchFeedbackImpl::GetAreaCount( TInt& aAreaCount, TInt& aWindowCount )
       
   807     {
       
   808     aWindowCount = 0;
       
   809     aAreaCount = 0;
       
   810     
       
   811     if ( iPenEnabled )
       
   812         {
       
   813         aWindowCount = iRegistryArray.Count();
       
   814         aAreaCount =  iNbOfFeedbackAreas;            
       
   815         }
       
   816     }
       
   817     
       
   818 // ---------------------------------------------------------------------------
       
   819 // This function is called by the application framework when any control's
       
   820 // visibility or dimming status has changed.
       
   821 //
       
   822 // We need to determine here whether the given control has any feedback,
       
   823 // and whether its current state requires a change in feedback
       
   824 // areas (for e.g. feedback areas will be disabled for any dimmed control).
       
   825 //
       
   826 // #1 Find control from cache (we don't need to do anything in case it
       
   827 //    is not found.
       
   828 // #2 Check if control's feedback areas are now active (based on dimming,
       
   829 //    visibility and feedback disabling). Also check control's current 
       
   830 //    visibility status as itself, as this determines whether the area will
       
   831 //    be put to registry at all.
       
   832 // #3 Save control's current dimming and visibility status
       
   833 // #4 Check again if control's areas should  be active
       
   834 // #5 Disable/Enable areas in case needed
       
   835 // ---------------------------------------------------------------------------
       
   836 //
       
   837 void CTouchFeedbackImpl::ControlVisibilityChanged( 
       
   838     const CCoeControl* aControl )
       
   839     {
       
   840     if ( iClient && aControl )
       
   841         {
       
   842         // #1
       
   843         TInt cacheIndex = FindControlFromCache( aControl );
       
   844         
       
   845         if ( cacheIndex >= 0 )
       
   846             {
       
   847             // #2
       
   848             TBool oldStatus = ControlsAreasActive( cacheIndex );
       
   849             TBool oldVisible = iControlCache[cacheIndex].iVisible;
       
   850             
       
   851             // #3
       
   852             iControlCache[cacheIndex].iVisible = aControl->IsVisible();
       
   853             iControlCache[cacheIndex].iDimmed  = aControl->IsDimmed();
       
   854                 
       
   855             
       
   856             // #4
       
   857             TBool newStatus = ControlsAreasActive( cacheIndex );
       
   858             
       
   859             // #5
       
   860             if ( ( oldStatus != newStatus ) || 
       
   861                  ( oldVisible != aControl->IsVisible() ) )
       
   862                 {
       
   863                 if ( newStatus ) // If control is now active
       
   864                     {
       
   865                     DoEnableControlsAreasInRegistry( 
       
   866                         cacheIndex, 
       
   867                         !iControlCache[cacheIndex].iVibraDisabled,
       
   868                         !iControlCache[cacheIndex].iAudioDisabled,
       
   869                         aControl->IsVisible() );
       
   870                     }
       
   871                 else
       
   872                     {
       
   873                     DoEnableControlsAreasInRegistry( cacheIndex, 
       
   874                                                      EFalse, 
       
   875                                                      EFalse,
       
   876                                                      aControl->IsVisible() );
       
   877                     }
       
   878                 }
       
   879             }
       
   880         }
       
   881     }
       
   882 
       
   883 // ---------------------------------------------------------------------------
       
   884 // Here we check whether the pen support status has changed, and update
       
   885 // registry in case needed.
       
   886 //
       
   887 // Notice that this has not effect on direct feedback: It is completely on
       
   888 // UI control's responsibility to check if pen is supported with direct
       
   889 // feedback (direct feedback is not automatically disabled because that
       
   890 // would cause problems in compatibility mode).
       
   891 //
       
   892 // Also notice that we don't actually destroy any feedback areas when pen
       
   893 // usage is not supported: We just report zero areas to server side, but
       
   894 // still keep everything in memory (see GetAreaCount -function)
       
   895 // ---------------------------------------------------------------------------
       
   896 //
       
   897 void CTouchFeedbackImpl::LayoutChanged()
       
   898     {    
       
   899     if ( iClient )
       
   900         {
       
   901         TBool penEnabledNow = AknLayoutUtils::PenEnabled();
       
   902 
       
   903         TRACE2("CTouchFeedbackImpl::LayoutChanged, PenEnabled = %d", penEnabledNow);
       
   904         
       
   905         if ( penEnabledNow != iPenEnabled )
       
   906             {
       
   907             iPenEnabled = penEnabledNow;
       
   908             
       
   909             iClient->RegistryChanged();                    
       
   910             }        
       
   911         }
       
   912     }
       
   913 
       
   914 // new functions from MTouchFeedback that came in 5.2
       
   915 // ---------------------------------------------------------------------------
       
   916 // 
       
   917 // ---------------------------------------------------------------------------
       
   918 //
       
   919 TBool CTouchFeedbackImpl::FeedbackEnabledForThisApp( TTouchFeedbackType aFeedbackType )
       
   920     {
       
   921     TBool feedbackEnabled( ETrue );
       
   922     
       
   923     if ( (aFeedbackType & ETouchFeedbackAudio) && !iAudioEnabledForThisApp )
       
   924         {
       
   925         feedbackEnabled = EFalse;
       
   926         }
       
   927 
       
   928     if ( (aFeedbackType & ETouchFeedbackVibra) && !iVibraEnabledForThisApp )
       
   929         {
       
   930         feedbackEnabled = EFalse;
       
   931         }        
       
   932         
       
   933     if ( !aFeedbackType )        
       
   934         {
       
   935         feedbackEnabled = EFalse;
       
   936         }
       
   937    
       
   938     return feedbackEnabled;
       
   939     }
       
   940 
       
   941 // ---------------------------------------------------------------------------
       
   942 // 
       
   943 // ---------------------------------------------------------------------------
       
   944 //
       
   945 void CTouchFeedbackImpl::StartFeedback( const CCoeControl* aControl,
       
   946                                         TTouchContinuousFeedback aType,
       
   947                                         const TPointerEvent* /*aPointerEvent*/,
       
   948                                         TInt aIntensity,
       
   949                                         TTimeIntervalMicroSeconds32 aTimeout )
       
   950     {
       
   951     if ( iClient && ( iAudioEnabledForThisApp || iVibraEnabledForThisApp ) )
       
   952         {
       
   953         // First take application level vibra and audio enablers
       
   954         // as default
       
   955         TBool vibraEnabled = iVibraEnabledForThisApp;
       
   956         TBool audioEnabled = iAudioEnabledForThisApp;
       
   957 
       
   958         TInt cacheIndex = FindControlFromCache( aControl );
       
   959         
       
   960         
       
   961         // Check control level disablers for vibra and audio.
       
   962         // (These can only prevent vibra or audio effect playback,
       
   963         //  but not to force it on)
       
   964         if ( cacheIndex >=0 && vibraEnabled ) 
       
   965             {
       
   966             vibraEnabled = !iControlCache[cacheIndex].iVibraDisabled;
       
   967             }
       
   968             
       
   969         if ( cacheIndex >=0 && audioEnabled ) 
       
   970             {
       
   971             audioEnabled = !iControlCache[cacheIndex].iAudioDisabled;
       
   972             }
       
   973             
       
   974         if ( vibraEnabled || audioEnabled )
       
   975             {
       
   976             TRACE4("CTouchFeedbackImpl::StartFeedback, type:=%d intensity:%d, timeout:%d", aType, aIntensity, aTimeout);
       
   977             TUint32 clientHandle = ClientHandle( aControl );
       
   978             iClient->StartFeedback( clientHandle, 
       
   979                                     aType, 
       
   980                                     aIntensity, 
       
   981                                     aTimeout );    
       
   982             }
       
   983         }    
       
   984     }
       
   985 
       
   986 // ---------------------------------------------------------------------------
       
   987 // 
       
   988 // ---------------------------------------------------------------------------
       
   989 //
       
   990 void CTouchFeedbackImpl::ModifyFeedback( const CCoeControl* aControl,
       
   991                                          TInt aIntensity )
       
   992     {
       
   993     if ( iClient )
       
   994         {
       
   995         TRACE2("CTouchFeedbackImpl::ModifyFeedbac, intensity:%d, timeout:%d", aIntensity);
       
   996         TUint32 clientHandle = ClientHandle( aControl );
       
   997         iClient->ModifyFeedback( clientHandle, aIntensity );
       
   998         }    
       
   999     }
       
  1000 
       
  1001 // ---------------------------------------------------------------------------
       
  1002 // 
       
  1003 // ---------------------------------------------------------------------------
       
  1004 //                             
       
  1005 void CTouchFeedbackImpl::StopFeedback( const CCoeControl* aControl )
       
  1006     {
       
  1007     if ( iClient )
       
  1008         {
       
  1009         TUint32 clientHandle = ClientHandle( aControl );
       
  1010         iClient->StopFeedback( clientHandle );
       
  1011         }        
       
  1012     }
       
  1013 
       
  1014 // ---------------------------------------------------------------------------
       
  1015 // 
       
  1016 // ---------------------------------------------------------------------------
       
  1017 //
       
  1018 TInt CTouchFeedbackImpl::SetFeedbackEnabledForDevice( TTouchFeedbackType aFeedbackType )
       
  1019     {
       
  1020     TInt ret( KErrGeneral );
       
  1021     if ( iClient )
       
  1022         {
       
  1023         ret = iClient->SetFeedbackEnabledForDevice( aFeedbackType );
       
  1024         }
       
  1025     return ret;
       
  1026     }
       
  1027 
       
  1028 // ---------------------------------------------------------------------------
       
  1029 // 
       
  1030 // ---------------------------------------------------------------------------
       
  1031 //
       
  1032 TTouchFeedbackType CTouchFeedbackImpl::FeedbackEnabledForDevice()
       
  1033     {
       
  1034     TTouchFeedbackType enabled( static_cast<TTouchFeedbackType>(0) );
       
  1035     if ( iClient )
       
  1036         {
       
  1037         enabled = iClient->FeedbackEnabledForDevice();
       
  1038         }
       
  1039     return enabled;
       
  1040     }
       
  1041 
       
  1042 // ---------------------------------------------------------------------------
       
  1043 // 
       
  1044 // ---------------------------------------------------------------------------
       
  1045 //
       
  1046 void CTouchFeedbackImpl::InstantFeedback( const CCoeControl* aControl,
       
  1047                                           TTouchLogicalFeedback aType,
       
  1048                                           const TPointerEvent& /*aPointerEvent*/ )
       
  1049     {
       
  1050     InstantFeedback(aControl, aType);
       
  1051     }
       
  1052 
       
  1053 // ---------------------------------------------------------------------------
       
  1054 // 
       
  1055 // ---------------------------------------------------------------------------
       
  1056 //
       
  1057 TInt CTouchFeedbackImpl::SetFeedbackArea( const CCoeControl* aControl, 
       
  1058                                           TUint32 aIndex,
       
  1059                                           TRect aRect, 
       
  1060                                           CFeedbackSpec* aFeedbackSpec )
       
  1061     {
       
  1062     // #1
       
  1063     if ( !iClient )
       
  1064         {
       
  1065         return KErrNone;
       
  1066         }
       
  1067     
       
  1068     // #2
       
  1069     if ( !aControl )
       
  1070         {
       
  1071         TRACE("CTouchFeedbackImpl::SetFeedbackArea(spec) - Err: NULL Control");
       
  1072         return KErrArgument;
       
  1073         }
       
  1074         
       
  1075     // #4        
       
  1076     TUint32 clientHandle = ClientHandle( aControl );
       
  1077     
       
  1078     if ( !clientHandle )
       
  1079         {
       
  1080         TRACE("CTouchFeedbackImpl::SetFeedbackArea(spec) - Err: Invalid Control");        
       
  1081         return KErrArgument;
       
  1082         }
       
  1083     
       
  1084     // #5    
       
  1085     TRAPD( err, 
       
  1086         DoSetFeedbackAreaL( 
       
  1087             aControl, 
       
  1088             aIndex, 
       
  1089             aRect, 
       
  1090             aFeedbackSpec, 
       
  1091             clientHandle ) );
       
  1092 
       
  1093     if (err)
       
  1094         {
       
  1095         TRACE2("CTouchFeedbackImpl::SetFeedbackArea(spec) err = %d", err );
       
  1096         }
       
  1097     
       
  1098     return err;    
       
  1099     }
       
  1100     
       
  1101 // ---------------------------------------------------------------------------
       
  1102 // 
       
  1103 // ---------------------------------------------------------------------------
       
  1104 //    
       
  1105 void CTouchFeedbackImpl::InstantFeedback( const CCoeControl* aControl,
       
  1106                                           TTouchLogicalFeedback aType,
       
  1107                                           TTouchFeedbackType aFeedbackType,
       
  1108                                           const TPointerEvent& /*aPointerEvent*/ )
       
  1109     {
       
  1110     if ( iClient && ( iAudioEnabledForThisApp || iVibraEnabledForThisApp ) )
       
  1111         {
       
  1112         // Initialize vibra and audio enablers as given in param.
       
  1113         TBool vibraEnabled = aFeedbackType & ETouchFeedbackVibra;
       
  1114         TBool audioEnabled = aFeedbackType & ETouchFeedbackAudio;
       
  1115 
       
  1116         // Check application level vibra and audio enablers
       
  1117         if ( !iVibraEnabledForThisApp )
       
  1118             {
       
  1119             vibraEnabled = EFalse;
       
  1120             }
       
  1121         if ( !iAudioEnabledForThisApp )
       
  1122             {
       
  1123             audioEnabled = EFalse;
       
  1124             }            
       
  1125 
       
  1126         TInt cacheIndex = FindControlFromCache( aControl );
       
  1127         
       
  1128         
       
  1129         // Check control level disablers for vibra and audio.
       
  1130         // (These can only prevent vibra or audio effect playback,
       
  1131         //  but not to force it on)
       
  1132         if ( cacheIndex >=0 && vibraEnabled ) 
       
  1133             {
       
  1134             vibraEnabled = !iControlCache[cacheIndex].iVibraDisabled;
       
  1135             }
       
  1136             
       
  1137         if ( cacheIndex >=0 && audioEnabled ) 
       
  1138             {
       
  1139             audioEnabled = !iControlCache[cacheIndex].iAudioDisabled;
       
  1140             }
       
  1141             
       
  1142         TRACE5("CTouchFeedbackImpl::InstantFeedback, 0x%x, type:=%d Vibra:%d Audio:%d", 
       
  1143                aControl, aType, vibraEnabled, audioEnabled);
       
  1144         iClient->ImmediateFeedback( aType, vibraEnabled, audioEnabled );   
       
  1145         }
       
  1146     }
       
  1147         
       
  1148 // ---------------------------------------------------------------------------
       
  1149 // Here we do the actual work for adding new area to the registry
       
  1150 // (or updating an existing one).
       
  1151 //
       
  1152 // #1 Check that control exist in the cache
       
  1153 //    #2a If it does not exist, then add it
       
  1154 //    #2b If control exists, but area not, then add new area
       
  1155 //    #2c If control and area both exist, then use existing id
       
  1156 // #3 Find corresponding registry entry
       
  1157 // #4 Create new entry if this was the first area for this window
       
  1158 // #5 Determine if new area should actually be active, and then
       
  1159 //    add it to registry
       
  1160 // #6 Inform server if we added an active area
       
  1161 //
       
  1162 // We use specific cleanup items for removing the added area and/or control
       
  1163 // from the control cache in caes adding of the area to the actual 
       
  1164 // registry fails. This way actual registry and control cache will remain
       
  1165 // in sync no matter what happens.
       
  1166 // ---------------------------------------------------------------------------
       
  1167 //
       
  1168 void CTouchFeedbackImpl::DoSetFeedbackAreaL( 
       
  1169                                 const CCoeControl* aControl, 
       
  1170                                 TUint32 aIndex,
       
  1171                                 TRect aRect, 
       
  1172                                 CFeedbackSpec* aFeedbackSpec, 
       
  1173                                 TUint32 aClientHandle )
       
  1174     {
       
  1175     TInt id = KErrNotFound;
       
  1176     TInt nbOfCleanupItems = 0;
       
  1177     TBool newArea = EFalse;
       
  1178     
       
  1179     // #1
       
  1180     TInt cacheIndex = KErrNotFound;
       
  1181     TInt areaIndex  = KErrNotFound;
       
  1182     FindAreaFromCache( aControl, aIndex, cacheIndex, areaIndex );
       
  1183 
       
  1184     // #2a
       
  1185     if ( cacheIndex < 0 )
       
  1186         {
       
  1187         id = GenerateUniqueIdL();
       
  1188         
       
  1189         TControlCacheEntry newCacheEntry;
       
  1190         
       
  1191         newCacheEntry.iControl            = aControl;
       
  1192         newCacheEntry.iClientHandle       = aClientHandle;
       
  1193         newCacheEntry.iVibraDisabled      = EFalse;
       
  1194         newCacheEntry.iAudioDisabled      = EFalse;
       
  1195         newCacheEntry.iVisible         = aControl->IsVisible();
       
  1196         newCacheEntry.iDimmed          = aControl->IsDimmed();
       
  1197         
       
  1198         // New entry will be added at the end of array
       
  1199         // This assignment will also make it possible to use
       
  1200         // "cacheIndex" -variable in the rest of the function
       
  1201         // in all cases.
       
  1202         cacheIndex = iControlCache.Count();
       
  1203         
       
  1204         iControlCache.AppendL( newCacheEntry );  
       
  1205         
       
  1206         // Use cleanup item to remove the control in case something
       
  1207         // fails later in this function.
       
  1208         CleanupStack::PushL(
       
  1209             TCleanupItem( CleanupCacheArray, &iControlCache ) );  
       
  1210         nbOfCleanupItems++;    
       
  1211         
       
  1212         TAreaIndexEntry newAreaEntry;
       
  1213         
       
  1214         newAreaEntry.iIndex  = aIndex;
       
  1215         newAreaEntry.iAreaId = id;
       
  1216         
       
  1217         iControlCache[cacheIndex].iAreaArray.AppendL( newAreaEntry );
       
  1218         
       
  1219         // Use cleanup item to remove the area id in case something
       
  1220         // fails later in this function.
       
  1221         CleanupStack::PushL( 
       
  1222             TCleanupItem( CleanupAreaArray, 
       
  1223                           &iControlCache[cacheIndex].iAreaArray) );  
       
  1224         nbOfCleanupItems++;    
       
  1225                  
       
  1226         newArea = ETrue;   
       
  1227         
       
  1228         // Enable control state change reports on the new control
       
  1229         CCoeControl* tmp =  const_cast<CCoeControl*>( aControl );
       
  1230         tmp->EnableReportControlStateChange( ETrue );
       
  1231         }
       
  1232     // #2b   
       
  1233     else if ( areaIndex < 0 )
       
  1234         {
       
  1235         id = GenerateUniqueIdL();
       
  1236         
       
  1237         TAreaIndexEntry newAreaEntry;
       
  1238     
       
  1239         newAreaEntry.iIndex  = aIndex;
       
  1240         newAreaEntry.iAreaId = id;
       
  1241 
       
  1242         iControlCache[cacheIndex].iAreaArray.AppendL( newAreaEntry );
       
  1243         
       
  1244         CleanupStack::PushL( 
       
  1245             TCleanupItem( CleanupAreaArray, 
       
  1246                           &iControlCache[cacheIndex].iAreaArray) );  
       
  1247         nbOfCleanupItems++;    
       
  1248 
       
  1249         newArea = ETrue;   
       
  1250         }
       
  1251     // #2c
       
  1252     else
       
  1253         {
       
  1254         id = iControlCache[cacheIndex].iAreaArray[areaIndex].iAreaId;
       
  1255         }
       
  1256                
       
  1257     // #3              
       
  1258     TInt registryIndex = FindWindowFromRegistry ( aClientHandle );
       
  1259     
       
  1260     // #4   
       
  1261     if (  registryIndex == KErrNotFound )
       
  1262         {
       
  1263         // There isn't yet a registry entry for this window
       
  1264         // --> Create it
       
  1265         CTouchFeedbackRegistry* newRegistry = 
       
  1266             CTouchFeedbackRegistry::NewL( aClientHandle );
       
  1267             
       
  1268         CleanupStack::PushL( newRegistry );
       
  1269         
       
  1270         registryIndex = iRegistryArray.Count();
       
  1271                 
       
  1272         iRegistryArray.AppendL( newRegistry );
       
  1273         
       
  1274         CleanupStack::Pop( newRegistry );
       
  1275         }
       
  1276 
       
  1277     // #5 Determine what is the vibra and audio status for the new area
       
  1278     //    (if control is invisible or dimmed then both will be disabled)    
       
  1279     TBool vibraEnabled = EFalse;
       
  1280     TBool audioEnabled = EFalse;
       
  1281     
       
  1282     TBool areaActive = ControlsAreasActive( cacheIndex );
       
  1283     
       
  1284     if ( areaActive )
       
  1285         {
       
  1286         vibraEnabled = !iControlCache[cacheIndex].iVibraDisabled;
       
  1287         audioEnabled = !iControlCache[cacheIndex].iAudioDisabled;
       
  1288         }
       
  1289         
       
  1290     
       
  1291     RArray<TTactileFbItem> feedbackEntries;
       
  1292     CleanupClosePushL( feedbackEntries );
       
  1293     TTouchEventType eventType(ETouchEventStylusDown);
       
  1294     TTouchLogicalFeedback feedbackTypeDown = ETouchFeedbackNone;
       
  1295     TTouchLogicalFeedback feedbackTypeUp   = ETouchFeedbackNone;
       
  1296     TTouchFeedbackType feedbackDown = ETouchFeedbackVibra;
       
  1297     TTouchFeedbackType feedbackUp   = ETouchFeedbackVibra;
       
  1298     aFeedbackSpec->GetFeedbackSpec(feedbackEntries);
       
  1299     TInt feedbackItems = feedbackEntries.Count();
       
  1300     for (TInt i=0;i<feedbackItems;i++)
       
  1301         {
       
  1302         TTactileFbItem item = feedbackEntries[i];
       
  1303         eventType = item.iEventType;
       
  1304         
       
  1305         if ( item.iEventType == ETouchEventStylusDown )
       
  1306             {
       
  1307             feedbackTypeDown = item.iFeedback;
       
  1308             feedbackDown = item.iFeedbackType;
       
  1309             }
       
  1310         else if ( item.iEventType == ETouchEventStylusUp )
       
  1311             {
       
  1312             feedbackTypeUp = item.iFeedback;
       
  1313             feedbackUp = item.iFeedbackType;
       
  1314             }
       
  1315         }
       
  1316     if ( feedbackItems > 0 )
       
  1317         {
       
  1318         iRegistryArray[registryIndex]->AddFeedbackAreaL( 
       
  1319             aRect, feedbackTypeDown, feedbackDown, feedbackTypeUp, feedbackUp, 
       
  1320             eventType, id, vibraEnabled, audioEnabled, aControl->IsVisible() );
       
  1321         }
       
  1322     CleanupStack::PopAndDestroy( &feedbackEntries );
       
  1323         
       
  1324     // We can now remove the cleanup items, because nothing can fail 
       
  1325     // anymore.    
       
  1326     CleanupStack::Pop( nbOfCleanupItems );    
       
  1327     
       
  1328     // We can also update the counter now, when we know that the area
       
  1329     // was actually added
       
  1330     if ( newArea )
       
  1331         {
       
  1332         iNbOfFeedbackAreas++;
       
  1333         }
       
  1334 
       
  1335     // #6 We only need to inform server in case we added an active area
       
  1336     // to the registry.
       
  1337     if ( areaActive ) 
       
  1338         {
       
  1339         iClient->RegistryChanged();        
       
  1340         }
       
  1341     }
       
  1342         
       
  1343 // ---------------------------------------------------------------------------
       
  1344 // A simple for -loop should be enough here, as we are not likely to have
       
  1345 // that many windows in one application process.
       
  1346 // ---------------------------------------------------------------------------
       
  1347 //
       
  1348 TInt CTouchFeedbackImpl::FindWindowFromRegistry( TUint aWindowHandle )
       
  1349     {
       
  1350     TInt index = KErrNotFound;
       
  1351     
       
  1352     for ( TInt i=0; i < iRegistryArray.Count(); i++ )
       
  1353         {
       
  1354         if ( iRegistryArray[i]->WindowHandle() == aWindowHandle )
       
  1355             {
       
  1356             index = i;
       
  1357             break;
       
  1358             }
       
  1359         }
       
  1360         
       
  1361     return index;
       
  1362     }
       
  1363     
       
  1364 // ---------------------------------------------------------------------------
       
  1365 // Just ask client to do updates immediately
       
  1366 // ---------------------------------------------------------------------------
       
  1367 //
       
  1368 void CTouchFeedbackImpl::FlushRegistryUpdates( )
       
  1369     {
       
  1370     if ( iClient )
       
  1371         {
       
  1372         TRACE("CTouchFeedbackImpl::FlushRegistryUpdates" ); 
       
  1373         iClient->FlushUpdates();
       
  1374         }
       
  1375     }    
       
  1376     
       
  1377 // ---------------------------------------------------------------------------
       
  1378 // We use integer numers starting from 1 as area identifiers. 
       
  1379 //
       
  1380 // There is a bookkeeping of last used identifier, and we'll start from one
       
  1381 // again after reaching the maximum value. 
       
  1382 //
       
  1383 // There is also a separate bookkeeping to know if our id values have been
       
  1384 // rotated at least once or not. From that we know if we have to check that
       
  1385 // the id is not in use already (if we are on the first round, then there 
       
  1386 // cannot be any area with the new id).
       
  1387 //
       
  1388 // Notice that it should be checked already _before_ calling this function,
       
  1389 // whether it is actually possible to find an unused identifier anymore.
       
  1390 // ---------------------------------------------------------------------------
       
  1391 //
       
  1392 TUint CTouchFeedbackImpl::GenerateUniqueIdL()
       
  1393     {
       
  1394     // First check that there actually is an identifier that we can find
       
  1395     // (i.e. check that maximum number of areas has not been reached)
       
  1396     if ( iNbOfFeedbackAreas >= KTouchMaxFeedbackAreaIdentifier )
       
  1397         {
       
  1398         User::Leave( KErrNoMemory );
       
  1399         }
       
  1400     
       
  1401     iCurrentId++;
       
  1402     
       
  1403     if ( iCurrentId > KTouchMaxFeedbackAreaIdentifier )
       
  1404         {
       
  1405         iCurrentId = 1;
       
  1406         
       
  1407         iCurrentIdCounterRotated = ETrue;
       
  1408         }
       
  1409         
       
  1410     if ( iCurrentIdCounterRotated )
       
  1411         {
       
  1412         while ( FeedbackAreaExists( iCurrentId ) )
       
  1413             {
       
  1414             iCurrentId++;
       
  1415             
       
  1416             if ( iCurrentId > KTouchMaxFeedbackAreaIdentifier )
       
  1417                 {
       
  1418                 iCurrentId = 1;
       
  1419                 }
       
  1420             }
       
  1421         
       
  1422         }
       
  1423     
       
  1424     return iCurrentId;
       
  1425     }
       
  1426     
       
  1427 // ---------------------------------------------------------------------------
       
  1428 // Scan through local registry in order to know whether the area with
       
  1429 // given identifier exists.
       
  1430 //
       
  1431 // This function is only used when creating a new unique identifier.
       
  1432 // ---------------------------------------------------------------------------
       
  1433 //
       
  1434 TBool CTouchFeedbackImpl::FeedbackAreaExists( TUint aAreaId )
       
  1435     {
       
  1436     TBool areaExists = EFalse;
       
  1437     
       
  1438     for ( TInt i=0; i < iRegistryArray.Count() && !areaExists; i++ )
       
  1439         {
       
  1440         RArray<TFeedbackEntry>* entryArray = 
       
  1441             iRegistryArray[i]->WindowRegistry(); 
       
  1442         
       
  1443         for ( TInt j=0; j < entryArray->Count() && !areaExists; j++ )
       
  1444             {
       
  1445             if ( (*entryArray)[j].iId == aAreaId )
       
  1446                 {
       
  1447                 areaExists = ETrue;
       
  1448                 }
       
  1449             }
       
  1450         }   
       
  1451     
       
  1452     return areaExists;
       
  1453     }
       
  1454         
       
  1455 // ---------------------------------------------------------------------------
       
  1456 // Because we use the so called "client handle" for identifying windows on
       
  1457 // client- and server sides, we must be able to generate a client handle
       
  1458 // from CCoeControl -pointer.
       
  1459 //
       
  1460 // The algorithm:
       
  1461 //
       
  1462 // #1 Loop as long as we haven't reached the top-level control, and we still
       
  1463 //    haven't found the first window-owning control.
       
  1464 // 
       
  1465 // #2 If this is a window-owning control, then it's address is the
       
  1466 //    client-side handle
       
  1467 //
       
  1468 // #3 Otherwise move up to next parent
       
  1469 //
       
  1470 // #4 If this control doesn't have paren't pointer, then try to get
       
  1471 //    a pointer to this control's window.
       
  1472 //
       
  1473 // #5 If we got the window, then use the ClientHandle -function for 
       
  1474 //    retrieving the pointer from server side
       
  1475 //
       
  1476 // #6 If we don't have parent- or window pointers, then give up.
       
  1477 // ---------------------------------------------------------------------------
       
  1478 //
       
  1479 TUint32 CTouchFeedbackImpl::ClientHandle( const CCoeControl* aControl )
       
  1480     {
       
  1481     TUint32 clientHandle = 0;
       
  1482     
       
  1483     const CCoeControl* parent = aControl;
       
  1484     
       
  1485     // #1
       
  1486     while ( clientHandle == 0 && parent )
       
  1487         {
       
  1488         if ( parent->OwnsWindow() )
       
  1489             {
       
  1490             // #2
       
  1491             clientHandle = reinterpret_cast<TUint32>( parent );            
       
  1492             }
       
  1493         else
       
  1494             {
       
  1495             // #3
       
  1496             parent = parent->Parent();
       
  1497             
       
  1498             if ( !parent )
       
  1499                 {      
       
  1500                 // #4          
       
  1501                 RDrawableWindow* window = aControl->DrawableWindow();
       
  1502                 
       
  1503                 if ( window )
       
  1504                     {
       
  1505                     // #5
       
  1506                     TRACE("CTouchFeedbackImpl::ClientHandle - Ask handle from wserv - begin" );
       
  1507                     clientHandle = window->ClientHandle();
       
  1508                     TRACE("CTouchFeedbackImpl::ClientHandle - Ask handle from wserv - end" );
       
  1509                     }
       
  1510                 else
       
  1511                     {
       
  1512                     // #6
       
  1513                     TRACE("CTouchFeedbackImpl::ClientHandle - Error: No window defined, not possible to get handle!!");
       
  1514                     }
       
  1515                 
       
  1516                 }
       
  1517             }        
       
  1518         }
       
  1519         
       
  1520     return clientHandle;
       
  1521     }
       
  1522     
       
  1523 // ---------------------------------------------------------------------------
       
  1524 // We could optimize this search in case we get very many controls to the
       
  1525 // array, but so far it hasn't been necessary.
       
  1526 // ---------------------------------------------------------------------------
       
  1527 //
       
  1528 TInt CTouchFeedbackImpl::FindControlFromCache( 
       
  1529     const CCoeControl* aControl )
       
  1530     {
       
  1531     TInt position = KErrNotFound;
       
  1532     
       
  1533     for ( TInt i=0; i < iControlCache.Count(); i++ )
       
  1534         {
       
  1535         if ( iControlCache[i].iControl == aControl )
       
  1536             {
       
  1537             position = i;
       
  1538             break;
       
  1539             }
       
  1540         }
       
  1541         
       
  1542     return position;    
       
  1543     }
       
  1544         
       
  1545 // ---------------------------------------------------------------------------
       
  1546 // If this search is starting to take too long time, then the best 
       
  1547 // optimization would be to optimize the FindControlFromCache -function,
       
  1548 // as there can potentially be very many controls, but not likely very many
       
  1549 // ares per each control.
       
  1550 // ---------------------------------------------------------------------------
       
  1551 //
       
  1552 void CTouchFeedbackImpl::FindAreaFromCache( 
       
  1553     const CCoeControl* aControl, 
       
  1554     TUint32 aIndex, 
       
  1555     TInt& aCacheIndex, 
       
  1556     TInt& aAreaIndex )
       
  1557     {
       
  1558     aAreaIndex  = KErrNotFound;
       
  1559 
       
  1560     aCacheIndex = FindControlFromCache( aControl );
       
  1561         
       
  1562     if ( aCacheIndex >= 0 )
       
  1563         {
       
  1564         TControlCacheEntry& entry (iControlCache[aCacheIndex]);
       
  1565         
       
  1566         for ( TInt i=0; i < entry.iAreaArray.Count(); i++ )
       
  1567             {
       
  1568             if ( entry.iAreaArray[i].iIndex == aIndex )
       
  1569                 {
       
  1570                 aAreaIndex = i;
       
  1571                 break;
       
  1572                 }
       
  1573             } 
       
  1574         }
       
  1575     }   
       
  1576    
       
  1577 // ---------------------------------------------------------------------------
       
  1578 // Here we remove the control from the cache. It is assumed that
       
  1579 // corresponding feedback areas have been removed from registry
       
  1580 // already.
       
  1581 // ---------------------------------------------------------------------------
       
  1582 //
       
  1583 void CTouchFeedbackImpl::RemoveControlFromCache( TInt aControlIndex )
       
  1584     {
       
  1585     __ASSERT_ALWAYS(  
       
  1586         aControlIndex >= 0 && aControlIndex < iControlCache.Count(),
       
  1587         Panic( ETouchClientPanicArrayAccess ) );
       
  1588         
       
  1589     iControlCache[aControlIndex].iAreaArray.Reset();
       
  1590     iControlCache[aControlIndex].iAreaArray.Close();
       
  1591     
       
  1592     iControlCache.Remove( aControlIndex );
       
  1593     }
       
  1594          
       
  1595 // ---------------------------------------------------------------------------
       
  1596 // We have a separate function for knowing if control's feedback areas
       
  1597 // should be active or not, because determining this is not so simple, and
       
  1598 // because this part can still change.
       
  1599 // 
       
  1600 // Control's areas are NOT active in case
       
  1601 //
       
  1602 //  #1 Its feedback has been explicitely disabled for audio and vibra
       
  1603 //
       
  1604 // OR
       
  1605 //
       
  1606 //  #2 It is not visible 
       
  1607 //
       
  1608 // OR 
       
  1609 //
       
  1610 //  #3 It is dimmed.
       
  1611 //
       
  1612 // ---------------------------------------------------------------------------
       
  1613 //
       
  1614 TBool CTouchFeedbackImpl::ControlsAreasActive( TInt aControlIndex )
       
  1615     {
       
  1616     __ASSERT_ALWAYS(  
       
  1617         aControlIndex >= 0 && aControlIndex < iControlCache.Count(),
       
  1618         Panic( ETouchClientPanicArrayAccess ) );
       
  1619 
       
  1620     TBool ret = ETrue;
       
  1621     
       
  1622     if ( ( iControlCache[aControlIndex].iVibraDisabled &&     // #1
       
  1623            iControlCache[aControlIndex].iAudioDisabled ) ||   
       
  1624           !iControlCache[aControlIndex].iVisible || // #2
       
  1625           iControlCache[aControlIndex].iDimmed )    // #3
       
  1626         {
       
  1627         ret = EFalse;
       
  1628         }
       
  1629         
       
  1630     return ret;
       
  1631     }   
       
  1632    
       
  1633 // ---------------------------------------------------------------------------
       
  1634 // This function can be used for disabling or enabling all control's 
       
  1635 // feedback areas in the registry.
       
  1636 //
       
  1637 // #1 Find out the registry index.
       
  1638 // #2 In a loop, disable / enable each feedback area for this control
       
  1639 // #3 Maintain bookkeeping, so that we will know in the end if anything 
       
  1640 //    changed or not (so that we won't make unnecessary updates to server)
       
  1641 // #4 Make a pending update request if registry really changed.
       
  1642 // ---------------------------------------------------------------------------
       
  1643 //
       
  1644 void CTouchFeedbackImpl::DoEnableControlsAreasInRegistry( 
       
  1645     TInt aControlIndex,
       
  1646     TBool aEnableVibra,
       
  1647     TBool aEnableAudio,
       
  1648     TBool aVisible )
       
  1649     {
       
  1650     __ASSERT_ALWAYS(  
       
  1651         aControlIndex >= 0 && aControlIndex < iControlCache.Count(),
       
  1652         Panic( ETouchClientPanicArrayAccess ) );
       
  1653 
       
  1654     TBool registryChanged = EFalse;
       
  1655     
       
  1656     TControlCacheEntry& entry ( iControlCache[aControlIndex] );
       
  1657     
       
  1658     // #1
       
  1659     TInt registryIndex = FindWindowFromRegistry ( entry.iClientHandle );
       
  1660 
       
  1661     if ( registryIndex != KErrNotFound )
       
  1662         {
       
  1663         for ( TInt i=0; i < entry.iAreaArray.Count(); i++ )
       
  1664             {
       
  1665             TInt id = entry.iAreaArray[i].iAreaId;
       
  1666             
       
  1667             // #2
       
  1668             TBool changedNow = 
       
  1669                 iRegistryArray[registryIndex]->SetFeedbackEnabled( 
       
  1670                     id, aEnableVibra, aEnableAudio, aVisible );
       
  1671                     
       
  1672             // #3       
       
  1673             registryChanged = registryChanged || changedNow;
       
  1674             }
       
  1675         }
       
  1676     
       
  1677     // #4
       
  1678     if ( registryChanged )
       
  1679         {
       
  1680         iClient->RegistryChanged();
       
  1681         }
       
  1682     }
       
  1683 
       
  1684 // ---------------------------------------------------------------------------
       
  1685 //
       
  1686 // ---------------------------------------------------------------------------
       
  1687 //    
       
  1688 EXPORT_C CFeedbackSpec* CFeedbackSpec::New()
       
  1689     {
       
  1690     return new CFeedbackSpec;
       
  1691     }
       
  1692 
       
  1693 // ---------------------------------------------------------------------------
       
  1694 //
       
  1695 // ---------------------------------------------------------------------------
       
  1696 //
       
  1697 CFeedbackSpec::~CFeedbackSpec()
       
  1698     {
       
  1699     iFbArray.Close();
       
  1700     }
       
  1701 
       
  1702 // ---------------------------------------------------------------------------
       
  1703 //
       
  1704 // ---------------------------------------------------------------------------
       
  1705 //
       
  1706 EXPORT_C TInt CFeedbackSpec::AddFeedback( TTouchEventType aEventType, 
       
  1707                                           TTouchLogicalFeedback aFeedback )
       
  1708     {
       
  1709     // Vibra feedback is enabled by default for every event type.
       
  1710     TInt fbType( ETouchFeedbackVibra | ETouchFeedbackAudio );
       
  1711     
       
  1712     return AddFeedback( aEventType, 
       
  1713                         aFeedback, 
       
  1714                         static_cast<TTouchFeedbackType>( fbType ) );
       
  1715     }
       
  1716     
       
  1717 // ---------------------------------------------------------------------------
       
  1718 //
       
  1719 // ---------------------------------------------------------------------------
       
  1720 //
       
  1721 EXPORT_C TInt CFeedbackSpec::AddFeedback( TTouchEventType aEventType, 
       
  1722                                           TTouchLogicalFeedback aFeedback,
       
  1723                                           TTouchFeedbackType aFeedbackType )
       
  1724     {
       
  1725     TTactileFbItem item;
       
  1726     if ( !(aEventType >= ETouchEventStylusDown && aEventType <= ETouchEventStylusPressUp ) )
       
  1727         {
       
  1728         return KErrArgument;
       
  1729         }
       
  1730     item.iEventType = aEventType;        
       
  1731     
       
  1732 	// range check. update when logical feedback types are changed.
       
  1733     if (! ( aFeedback >= ETouchFeedbackNone || aFeedback <= ETouchFeedbackSensitive) 
       
  1734      || ! ( aFeedback >= ETouchFeedbackBasicButton || 
       
  1735             aFeedback <= ETouchFeedbackMultiTouchRecognized ) )
       
  1736         {
       
  1737         return KErrArgument;
       
  1738         }
       
  1739     item.iFeedback = aFeedback;        
       
  1740     item.iFeedbackType = aFeedbackType;
       
  1741         
       
  1742     iFbArray.Append(item);
       
  1743     return KErrNone;
       
  1744     }    
       
  1745 
       
  1746 // ---------------------------------------------------------------------------
       
  1747 //
       
  1748 // ---------------------------------------------------------------------------
       
  1749 //
       
  1750 void CFeedbackSpec::GetFeedbackSpec( RArray<TTactileFbItem>& aArray )
       
  1751     {
       
  1752     // copy values from one array to another
       
  1753     TInt count = iFbArray.Count();
       
  1754     aArray.Reset(); // remove records from array if any
       
  1755     
       
  1756     for ( TInt i=0 ; i < count ; i++ )
       
  1757         {
       
  1758         TTactileFbItem item;
       
  1759         item.iFeedback  = iFbArray[i].iFeedback;
       
  1760         item.iEventType = iFbArray[i].iEventType;
       
  1761         item.iFeedbackType = iFbArray[i].iFeedbackType;
       
  1762         aArray.Append(item);
       
  1763         }
       
  1764     }
       
  1765 
       
  1766 // ---------------------------------------------------------------------------
       
  1767 //
       
  1768 // ---------------------------------------------------------------------------
       
  1769 //
       
  1770 CFeedbackSpec::CFeedbackSpec()
       
  1771     {
       
  1772     }
       
  1773 
       
  1774 // End of File