// Copyright (c) 1999-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:
//

#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
#include "vwsinternal.h"
#include "vwsdefpartner.h"
#endif //SYMBIAN_ENABLE_SPLIT_HEADERS
#include "VWSEVENT.H"
#include "VWSERVER.H"
#include "VWSDEBUG.H"
#include "VWSPRIV.H"
#include "vwspatchdata.h"

#include <u32hal.h>



//
// class CVwsThreadWatcher
//

CVwsThreadWatcher::~CVwsThreadWatcher()
	{
	Cancel();
	iThread.Close();
	}

CVwsThreadWatcher::CVwsThreadWatcher()
	: CActive(EPriorityStandard)
	{
	}
	
TInt CVwsThreadWatcher::StartWatching(const TThreadId& aThreadId, const TCallBack& aCallBack)
	{
	iCallBack=aCallBack;
	if(aThreadId!=iThread.Id())
		{
		if(IsAdded())
			{
			Deque();
			iThread.Close();
			}
		TInt err=iThread.Open(aThreadId);
		if (err==KErrNone)
			{
			CActiveScheduler::Add(this);
			iThread.Logon(iStatus);
			SetActive();
			}
		return err;
		}
	return KErrNone;
	}

void CVwsThreadWatcher::DoCancel()
	{
	iThread.LogonCancel(iStatus);
	}

void CVwsThreadWatcher::RunL()
	{
	iCallBack.CallBack();
	}


//
// CVwsEventTimer.
//

CVwsEventTimer::~CVwsEventTimer()
	{
	delete iPeriodic;
	}

CVwsEventTimer* CVwsEventTimer::NewLC(const TTimeIntervalMicroSeconds32& aClientRequestTimeOut, const TTimeIntervalMicroSeconds32& aServerEventTimeOut)
	{ // static
	CVwsEventTimer* self = new(ELeave) CVwsEventTimer(aClientRequestTimeOut, aServerEventTimeOut);
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

CVwsEventTimer::CVwsEventTimer(const TTimeIntervalMicroSeconds32& aClientRequestTimeOut, const TTimeIntervalMicroSeconds32& aServerEventTimeOut)
	: iClientRequestTimeOut(aClientRequestTimeOut),
	  iServerEventTimeOut(aServerEventTimeOut),
	  iTimeOutState(EUndefined),
	  iScreenDeviceChangeEvent(EFalse)
	{}

void CVwsEventTimer::ConstructL()
	{
	iPeriodic=CPeriodic::NewL(0);
	}

void CVwsEventTimer::Start(MVwsEventTimerObserver* aObserver,const TBool& aScreenDeviceChangeEvent)
	{
	iObserver=aObserver;

	if (iPeriodic->IsActive())
		{
		iPeriodic->Cancel();
		}
	
	TTimeIntervalMicroSeconds32 firstDelay(0);
	iTimeOutState=EUndefined;

	if (iClientRequestTimeOut < iServerEventTimeOut)
		{
		iTimeOutState=EClientRequestTimeOut;
		firstDelay=iClientRequestTimeOut;
		}
	else 
		{
		iTimeOutState=EServerEventTimeOut;
		firstDelay=iServerEventTimeOut;
		}

	TTimeIntervalMicroSeconds32 delay(firstDelay);
	iPeriodic->Start(delay,delay,TCallBack(TimerCallBack,this));	
	iScreenDeviceChangeEvent = aScreenDeviceChangeEvent;

	}

TInt CVwsEventTimer::TimerCallBack(TAny* aSelf)
	{ // static
	REINTERPRET_CAST(CVwsEventTimer*,aSelf)->DoTimerCallBack();
	return 0;
	}

void CVwsEventTimer::DoTimerCallBack()
	{
	if (iPeriodic != NULL && iPeriodic->IsActive())
		{
		iPeriodic->Cancel();
		}
	if (iScreenDeviceChangeEvent && iObserver)
		{
		iObserver->HandleTimeOut(iTimeOutState);
		}
	else
		{
		if (iObserver)
			{
			iObserver->HandleTimeOut(iTimeOutState);
			}
		if (iTimeOutState == EClientRequestTimeOut || iTimeOutState == EIntermediateEventTimeOut) 
			{
			TTimeIntervalMicroSeconds32 delay;
			if (iTimeOutState == EClientRequestTimeOut) 
				{
				//Normal delay is given before considering boosting the priority of an application
				delay = iServerEventTimeOut.Int()-iClientRequestTimeOut.Int();
				iTimeOutState = EIntermediateEventTimeOut;
				}
			else
				{
				//Delay of KTimeoutValueForPreemptedProcess is given after boosting priority of an application
				TUint8 patchableConst = KTimeoutValueForPreemptedProcess;
				#ifdef __WINS__
				// For the emulator allow the constant to be patched via epoc.ini
				UserSvr::HalFunction(EHalGroupEmulator, EEmulatorHalIntProperty,
					(TAny*)"KTimeoutValueForPreemptedProcess", &patchableConst); // read emulator property (if present)
				#endif
				delay = patchableConst;
				iTimeOutState = EServerEventTimeOut;
				}
			
            iPeriodic->Start(delay,delay,TCallBack(TimerCallBack,this));
			}
		}
	}

//
// CVwsServerEvent.
//

CVwsServerEvent::CVwsServerEvent(CVwsServer& aServer,TType aType,CVwsEventQueue& aQueue)
	:CVwsEvent(aType,aQueue),iServer(aServer)
	{
	}

CVwsServerEvent::~CVwsServerEvent()
	{
	if (iObserved)
		{
		iObserved->NullifyObserver();
		}
	}


void CVwsServerEvent::HandleLastOnQueue()
	{
	iServer.HandleLastServerEventOnQueue();
	}


//
// CVwsServerEvent_Activate.
//

CVwsServerEvent_Activate::CVwsServerEvent_Activate(CVwsServer& aServer,TType aType,CVwsEventQueue& aQueue,const TVwsViewId& aViewIdToActivate,CVwsClientMessage* aClientMessage,const RMessage2& aMessage,const TThreadId& aClientThreadId,TVwsCompleteRequest aCompleteRequest,CVwsThreadWatcher* aThreadWatcher,CVwsEventTimer* aEventTimer,const RThread& aThreadOfClientInitiatingViewSwitch)
	: CVwsServerEvent(aServer,aType,aQueue),
	iViewIdToActivate(aViewIdToActivate),
	iClientMessage(aClientMessage),
	iNewViewClientThreadId(0),
	iCompleteRequest(aCompleteRequest),
	iClientThreadId(aClientThreadId),
	iMessage(aMessage),
	iThreadWatcher(aThreadWatcher),
	iEventTimer(aEventTimer),
	iThreadOfClientInitiatingViewSwitch(aThreadOfClientInitiatingViewSwitch)
	{
	}

CVwsServerEvent_Activate::~CVwsServerEvent_Activate()
	{
	delete iClientMessage;
	delete iThreadWatcher;
	delete iEventTimer;
	iThreadOfClientInitiatingViewSwitch.Close();
	}

void CVwsServerEvent_Activate::HandleTimeOut(CVwsEventTimer::TTimeOut aTimeOut)
	{
	if (aTimeOut==CVwsEventTimer::EServerEventTimeOut && iServer.IsServerEventTimeOutEnabled())
		{
		if (iState==EActivationRequested)
			{
			LOG3(CVwsLog::ENormal,_L("PANIC CLIENT \"%x\" for timing out activation view event - activation request was not completed"),iViewIdToActivate.iAppUid.iUid);
			if (TUint(iNewViewClientThreadId)!=0)
				{
				CVwsSession* newViewSession=iServer.SessionByThreadId(iNewViewClientThreadId);
				if (newViewSession)
					{
					if (iServer.IsPriorityBoostBeforePanicEnabled())
						{
						if (iServer.InitializationFinished())
							{
							newViewSession->PanicClient(EVwsViewActivationEventTimeOut);
							}
						}
					else
						{
						newViewSession->PanicClient(EVwsViewActivationEventTimeOut);
						}
					}
				}
			}
		else if (iState==EDeactivationRequested)
			{
			LOG3(CVwsLog::ENormal,_L("PANIC CLIENT \"%x\" for timing out activation view event - deactivation request was not completed"),iServer.ActiveView().iAppUid.iUid);
			CVwsSession* sessionWithActiveView=iServer.ActiveViewSession();
			if (sessionWithActiveView)
				{
				if (iServer.IsPriorityBoostBeforePanicEnabled())
					{
					if (iServer.InitializationFinished())
						{
						sessionWithActiveView->PanicClient(EVwsViewDeactivationEventTimeOut);
						}
					}
				else
					{
					sessionWithActiveView->PanicClient(EVwsViewDeactivationEventTimeOut);
					}
				}
			}
		else
			{
			LOG4(CVwsLog::EQuiet,_L("Aborting activation of view \"%x,%x\" - server event processing timed-out"),iViewIdToActivate.iAppUid.iUid,iViewIdToActivate.iViewUid.iUid);
			Complete(KErrCancel);
			}
		}
	else if (aTimeOut==CVwsEventTimer::EClientRequestTimeOut)
			{
			LOG2(CVwsLog::ELoud,_L("Activation event timer has passed client request time-out"));
			if (iCompleteRequest==ECompleteRequest && iServer.SessionByThreadId(iClientThreadId)!=NULL)
				{
				LOG2(CVwsLog::ELoud,_L("Client request timed-out - silently completing request"));
				iCompleteRequest=EDoNotCompleteRequest;
				iMessage.Complete(KErrNone);
				}
			}
		else if (aTimeOut==CVwsEventTimer::EIntermediateEventTimeOut) 
           { 
           if (iState==EActivationRequested) 
               { 
               iServer.BoostPriority(iServer.SessionByThreadId(iNewViewClientThreadId)); 
               } 
           else if (iState==EDeactivationRequested) 
               { 
               iServer.BoostPriority(iServer.ActiveViewSession()); 
               } 
           } 

	}

void CVwsServerEvent_Activate::ProcessEventL()
	{
LOG4(CVwsLog::ELoud,_L("Starting to process activation of \"%x,%x\""),iViewIdToActivate.iAppUid.iUid,iViewIdToActivate.iViewUid.iUid);

	RequestActivateNewView();
	}

#ifdef _DEBUG
void CVwsServerEvent_Activate::RequestCompleted(TRequestType aType,TInt aError,const RMessage2&)
#else
void CVwsServerEvent_Activate::RequestCompleted(TRequestType /*aType*/,TInt aError,const RMessage2&)
#endif // _DEBUG
	{
	switch (iState)
		{
		case EPending:
			ASSERT(EFalse);
			break;
		case EActivationRequested:
			ASSERT(aType==MVwsSessionObserver::EActivation);
			LOG5(CVwsLog::ELoud,_L("Session request complete [activation event state: EActivationRequested; view to activate: \"%x,%x\", error: %d]"),iViewIdToActivate.iAppUid.iUid,iViewIdToActivate.iViewUid.iUid,aError);
			if (aError)
				{
				if (aError==KErrViewWrongMode)
					{
					RequestActivateSystemDefaultView();
					}
				else
					{
					Complete(aError);
					}
				}
			else
				{
				TVwsViewId viewToDeactivate(iServer.ActiveView());
				// When an application whose view has to be activated is in background, the currently active view will not be deactivated.
				// Note: Switching between different views of the same application must be followed by deactivation of old view
				if ((iMessage.Int3() && !(iServer.IsAppInForeground())) && (viewToDeactivate.iAppUid != iViewIdToActivate.iAppUid))
					{
					LOG4(CVwsLog::ELoud,_L("\"%x,%x\", is activated at the background, so foreground view will not be deactivated"),iViewIdToActivate.iAppUid.iUid,iViewIdToActivate.iViewUid.iUid);
					Complete(KErrNone);
					}
				else
					{
				RequestDeactivateOldView();
					}
				}
			break;
		case ESystemDefaultActivationRequested:
			ASSERT(aType==MVwsSessionObserver::EActivation);
			if (aError)
				{
				LOG3(CVwsLog::EQuiet,_L("Failed to activate system default view, error: %d"),aError);
				RequestActivateSystemDefaultView();
				}
			else
				{
				RequestDeactivateOldView();
				}
			break;
		case EDeactivationRequested:
			ASSERT(aType==MVwsSessionObserver::EDeactivation);
			LOG5(CVwsLog::ELoud,_L("Session request complete [activation event state: EDeactivationRequested; view to activate: \"%x,%x\", error: %d]"),iViewIdToActivate.iAppUid.iUid,iViewIdToActivate.iViewUid.iUid,aError);
			iServer.HandleDeactivation(iServer.ActiveView(),iViewIdToActivate);
			Complete(KErrNone);
			break;
		default:
		case EAppStartRequested:
			ASSERT(EFalse);
		}

// Disable unused parameter warning under release builds
#pragma warning (disable: 4100) 
	}
#pragma warning (default: 4100)

void CVwsServerEvent_Activate::NowObserving(CVwsSessionEvent* aObserved)
	{
	if(iObserved)
	    {
	    iObserved->NullifyObserver();
	    }
       	iObserved = aObserved;
	}

void CVwsServerEvent_Activate::NullifyObserved()
	{
	iObserved = NULL;	
	}

void CVwsServerEvent_Activate::HandleViewAdded(const TVwsViewId& aViewId, const TThreadId& aNewViewClientThreadId)
	{
	ASSERT(iState==EAppStartRequested);
	if (aViewId.iAppUid==iViewIdToActivate.iAppUid
	  &&aViewId.iAppUid==aViewId.iViewUid)
		{
		iViewIdToActivate = aViewId;
		}
	if (aViewId==iViewIdToActivate)
		{
		iServer.SetViewAdditionObserver(NULL);
		
		// set iNewViewClientThreadId to indicate that the new view should come from the session specified if possible
		iNewViewClientThreadId = aNewViewClientThreadId;
		RequestActivateNewView();
		}
	}

void CVwsServerEvent_Activate::RequestActivateNewView()
	{
	CVwsSession* sessionWithNewView=iServer.SessionByThreadIdAndAppUid(iClientThreadId,iViewIdToActivate.iAppUid);
	
	// iNewViewClientThreadId may have been set by the caller to indicate a preference between
	// sessions with the same App Uid
	if (sessionWithNewView==NULL && iNewViewClientThreadId!=TThreadId(0))
		{
		sessionWithNewView=iServer.SessionByThreadIdAndAppUid(iNewViewClientThreadId,iViewIdToActivate.iAppUid);
		}

	if (sessionWithNewView==NULL)
		{
		sessionWithNewView=iServer.SessionByUid(iViewIdToActivate.iAppUid);
		}

	if (sessionWithNewView==NULL || (sessionWithNewView && sessionWithNewView->IsExiting()))
		{
		RequestAppStart();
		}
	else
		{
		iNewViewClientThreadId=sessionWithNewView->ClientThreadId();
		DoRequestActivateNewView(*sessionWithNewView);
		}
	}

void CVwsServerEvent_Activate::RequestActivateSystemDefaultView()
	{
	iServer.GetSystemDefaultView(iViewIdToActivate);
	CVwsSession* sessionWithSystemDefaultView=iServer.SessionByUid(iViewIdToActivate.iAppUid);
	// need an empty client message 
	CVwsClientMessage* emptyClientMessage=CVwsClientMessage::New();
	if (emptyClientMessage==NULL)
		{
		Complete(KErrNoMemory);
		}

	if (sessionWithSystemDefaultView)
		{
		iNewViewClientThreadId=sessionWithSystemDefaultView->ClientThreadId();
		RequestClientActivation(*sessionWithSystemDefaultView,emptyClientMessage,ESystemDefaultActivationRequested);
		}
	else if (iThreadWatcher==NULL)
		{
		// app died
		StopActivationProfile();
		ASSERT(iState!=EAppStartRequested);	// Already asked to start app once.
		StartAppStartProfile();
		iServer.SetViewAdditionObserver(this);
		TThreadId appThreadId;
		iClientMessage = emptyClientMessage;
		TInt err=iServer.StartApp(iViewIdToActivate.iAppUid,appThreadId);
		if (err)
			{
			LOG3(CVwsLog::EQuiet,_L("App start FAILED with %d"),err);
			Complete(err);
			}
		else
			{
			iState=EAppStartRequested;
			}
		}
	else
		{
		delete emptyClientMessage;
		}
	}

void CVwsServerEvent_Activate::RequestAppStart()
	{
	ASSERT(iState!=EAppStartRequested);	// Already asked to start app once.
	StartAppStartProfile();
	iServer.SetViewAdditionObserver(this);
	TThreadId appThreadId;
	TInt err=iServer.StartApp(iViewIdToActivate.iAppUid,appThreadId);
	if (err)
		{
		LOG3(CVwsLog::EQuiet,_L("App start FAILED with %d"),err);
		Complete(err);
		}
	else
		{
		iState=EAppStartRequested;
		err=iThreadWatcher->StartWatching(appThreadId,TCallBack(&AppThreadWatcherCallBack,this));
		if (err)
			{
			LOG3(CVwsLog::EQuiet,_L("App start FAILED with %d"),err);
			Complete(err);
			}
		}
	}

TInt CVwsServerEvent_Activate::AppThreadWatcherCallBack(TAny* aPtr)
	// static
	{
	LOG2(CVwsLog::EQuiet,_L("App start FAILED with app client thread death"));
	REINTERPRET_CAST(CVwsServerEvent_Activate*,aPtr)->Complete(KErrCancel);
	return 0;
	}

TInt CVwsServerEvent_Activate::RequestClientActivation(CVwsSession& aSession,CVwsClientMessage* aClientMessage,TState aNewState)
	{
	TRAPD(error,
			aSession.RequestClientActivationL(*this,iViewIdToActivate,iServer.ActiveView(),aClientMessage,iThreadOfClientInitiatingViewSwitch));
	if (error)
		{
		LOG3(CVwsLog::ELoud,_L("RequestClientActivationL FAILED with %d - unable to activate new view"),error);
		if(aSession.IsLeaveAfterOwnershipTaken())
			{
			aSession.ResetLeaveAfterOwnershipTaken();
			iClientMessage=NULL;
			}
		Complete(error);
		}
	else
		{
		iClientMessage=NULL; // The session is now the owner of the custom message buf.
		iState=aNewState;
		}
	return error;
	}

void CVwsServerEvent_Activate::CustomCrossCheck(CVwsSession& aSessionWithNewView)
	{
	if (iClientMessage->iMessageId == KUidCustomCrossCheck && iClientMessage->iMessage == NULL)
		{
		iClientMessage->iMessageId = KNullUid;
		TVwsViewId viewId;
		if (aSessionWithNewView.GetTopView(viewId) == KErrNone)
			{
#ifdef _DEBUG
			if (iViewIdToActivate != viewId)
				{
				LOG4(CVwsLog::ELoud,_L("Cross check to \"%x,%x\""), viewId.iAppUid.iUid, viewId.iViewUid.iUid);
				}
#endif //_DEBUG
			iViewIdToActivate = viewId;
			iClientMessage->iMessageId = KNullUid;
			}
		}
	}

void CVwsServerEvent_Activate::DoRequestActivateNewView(CVwsSession& aSessionWithNewView)
	{
	StopAppStartProfile();
	delete iThreadWatcher;
	iThreadWatcher=NULL;

	iEventTimer->Start(this,EFalse);

	if (iClientMessage)
		{
		CustomCrossCheck(aSessionWithNewView);
		}

	if (iServer.CheckViewExists(aSessionWithNewView.ClientThreadId(),iViewIdToActivate)==KErrNotFound)
		{
		LOG4(CVwsLog::EQuiet,_L("Aborting activation - view \"%x,%x\" not found"),iViewIdToActivate.iAppUid.iUid,iViewIdToActivate.iViewUid.iUid);
		Complete(KErrNotFound);
		return;
		}

	StartActivationProfile();
	RequestClientActivation(aSessionWithNewView,iClientMessage,EActivationRequested);
	}

void CVwsServerEvent_Activate::RequestDeactivateOldView()
	{
	StopActivationProfile();
	TVwsViewId viewToDeactivate(iServer.ActiveView());
	CVwsSession* sessionWithOldView=iServer.ActiveViewSession();
	CVwsSession* sessionWithNewView=iServer.SessionByThreadIdAndAppUid(iClientThreadId,iViewIdToActivate.iAppUid);
		
	//If the client that is requesting view activation is same as the client which has the new active view, ie, reactivation of same view, 
	//then the session with new active view is taken. 
	if (sessionWithNewView==NULL && iNewViewClientThreadId!=TThreadId(0))
		{
		sessionWithNewView=iServer.SessionByThreadIdAndAppUid(iNewViewClientThreadId,iViewIdToActivate.iAppUid);
		}
	
	if (sessionWithNewView==NULL)
		{
		sessionWithNewView=iServer.SessionByUid(iViewIdToActivate.iAppUid);
		}
	
	if (viewToDeactivate.iAppUid.iUid && (viewToDeactivate != iViewIdToActivate || sessionWithOldView != sessionWithNewView))
		{
		if (sessionWithOldView==NULL)
			{	// Session with old view has disconnected, so abort deactivation.
			LOG4(CVwsLog::ELoud,_L("Aborting deactivation of view \"%x,%x\" - client disconnected"),viewToDeactivate.iAppUid.iUid,viewToDeactivate.iViewUid.iUid);
			Complete(KErrNone);
			}
		else
			{
			TBool differentInstanceOfSameApp = EFalse;
			if (viewToDeactivate.iAppUid == iViewIdToActivate.iAppUid && sessionWithOldView != sessionWithNewView)
				differentInstanceOfSameApp = ETrue;
			TRAPD(err,sessionWithOldView->RequestClientDeactivationL(*this,viewToDeactivate,iViewIdToActivate, differentInstanceOfSameApp));
			if (err)
				{
				LOG3(CVwsLog::ELoud,_L("RequestClientDeactivationL FAILED with %d - unable to deactivate currently active view"),err);
				Complete(err);
				}
			else
				{
				iState=EDeactivationRequested;
				}
			}
		}
	else
		{
		// No view to deactivate, so complete.
		LOG2(CVwsLog::ELoud,_L("Aborting deactivation - no view to deactivate"));
		Complete(KErrNone);
		}
	}

void CVwsServerEvent_Activate::Complete(TInt aError)
	{
	LOG5(CVwsLog::ELoud,_L("Completing activation of \"%x,%x\" with %d"),iViewIdToActivate.iAppUid,iViewIdToActivate.iViewUid,aError);
	if (aError==KErrNone && TUint(iNewViewClientThreadId)!=0) 
		{
		iServer.HandleActivation(iViewIdToActivate,iServer.ActiveView());
		TVwsViewId viewToDeactivate(iServer.ActiveView());
		// The active active viewid will be set in the server when
		// 1. Application whose view is getting activated is in foreground
		// 2. Switching between different views of the same application
		if(iServer.IsAppInForeground() || (iViewIdToActivate.iAppUid == viewToDeactivate.iAppUid))
			{
			iServer.SetActiveView(iNewViewClientThreadId,iViewIdToActivate);	
			}
		}
	iServer.SetViewAdditionObserver(NULL);
	if ((iCompleteRequest==ECompleteRequest) && (iServer.SessionByThreadId(iClientThreadId)!=NULL))
		{
		if(!iMessage.IsNull())
			{
			iMessage.Complete(aError);
			}
		}
#ifdef __DO_LOGGING__
	else if (iCompleteRequest==ECompleteRequest)
		{
		LOG2(CVwsLog::ELoud,_L("Client requesting activation not current - completing activation will not complete message handle"));
		}
#endif
	ReportEventProcessed();
	}

void CVwsServerEvent_Activate::HandleSessionRemoval(const TThreadId& aClientThreadId)
	{
	TThreadId threadId(aClientThreadId);
	TBool iCancel=EFalse;
	if (iState==EDeactivationRequested)
		{
		CVwsSession* sessionWithActiveView=iServer.ActiveViewSession();
		if (sessionWithActiveView && threadId==sessionWithActiveView->ClientThreadId())
			{
			LOG2(CVwsLog::ELoud,_L("Client with active view removed while session deactivation request outstanding"));
			iCancel=ETrue;
			}
#ifdef __DO_LOGGING__
		else if (threadId==iNewViewClientThreadId)
			{
			LOG2(CVwsLog::ELoud,_L("Client with new view removed while session deactivation request outstanding - waiting for deactivation to complete"));
			}
#endif
		}
	else if (threadId==iNewViewClientThreadId)
		{
		LOG2(CVwsLog::ELoud,_L("Client with new view removed"));
		iCancel=ETrue;
		}
	if (iCancel)
		{
		LOG2(CVwsLog::ELoud,_L("Client removal means activation event will not complete normally - activation cancelled"));
		Complete(KErrCancel);
		}
	}

void CVwsServerEvent_Activate::StartAppStartProfile()
	{
	ASSERT(iWhichProfile==ENone);
	iWhichProfile=EAppStart;
	}

void CVwsServerEvent_Activate::StopAppStartProfile()
	{
	if (iWhichProfile==EAppStart)
		{
		iWhichProfile=ENone;
		}
	}

void CVwsServerEvent_Activate::StartActivationProfile()
	{
	ASSERT(iWhichProfile==ENone);
	iWhichProfile=EActivation;
	}

void CVwsServerEvent_Activate::StopActivationProfile()
	{
	if (iWhichProfile==EActivation)
		{
		iWhichProfile=ENone;
		}
	}


//
// CVwsServerEvent_ScreenDeviceChanged.
//

CVwsServerEvent_ScreenDeviceChanged::CVwsServerEvent_ScreenDeviceChanged(CVwsServer& aServer,CVwsEventQueue& aQueue,CVwsThreadWatcher* aThreadWatcher,CVwsEventTimer* aEventTimer)
	: CVwsServerEvent_Activate(aServer,CVwsServerEvent::ERejectPairs,aQueue,KNullViewId,NULL,RMessage2(),0,EDoNotCompleteRequest,aThreadWatcher,aEventTimer,RThread()),
	iThreadWatcher(aThreadWatcher) ,iEventTimer(aEventTimer)
	{
	}

CVwsServerEvent_ScreenDeviceChanged::~CVwsServerEvent_ScreenDeviceChanged()
	{
	}

void CVwsServerEvent_ScreenDeviceChanged::ProcessEventL()
	{
	LOG2(CVwsLog::ELoud,_L("Started processing of screen device changed event"));
	if(iServer.ActiveViewSession()!=NULL)
		{
		TThreadId activeClientThread = iServer.ActiveViewSession()->ClientThreadId();
		TRAPD(err,iThreadWatcher->StartWatching(activeClientThread,TCallBack(&AppThreadWatcherCallBack,this)));
		iEventTimer->Start(this,ETrue);
		if (err)
			{
			Complete(err);
			}
		}
	TVwsViewId activeView(iServer.ActiveView());
	if (activeView.iAppUid.iUid)
		{
		RequestChangeNotification();
		}
	else
		{
		LOG2(CVwsLog::ELoud,_L("No active view, so ignoring screen device changed event"));
		Complete(KErrNone);
		}
	}
TInt CVwsServerEvent_ScreenDeviceChanged::AppThreadWatcherCallBack(TAny* aPtr)
	// static
	{
	LOG2(CVwsLog::ELoud,_L("Client thread died while processing Screendevice change event"));
	REINTERPRET_CAST(CVwsServerEvent_ScreenDeviceChanged*,aPtr)->Complete(KErrCancel);
	return 0;
	}

void CVwsServerEvent_ScreenDeviceChanged::RequestCompleted(TRequestType aType,TInt aError,const RMessage2& aMessage)
	{
	switch (iScreenDeviceNotificationState)
		{
		case EPending:
			ASSERT(EFalse);
			break;
		case EScreenDeviceChangeNotificationRequested:
			{
			ASSERT(aType==EScreenDeviceChangeNotification);
			TRAPD(err,RequestActivationAsRequiredL(aMessage));
			if (err)
				{
				LOG3(CVwsLog::ELoud,_L("CVwsClientMessage::NewL FAILED with %d, unable to activate view in responce to screen device changed event"),err);
				RequestActivateSystemDefaultView();
				}
			}
			break;
		case EViewActivationRequested:
		case EDefaultSystemViewActivationRequested:
			CVwsServerEvent_Activate::RequestCompleted(aType,aError,aMessage);
			break;
		default:
			ASSERT(EFalse);
		}

// Disable unused parameter warning under release builds
#pragma warning (disable: 4100) 
	}
#pragma warning (default: 4100)

void CVwsServerEvent_ScreenDeviceChanged::NowObserving(CVwsSessionEvent* aObserved)
	{
	if(iObserved)
	    {
	    iObserved->NullifyObserver();
	    }
	iObserved = aObserved;
	}

void CVwsServerEvent_ScreenDeviceChanged::NullifyObserved()
	{
	iObserved = NULL;	
	}

void CVwsServerEvent_ScreenDeviceChanged::RequestChangeNotification()
	{
	const TVwsViewId activeView(iServer.ActiveView());
	CVwsSession* sessionWithActiveView=iServer.ActiveViewSession();
	ASSERT(sessionWithActiveView); // Session with active view MUST be found.
	TRAPD(err,sessionWithActiveView->RequestScreenDeviceChangeNotificationL(*this,activeView));
	if (err)
		{
		LOG3(CVwsLog::ELoud,_L("RequestScreenDeviceChangeNotificationL FAILED with %d, unable to notify screen device changed"),err);
		iScreenDeviceNotificationState=EDefaultSystemViewActivationRequested;
		RequestActivateSystemDefaultView();
		}
	else
		{
		iScreenDeviceNotificationState=EScreenDeviceChangeNotificationRequested;
		}
	}

void CVwsServerEvent_ScreenDeviceChanged::RequestActivationAsRequiredL(const RMessage2& aMessage)
	{
	TVwsViewIdAndMessageBuf viewToActivateBuf;
	aMessage.ReadL(2,viewToActivateBuf);
	TVwsViewIdAndMessage viewToActivate(viewToActivateBuf());
	iViewIdToActivate=viewToActivate.iViewId;
	if (iViewIdToActivate==TVwsViewId())
		{	// Null view id, so ignore.
		Complete(KErrNone);
		}
	else if (iServer.IsViewActive(iViewIdToActivate))
		{
		LOG4(CVwsLog::ELoud,_L("View \"%x,%x\" already active - aborting activation"),iViewIdToActivate.iAppUid.iUid,iViewIdToActivate.iViewUid.iUid);
		Complete(KErrNone);
		}
	else
		{
		iClientMessage=CVwsClientMessage::NewL(viewToActivate.iCustomMessageId,viewToActivate.iCustomMessageLength,aMessage,3);
		iScreenDeviceNotificationState=EViewActivationRequested;
		
		// Setting the iNewViewClientThreadId here indicates that if there are multiple sessions
		// with the same app uid and we are switching views within one app then the one with the
		// currently active view should be preferred
		iNewViewClientThreadId = iServer.ActiveViewSession()->ClientThreadId();
		RequestActivateNewView();
		}
	}

#ifdef _DEBUG
void CVwsServerEvent_ScreenDeviceChanged::Complete(TInt aError)
#else
void CVwsServerEvent_ScreenDeviceChanged::Complete(TInt /*aError*/)
#endif // _DEBUG
	{
	LOG3(CVwsLog::ELoud,_L("Completed processing of screen device changed event with %d"),aError);
	ReportEventProcessed();

// Disable unused parameter warning under release builds
#pragma warning (disable: 4100) 
	}
#pragma warning (default: 4100)

void CVwsServerEvent_ScreenDeviceChanged::HandleAddedToQueue()
	{
	// display opaque intercepting window
	iServer.MakeInterceptingWindowVisibleAndUpdateScreen();
	}

void CVwsServerEvent_ScreenDeviceChanged::HandleSessionRemoval(const TThreadId& aClientThreadId)
	{
	switch (iScreenDeviceNotificationState)
		{
	case EScreenDeviceChangeNotificationRequested:
		{
		CVwsSession* sessionWithActiveView=iServer.ActiveViewSession();
		if(sessionWithActiveView && aClientThreadId==sessionWithActiveView->ClientThreadId())
			{
			LOG2(CVwsLog::ELoud,_L("Client with active view removed while screen device change request outstanding"));
			RequestActivateSystemDefaultView();
			iScreenDeviceNotificationState=EDefaultSystemViewActivationRequested;
			}
		}
	case EViewActivationRequested:
	case EDefaultSystemViewActivationRequested:
		CVwsServerEvent_Activate::HandleSessionRemoval(aClientThreadId);
		break;
	case EPending:
	default:
		break;
	}
}

void CVwsServerEvent_ScreenDeviceChanged::HandleTimeOut(CVwsEventTimer::TTimeOut /*aTimeOut*/)
	{
	LOG2(CVwsLog::ELoud,_L("CVwsServerEvent_ScreenDeviceChanged view event timer has passed client request time-out"));
	switch (iScreenDeviceNotificationState)
		{
		case EScreenDeviceChangeNotificationRequested:
			Complete(KErrNone);
			break;

		case EViewActivationRequested:
		case EDefaultSystemViewActivationRequested:
			CVwsServerEvent_Activate::HandleTimeOut(CVwsEventTimer::EClientRequestTimeOut);
			break;

		case EPending:
		default:
			break;
		}
	}

//
// CVwsServerEvent_DeactivateActiveView.
//

CVwsServerEvent_DeactivateActiveView::CVwsServerEvent_DeactivateActiveView(CVwsServer& aServer,CVwsEventQueue& aQueue,const RMessage2& aMessage,const TThreadId& aClientThreadId,TVwsCompleteRequest aCompleteRequest,CVwsEventTimer* aEventTimer)
	: CVwsServerEvent(aServer,CVwsServerEvent::ENormal,aQueue),
	iMessage(aMessage),
	iClientThreadId(aClientThreadId),
	iCompleteRequest(aCompleteRequest),
	iEventTimer(aEventTimer)
	{
	}

CVwsServerEvent_DeactivateActiveView::~CVwsServerEvent_DeactivateActiveView()
	{
	delete iEventTimer;
	}

void CVwsServerEvent_DeactivateActiveView::ProcessEventL()
	{
	LOG2(CVwsLog::ELoud,_L("Started processing of deactivate active view event"));
	const TVwsViewId activeView(iServer.ActiveView());

	//Check if the Cross Check UID is set, if it is then enable customised behaviour here
	if(iServer.CrossCheckUid()!=KNullUid)
		{
		CVwsSession* self = iServer.SessionByThreadId(iClientThreadId);
		CVwsSession* active = iServer.ActiveViewSession();
		if (self != active)
			{
			LOG2(CVwsLog::ELoud,_L("Requested session does not have Active view, so ignoring deactivate active view event"));
			if(iCompleteRequest==ECompleteRequest&& iServer.SessionByThreadId(iClientThreadId)!=NULL)
				{
				iMessage.Complete(KErrNone);
				}
			ReportEventProcessed();
			return;
			}
		}

	if (activeView.iAppUid.iUid)
		{
		TRAPD(err,RequestDeactivationL());
		if (err)
			{
			Complete(err);
			}
		}
	else
		{
		LOG2(CVwsLog::ELoud,_L("No active view, so ignoring deactivate active view event"));
		Complete(KErrNone);
		}
	}

#ifdef _DEBUG
void CVwsServerEvent_DeactivateActiveView::RequestCompleted(TRequestType aType,TInt,const RMessage2&)
#else
void CVwsServerEvent_DeactivateActiveView::RequestCompleted(TRequestType /*aType*/,TInt,const RMessage2&)
#endif // _DEBUG
	{
	switch (iState)
		{
		case EPending:
			ASSERT(EFalse);
			break;
		case EDeactivationRequested:
			ASSERT(aType==EDeactivation);
			Complete(KErrNone);
			break;
		default:
			ASSERT(EFalse);
		}

// Disable unused parameter warning under release builds
#pragma warning (disable: 4100) 
	}
#pragma warning (default: 4100)

void CVwsServerEvent_DeactivateActiveView::NowObserving(CVwsSessionEvent* aObserved)
	{
	if(iObserved)
	    {
	    iObserved->NullifyObserver();
	    }
	iObserved = aObserved;
	}

void CVwsServerEvent_DeactivateActiveView::NullifyObserved()
	{
	iObserved = NULL;	
	}

void CVwsServerEvent_DeactivateActiveView::RequestDeactivationL()
	{
	ASSERT(iState==EPending);

	iEventTimer->Start(this,EFalse);

	iActiveView=iServer.ActiveView();
	CVwsSession* sessionWithActiveView=iServer.ActiveViewSession();
	// If the session with currently active view is NULL, then the deactivation request is
 	// completed with KErrNotFound and the previously active view is activated.
	if (sessionWithActiveView)
 		{
 		//EFalse always because the deactivation of view is requested by the application directly
 		sessionWithActiveView->RequestClientDeactivationL(*this,iActiveView,TVwsViewId(),EFalse);
 		iState=EDeactivationRequested;
 		}
 	else
 		{
 		LOG2(CVwsLog::ELoud,_L("Session with active view is NULL, so completing the deactivation request with KErrNotFound"));
 		User::Leave(KErrNotFound);
 		}
	}

void CVwsServerEvent_DeactivateActiveView::Complete(TInt aErr)
	{
	LOG3(CVwsLog::ELoud,_L("Completing deactivate active view event with %d"),aErr);
	if (aErr)
		{
		iServer.HandleDeactivation(iActiveView,TVwsViewId());
		}
	iServer.ClearActiveView();
	if(iCompleteRequest==ECompleteRequest&& iServer.SessionByThreadId(iClientThreadId)!=NULL)
		{
		iMessage.Complete(aErr);
		}
	ReportEventProcessed();
	}

void CVwsServerEvent_DeactivateActiveView::HandleSessionRemoval(const TThreadId& aClientThreadId)
	{
	TThreadId threadId(aClientThreadId);
	if (iState==EDeactivationRequested)
		{
		CVwsSession* sessionWithActiveView=iServer.ActiveViewSession();
		if (sessionWithActiveView && threadId==sessionWithActiveView->ClientThreadId())
			{
			LOG2(CVwsLog::ELoud,_L("Client with active view removed while session deactivation request outstanding"));
			LOG2(CVwsLog::ELoud,_L("Client removal means deactivate active view event will not complete normally - deactivation cancelled"));
			Complete(KErrCancel);
			}
		}
	}

void CVwsServerEvent_DeactivateActiveView::HandleTimeOut(CVwsEventTimer::TTimeOut aTimeOut)
	{
	if (aTimeOut==CVwsEventTimer::EServerEventTimeOut && iServer.IsServerEventTimeOutEnabled())
		{
		if (iState==EDeactivationRequested)
			{
			LOG3(CVwsLog::ENormal,_L("PANIC CLIENT \"%x\" for timing out activation view event - deactivation request was not completed"),iServer.ActiveView().iAppUid.iUid);
			CVwsSession* sessionWithActiveView=iServer.ActiveViewSession();
			if (sessionWithActiveView)
				{
				if(iServer.IsPriorityBoostBeforePanicEnabled())
					{
					if (iServer.InitializationFinished())
						{
						sessionWithActiveView->PanicClient(EVwsViewDeactivationEventTimeOut);
						}
					}
				else
					{
					sessionWithActiveView->PanicClient(EVwsViewDeactivationEventTimeOut);
					}
				}
			}
		else
			{
			LOG4(CVwsLog::EQuiet,_L("Aborting deactivation of active view \"%x,%x\" - server event processing timed-out"),iServer.ActiveView().iAppUid.iUid,iServer.ActiveView().iViewUid.iUid);
			Complete(KErrCancel);
			}
		}
	else if (aTimeOut==CVwsEventTimer::EClientRequestTimeOut)
			{
			LOG2(CVwsLog::ELoud,_L("Deactivate active view event timer has passed client request time-out"));
			if (iCompleteRequest==ECompleteRequest && iServer.SessionByThreadId(iClientThreadId)!=NULL)
				{
				LOG2(CVwsLog::ELoud,_L("Client request timed-out - silently completing request"));
				iCompleteRequest=EDoNotCompleteRequest;
				iMessage.Complete(KErrNone);
				}
			}
		else if (aTimeOut==CVwsEventTimer::EIntermediateEventTimeOut) 
           { 
           if (iState==EDeactivationRequested) 
               { 
               iServer.BoostPriority(iServer.ActiveViewSession()); 
               } 
           }
	}

//
// CVwsServerEvent_AppStart.
//

CVwsServerEvent_AppStart::CVwsServerEvent_AppStart(CVwsServer& aServer,CVwsEventQueue& aQueue,const RMessage2& aMessage,const TUid& aAppToStart,CVwsThreadWatcher* aThreadWatcher)
	: CVwsServerEvent(aServer,CVwsServerEvent::ENormal,aQueue),iAppToStart(aAppToStart),iMessage(aMessage),iThreadWatcher(aThreadWatcher)
	{
	}

CVwsServerEvent_AppStart::~CVwsServerEvent_AppStart()
	{
	delete iThreadWatcher;
	}

void CVwsServerEvent_AppStart::ProcessEventL()
	{
	LOG2(CVwsLog::ELoud,_L("Started processing of app start event"));

	iSessionWithNewApp=iServer.SessionByUid(iAppToStart);
	if (iSessionWithNewApp==NULL)
		{
		RequestAppStart();
		}
	else
		{
		Complete(KErrNone);
		}
	}

void CVwsServerEvent_AppStart::HandleViewAdded(const TVwsViewId& aViewId, const TThreadId& aNewViewClientThreadId)
	{
	ASSERT(iState==EAppStartRequested);

	if (aViewId.iAppUid==iAppToStart)
		{
		delete iThreadWatcher;
		iThreadWatcher=NULL;
		iServer.SetViewAdditionObserver(NULL);
		ASSERT(iSessionWithNewApp==NULL);
		iSessionWithNewApp=iServer.SessionByThreadIdAndAppUid(aNewViewClientThreadId,aViewId.iAppUid);
		ASSERT(iSessionWithNewApp);
		Complete(KErrNone);
		}
	}

void CVwsServerEvent_AppStart::RequestAppStart()
	{
	iServer.SetViewAdditionObserver(this);
	TThreadId appThreadId;
	TInt err=iServer.StartApp(iAppToStart,appThreadId);
	if (err)
		{
		LOG3(CVwsLog::EQuiet,_L("App start FAILED with %d"),err);
		Complete(err);
		}
	else
		{
		iState=EAppStartRequested;
		err=iThreadWatcher->StartWatching(appThreadId,TCallBack(&AppThreadWatcherCallBack,this));
		if (err)
			{
			LOG3(CVwsLog::EQuiet,_L("App start FAILED with %d"),err);
			Complete(err);
			}
		}
	}

TInt CVwsServerEvent_AppStart::AppThreadWatcherCallBack(TAny* aPtr)
	// static
	{
	LOG2(CVwsLog::EQuiet,_L("App start FAILED with app client thread death"));
	REINTERPRET_CAST(CVwsServerEvent_AppStart*,aPtr)->Complete(KErrCancel);
	return 0;
	}

void CVwsServerEvent_AppStart::Complete(TInt aErr)
	{
	LOG3(CVwsLog::EQuiet,_L("App start event completed with %d"),aErr);
	iServer.SetViewAdditionObserver(NULL);
	iMessage.Complete(aErr);
	ReportEventProcessed();
	}
