predictivesearch/adapters/contacts/src/cpcscontactstore.cpp
branchRCL_3
changeset 20 f4a778e096c2
child 21 9da50d567e3c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/predictivesearch/adapters/contacts/src/cpcscontactstore.cpp	Wed Sep 01 12:29:52 2010 +0100
@@ -0,0 +1,1041 @@
+/*
+* Copyright (c) 2007 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:  Active object to read all the contacts from a 
+*                particular data store. Handles add/ modify/ delete of contacts.
+*
+*/
+
+// SYSTEM INCLUDES
+#include <barsread.h>
+#include <coemain.h>
+#include <utf.h>
+#include <e32std.h>
+#include <badesca.h>
+#include <CVPbkContactManager.h>
+#include <CVPbkContactStoreUriArray.h>
+#include <CVPbkContactFieldIterator.h>
+#include <CVPbkFieldTypeRefsList.h>
+#include <CVPbkContactLinkArray.h>
+#include <TVPbkContactStoreUriPtr.h>
+#include <MVPbkContactOperationBase.h>
+#include <MVPbkContactStoreList.h>
+#include <MVPbkContactStore.h>
+#include <MVPbkStoreContact.h>
+#include <MVPbkContactFieldData.h>
+#include <MVPbkContactFieldTextData.h>
+#include <MVPbkContactStoreProperties.h>
+#include <MVPbkContactLink.h>
+#include <VPbkEng.rsg>
+#include <VPbkContactStoreUris.h>
+#include <CVPbkContactViewDefinition.h>
+#include <MVPbkContactViewBase.h>
+#include <VPbkContactView.hrh>
+#include <CVPbkContactIdConverter.h>
+#include <centralrepository.h>
+#include <MVPbkContactGroup.h>
+#include <CVPbkFieldTypeSelector.h>
+#include <CVPbkContactLinkArray.h>
+#include <CVPbkSortOrder.h>
+#include <data_caging_path_literals.hrh>
+#include <bautils.h>
+#include <featmgr.h>
+#include <CPbk2SortOrderManager.h>
+
+// USER INCLUDES
+#include "cpcscontactstore.h"
+#include "CPsData.h"
+#include "CPcsDebug.h" 
+#include "CPcsDefs.h"
+#include <contactsort.rsg>
+
+// CONSTANTS
+namespace {
+const TInt KSimStoreOffset            = -5000;
+const TInt KTimerInterval             = 100000;   // 100 milliseconds
+
+_LIT(KResourceFileName, "contactsort.rsc");
+_LIT(KPcsViewPrefix,"PCSView_");
+}
+// FORWARD DECLARATION
+
+// ============================== MEMBER FUNCTIONS ================================
+
+// ---------------------------------------------------------------------------------
+// 2 phase construction
+// ---------------------------------------------------------------------------------
+CPcsContactStore* CPcsContactStore::NewL(CVPbkContactManager&  aContactManager,
+                                         MDataStoreObserver& aObserver,
+                                         const TDesC& aUri)
+{
+	PRINT ( _L("Enter CPcsContactStore::NewL") );
+
+	CPcsContactStore* self = new ( ELeave ) CPcsContactStore( );
+	CleanupStack::PushL( self );
+	
+	self->ConstructL(aContactManager,aObserver,aUri);
+	CleanupStack::Pop( self );
+	
+	PRINT ( _L("End CPcsContactStore::NewL") );
+	return self;
+}
+
+// ---------------------------------------------------------------------------------
+// Constructor
+// ---------------------------------------------------------------------------------
+CPcsContactStore::CPcsContactStore():
+    CActive( CActive::EPriorityLow ),
+    iInitialContactCount( 0 ),
+    iFetchBlockLowerNumber( 0 ),
+    iFetchBlockUpperNumber( 0 ),
+    iVPbkCallbackCount( 0 ),
+    iContactViewReady( EFalse )
+{
+    PRINT ( _L("Enter CPcsContactStore::CPcsContactStore") );
+    CActiveScheduler::Add( this );
+    PRINT ( _L("End CPcsContactStore::CPcsContactStore") );
+}
+
+// ---------------------------------------------------------------------------------
+// CPcsContactStore::ConstructL() 
+// 2nd phase constructor
+// ---------------------------------------------------------------------------------
+void CPcsContactStore::ConstructL(CVPbkContactManager&  aContactManager,
+                                  MDataStoreObserver& aObserver,
+                                  const TDesC& aUri)
+{
+    PRINT ( _L("Enter CPcsContactStore::ConstructL") );
+    
+	iContactManager = &aContactManager;
+	iObserver = &aObserver;
+	
+	iUri = aUri.AllocL();
+	
+	// create containers for holding the sim data
+    iSimContactItems = CVPbkContactLinkArray::NewL();
+   
+	
+	// for creating sort order
+	iSortOrder = CVPbkFieldTypeRefsList::NewL();
+	
+	// Read the fields to cache from the central repository
+	ReadFieldsToCacheFromCenrepL();
+	
+    // Local timer for block fetch delay
+    iTimer.CreateLocal();
+    
+    // Initial state
+	iNextState = ECreateView;
+	IssueRequest( 0 );
+	
+    FeatureManager::InitializeLibL();
+    if( FeatureManager::FeatureSupported( KFeatureIdffContactsMycard ) )
+        {
+        iMyCardSupported = ETrue;
+        }
+    FeatureManager::UnInitializeLib();    
+
+	PRINT ( _L("End CPcsContactStore::ConstructL") );
+}
+
+// ---------------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------------
+CPcsContactStore::~CPcsContactStore() 
+{
+	PRINT ( _L("Enter CPcsContactStore::~CPcsContactStore") );
+	
+	delete iContactViewBase;
+	delete iSortOrder;
+    delete iSimContactItems;   
+	delete iWait;
+	delete iUri;
+	
+	iTimer.Cancel();
+    iTimer.Close();
+	iFieldsToCache.Close();	
+	
+	iFs.Close();
+
+	iInitialContactLinks.ResetAndDestroy();
+    
+	if(IsActive())
+	{
+		Deque();
+	}
+	
+	delete iSortOrderMan;
+	
+	PRINT ( _L("End CPcsContactStore::~CPcsContactStore") );
+}
+
+// ---------------------------------------------------------------------------------
+// Handles addition/deletion/modification of contacts
+// ---------------------------------------------------------------------------------
+void CPcsContactStore::HandleStoreEventL(MVPbkContactStore& aContactStore, 
+                TVPbkContactStoreEvent aStoreEvent)
+{
+   	PRINT ( _L("Enter CPcsContactStore::HandleStoreEventL") );
+   	
+    PRINT2 ( _L("CPcsContactStore::HandleStoreEventL: URI=%S, event TVPbkContactStoreEventType::%d received"),
+             &*iUri, aStoreEvent.iEventType);
+   	        
+    switch (aStoreEvent.iEventType) 
+    {
+		case TVPbkContactStoreEvent::EContactAdded:
+        case TVPbkContactStoreEvent::EGroupAdded:
+		{
+		    // Observer will be notified once the cache update is complete
+		    iOngoingCacheUpdate = ECacheUpdateContactAdded;
+		                    
+		    iContactManager->RetrieveContactL( *(aStoreEvent.iContactLink), *this );
+			break;
+		}
+
+        case TVPbkContactStoreEvent::EUnknownChanges:
+        {
+            iObserver->RemoveAll( *iUri );      
+            // To indicate that contact view is not ready when unknown changes happens 
+            iContactViewReady = EFalse;
+            iContactViewBase->AddObserverL(*this);
+            break;
+        }
+
+		case TVPbkContactStoreEvent::EContactDeleted:
+        case TVPbkContactStoreEvent::EGroupDeleted:
+		case TVPbkContactStoreEvent::EContactChanged:
+		case TVPbkContactStoreEvent::EGroupChanged:
+		{
+			CVPbkContactIdConverter* converter = NULL;
+			
+		    TRAPD ( err, converter = CVPbkContactIdConverter::NewL( aContactStore ) );
+
+	        TInt32 contactId(-1);
+	        
+	        if ( err == KErrNotSupported )
+	        {
+	            // sim domain  
+	            // Pass the sim observer string in the next line
+	            TInt contactLocation = iSimContactItems->Find(*aStoreEvent.iContactLink);
+				if( KErrNotFound != contactLocation)
+				{
+				    // We are not removing from the array cache. If you try to fetch, 
+				    // then it will give an error
+				    TInt index = CreateCacheIDfromSimArrayIndex( contactLocation );
+				    
+	                iObserver->RemoveData(*iUri,index );
+		       	}
+		    
+	        }
+	        else
+	        {
+	           // cntdb domain
+	           // Get contact id by mapping the link
+	           contactId = converter->LinkToIdentifier(*(aStoreEvent.iContactLink));
+	           
+	           // Remove the contact
+		       iObserver->RemoveData(*iUri, contactId);
+		    }
+		    
+		    delete converter;
+		    converter = NULL;
+		    
+	        if (( aStoreEvent.iEventType == TVPbkContactStoreEvent::EContactChanged ) ||
+	            ( aStoreEvent.iEventType == TVPbkContactStoreEvent::EGroupChanged ) )
+	        {
+	            // Observer will be notified once the cache update is complete
+	            iOngoingCacheUpdate = ECacheUpdateContactModified;
+	            
+	            // Add the contact
+	            iContactManager->RetrieveContactL( *(aStoreEvent.iContactLink), *this );
+	        }
+	        else
+	        {
+	            // Inform observer immediately about contact removal
+                iObserver->UpdateCachingStatus( *iUri, ECacheUpdateContactRemoved );
+	        }
+	        
+			break;
+		}
+	}
+
+	PRINT ( _L("End CPcsContactStore::HandleStoreEventL") );
+}
+
+// ---------------------------------------------------------------------------
+//  Returns ths database URI
+// ---------------------------------------------------------------------------
+TDesC& CPcsContactStore::GetStoreUri()
+{
+    return *iUri;
+}
+
+// ---------------------------------------------------------------------------
+//  Check next state of state machine for contacts retrieval and perform
+//  transition
+// --------------------------------------------------------------------------- 
+void CPcsContactStore::CheckNextState()
+{
+    PRINT5 ( _L("CPcsContactStore::CheckNextState(state %d) %d:(%d..%d)/%d"),
+             iNextState, iVPbkCallbackCount,
+             iFetchBlockLowerNumber, iFetchBlockUpperNumber, iInitialContactCount );
+
+    if ( iNextState == EComplete )
+    {
+        return;
+    }
+
+    // If during the caching of the contacts initially in the view we get some
+    // contact events for other contact operations from the user, then it can
+    // happen at the end of the caching process that iCallbackCount > iAllContactLinksCount.
+    // We assume that it can never be that at the end of the caching it results
+    // iCallbackCount < iAllContactLinksCount.
+
+    // Check if caching is complete
+    if( iFetchBlockUpperNumber == iInitialContactCount       // All contacts initially in the view were fetched
+        && iVPbkCallbackCount >= iInitialContactCount )        // We got at least the same amount of callbacks
+    {
+        iObserver->UpdateCachingStatus(*iUri, ECachingComplete);
+        iNextState = EComplete;
+        IssueRequest( 0 );
+    }
+    // We could have a number of callbacks that is the same of the fetched contacts
+    // from the view even before we get the all the callbacks for the fetched contacts.
+    // This can happen for instance if a contact is added by the user.
+    // With the following condition it will happen just that the fetching of more
+    // contacts from the initial view is happening before all the callbacks for
+    // those are received.
+    else if ( iVPbkCallbackCount >= iFetchBlockUpperNumber ) // Fetch next block
+    {
+        iObserver->UpdateCachingStatus(*iUri, ECachingInProgress);
+        iNextState = EFetchContactBlock;
+        // Delay the next fetch since contact fetch is CPU intensive,
+        // this will give other threads a chance to use CPU
+        IssueRequest( KTimerInterval ); // 100 milliseconds
+    }
+    else
+    {
+    // Otherwise, just pass through.
+    }
+
+}
+
+// ---------------------------------------------------------------------------
+//  Callback Method. Called when one Retrieve operation is complete
+// --------------------------------------------------------------------------- 
+void CPcsContactStore::VPbkSingleContactOperationComplete(
+        MVPbkContactOperationBase& aOperation, MVPbkStoreContact* aContact)
+{
+    PRINT ( _L("Enter CPcsContactStore::VPbkSingleContactOperationComplete") );
+
+    // We get this incremented even during add/del of contacts during caching
+    iVPbkCallbackCount++;
+    
+	// Handle the fetched contact....
+	TRAPD(err, HandleRetrievedContactL(aContact) );
+	if( err != KErrNone)
+	{
+		iObserver->UpdateCachingStatus(*iUri, err);
+	}
+
+	MVPbkContactOperationBase* Opr = &aOperation;
+	if ( Opr )
+	{
+		delete Opr;
+		Opr = NULL;
+	}
+
+	CheckNextState();
+
+    PRINT ( _L("End CPcsContactStore::VPbkSingleContactOperationComplete") );
+}
+    
+// ---------------------------------------------------------------------------
+//  Callback Method. Called when one Retrieve operation fails.
+// ---------------------------------------------------------------------------
+void CPcsContactStore::VPbkSingleContactOperationFailed(
+        MVPbkContactOperationBase& /*aOperation*/, TInt /*aError*/ )
+{
+  	PRINT ( _L("Enter CPcsContactStore::VPbkSingleContactOperationFailed") );
+
+  	iVPbkCallbackCount++;
+
+	CheckNextState();
+
+	PRINT ( _L("End CPcsContactStore::VPbkSingleContactOperationFailed") );
+}
+
+// ---------------------------------------------------------------------------
+// Handles the operations for a single contact after it is fetched
+// ---------------------------------------------------------------------------
+void CPcsContactStore::HandleRetrievedContactL(MVPbkStoreContact* aContact)
+{    
+    // Take the ownership
+    aContact->PushL();
+
+    if ( iMyCardSupported && IsMyCard( *aContact ) )
+        {
+        CleanupStack::PopAndDestroy( aContact );
+        return;
+        }
+    
+    // Fill the contact link
+	MVPbkContactLink* tmpLink = aContact->CreateLinkLC();
+	
+    // If the link is null, then it is not put on the cleanup stack,
+    // so we need not pop in such a case
+    if ( NULL == tmpLink )
+    {
+        CleanupStack::PopAndDestroy( aContact );
+        return;
+    }
+
+	CPsData* phoneContact = CPsData::NewL();
+
+	// Fill the contact id
+	CVPbkContactIdConverter* converter = NULL;
+	TRAPD ( err, converter = CVPbkContactIdConverter::NewL( aContact->ParentStore() ) );
+	
+	if ( err == KErrNotSupported )
+	{
+		// simdb domain
+		PRINT ( _L("CPcsContactStore::HandleRetrievedContactL: SIM domain data received") );
+		
+        // Set the contact link 
+        HBufC8* extnInfo = tmpLink->PackLC();
+        phoneContact->SetDataExtension(extnInfo);
+        CleanupStack::Pop( extnInfo );
+
+        // Get the index of the SIM contact
+        TInt tempIndex =  iSimContactItems->Find(*tmpLink);	
+		
+		if ( KErrNotFound == tempIndex)
+		    {
+		    tempIndex = iSimContactItems->Count();
+	        iSimContactItems->AppendL(tmpLink);
+	        CleanupStack::Pop(); // tmpLink
+	        }
+		else
+		    {
+            CleanupStack::PopAndDestroy(); // tmpLink
+		    }
+		
+	    //Create a dummy sim index and set it
+	    TInt simIndex = CreateCacheIDfromSimArrayIndex(tempIndex);
+	    phoneContact->SetId(simIndex);
+	}
+	else 
+	{
+	    // cntdb domain
+		TInt32 contactId = converter->LinkToIdentifier(*tmpLink);
+		phoneContact->SetId(contactId);
+		CleanupStack::PopAndDestroy(); // tmpLink
+	}
+   	 
+	MVPbkContactGroup* myContactGroup= aContact->Group();
+	
+	// The retrieved contact can be a contact item or a contact group, Handle accordingly
+	if ( NULL == myContactGroup )
+	{
+		// The fetched contact item (and not a contact group.)
+		GetDataForSingleContactL( *aContact, phoneContact );
+	    // Recover the URI
+	    HBufC* storeUri = aContact->ParentStore().StoreProperties().Uri().UriDes().AllocL();
+		//Add the data to the relevent cache through the observer
+		iObserver->AddData(*storeUri, phoneContact);
+		delete storeUri;
+	}
+	else
+	{  
+	    // Fetch the group name 
+	    HBufC* groupName = myContactGroup->GroupLabel().AllocLC();
+	    TInt grpArrayIndex = -1; 
+	    for (TInt i =0; i  <iFieldsToCache.Count(); i++)
+	    {
+	    	if (iFieldsToCache[i] == R_VPBK_FIELD_TYPE_LASTNAME)
+			{
+			    grpArrayIndex = i;
+			}
+			phoneContact->SetDataL(i, KNullDesC);
+	    }
+	    if (grpArrayIndex != -1)
+	    {
+	    	phoneContact->SetDataL(grpArrayIndex, *groupName);
+	    
+            // Check for the contact in the group.
+            MVPbkContactLinkArray* contactsContainedInGroup = myContactGroup->ItemsContainedLC();
+            for (TInt i = 0; i < contactsContainedInGroup->Count(); i++)
+            {
+                TInt grpContactId = converter->LinkToIdentifier(contactsContainedInGroup->At(i));
+                phoneContact->AddIntDataExtL(grpContactId);
+            }
+            CleanupStack::PopAndDestroy(); // contactsContainedInGroup
+            
+            // Recover the URI
+            HBufC* storeUri = KVPbkDefaultGrpDbURI().AllocL();
+            
+            //Add the data to the relevent cache through the observer
+            iObserver->AddData(*storeUri, phoneContact);
+            
+            delete storeUri;
+	 	}
+	    else
+	    {
+	    	//We do not add anything here since Lastname does not exists in cenrep
+	    	delete phoneContact;
+	    	phoneContact = NULL;
+	    }
+	    CleanupStack::PopAndDestroy( groupName );
+	}
+	
+	delete converter;
+	converter = NULL;
+
+	CleanupStack::PopAndDestroy(aContact);
+	
+	// Inform observer if this contact addition was a result of contact store event.
+	if ( iOngoingCacheUpdate == ECacheUpdateContactModified ||
+	     iOngoingCacheUpdate == ECacheUpdateContactAdded )
+	    {
+        iObserver->UpdateCachingStatus( *iUri, iOngoingCacheUpdate );
+        iOngoingCacheUpdate = ECachingComplete;
+	    }
+}
+
+// ---------------------------------------------------------------------------
+// Fetches the data from a particular contact 
+// --------------------------------------------------------------------------- 
+void CPcsContactStore::GetDataForSingleContactL( MVPbkBaseContact& aContact,
+                                                 CPsData* aPhoneData )
+{      
+    for(TInt i =0; i < iFieldsToCache.Count(); i++)
+    {
+	    aPhoneData->SetDataL(i, KNullDesC);
+		AddContactFieldsL( aContact, iFieldsToCache[i], aPhoneData);			
+    }
+}
+
+// ---------------------------------------------------------------------------
+// Add the data from contact fields
+// --------------------------------------------------------------------------- 
+void CPcsContactStore::AddContactFieldsL( MVPbkBaseContact& aContact,
+                                          TInt aFieldType,
+                                          CPsData *aPhoneData)
+{
+	const MVPbkFieldType* myContactDataField = 
+		iContactManager->FieldTypes().Find( aFieldType );
+
+	CVPbkBaseContactFieldTypeIterator* itr = 
+		CVPbkBaseContactFieldTypeIterator::NewLC( *myContactDataField, 
+		aContact.Fields() );	
+			
+	// Iterate through each of the data fields
+	while ( itr->HasNext() )
+	{
+		const MVPbkBaseContactField* field = itr->Next();
+
+	    if ( ( field->FieldData()).DataType() == EVPbkFieldStorageTypeText )
+		{
+			const MVPbkContactFieldTextData& data = 
+				MVPbkContactFieldTextData::Cast( field->FieldData() );
+			
+			//If the field exist in iFieldsToCache, then set it
+			for ( TInt i = 0 ; i< iFieldsToCache.Count(); i++ )
+			{
+				if (aFieldType == iFieldsToCache[i])
+				{	
+                    // Check if the field has any data entry. If so
+                    // concatenate the next data to the existing one.
+                    // A unit seperator is used to show that these are
+                    // two entries.
+                    HBufC* previousData = aPhoneData->Data(i);
+                    if( (previousData != NULL) && (previousData->Des().Length()> 1) )
+                    {
+                        HBufC* newData = HBufC::NewLC(data.Text().Length() + previousData->Des().Length() + 5);
+                        TPtr newDataPtr(newData->Des());
+                        newDataPtr.Append(previousData->Des());
+                        newDataPtr.Append(KSpaceCharacter);
+                        newDataPtr.Append(KUnitSeparator);
+                        newDataPtr.Append(KSpaceCharacter);
+                        newDataPtr.Append(data.Text());
+                        aPhoneData->SetDataL(i,*newData);
+                        CleanupStack::PopAndDestroy(newData);
+                    }
+                    else
+                    {
+                        aPhoneData->SetDataL(i,data.Text());
+                    }
+				}
+			}
+		}
+	}
+	
+	CleanupStack::PopAndDestroy( itr ); 
+}
+
+// ---------------------------------------------------------------------------
+// Fetches all the initial contact links from vpbk 
+// --------------------------------------------------------------------------- 
+void CPcsContactStore::FetchAllInitialContactLinksL()
+{
+    PRINT2 ( _L("CPcsContactStore::FetchAllInitialContactLinksL: URI=%S. Fetching %d contact links"),
+             &*iUri, iInitialContactCount );
+
+    __LATENCY_MARK ( _L("CPcsContactStore::FetchAllInitialContactLinksL ==== fetch contact links start") );
+    
+    for(TInt cnt = 0; cnt < iInitialContactCount; cnt++)
+    {
+        // Get the contact link
+        MVPbkContactLink* tempLink = iContactViewBase->CreateLinkLC(cnt);
+        iInitialContactLinks.AppendL( tempLink );
+        CleanupStack::Pop();
+    }
+
+    __LATENCY_MARKEND ( _L("CPcsContactStore::FetchAllInitialContactLinksL ==== fetch contact links end") );                          
+
+    // No callback to wait for next state
+    iObserver->UpdateCachingStatus(*iUri, ECachingInProgress);
+    iNextState = EFetchContactBlock;
+    IssueRequest( 0 );
+}
+
+// ---------------------------------------------------------------------------
+// Fetches the data from the vpbk using the contact links 
+// --------------------------------------------------------------------------- 
+void CPcsContactStore::FetchContactsBlockL()
+{
+    iFetchBlockLowerNumber = iFetchBlockUpperNumber;
+    iFetchBlockUpperNumber += KLinksToFetchInOneGo;
+    if ( iFetchBlockUpperNumber > iInitialContactCount )
+    {
+        iFetchBlockUpperNumber = iInitialContactCount;
+    }
+    
+    PRINT2 ( _L("CPcsContactStore::FetchContactsBlockL: Fetched %d contacts, fetching more until %d"),
+             iFetchBlockLowerNumber, iFetchBlockUpperNumber );
+
+    for(TInt cnt = iFetchBlockLowerNumber; cnt < iFetchBlockUpperNumber; cnt++)
+    {
+        // Retrieve the contact
+        iContactManager->RetrieveContactL( *iInitialContactLinks[cnt], *this );
+    }
+
+    // Destroy the array of temporary contact links when all
+    // contacts from the initial view are retrieved
+    if (iFetchBlockUpperNumber == iInitialContactCount)
+    {
+        iInitialContactLinks.ResetAndDestroy();
+    }
+}
+
+// ---------------------------------------------------------------------------
+// Implements the view ready function of MVPbkContactViewObserver
+// --------------------------------------------------------------------------- 
+void CPcsContactStore::ContactViewReady(
+                MVPbkContactViewBase& aView ) 
+{
+    PRINT ( _L("Enter CPcsContactStore::ContactViewReady") );
+
+    iFs.Close();
+    aView.RemoveObserver(*this);
+    // Get the total number of contacts for this view
+    TRAPD(err, iInitialContactCount = aView.ContactCountL());
+    
+    if(err != KErrNone)
+    {
+    	PRINT( _L("CPcsContactStore::ContactViewReady: Unable to obtain Contacts count"));
+        iObserver->UpdateCachingStatus(*iUri, ECachingCompleteWithErrors);
+    	iNextState = EComplete;
+   		IssueRequest( 0 );
+   		return;
+    }
+    
+    PRINT1 ( _L("CPcsContactStore::ContactViewReady: Total number of contacts for this view: %d"),
+            iInitialContactCount );
+    if(iInitialContactCount == 0)
+    {
+        // No Contacts to cache, hence update the status accordingly
+    	iObserver->UpdateCachingStatus(*iUri, ECachingComplete);
+    	iNextState = EComplete;
+   		IssueRequest( 0 );
+   		return;
+    }
+    iFetchBlockLowerNumber = 0;
+    iFetchBlockUpperNumber = 0;
+    iVPbkCallbackCount = 0;
+    
+    // Change the iNextState to fetch the contacts 
+    if(iContactViewReady == EFalse)
+    {
+    	iObserver->UpdateCachingStatus(*iUri, ECachingInProgress);
+    	iContactViewReady = ETrue;
+    	iNextState = EFetchAllLinks;
+   		IssueRequest( 0 );
+    }
+	
+	PRINT ( _L("End CPcsContactStore::ContactViewReady") );
+}
+
+// ---------------------------------------------------------------------------
+// Implements the view unavailable function of MVPbkContactViewObserver
+// --------------------------------------------------------------------------- 
+void CPcsContactStore::ContactViewUnavailable(
+         MVPbkContactViewBase& /*aView*/ )  
+{
+    PRINT ( _L("Enter CPcsContactStore::ContactViewUnavailable") );
+    PRINT1 ( _L("CPcsContactStore::ContactViewUnavailable: URI=%S"),
+             &*iUri );
+
+    // Update the caching status to cachingComplete, the client of PCS--Cmail can
+    // perform searching even when contactview of somestore is unavailable.
+    // For Contacts and Group view we get one of this event brfore ContactViewReady
+	iObserver->UpdateCachingStatus(*iUri, ECachingComplete);
+    iFs.Close();
+
+    PRINT ( _L("End CPcsContactStore::ContactViewUnavailable") );
+}
+
+// ---------------------------------------------------------------------------
+// Implements the add contact function of MVPbkContactViewObserver
+// --------------------------------------------------------------------------- 
+void CPcsContactStore::ContactAddedToView(
+         MVPbkContactViewBase& /*aView*/, 
+         TInt /*aIndex*/, 
+         const MVPbkContactLink& /*aContactLink*/ ) 
+{
+}
+
+// ---------------------------------------------------------------------------
+// Implements the remove contact function of MVPbkContactViewObserver
+// --------------------------------------------------------------------------- 
+void CPcsContactStore::ContactRemovedFromView(
+         MVPbkContactViewBase& /*aView*/, 
+         TInt /*aIndex*/, 
+         const MVPbkContactLink& /*aContactLink*/ )  
+{
+}
+
+// ---------------------------------------------------------------------------
+// Implements the view error function of MVPbkContactViewObserver
+// --------------------------------------------------------------------------- 
+void CPcsContactStore::ContactViewError(
+         MVPbkContactViewBase& /*aView*/, 
+         TInt aError, 
+         TBool /*aErrorNotified*/ )  
+{
+    PRINT2 ( _L("CPcsContactStore::ContactViewError: URI=%S, Error=%d"),
+             &*iUri, aError );
+}
+
+// ---------------------------------------------------------------------------
+// Creates the contact view to fetch data from this store
+// --------------------------------------------------------------------------- 
+void CPcsContactStore::CreateContactFetchViewL()
+{
+	PRINT ( _L("Enter CPcsContactStore::CreateContactFetchViewL") );
+    PRINT1 ( _L("CPcsContactStore::CreateContactFetchViewL: URI=%S"),
+             &*iUri );
+	
+	// Create the view definition
+    CVPbkContactViewDefinition* viewDef = CVPbkContactViewDefinition::NewL();
+	CleanupStack::PushL( viewDef );
+
+    // Create the View Name for the view
+    // The views are named as PCSView_<uri>		
+	HBufC* viewName = HBufC::NewL(KBufferMaxLen);
+	viewName->Des().Append(KPcsViewPrefix);
+	viewName->Des().Append(iUri->Des());
+	CleanupStack::PushL(viewName);
+
+	// Set the Uri
+	if ( iUri->CompareC(KVPbkDefaultGrpDbURI) == 0)
+	{	    
+		// Special Handling required for Groups Data Store
+		// Read the resource file and create the sort order
+		// The sort order created is used in view creation.
+		
+		User::LeaveIfError( iFs.Connect() );
+		TPtrC driveLetter = TParsePtrC( RProcess().FileName() ).Drive();
+		TBuf<KMaxFileName> resourceFileName;
+		RResourceFile iResourceFile;
+		
+		//Read the path of the resource file
+		resourceFileName.Copy( driveLetter );
+		resourceFileName.Append( KDC_RESOURCE_FILES_DIR );
+		resourceFileName.Append( KResourceFileName );
+		
+		//Open the resource file
+	  	BaflUtils::NearestLanguageFile( iFs, resourceFileName );
+	    iResourceFile.OpenL( iFs, resourceFileName );
+	  	iResourceFile.ConfirmSignatureL(0);
+	
+
+        //Read resource	             
+        HBufC8* textbuffer = iResourceFile.AllocReadL(R_SORTORDER_LASTNAME);
+        CleanupStack::PushL(textbuffer);
+        
+        // Set the resource information into the reader
+        TResourceReader reader;
+        reader.SetBuffer(textbuffer);
+	
+	    // Create sort order with only last name
+	    CVPbkSortOrder* sortOrder = CVPbkSortOrder::NewL( reader, 
+	                                                      iContactManager->FieldTypes() );
+
+	    CleanupStack::PushL(sortOrder);
+		
+		// Set the groups type
+		viewDef->SetUriL(KVPbkDefaultCntDbURI);
+		viewDef->SetType( EVPbkGroupsView );
+
+		// Set name for the view
+		viewDef->SetNameL( *viewName );	
+		
+		// Create the contact view
+		iContactViewBase = iContactManager->CreateContactViewLC( 
+		                         *this, 
+		                         *viewDef, 
+		                         *sortOrder);
+
+        CleanupStack::Pop(); // iContactViewBase
+        CleanupStack::PopAndDestroy(sortOrder);	
+        CleanupStack::PopAndDestroy(textbuffer);
+
+    	// Close the resouce File
+        iResourceFile.Close();
+	}
+	else if ( iUri->CompareC(KVPbkDefaultCntDbURI) == 0)
+    {       
+        // For phone contacts DB we use the shared "AllContacts" -view so that 
+        // we don't need to generate a new view. This way we save some RAM
+        // from contacts server and some CPU time because the view is already
+        // generated and sorted. Difference is noticiable with larger amount 
+        // of contacts e.g. 7000. 
+	
+        viewDef->SetUriL( iUri->Des() );
+        viewDef->SetType( EVPbkContactsView );
+
+        if( !iSortOrderMan )
+            {
+            iSortOrderMan = CPbk2SortOrderManager::NewL( 
+                iContactManager->FieldTypes(), &iContactManager->FsSession() );
+            }
+
+        iContactViewBase = iContactManager->CreateContactViewLC( 
+            *this, *viewDef, iSortOrderMan->SortOrder() );
+        CleanupStack::Pop(); // iContactViewBase       
+    }
+	else
+	{
+		// Create sort order with the fields from cenrep
+		CreateSortOrderL(iContactManager->FieldTypes());
+		
+		CVPbkSortOrder* sortOrderPhone = CVPbkSortOrder::NewL(*iSortOrder);
+	    CleanupStack::PushL(sortOrderPhone);
+	    
+		// set contacts type
+		viewDef->SetUriL(iUri->Des());
+		viewDef->SetType( EVPbkContactsView );
+			
+		// Set name for the view
+		viewDef->SetNameL( *viewName );	
+		__LATENCY_MARK ( _L("CPcsContactStore::CreateContactFetchViewL ==== create view start") );
+    	iContactViewBase = iContactManager->CreateContactViewLC( 
+		                         *this, 
+		                         *viewDef, 
+		                         *sortOrderPhone );
+		__LATENCY_MARKEND ( _L("CPcsContactStore::CreateContactFetchViewL ==== create view end") );	                         
+        
+        CleanupStack::Pop(); // iContactViewBase	
+        CleanupStack::PopAndDestroy(sortOrderPhone);	
+	}		 
+		                             
+    CleanupStack::PopAndDestroy( viewName );	
+    CleanupStack::PopAndDestroy( viewDef );	
+    
+    PRINT ( _L("End CPcsContactStore::CreateContactFetchViewL") );
+}
+
+// ---------------------------------------------------------------------------------
+// Implements cancellation of an outstanding request.
+// ---------------------------------------------------------------------------------
+void CPcsContactStore::DoCancel() 
+{    
+}
+
+// ---------------------------------------------------------------------------------
+// The function is called by the active scheduler 
+// ---------------------------------------------------------------------------------
+void CPcsContactStore::RunL() 
+{
+	TRequestStatus timerStatus;
+	iTimer.Cancel();
+	
+    switch( iNextState)
+    {
+        case ECreateView:
+            PRINT1 ( _L("CPcsContactStore::RunL(ECreateView): URI=%S. Create contact view to fetch data from store"),
+                     &*iUri );
+            CreateContactFetchViewL();
+            break;
+
+        case EFetchAllLinks:
+            PRINT1 ( _L("CPcsContactStore::RunL(EFetchAllLinks): URI=%S. Get all contact links in initial view"),
+                     &*iUri );
+            FetchAllInitialContactLinksL();
+            break;
+   		
+	   	case EFetchContactBlock:
+            PRINT4 ( _L("CPcsContactStore::RunL(EFetchContactBlock): URI=%S. Issuing fetch request for next block of max %d contacts (%d/%d fetched)"),
+                     &*iUri, KLinksToFetchInOneGo, iFetchBlockUpperNumber, iInitialContactCount);
+            FetchContactsBlockL();
+			break;
+	   	
+	   	case EComplete:
+		    PRINT3 ( _L("CPcsContactStore::RunL(EComplete): URI=%S. Contacts Caching FINISHED, (%d/%d contacts fetched)"),
+		             &*iUri, iFetchBlockUpperNumber, iInitialContactCount );
+		    PRINT1_BOOT_PERFORMANCE ( _L("CPcsContactStore::RunL(EComplete): URI=%S. Contacts Caching FINISHED"),
+		                              &*iUri );
+		    break;
+    }
+}
+
+// ---------------------------------------------------------------------------------
+// Called in case of any errros 
+// ---------------------------------------------------------------------------------
+TInt CPcsContactStore::RunError(TInt /*aError*/) 
+{
+	PRINT ( _L("Enter CPcsContactStore::RunError") );
+
+	PRINT1 ( _L("CPcsContactStore::RunError(): URI=%S. Completing caching with status ECachingCompleteWithErrors"),
+	         &*iUri );
+    iObserver->UpdateCachingStatus(*iUri, ECachingCompleteWithErrors);
+
+    PRINT ( _L("End CPcsContactStore::RunError") );
+	return KErrNone;
+}
+
+// ---------------------------------------------------------------------------------
+// Read the fields to cache from the central repository
+// ---------------------------------------------------------------------------------
+void CPcsContactStore::ReadFieldsToCacheFromCenrepL()
+{
+    CRepository* repository = CRepository::NewL( KCRUidPSContacts );
+
+    // Read the data fields from cenrep
+    for (TInt i(KCenrepFieldsStartKey); i < KCenrepFieldsStartKey + KCenrepNumberOfFieldsCount; i++ )
+    {
+        TInt fieldToCache (-1);
+        TInt err = repository->Get(i, fieldToCache );
+        
+        if ( KErrNone != err )
+        {
+            break;
+        }
+        if ( fieldToCache != 0 )
+        {
+            iFieldsToCache.Append(fieldToCache);
+        }
+    }
+    
+    delete repository;
+}
+
+// ---------------------------------------------------------------------------------
+// Creates a dummy id for the cache
+// ---------------------------------------------------------------------------------
+
+TInt CPcsContactStore::CreateCacheIDfromSimArrayIndex(TInt aSimId)
+{
+	return (KSimStoreOffset + aSimId);
+}
+
+// ---------------------------------------------------------------------------------
+// Issues request to active object to call RunL method
+// ---------------------------------------------------------------------------------
+void CPcsContactStore::IssueRequest( TInt aTimeDelay )
+{
+    if( IsActive() ) // cannot activate allready active object
+        return;
+
+    if ( 0 == aTimeDelay )
+    {
+        TRequestStatus* status = &iStatus;
+        User::RequestComplete( status, KErrNone );
+    }
+    else
+    {
+        PRINT1 ( _L("CPcsContactStore::IssueRequest: Applying delay of %d milliseconds"),
+                 aTimeDelay );
+
+        iTimer.After( iStatus, aTimeDelay);
+    }
+
+    SetActive();
+}
+
+// ---------------------------------------------------------------------------------
+// Creates a sort order depending on the fields specified 
+// in the cenrep when calling this function pass the 
+// masterList (i.e list containing all the vpbk fields)
+// ---------------------------------------------------------------------------------
+void CPcsContactStore::CreateSortOrderL(const MVPbkFieldTypeList& aMasterList)
+{
+		
+	TInt count = aMasterList.FieldTypeCount();
+	
+	// loop through the master list and find the types that are supported
+	for(TInt i = 0; i < count; i++)
+	{
+		const MVPbkFieldType& fieldType = aMasterList.FieldTypeAt(i);
+		TInt resourceId = fieldType.FieldTypeResId();
+		// if the field type is supported
+		// then append MVPbkFieldType to sortOrder
+		for(TInt j =0; j < iFieldsToCache.Count(); j++)
+		{
+			if(iFieldsToCache[j] == resourceId)
+			{
+				iSortOrder->AppendL(fieldType);
+			}
+		}
+		
+		if(iSortOrder->FieldTypeCount() == iFieldsToCache.Count())
+		{
+			break;
+		}
+	}
+	
+}
+
+// ---------------------------------------------------------------------------------
+// Checks MyCard extension of contact
+// ---------------------------------------------------------------------------------
+TBool CPcsContactStore::IsMyCard( const MVPbkBaseContact& aContact )
+    {
+    TBool isMyCard( EFalse);
+    // this is temporary solution to hide own contact from phonebook contacts list,
+    // TODO remove this code when we can hide own contact with contact model
+
+    MVPbkBaseContact& contact = const_cast<MVPbkBaseContact&>( aContact );
+    TAny* extension = contact.BaseContactExtension( KVPbkBaseContactExtension2Uid );
+
+    if ( extension )
+        {
+        MVPbkBaseContact2* baseContactExtension = static_cast<MVPbkBaseContact2*>( extension );
+        TInt error( KErrNone );
+        isMyCard = baseContactExtension->IsOwnContact( error );
+        }
+    
+    return isMyCard;
+    }
+// End of file