phonebookengines/contactsmodel/cntsrv/src/CViewSubSessions.cpp
changeset 0 e686773b3f54
child 8 5586b4d2ec3e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/contactsmodel/cntsrv/src/CViewSubSessions.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,1135 @@
+// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+/**
+ @file
+ @internalComponent
+ @released
+*/
+
+
+#include "cntviewprivate.h"
+#include "CViewSubSessions.h"
+#include "CCntIpcCodes.h"
+#include "CCntDbManager.h"
+#include "CCntServer.h"
+#include <cntviewstore.h>
+#include "CCntLogger.h"
+#include "CCntStateMachine.h"
+
+
+extern void DebugLogViewNotification(const TDesC& aMethod, const TContactViewEvent& aEvent);
+
+
+CViewSubSessionQueue::CViewSubSessionQueue()
+	{
+	}
+
+
+CViewSubSessionQueue::~CViewSubSessionQueue()
+	{
+	iEvents.Close();
+	}
+
+
+void CViewSubSessionQueue::QueueEvent(const TContactViewEvent& aEvent)
+	{
+	const TInt KInvalidValueForRemoteView = -1;
+
+	TBool haveToAddEventInQueue = ETrue;
+
+ 	if (iRequestPending)
+ 		{
+		if(aEvent.iEventType == TContactViewEvent::EItemAdded)
+			{
+			// is this first event sent? If yes and if the event is an 
+			// EItemAdded event send first a fake event. 
+			// This is because all EItemAdded should be sorted before send them
+
+			TContactViewEvent event;
+			event.iEventType = TContactViewEvent::EItemAdded;
+			event.iContactId = KInvalidValueForRemoteView;
+			event.iInt = KInvalidValueForRemoteView;
+			SendEventL(event);
+			}
+		else
+			{
+			SendEventL(aEvent);
+			haveToAddEventInQueue = EFalse;
+			}
+ 		}
+
+	if (haveToAddEventInQueue  && !iQueueError)
+		{
+		// There are two requirements for this queue of events:
+		// 1. The iInt values for events in the Q at any given point in time
+		//    should match the index of the underlying localview array. i.e If the addition/removal
+		//    of a contact has caused the position of other contacts items to change in the underlying localview
+		//    then previous events sent by them in this Q will have old iInt values and these need to be corrected.
+		
+		// 2. When the client gets these events in order, it should have a valid view after every event,
+		//    ie. if we have 2 additions, at positions 0 and 1, 
+		//    we cannot send the event for addition at position 1 before the addition at position 0.
+		//	
+		// These requirements are fulfilled using the following algorithm.
+		// Events are inserted in the queue using following two condition
+		// 1. EItemAdded -
+		//    1.1 Find if an existing EItemAdded events iInt is greater or equal with incoming events iInt.
+		//        if found,insert event before the found one and increment the iInt of the rest event by 1
+		//    1.2 if no match is found with same iInt, modify its iInt value with incoming events iInt, 
+		//        then append to the event queue.
+		//	  1.3 If no EItemAdded events are in queue, append this one to Queue.
+		// 2. EItemRemoved -
+		//    2.1 Find if an existing EItemAdded events iInt matches with incoming EItemRemoved events iInt.
+		//        if found, then remove that EItemAdded event from the Queue and decrement rest of the 
+		//        events iInt by 1.
+		//    2.2 if no match is found with same iInt, then insert the event before next greater iInt event
+		//        and then decerement the iInt value of rest of the event by 1.
+		//	  2.3 if no events greater than this  then append this one to Queue.
+		
+		TContactViewEvent event;
+		event.iEventType = aEvent.iEventType;
+		event.iContactId = aEvent.iContactId;
+		event.iInt = aEvent.iInt;		
+		TInt eventsCount = iEvents.Count();		
+		TUint pos=0;		
+		if( event.iEventType == TContactViewEvent::EItemAdded )
+			{	
+			TInt lastItemRemovedPosition = KErrNotFound;
+			//first check if this add event is not generated by a contact item change
+			for( pos=0; pos<eventsCount; ++pos ) 
+				{
+				if( iEvents[pos].iContactId == aEvent.iContactId && 
+							iEvents[pos].iEventType == TContactViewEvent::EItemRemoved )
+					{
+					lastItemRemovedPosition = pos;
+					}
+				}
+			if( lastItemRemovedPosition != KErrNotFound ) 
+				{
+				++lastItemRemovedPosition;
+				if(lastItemRemovedPosition < eventsCount)
+					{
+					for( pos = lastItemRemovedPosition-1; pos < eventsCount;++pos ) 
+						{
+						if(iEvents[pos].iInt >= aEvent.iInt && 
+								iEvents[pos].iContactId != aEvent.iContactId)
+							{
+							if( iEvents[pos].iEventType == TContactViewEvent::EItemRemoved || iEvents[pos].iEventType == TContactViewEvent::EItemAdded)  
+								{
+								iEvents[pos].iInt++;
+								}
+							}
+						}
+					iQueueError = iEvents.Insert(aEvent, lastItemRemovedPosition);		
+					}
+				else
+					{
+					iQueueError = iEvents.Append(aEvent);	
+					}
+				}
+			else
+				{				
+				TBool haveToAppendEvent = ETrue; 			
+				for( pos=0; pos<eventsCount; ++pos ) 
+					{
+					if(iEvents[pos].iEventType == TContactViewEvent::EItemAdded)
+						{
+						if(iEvents[pos].iInt >= event.iInt)
+							{
+							iQueueError = iEvents.Insert(event, pos);
+							eventsCount=iEvents.Count();
+							for(TUint loop=pos+1; loop<eventsCount; ++loop)
+								{
+								if( iEvents[pos].iEventType == TContactViewEvent::EItemRemoved || iEvents[pos].iEventType == TContactViewEvent::EItemAdded)
+									{
+									iEvents[loop].iInt++;
+									}
+								}						
+							haveToAppendEvent = EFalse;										
+							break;
+							}				
+						}
+					}
+				if( haveToAppendEvent )
+					{
+					iQueueError = iEvents.Append(event);
+				 	}
+				}
+			}
+		else 
+			{
+			iQueueError = iEvents.Append(event);	
+			}
+		DEBUG_PRINTVN2(__VERBOSE_DEBUG__,_L("[CNTMODEL] CViewSubSessionQueue::QueueEvent(): ->Q:"), event);
+		}
+	}
+
+
+void CViewSubSessionQueue::RequestEvent(const RMessage2& aMessage)
+	{
+	__ASSERT_DEBUG(!iRequestPending,User::Leave(KErrAlreadyExists)); // can only leave in debug mode
+	if (!iRequestPending)
+		{
+		iMessage=aMessage;
+		iRequestPending=ETrue;
+		if (iQueueError)
+			{
+			TContactViewEvent errorEvent(TContactViewEvent::EServerError,iQueueError);
+			iQueueError=KErrNone;
+			SendEventL(errorEvent);
+			}
+		else if (iEvents.Count()>0)
+			{
+			SendEventL(iEvents[0]);
+			iEvents.Remove(0);
+			}
+		}
+	}
+
+
+void CViewSubSessionQueue::CancelEventRequest()
+	{
+	if (iRequestPending)
+		{
+		iMessage.Complete(KErrCancel);
+		iRequestPending=EFalse;
+		}
+	}
+
+/**
+Send contact view event.
+
+@leave KErrNotFound In debug mode only, if there is a queue error.
+@leave KErrNotReady In debug mode only, if there is already an existing request still pending.
+@leave KErrBadDescriptor If there is a error writing aEvent to the RMessage2 to be sent.
+*/
+void CViewSubSessionQueue::SendEventL(const TContactViewEvent& aEvent)
+	{
+	__ASSERT_DEBUG(!iQueueError,User::Leave(KErrNotFound));
+
+	if (!iRequestPending)
+		{
+		return;
+		}
+
+   DEBUG_PRINTVN2(__VERBOSE_DEBUG__,_L("[CNTMODEL] CViewSubSessionQueue::SendEventL(): Q->:"), aEvent);
+
+	TRAPD(err,iMessage.WriteL(KSlot0,TPckgC<TContactViewEvent>(aEvent)));
+	if (err)
+		{
+		iRequestPending=EFalse;
+		User::Leave(KErrBadDescriptor);//iMessage is completed in CCntSession::ServiceError()
+		}
+	else
+		{
+		iMessage.Complete(KErrNone);
+		}
+
+	iRequestPending=EFalse;
+	}
+
+
+/**
+Called if derived class ServiceL()'s do not consume the opcode.
+*/
+TInt CViewSubSessionBase::ServiceL(const RMessage2& aMessage)
+	{
+	TInt reply(KErrNone);
+	switch (aMessage.Function())
+		{
+		case ECntViewCount:
+			CountL(aMessage);
+			break;
+		case ECntViewAt:
+			reply=AtL(aMessage);
+			break;
+		case ECntViewContactAtLength:
+			reply=ContactAtLengthL(aMessage);
+			break;
+		case ECntViewContactAt:
+			ContactAtL(aMessage);
+			break;
+		case ECntViewFind:
+			FindL(aMessage);
+			break;
+		case ECntAllFieldsLength:
+			reply=GetAllFieldsLengthL(aMessage);
+			break;
+		case ECntAllFieldsText:
+			GetAllFieldsTextL(aMessage);
+			break;
+		case ECntContactMatchingCriteriaExternalizedSize:
+			ContactMatchingCriteriaExternalizedSizeL(aMessage);
+			break;
+		case ECntGetContactMatchingCriteria:
+			GetContactMatchingCriteriaL(aMessage);
+			break;
+		case ECntGetIncludedTypes:
+			GetIncludedTypesL(aMessage);
+			break;
+		case ECntRequestViewEvent:
+			RequestViewEvent(aMessage);
+			reply=KErrNoComplete;
+			break;
+		case ECntCancelRequestViewEvent:
+			CancelRequestViewEvent();
+			break;
+		case ECntGetContactIds:
+			GetContactIdsL(aMessage);
+			break;
+		case ECntSendPluginUidToServer:
+			SendPluginUidToServer(aMessage);
+			break;
+		case ECntGetContactsMatchingFilter:
+			GetContactsMatchingFilterL(aMessage);
+			break;
+		case ECntGetSortPluginUidFromServer:
+			GetSortPluginUidFromServerL(aMessage);
+			break;
+		default:
+			User::Leave(KErrNotFound);
+			break;
+		}
+	return reply;
+	}
+
+
+CViewSubSessionBase::~CViewSubSessionBase()
+	{
+	delete iQueue;
+	delete iSortableText;
+	delete iContact;
+	DeleteFindContacts();
+	}
+
+
+CViewSubSessionBase::CViewSubSessionBase(CViewManager& aViewManager) : iViewManager(aViewManager),iContact(0)
+	{
+	}
+
+
+void CViewSubSessionBase::ConstructL()
+	{
+	iQueue = new(ELeave) CViewSubSessionQueue();
+	}
+
+
+void CViewSubSessionBase::CountL(const RMessage2& aMessage) const
+	{
+	TPckgBuf<TInt> pckg(iView->CountL());
+	aMessage.WriteL(0,pckg);
+	}
+
+
+TInt CViewSubSessionBase::AtL(const RMessage2& aMessage) const
+	{
+	TInt reply = KErrNone;
+	const TInt index=aMessage.Int0();
+	__ASSERT_ALWAYS(index>=0,User::Leave(KErrUnderflow));
+	if(!(index<iView->CountL()))
+		{
+		// Index is out of bounds.
+		reply=KErrNotFound;
+		return reply;
+		}
+	TPckgBuf<TContactItemId> pckg(iView->AtL(index));
+	aMessage.WriteL(1,pckg);
+	return reply;
+	}
+
+
+void CViewSubSessionBase::ContactAtL(const RMessage2& aMessage) const
+	{
+	const TInt externalizedSize=iContact->ExternalizedSize();
+	HBufC8* buf=HBufC8::NewLC(externalizedSize);
+	TPtr8 bufPtr(buf->Des());
+	RDesWriteStream writeStream(bufPtr);
+	CleanupClosePushL(writeStream);
+	writeStream << *iContact;
+	bufPtr.SetLength(externalizedSize);
+	aMessage.WriteL(0,*buf);
+	CleanupStack::PopAndDestroy(2); // writeStream, buf.
+	}
+
+
+/** 
+Return the size of the externalized contact data.
+
+@param aMessage.Int0() Index.
+@param aMessage.Ptr1() Package buffer to return size.
+*/
+TInt CViewSubSessionBase::ContactAtLengthL(const RMessage2& aMessage) 
+	{
+	TInt reply=KErrNone;
+	TInt index = aMessage.Int0();
+
+	__ASSERT_ALWAYS(index>=0,User::Leave(KErrUnderflow));
+
+	if(!(index<iView->CountL()))
+		{
+		// Index is out of bounds.
+		reply=KErrNotFound;
+		return reply;
+		}
+
+	const CViewContact& contact=iView->ContactAtL(index);
+
+	delete iContact;
+	iContact=NULL;
+	iContact = CViewContact::NewL(contact);
+
+	//Always keep server side local view in memory saving mode, so we
+	//change the view contact object stored in iView into lightweight object
+	const_cast<CViewContact&>(contact).ChangeToLightweightObject();
+	
+	const TInt externalizedSize=iContact->ExternalizedSize();
+	TPckgBuf<TInt> pckg(externalizedSize);
+	aMessage.WriteL(1,pckg);
+
+	return reply;
+	}
+
+
+void CViewSubSessionBase::GetIncludedTypesL(const RMessage2& aMessage)
+	{
+	TPckgBuf<TContactViewPreferences> pckg(iView->ContactViewPreferences());
+	aMessage.WriteL(0,pckg);	
+	}
+
+
+void CViewSubSessionBase::DeleteFindContacts()
+	{
+	iContacts.ResetAndDestroy();
+	}
+
+
+#ifdef _DEBUG
+void CViewSubSessionBase::HandleContactViewEvent(const CContactViewBase& aView,const TContactViewEvent& aEvent)
+#else
+void CViewSubSessionBase::HandleContactViewEvent(const CContactViewBase& /*aView*/,const TContactViewEvent& aEvent)
+#endif
+	{
+	ASSERT(&aView==iView);
+	iQueue->QueueEvent(aEvent);
+	}
+
+
+/** 
+Match an array of search strings against the contacts in the view.
+
+The descriptor from the client contains a flag at the start to indicate if a
+prefix or substring search has been requested.
+
+@param aMessage.Ptr0() Size of contact data to read (to client).
+@param aMessage.Int1() Size of descriptor (from client).
+@param aMessage.Ptr2() Descriptor (from client).
+*/
+void CViewSubSessionBase::ContactMatchingCriteriaExternalizedSizeL(const RMessage2& aMessage)
+	{
+	TPckgBuf<TInt> size;
+	aMessage.ReadL(1,size);
+	const TInt bufferSize = size();
+
+	// Restore buffer.
+	CBufFlat* buffer = CBufFlat::NewL(bufferSize);
+	CleanupStack::PushL(buffer);
+	buffer->ExpandL(0,bufferSize);
+	TPtr8 des(buffer->Ptr(0));
+	aMessage.ReadL(2,des);
+
+	// Internalize the data from the stream.
+	RBufReadStream readStream(*buffer);
+	CleanupClosePushL(readStream);
+
+	TBool prefixSearch = readStream.ReadUint32L(); 
+	const TInt numFindWords = readStream.ReadUint32L();
+	CPtrC16Array* findDesArray = new(ELeave) CPtrC16Array(numFindWords);
+	CleanupStack::PushL(findDesArray);
+
+	TInt findWordLength=0;
+	for (TInt i=0; i<numFindWords; ++i)
+		{
+		findWordLength = readStream.ReadUint32L();
+		HBufC* findword = HBufC::NewLC(readStream,findWordLength);
+		findDesArray->AppendL(*findword);
+		}
+
+	DeleteFindContacts();
+
+	if (prefixSearch)
+		iView->ContactsMatchingPrefixL(*findDesArray,iContacts);
+	else
+		iView->ContactsMatchingCriteriaL(*findDesArray,iContacts);
+
+	findDesArray->Reset();
+	
+	CleanupStack::PopAndDestroy(numFindWords);
+	CleanupStack::PopAndDestroy(3, buffer);
+
+	// Compute contacts externalized size.
+	const TInt contactsCount = iContacts.Count();
+	TInt contactsExternalizedSize=0;
+	contactsExternalizedSize+=sizeof(TInt32);
+	for (TInt jj=0;jj<contactsCount;++jj)
+		{
+		contactsExternalizedSize+=(iContacts)[jj]->ExternalizedSize();
+		}
+
+	TPckgBuf<TInt> pckg(contactsExternalizedSize);
+	aMessage.WriteL(0,pckg);
+	}
+
+
+/** 
+Write matching contacts back to client.
+
+@param aMessage.Ptr0() Descriptor to write array of matching contacts.
+*/
+void CViewSubSessionBase::GetContactMatchingCriteriaL(const RMessage2& aMessage)
+	{
+	// Compute contacts externalized size.
+	const TInt contactsCount = iContacts.Count();
+	TInt contactsExternalizedSize=0;
+	contactsExternalizedSize+=sizeof(TInt32);
+	for (TInt jj=0;jj<contactsCount;++jj)
+		{
+		contactsExternalizedSize+=(iContacts)[jj]->ExternalizedSize();
+		}
+
+	HBufC8* buf=HBufC8::NewLC(contactsExternalizedSize);
+	TPtr8 bufPtr(buf->Des());
+	RDesWriteStream writeStream(bufPtr);
+	CleanupClosePushL(writeStream);
+
+	writeStream.WriteUint32L(contactsCount);
+	for (TInt ii=0;ii<contactsCount;++ii)
+		{
+		CViewContact* thisContact = (iContacts)[ii];
+		writeStream << *thisContact;
+		}
+
+	bufPtr.SetLength(contactsExternalizedSize);
+	aMessage.WriteL(0,*buf);
+
+	CleanupStack::PopAndDestroy(2, buf); //writeStream.Close(), buf
+
+	DeleteFindContacts();
+	}
+
+
+void CViewSubSessionBase::FindL(const RMessage2& aMessage) const
+	{
+	TPckgBuf<TContactItemId> pckg(iView->FindL(aMessage.Int0()));
+	aMessage.WriteL(1,pckg);
+	}
+
+
+TInt CViewSubSessionBase::GetAllFieldsLengthL(const RMessage2& aMessage)
+	{
+	TInt reply = KErrNone;
+	TInt index = aMessage.Int0();
+
+	__ASSERT_ALWAYS(index>=0,User::Leave(KErrUnderflow));
+
+	if(!(index<iView->CountL()))
+		{
+		// Index is out of bounds.
+		reply=KErrNotFound;
+		return reply;
+		}
+
+	TBuf<256> bufPtr;// = buf->Des();
+	aMessage.ReadL(1,bufPtr);
+
+	// Create sortable text from all fields of view contact at specified index.
+	delete iSortableText;
+	iSortableText=NULL;
+	HBufC* allfields=iView->AllFieldsLC(index,bufPtr);
+	CleanupStack::Pop(); // allfields
+	iSortableText=allfields;
+
+	TPckgBuf<TInt> pckg(iSortableText->Length());
+	aMessage.WriteL(2,pckg);
+
+	return reply;
+	}
+
+
+void  CViewSubSessionBase::GetAllFieldsTextL(const RMessage2& aMessage)
+	{
+	TPtrC8 narrowPtr((TUint8*)iSortableText->Ptr(),iSortableText->Size());
+	aMessage.WriteL(0,narrowPtr);
+	}
+
+
+void CViewSubSessionBase::RequestViewEvent(const RMessage2& aMessage)
+	{
+	iQueue->RequestEvent(aMessage);
+	}
+
+
+void CViewSubSessionBase::CancelRequestViewEvent()
+	{
+	iQueue->CancelEventRequest();
+	}
+
+
+/**
+Provides conversion between view indexes and contact IDs.
+
+@param aMessage.Int0() Buffer size (from client).
+@param aMessage.Ptr1() Descriptor containing indices (from client).
+@param aMessage.Ptr2() Descriptor containing contact IDs (to client).
+*/
+void CViewSubSessionBase::GetContactIdsL(const RMessage2& aMessage)
+	{
+	TPckgBuf<TInt> size;
+	aMessage.ReadL(0,size);
+	const TInt bufferSize = size();
+	
+	CBufFlat* buffer = CBufFlat::NewL(bufferSize);
+	CleanupStack::PushL(buffer);
+	buffer->ExpandL(0,bufferSize);
+	TPtr8 des(buffer->Ptr(0));
+	aMessage.ReadL(1,des);
+
+	RBufReadStream readStream(*buffer);
+	CleanupClosePushL(readStream);
+	const TInt count = readStream.ReadUint32L(); 
+
+	CArrayFixFlat<TInt>* indexes = new(ELeave) CArrayFixFlat<TInt>(8);	
+	CleanupStack::PushL(indexes);
+
+	for (TInt i=0; i<count; ++i)
+		{
+		TInt index = readStream.ReadUint32L();
+		indexes->AppendL(index);
+		}
+
+	CContactIdArray* array = CContactIdArray::NewLC();
+	iView->GetContactIdsL(*indexes, *array);
+
+	HBufC8* buf=HBufC8::NewLC(bufferSize);
+	TPtr8 bufPtr(buf->Des());
+	RDesWriteStream writeStream(bufPtr);
+	CleanupClosePushL(writeStream);
+	writeStream << *array;
+	bufPtr.SetLength(bufferSize);
+	aMessage.WriteL(2,*buf);
+
+	CleanupStack::PopAndDestroy(6, buffer); // &writeStream, buf, array, indexes, &readStream, buffer
+	}
+
+
+void CViewSubSessionBase::SendPluginUidToServer(const RMessage2& aMessage)
+	{
+	TUid uid;
+	uid.iUid = aMessage.Int0();
+	iView->SetViewFindConfigPlugin(uid);
+	}
+
+
+/** 
+Filter server-side view based on filter supplied by client.  The IDs of matching
+contact items are externalized to the client-side.
+
+@param aMessage.Int0() Filter (from client).
+@param aMessage.Ptr1() Descriptor containing matching contact IDs (to client).
+*/
+void CViewSubSessionBase::GetContactsMatchingFilterL(const RMessage2& aMessage)
+	{
+	const TInt filter(aMessage.Int0());
+	
+	RArray<TContactIdWithMapping> array;
+	CleanupClosePushL(array);
+	TContactIdWithMapping idMap;
+
+	// Filter view contacts.
+	const TInt viewCount(iView->CountL());
+	for (TInt i=0;i<viewCount;++i)
+		{
+		const CViewContact& contact = iView->ContactAtL(i);
+		if(contact.ContactMatchesFilter(filter))
+			{
+			idMap.iId=contact.Id();
+			idMap.iMapping=i;
+			User::LeaveIfError(array.Append(idMap));
+			}
+		}
+
+	// Externalize array to client.
+	const TInt count(array.Count());
+	const TInt maxBufSize = (1+(array.Count()*2))*sizeof(TInt);
+	HBufC8* buf=HBufC8::NewLC(maxBufSize);
+	TPtr8 bufPtr(buf->Des());
+	RDesWriteStream writeStream(bufPtr);
+	CleanupClosePushL(writeStream);
+	writeStream.WriteUint32L(count);
+	for (TInt j=0; j<count; ++j)
+		{
+		writeStream.WriteInt32L(array[j].iId);
+		writeStream.WriteInt32L(array[j].iMapping);
+		}
+	bufPtr.SetLength(maxBufSize);
+	aMessage.WriteL(1,*buf);
+	CleanupStack::PopAndDestroy(3,&array);
+	}
+
+
+void CViewSubSessionBase::GetSortPluginUidFromServerL(const RMessage2& aMessage)
+	{
+	TUid uid = iView->GetViewSortPluginImplUid();
+	TPckgBuf<TInt> pckg(uid.iUid);
+	aMessage.WriteL(0,pckg);
+	}
+
+
+CViewSubSession* CViewSubSession::NewL(CViewManager& aViewManager,const RMessage2& aMessage)
+	{
+	CViewSubSession* self=new(ELeave) CViewSubSession(aViewManager);
+	CleanupClosePushL (*self);
+	self->ConstructL(aMessage);
+	CleanupStack::Pop(); // self.
+	return self;
+	}
+
+
+/**
+Attempt to consume opcode.  If the opcode is not consumed then the base class
+ServiceL() is called.
+*/
+TInt CViewSubSession::ServiceL(const RMessage2& aMessage)
+	{
+	switch (aMessage.Function())
+		{
+		case ECntViewSortOrderExternalizedSize:
+			ExternalizedSortOrderSizeL(aMessage);
+			break;
+		case ECntGetViewSortOrder:
+			GetSortOrderL(aMessage);
+			break;
+		default:
+			return CViewSubSessionBase::ServiceL(aMessage);
+		}
+	return 0;
+	}
+
+
+CViewSubSession::~CViewSubSession()
+	{
+	iViewManager.CloseView(View(),*this);
+	}
+
+
+CViewSubSession::CViewSubSession(CViewManager& aViewManager) : CViewSubSessionBase(aViewManager)
+	{
+	}
+
+
+void CViewSubSession::ConstructL(const RMessage2& aMessage) 
+	{
+	CViewSubSessionBase::ConstructL();
+
+	RContactViewSortOrder sortOrder;
+	CleanupClosePushL(sortOrder);
+	TContactViewPreferences contactsToInclude;
+
+	TUid sortPluginImplUid;
+	HBufC8* sortPluginName = UnpackageSortOrderAndPluginDetailsLC(aMessage,sortOrder,contactsToInclude,sortPluginImplUid);
+
+	iView = &iViewManager.OpenViewL(sortOrder,*this,contactsToInclude,sortPluginImplUid,*sortPluginName);
+
+	CleanupStack::PopAndDestroy(2, &sortOrder); // sortPluginName, sortOrder
+	}
+
+
+void CViewSubSession::UnpackageSortOrderL(const RMessage2& aMessage,RContactViewSortOrder& aSortOrder,TContactViewPreferences& aContactTypes) const
+	{
+	HBufC8* buf=HBufC8::NewLC(aMessage.Int0());
+
+	TPtr8 bufPtr(buf->Des());
+	aMessage.ReadL(1,bufPtr);
+	RDesReadStream readStream(bufPtr);
+	CleanupClosePushL(readStream);
+
+	readStream >> (TInt32&)aContactTypes;
+	readStream >> aSortOrder;
+
+	CleanupStack::PopAndDestroy(2); //readstream, buf.
+	}
+
+
+HBufC8* CViewSubSession::UnpackageSortOrderAndPluginDetailsLC(const RMessage2& aMessage,RContactViewSortOrder& aSortOrder,TContactViewPreferences& aContactTypes,TUid& aSortPluginImplUid) const
+	{
+	HBufC8* buf=HBufC8::NewLC(aMessage.Int0());
+
+	TPtr8 bufPtr(buf->Des());
+	TInt32 nameLen;
+	aMessage.ReadL(1,bufPtr);
+	RDesReadStream readStream(bufPtr);
+	CleanupClosePushL(readStream);
+
+	readStream >> (TInt32&)aContactTypes;
+	readStream >> aSortOrder;
+
+	// Extract sort plugin UID.
+	aSortPluginImplUid.iUid = readStream.ReadInt32L();
+
+	// Extract sort plugin name.
+	nameLen = readStream.ReadInt32L();
+	HBufC8* pluginNameBuf = HBufC8::NewLC(nameLen);
+	TPtr8	pluginNamePtr = pluginNameBuf->Des();
+	readStream.ReadL(pluginNamePtr, nameLen);
+	CleanupStack::Pop(pluginNameBuf);
+	CleanupStack::PopAndDestroy(2); //readstream, buf.
+
+	CleanupStack::PushL(pluginNameBuf);
+	return pluginNameBuf;
+	}
+
+
+CContactLocalView& CViewSubSession::View() const
+	{
+	return STATIC_CAST(CContactLocalView&,*iView);
+	}
+
+
+void CViewSubSession::ExternalizedSortOrderSizeL(const RMessage2& aMessage) const
+	{
+	TPckgBuf<TInt> pckg(View().SortOrder().ExternalizedSize());
+	aMessage.WriteL(0,pckg);
+	}
+
+
+void CViewSubSession::GetSortOrderL(const RMessage2& aMessage) const
+	{
+	const RContactViewSortOrder& sortOrder=View().SortOrder();
+	const TInt externalizedSize=sortOrder.ExternalizedSize();
+	HBufC8* buf=HBufC8::NewLC(externalizedSize);
+	TPtr8 bufPtr(buf->Des());
+	RDesWriteStream writeStream(bufPtr);
+	CleanupClosePushL(writeStream);
+	writeStream << sortOrder;
+	bufPtr.SetLength(externalizedSize);
+	aMessage.WriteL(0,*buf);
+	CleanupStack::PopAndDestroy(2); // writeStream, buf.
+	}
+
+
+CNamedViewSubSession* CNamedViewSubSession::NewL(CViewManager& aViewManager,const RMessage2& aMessage)
+	{
+	CNamedViewSubSession* self=new(ELeave) CNamedViewSubSession(aViewManager);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMessage);
+	CleanupStack::Pop(); // self.
+	return self;
+	}
+
+
+/**
+Attempt to consume opcode.  If the opcode is not consumed then the base class
+ServiceL() is called.
+*/
+TInt CNamedViewSubSession::ServiceL(const RMessage2& aMessage)
+	{
+	switch (aMessage.Function())
+		{
+		case ECntChangeViewSortOrder:
+			ChangeSortOrderL(aMessage);
+			break;
+		default:
+			return CViewSubSession::ServiceL(aMessage);
+		}
+	return 0;
+	}
+
+
+CNamedViewSubSession::~CNamedViewSubSession()
+	{
+	iViewManager.CloseNamedView(View(),*this);
+	}
+
+
+CNamedViewSubSession::CNamedViewSubSession(CViewManager& aViewManager) : CViewSubSession(aViewManager)
+	{
+	}
+
+
+void CNamedViewSubSession::ConstructL(const RMessage2& aMessage)
+	{
+	CViewSubSessionBase::ConstructL();
+
+	// Read sort order.
+	RContactViewSortOrder sortOrder;
+	CleanupClosePushL(sortOrder);
+	TContactViewPreferences contactsToInclude;
+	TUid sortPluginImplUid;
+	HBufC8* sortPluginName = UnpackageSortOrderAndPluginDetailsLC(aMessage,sortOrder,contactsToInclude,sortPluginImplUid);
+
+	// Create a descriptor of the correct length.
+	HBufC* nameBuf=HBufC::NewLC(aMessage.GetDesLengthL(2));
+	TPtr  wideNameBufPtr(nameBuf->Des());
+	// Extract the name of the view from the message.
+	aMessage.ReadL(2, wideNameBufPtr);
+
+	// Open view using name provided.
+	iView = &iViewManager.OpenNamedViewL(wideNameBufPtr,sortOrder,*this,contactsToInclude,sortPluginImplUid,*sortPluginName);
+
+	CleanupStack::PopAndDestroy(3,&sortOrder); // nameBuf, sortPluginName, sortOrder
+
+	sortOrder.Close();
+	}
+
+
+void CNamedViewSubSession::ChangeSortOrderL(const RMessage2& aMessage)
+	{
+	RContactViewSortOrder newSortOrder;
+	TContactViewPreferences contactsToInclude;
+	UnpackageSortOrderL(aMessage,newSortOrder,contactsToInclude);
+	View().ChangeSortOrderL(newSortOrder);
+	newSortOrder.Close();
+	}
+
+
+CContactNamedLocalView& CNamedViewSubSession::View() const
+	{
+	return STATIC_CAST(CContactNamedLocalView&,*iView);
+	}
+
+
+CViewManager* CViewManager::NewL(MLplPersistenceLayerFactory& aFactory,CCntDbManager& aManager)
+	{
+	CViewManager* self =new (ELeave) CViewManager(aFactory,aManager);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+
+CContactLocalView& CViewManager::OpenViewL(const RContactViewSortOrder& aSortOrder,MContactViewObserver& aObserver,TContactViewPreferences aContactTypeToInclude, const TUid aSortPluginImplUid, const TDesC8& aSortPluginName)
+	{
+	// Check to see if there is already a view with the required sort order,
+	// preferences and sort plugin.
+	const TInt numViews=iLocalViews.Count();
+	for (TInt ii=0;ii<numViews;++ii)
+		{
+		CContactLocalView& thisView=*iLocalViews[ii].iLocalView; 
+		if ( thisView.SortOrder()==aSortOrder && thisView.ContactViewPreferences() == aContactTypeToInclude &&
+				iLocalViews[ii].iSortPluginImplUid == aSortPluginImplUid)
+			{
+			if(thisView.Error() == KErrNone)
+				{
+				// Found one with no sorting error, so share it.
+				thisView.OpenL(aObserver);
+				return thisView;
+				}
+			}
+		}
+
+	// No view found, so create a new one.
+	TViewHandle	viewHandle;
+	viewHandle.iSortPluginImplUid = aSortPluginImplUid;
+	
+	if (!iManager.StateMachineL().DatabaseReady())
+		{
+		User::Leave(KErrNotReady);
+		}
+
+	// Dummy CContactDatabase done for BC.  CContactLocalView does not use
+	// CContactDatabase.
+	CContactDatabase* dummy = NULL;
+
+	// If aSortPluginImplUid is KNullUid indicates no sort plugin.
+	if (aSortPluginName.Length() || (aSortPluginImplUid == KNullUid))
+		{
+		viewHandle.iLocalView=CContactLocalView::NewL(aObserver,*dummy,aSortOrder,aContactTypeToInclude,&iFactory,aSortPluginName);
+		}
+	else
+		{
+		viewHandle.iLocalView=CContactLocalView::NewL(aObserver,*dummy,aSortOrder,aContactTypeToInclude,&iFactory,KNullDesC8);
+		}
+
+	// Register this view as an observer of database events with the
+	// associated CCntDbManager.
+	iManager.RegisterDatabaseEventObserverL(*viewHandle.iLocalView);
+
+	TInt error = iLocalViews.Append(viewHandle);
+	if (error != KErrNone)
+		{
+		iManager.UnRegisterDatabaseEventObserver(*viewHandle.iLocalView);
+		viewHandle.iLocalView->Close(aObserver);
+		User::Leave(error);
+		}
+
+	return *viewHandle.iLocalView;
+	}
+
+	
+CContactNamedLocalView& CViewManager::OpenNamedViewL(const TDesC& aName,const RContactViewSortOrder& aSortOrder,MContactViewObserver& aObserver,TContactViewPreferences aContactTypeToInclude, const TUid aSortPluginImplUid, const TDesC8& aSortPluginName)
+	{
+	// Check to see if named view already exists.
+	const TInt numViews=iNamedLocalViews.Count();
+	for (TInt ii=0;ii<numViews;++ii)
+		{
+		CContactNamedLocalView& thisView=*iNamedLocalViews[ii];
+		if (aName.Compare(thisView.Name())==0 )
+			{
+			if(thisView.Error() == KErrNone)
+				{
+				// Found a name match, so share it.
+				thisView.OpenL(aObserver);
+				return thisView;
+				}
+			}
+		}
+
+	// No name match found, so create a new one.
+	CContactNamedLocalView* newNamedView = NULL;
+
+	// Dummy CContactDatabase done for BC.  CContactLocalView does not use
+	// CContactDatabase.
+	CContactDatabase* dummy = NULL;
+
+	// If aSortPluginImplUid is KNullUid indicates no sort plugin.
+	if (aSortPluginName.Length() || (aSortPluginImplUid == KNullUid))
+		{
+		newNamedView=CContactNamedLocalView::NewL(aObserver,aName,*dummy,aSortOrder,aContactTypeToInclude,&iFactory,aSortPluginName);
+		}
+	else
+		{
+		newNamedView=CContactNamedLocalView::NewL(aObserver,aName,*dummy,aSortOrder,aContactTypeToInclude,&iFactory,KNullDesC8);
+		}
+
+	// Register this view as an observer of database events with the
+	// associated CCntDbManager.
+	iManager.RegisterDatabaseEventObserverL(*newNamedView);
+
+	TInt error = iNamedLocalViews.Append(newNamedView);
+	if (error != KErrNone)
+		{
+		iManager.UnRegisterDatabaseEventObserver(*newNamedView);
+		newNamedView->Close(aObserver);
+		User::Leave(error);
+		}
+
+	return *newNamedView;
+	}
+
+
+void CViewManager::CloseView(const CContactLocalView& aView,MContactViewObserver& aObserver)
+	{
+	const TInt count = iLocalViews.Count();
+
+	// Be tolerant to view not being found, since a leave may have occured
+	// before the CViewSubSession derived object has had a chance to call
+	// OpenViewL().
+	for (TInt index = 0; index < count; index++)
+		{
+		// Found it?
+		if (iLocalViews[index].iLocalView == &aView)
+			{
+			if(iLocalViews[index].iLocalView->Close(aObserver))
+				{
+				// Removed last reference to the Local View so un-Register this
+				// view as an observer of database events with the associated 
+				// CCntDbManager.
+				iManager.UnRegisterDatabaseEventObserver(*iLocalViews[index].iLocalView);
+				iLocalViews.Remove(index);
+				}
+			break;
+			}
+		}
+	}
+
+
+void CViewManager::CloseNamedView(const CContactNamedLocalView& aView,MContactViewObserver& aObserver)
+	{
+	TInt index = iNamedLocalViews.Find(&aView);
+
+	// Be tolerant to view not being found, since a leave may have occured
+	// before the CNamedViewSubSession derived object has had a chance to call
+	// OpenViewL().
+	if (index != KErrNotFound)
+		{
+		if (iNamedLocalViews[index]->Close(aObserver))
+			{
+			// Removed last reference to the Local View so un-Register this view
+			// as an observer of database events with the associated
+			// CCntDbManager.
+			iManager.UnRegisterDatabaseEventObserver(*iNamedLocalViews[index]);
+			iNamedLocalViews.Remove(index);
+			}
+		}
+	}
+
+
+CViewManager::CViewManager(MLplPersistenceLayerFactory& aFactory,CCntDbManager& aManager) :
+	iFactory(aFactory),
+	iManager(aManager)
+	{
+	}
+
+
+CViewManager::~CViewManager()
+	{
+	iLocalViews.Close();
+	iNamedLocalViews.Close();
+	}
+
+
+void CViewManager::ConstructL()
+	{
+	}
+
+
+#if defined(_DEBUG)
+void CViewManager::GetDefinitionsOfExistingViewsL(RPointerArray<CContactDefaultViewDefinition>& aViewDefs)
+	{
+	__ASSERT_DEBUG(aViewDefs.Count() == 0, User::Leave(KErrArgument));
+
+	TInt i;
+	CContactDefaultViewDefinition* viewDef;
+	
+	// Anonymous views.
+	for (i = 0; i < iLocalViews.Count(); i++)
+		{
+		CContactLocalView* view = iLocalViews[i].iLocalView;
+		viewDef = CContactDefaultViewDefinition::NewLC(CContactDefaultViewDefinition::ERemoteView,
+														KNullDesC, view->SortOrderL(), 
+														view->ContactViewPreferences(), 
+														KNullDesC8/*pluginName*/);
+		aViewDefs.AppendL(viewDef);
+		CleanupStack::Pop(viewDef);
+		}
+	
+	// Named views.
+	for (i = 0; i < iNamedLocalViews.Count(); i++)
+		{
+		CContactNamedLocalView* view = iNamedLocalViews[i];
+		viewDef = CContactDefaultViewDefinition::NewLC(CContactDefaultViewDefinition::ENamedRemoteView,
+														view->Name(), view->SortOrderL(), 
+														view->ContactViewPreferences(), 
+														KNullDesC8/*pluginName*/);
+		aViewDefs.AppendL(viewDef);
+		CleanupStack::Pop(viewDef);		
+		}
+	}
+#else
+void CViewManager::GetDefinitionsOfExistingViewsL(RPointerArray<CContactDefaultViewDefinition>& )
+	{
+	}
+#endif // _DEBUG