// EIKSRV.CPP
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#include <bautils.h>
#include <eiksrv.h>
#include <eiksvdef.h>
#include "eiksvprv.h"
#include <eikkeys.h>
#include <e32hal.h>
#include <eikdll.h>
#include <eiksrv.rsg>
#include "eiknfysv.h"
#include "eikbaksv.h"
#include "eikalsrv.h"
#include "eiksrv.pan"
#include <t32start.h>
#include <eikcfdlg.h>
#include "eikunder.h"
#include <c32comm.h>
#include <s32file.h>
#include <apasvst.h>
#include <basched.h>
#include <eikkwin.h>
#include <eiktxlbx.h>
#include <eikalert.h>
#include <eikmover.h>
#include <t32alm.h>
#include <apgcli.h>

#include <eikon.rsg>


const TUid KUidPasswordMode={268435755};
#define KPasswordMode _L8("Mode")
const TInt KEikServServerRestartDelay=500000; // .5 sec
const TInt KEikServServerRestartInterval=3000000; // 3 sec

const TInt KEikServGapBetweenScreenAndAppBar=10;
const TInt KEikServGapBetweenScreenAndSideBar=10;
const TInt KEikServAppBarLeftOffset=24;
#if defined(__WINS__)
const TInt KEikServSideBarWidth=35;
const TInt KEikServAppbarHeight=50;
#endif

//#define __HELP_DATABASE_PATH _L("z:\\System\\Data\\Help")
#define __EXTERNAL_KEY_HANDLER_APP_PATH _L("z:\\System\\Apps\\Record\\record.app")

GLDEF_C void Panic(TEikServPanic aPanic)
	{
	User::Panic(_L("EIKON-SERVER"),aPanic);
	}

EXPORT_C TEikPasswordModeCategory::TEikPasswordModeCategory()
	: TRegistryCategory(KUidPasswordMode)
	{}

EXPORT_C void TEikPasswordModeCategory::PasswordMode(TPasswordMode& aMode) const
	{
	aMode=(TPasswordMode)ItemInt( KPasswordMode, (TInt)EPasswordNone); 
	}

EXPORT_C TInt TEikPasswordModeCategory::SetPasswordMode(TPasswordMode aMode)
	{
	return SetItemInt(KPasswordMode, (TInt)aMode); 
	}

//
// CEikServKeyFilter
//

class CFbsBitmap;

class CEikServKeyFilter : public CCoeControl
	{
public:
	void ConstructL(CEikServAppUi& aAppUi);
private: // framework
	TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType);
private: // new functions
	void HandleExternalKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType);
	void HandleScreenCaptureKeyEventL();
	void ConvertToMonochromeAndSaveToFileL(const TDesC& aFilename,CFbsBitmap* aBitmap);	
	void HandleHelpKeyEventL();
private:
	CEikServAppUi* iAppUi;
	TBool iScreenCaptureDialogDisplayed;
	};

void CEikServKeyFilter::ConstructL(CEikServAppUi& aAppUi)
	{
    aAppUi.AddToStackL(this,ECoeStackPriorityEnvironmentFilter,ECoeStackFlagRefusesFocus|ECoeStackFlagOwnershipTransfered|ECoeStackFlagSharable);
	iAppUi=(&aAppUi);
	iScreenCaptureDialogDisplayed=EFalse;
	}

TKeyResponse CEikServKeyFilter::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
	{
	TInt code=aKeyEvent.iCode;
	TInt modifiers=aKeyEvent.iModifiers;
    if (aType!=EEventKey)
        return(EKeyWasNotConsumed);
	if ((modifiers&EAllStdModifiers)==EAllStdModifiers && code==CTRL('l'))
		{
		CApaCommandLine* cmdLine=CApaCommandLine::NewLC();
		cmdLine->SetLibraryNameL(_L("z:\\System\\Apps\\lshell.app"));
		cmdLine->SetCommandL(EApaCommandRun);
		EikDll::StartAppL(*cmdLine);
		CleanupStack::PopAndDestroy(); // cmdLine
		return(EKeyWasConsumed);
		}
	else if ((modifiers&EAllStdModifiers)==EAllStdModifiers && code==CTRL('s'))
		{
		HandleScreenCaptureKeyEventL();
		return(EKeyWasConsumed);
		}
	else if (code==KExternalKey1 || code==KExternalKey2 || code==KExternalKey3)
		{
		if (iAppUi->iAlarmAlertServer->AlarmAlertIsVisible())
			return EKeyWasNotConsumed;
		HandleExternalKeyEventL(aKeyEvent, aType);
		return EKeyWasConsumed;
		}
	else if (code==EKeyHelp && (modifiers&EAllStdModifiers)==EModifierFunc)
		{
		HandleHelpKeyEventL();
		return EKeyWasConsumed;
		}
	return EKeyWasNotConsumed;
	}

void CEikServKeyFilter::HandleHelpKeyEventL()
	{
	if (iAppUi->iHelpAppRunning)
		{
		// task to the help app
		RWsSession& wsSession=iEikonEnv->WsSession();
		TInt wgId=wsSession.FindWindowGroupIdentifier(0, iAppUi->iHelpAppThreadId);
		TApaTask task(wsSession);
		task.SetWgId(wgId);
		if (task.Exists())
			task.BringToForeground();
		}
	else
		{
		CApaCommandLine* cmdLine=CApaCommandLine::NewLC();
		cmdLine->SetLibraryNameL(_L("z:\\System\\Apps\\Data\\data.app"));
		cmdLine->SetCommandL(EApaCommandOpen);
//		cmdLine->SetDocumentNameL(__HELP_DATABASE_PATH); 
		TFileName helpPath;
		iEikonEnv->ReadResource(helpPath, R_EIKSRV_HELP_DATABASE_PATH);
		cmdLine->SetDocumentNameL(helpPath); 
		iAppUi->iHelpAppThreadId=EikDll::StartAppL(*cmdLine);
		CleanupStack::PopAndDestroy(); // cmdLine
		iAppUi->iHelpAppRunning=ETrue;
		}
	}

void CEikServKeyFilter::HandleScreenCaptureKeyEventL()
	{
	if (!iScreenCaptureDialogDisplayed)
		{
		CWsBitmap* screenBitmap=new(ELeave) CWsBitmap(iEikonEnv->WsSession());
		CleanupStack::PushL(screenBitmap);
		User::LeaveIfError(screenBitmap->Create(iEikonEnv->ScreenDevice()->SizeInPixels(),EGray4));
		iEikonEnv->ScreenDevice()->CopyScreenToBitmap(screenBitmap);
		TFileName* fileName = new(ELeave) TFileName;
		CleanupStack::PushL(fileName);
		*fileName=_L("c:\\*.mbm");
		TBool saveAsMonochrome = EFalse;
		CEikDialog* fileDialog=new(ELeave) CEikScreenCaptureDialog(fileName, saveAsMonochrome);
		iScreenCaptureDialogDisplayed=ETrue;
		TInt ret=0;
		TRAPD(err, ret=fileDialog->ExecuteLD(R_EIK_DIALOG_SCREEN_CAPTURE));
		iScreenCaptureDialogDisplayed=EFalse;
		User::LeaveIfError(err);
		if (ret)
			{
			if (saveAsMonochrome)
				ConvertToMonochromeAndSaveToFileL(*fileName, screenBitmap);
			else
				screenBitmap->Save(*fileName);
			}
		CleanupStack::PopAndDestroy(2); // screenBitmap and fileName
		}
	}

void CEikServKeyFilter::ConvertToMonochromeAndSaveToFileL(const TDesC& aFilename,CFbsBitmap* aBitmap)
	{
	// this function needs a better home...
//	__ASSERT_ALWAYS(aBitmap,User::Panic(_L("ConvertToMonochromeAndSaveToFileL"),KErrArgument));
	TSize oldsize=aBitmap->SizeInPixels();
	TSize newsize(oldsize.iWidth<<1,oldsize.iHeight<<1);
	CFbsBitmap* newbitmap=new(ELeave) CFbsBitmap;
	CleanupStack::PushL(newbitmap);
	User::LeaveIfError(newbitmap->Create(newsize,EGray4));
	CFbsBitmapDevice* newbmpdev=CFbsBitmapDevice::NewL(newbitmap);
	CleanupStack::PushL(newbmpdev);
	CFbsBitGc* gc=NULL;
	User::LeaveIfError(newbmpdev->CreateContext(gc));
	gc->DrawBitmap(TRect(newsize),aBitmap);
	delete gc;
	CleanupStack::PopAndDestroy();
	CFbsBitmap* monobmp=new(ELeave) CFbsBitmap;
	CleanupStack::PushL(monobmp);
	User::LeaveIfError(monobmp->Create(newsize,EGray2));
	CFbsBitmapDevice* monobmpdev=CFbsBitmapDevice::NewL(monobmp);
	CleanupStack::PushL(monobmpdev);
	User::LeaveIfError(monobmpdev->CreateContext(gc));
	gc->BitBlt(TPoint(0,0),newbitmap);
	delete gc;
	CleanupStack::PopAndDestroy();
	User::LeaveIfError(monobmp->Save(aFilename));
	CleanupStack::PopAndDestroy(2);
	}

void CEikServKeyFilter::HandleExternalKeyEventL(const TKeyEvent& aKeyEvent ,TEventCode /*aType*/)
	//
	// Start the app which handles the external buttons
	//
	{
	if (iAppUi->iExternalKeyHandlerRunning)
		return;
	TInt code=aKeyEvent.iCode;
	if (code==EKeyDictaphonePlay || code==EKeyDictaphoneRecord)
		{
		iAppUi->EnsureExternalKeyHandlerAppStreamExistsL();
		// read the app name and doc name from system.ini file
		CApaCommandLine* cmdLine=CApaCommandLine::NewLC();
		CDictionaryStore* sysIniStore=CDictionaryFileStore::SystemLC(iEikonEnv->FsSession());
		TFileName name;
		RDictionaryReadStream stream;
		// app name
		stream.OpenLC(*sysIniStore, KUidExternalKeyHandlerAppStream);
		stream >> name;
		cmdLine->SetLibraryNameL(name);
		CleanupStack::PopAndDestroy();	// stream 
		cmdLine->SetCommandL(EApaCommandOpen);
		// doc name
		name.Zero(); // just in case
		stream.OpenLC(*sysIniStore, KUidDictaphoneFileStream);
		stream >> name;
		cmdLine->SetDocumentNameL(name);
		CleanupStack::PopAndDestroy(2);	// stream & sysIniStore
		iAppUi->iExternalKeyHandlerThreadId=EikDll::StartAppL(*cmdLine); 
		CleanupStack::PopAndDestroy(); // cmdLine
		iAppUi->iExternalKeyHandlerRunning=ETrue;
		}
	}


//
// CEikServAppUi
//

#if defined (__WINS__)
#define COMMS_PDD_NAME _L("ECDRV")
#define COMMS_LDD_NAME _L("ECOMM")
#else
#define COMMS_PDD_NAME _L("EUART1")
#define COMMS_LDD_NAME _L("ECOMM")
#endif

const TInt KMaxNumPartitionsPerDisk=4;	// !! should be declared somewhere in F32
const TInt KMaxNumPartitions=8;			// !! should be declared somewhere in F32

EXPORT_C CEikServAppUi* CEikServAppUi::NewLC()
    { 
	RWsSession& wsSession=CEikonEnv::Static()->WsSession();
	if (wsSession.FindWindowGroupIdentifier(0, __EIKON_SERVER_NAME, 0) > KErrNotFound)
		return NULL;	// already an Eikon server running
    CEikServAppUi* This=new(ELeave) CEikServAppUi;
	CleanupStack::PushL(This);
    This->ConstructL();
	return This;
    }

EXPORT_C void CEikServAppUi::NotifyAlarmServerOfTaskChange() const
	{
	iAlarmAlertServer->TaskKeyPressed();
	}

EXPORT_C void CEikServAppUi::LaunchTaskListL() const
	{
	__ASSERT_DEBUG(iTaskListDialog, Panic(EEikServPanicNoTaskListDialog));
	iTaskListDialog->RunTaskListL();
	}

EXPORT_C void CEikServAppUi::CycleTasks(TTaskCycleDirection aDirection) const
	{
	TApaTaskList taskList(iCoeEnv->WsSession());
	if (aDirection==EBackwards)
		{
		TApaTask task=taskList.FindByPos(-1);
		task.BringToForeground();
		}
	else
		{
		TApaTask task=taskList.FindByPos(0);
		task.SendToBackground();
		}
	NotifyAlarmServerOfTaskChange(); // !! will also task away from alarm when only 1 task. Correct?
	}

CEikServAppUi::CEikServAppUi()
	{
	}

void CEikServAppUi::ConstructL() 
    {
	RWindowGroup& groupWin=iCoeEnv->RootWin();
	RWsSession& wsSession=iCoeEnv->WsSession();
	iEikonEnv->SetAutoForwarding(ETrue);
	iEikonEnv->FsSession().SetNotifyUser(EFalse);
	CEikAppUi::BaseConstructL(ENonStandardResourceFile);
    TFileName fileName(_L("z:\\System\\Data\\eiksrv.rsc"));
	BaflUtils::NearestLanguageFile(iEikonEnv->FsSession(),fileName);
	iResourceFileOffset=iCoeEnv->AddResourceFileL(fileName);
	groupWin.SetName(__EIKON_SERVER_NAME);
	groupWin.EnableErrorMessages(EEventControlAlways);
	groupWin.EnableOnEvents(EEventControlAlways);

	wsSession.ComputeMode(RWsSession::EPriorityControlDisabled);
	RThread thread;
#if defined(__EPOC32__)
	thread.SetProcessPriority(EPriorityHigh);
#else
	thread.SetPriority(EPriorityMore);
#endif

	RFs& fsSession=iCoeEnv->FsSession();
	fsSession.MkDirAll(_L("C:\\System\\Apps\\")); // !! prevent app arch crash
//	SetDriveNames();

	// initialize some system settings
	wsSession.SetDoubleClick(KTimeBetweenClicks,KDoubleClickDistance);
	wsSession.SetKeyboardRepeatRate(KKeyboardRepeatInitialDelay,KKeyboardRepeatRate);
	SetSystemTime();
	TRAPD(ignored, EnsureExternalKeyHandlerAppStreamExistsL());
	groupWin.EnableOnEvents(EEventControlAlways);

	// capture some keys
	iScreenCaptureKey=groupWin.CaptureKey(CTRL('s'), EAllStdModifiers, EAllStdModifiers);
	iHelpKey=groupWin.CaptureKey(EKeyHelp, EAllStdModifiers, EModifierFunc);
/*
	iExternalKeys[0]=groupWin.CaptureKey(KExternalKey1, KExternalKeyModifierMask, KExternalKeyModifier);
	iExternalKeys[1]=groupWin.CaptureKey(KExternalKey2, KExternalKeyModifierMask, KExternalKeyModifier);
	iExternalKeys[2]=groupWin.CaptureKey(KExternalKey3, KExternalKeyModifierMask, KExternalKeyModifier);
*/

	// create a high priority key filter
	CEikServKeyFilter* filter=new(ELeave) CEikServKeyFilter();
	CleanupStack::PushL(filter);
	filter->ConstructL(*this);
	CleanupStack::Pop();

	TPasswordMode mode=EPasswordNone;
	TEikPasswordModeCategory pcategory;
	pcategory.PasswordMode(mode);
	if (Password::IsEnabled() && mode==EPasswordNone) // prevent overwriting once per day
		mode=EPasswordAlways;	 
	// initialise(write to the registry) here so that it won't fail in the future due to oom.	
	pcategory.SetPasswordMode(mode);   

	// create a window group for the password and alarm screens
	iAlertGroupWin=RWindowGroup(wsSession);
	User::LeaveIfError(iAlertGroupWin.Construct((TUint32)this)+1);
	iAlertGroupWin.SetOrdinalPosition(0, ECoeWinPriorityNeverAtFront);

	//password dialog
	iPasswordControl=new(ELeave) CEikPasswordControl(this);
	iPasswordControl->ConstructL();

	// create "sleeping dialog" for task list
	iTaskListDialog=new(ELeave) CEikTaskListDialog;
	iTaskListDialog->ConstructL(this);

	// create and start the notify, backup/restore and alarm/alert servers
	iAlarmAlertServer=CEikServAlarmAlertServer::NewL();
	iNotifyServer=CEikServNotifyServer::NewL();
	iBackupRestoreServer=CEikServBackupServer::NewL(wsSession);

	// load the sound drivers
	TInt err=User::LoadPhysicalDevice(_L("ESDRV.PDD"));
	if (!err)
		err=User::LoadLogicalDevice(_L("ESOUND.LDD"));
	if (err && err!=KErrAlreadyExists && err!=KErrNotFound) // third clause to aid porting to other platforms
		User::Leave(err);

	// Start Comms
	err=StartC32();
	if (err!=KErrNone && err!=KErrAlreadyExists)
		User::Leave(err);
	
	err=User::LoadPhysicalDevice(COMMS_PDD_NAME);
	if (err!=KErrNone && err!=KErrAlreadyExists)
		User::Leave(err);
	err=User::LoadLogicalDevice(COMMS_LDD_NAME);
	if (err!=KErrNone && err!=KErrAlreadyExists)
		User::Leave(err);

	StartupEALWL();	// start the Alarm server (client of the alarm/alert server!)
	
	// start the AppArc server
	
	StartupApaServer(*iEikonEnv); // iEikonEnv is for the MApaAppStarter interface

	// create high priority windows for app bar and side bar
	iOffScreenGroupWin=RWindowGroup(wsSession);
	User::LeaveIfError(iOffScreenGroupWin.Construct((TUint32)this));
	iOffScreenGroupWin.SetOrdinalPosition(0,ECoeWinPriorityHigh);
	iOffScreenGroupWin.EnableReceiptOfFocus(EFalse); // disable key events

	TMachineInfoV1Buf machineInfoBuf;
	UserHal::MachineInfo(machineInfoBuf);
	TPoint offsetToDisplay=machineInfoBuf().iOffsetToDisplayInPixels;
	TSize displaySize=machineInfoBuf().iDisplaySizeInPixels;
	TSize digitizerSize=machineInfoBuf().iXYInputSizeInPixels;
	iSidebarWindow=new(ELeave) CEikKeyWindow;
    iAppbarWindow=new(ELeave) CEikKeyWindow;
#if defined(__WINS__)
	iSidebarWindow->ConstructL(TPoint(-(KEikServSideBarWidth),0),TSize(KEikServSideBarWidth,displaySize.iHeight),0,KEikServGapBetweenScreenAndSideBar,EEikSidebarMenuKey,KNumOfSideButtons,CEikKeyWindow::EVertical,&iOffScreenGroupWin);
	iAppbarWindow->ConstructL(TPoint(-(KEikServSideBarWidth+20),displaySize.iHeight),TSize(displaySize.iWidth+KEikServSideBarWidth+20,KEikServAppbarHeight),KEikServGapBetweenScreenAndAppBar,0,EEikAppbarSystemKey,KNumOfAppButtons,CEikKeyWindow::EHorizontal,&iOffScreenGroupWin);
#else
	iSidebarWindow->ConstructL(-offsetToDisplay, TSize(offsetToDisplay.iX, displaySize.iHeight+offsetToDisplay.iY),0,KEikServGapBetweenScreenAndAppBar,EEikSidebarMenuKey,KNumOfSideButtons,CEikKeyWindow::EVertical,&iOffScreenGroupWin);
	iAppbarWindow->ConstructL(TPoint(-(offsetToDisplay.iX+KEikServAppBarLeftOffset), displaySize.iHeight), TSize(digitizerSize.iWidth+KEikServAppBarLeftOffset, digitizerSize.iHeight-displaySize.iHeight-offsetToDisplay.iY),KEikServGapBetweenScreenAndAppBar,0,EEikAppbarSystemKey,KNumOfAppButtons,CEikKeyWindow::EHorizontal,&iOffScreenGroupWin);
#endif

	// create undertaker active object
	iUndertaker=new(ELeave) CEikUndertaker(this);
	iUndertaker->ConstructL();

	// create an active object to restart servers
	iServerRestarter=CPeriodic::NewL(CActive::EPriorityStandard);

	// Make sure a password is displayed after a warm boot
	TEikPasswordModeCategory passCat;
	TPasswordMode passMode=EPasswordAlways;
	passCat.PasswordMode(passMode);
	if (passMode==EPasswordAlways)
		iPasswordControl->DrawableWindow()->PasswordWindow(EPasswordAlwaysTriggerNow);
	else if (passMode==EPasswordOnceADay)
		iPasswordControl->DrawableWindow()->PasswordWindow(EPasswordOnceADayTriggerNow);
	if (passMode>EPasswordNone)
		{
		TWsEvent event;
		event.SetTimeNow();
		event.SetType(EEventPassword);
		HandleWsEventL(event, NULL); // switch on event will follow
		}
	else
		HandleSwitchOnEventL(NULL);	// fake a switch on event to check battery status 
	}

	/*
	void CEikServAppUi::SetDriveNames()
	// 
	// Set the language dependant names for the drives
	//
	{
	RFs& fs=iEikonEnv->FsSession();
	TInt driveId;
	TBuf<32> driveName;
	// first do the internal drive
	TInt err=RFs::CharToDrive('c', driveId);
	if (!err)
		{
		iEikonEnv->ReadResource(driveName, R_EIKSRV_DRIVE_NAME_INTERNAL);
		fs.SetDriveName(driveId, driveName);
		}
	iEikonEnv->ReadResource(driveName, R_EIKSRV_DRIVE_NAME_EXTERNAL);
	// ask E32 for drive info (num partitions etc)
	TDriveInfoV1Buf driveInfoBuf;
	UserHal::DriveInfo(driveInfoBuf);
	TInt numSockets=driveInfoBuf().iTotalSockets;
	// now do external drive 
	TChar startDrive='d';
	TInt numExtDrives=Min(KMaxNumPartitionsPerDisk*(numSockets-1), KMaxNumPartitions);
	for (TInt i=0; i<numExtDrives; i++)
		{
		err=RFs::CharToDrive(startDrive, driveId);
		if (!err)
			fs.SetDriveName(driveId, driveName);
		startDrive+=1;
		}
	}
*/

void CEikServAppUi::HandleThreadExitL(RThread& aThread)
	{
	UpdateTaskListL();
	TThreadId id=aThread.Id();
	TExitType exitType=aThread.ExitType();
	if (id==iExternalKeyHandlerThreadId)
		iExternalKeyHandlerRunning=EFalse;
	else if (id==iHelpAppThreadId)
		iHelpAppRunning=EFalse;
	if (exitType==EExitPanic)
		{
		CEikServPanicScreen* panicScreen=new(ELeave) CEikServPanicScreen(aThread);
		panicScreen->ExecuteLD(R_EIKSERV_PANIC_DIALOG);
		}
	if (aThread.Name()==NameEalwlServerThread()) // alarm server died
		{
		aThread.Close(); // need to Close() before restarting with same name
		iServerToRestart|=EAlwlSvr; // restarted under active object
		}
	else if (aThread.Name()==NameApaServServerThread()) // AppArc server died
		{
		aThread.Close();
		iServerToRestart|=EApaSvr;
		}
	if (iServerToRestart && !iServerRestarter->IsActive())
		iServerRestarter->Start(KEikServServerRestartDelay,KEikServServerRestartInterval,TCallBack(RestartServerCallback,this));
	}

TInt CEikServAppUi::RestartServerCallback(TAny* aObj)
	{
	STATIC_CAST(CEikServAppUi*,aObj)->RestartServer();
	return KErrNone;
	}

void CEikServAppUi::RestartServer()
// Kick dead servers back to life, if we can connect then stop kicking
	{
	if (iServerToRestart&EAlwlSvr)
		{
		StartupEALWL();
		RAlarmServer als;
		TInt err=als.Connect();
		if (err==KErrNone)
			{
			als.Close();
			iServerToRestart&=(~EAlwlSvr);
			}
		}
	if (iServerToRestart&EApaSvr)
		{
		StartupApaServer(*iEikonEnv);
		// try to connect to the server
		RApaLsSession ls;
		TInt err=ls.Connect();
		if (err==KErrNone)
			{
			ls.Close();
			iServerToRestart&=(~EApaSvr);
			}
		}
	if (!iServerToRestart)
		{
		iServerRestarter->Cancel();
		}
	}

void CEikServAppUi::UpdateTaskListL()
	{
	__ASSERT_DEBUG(iTaskListDialog, Panic(EEikServPanicNoTaskListDialog));
	if (!(iTaskListDialog->IsVisible()))
		return;
	CEikServTaskListBox* listBox=iTaskListDialog->ListBox();
	TInt currentItem=listBox->CurrentItemIndex();
	iTaskListDialog->PrepareTaskArraysL(); // update the task list
	iTaskListDialog->SetArrayIntoListBox();
	TInt numTasks=iTaskListDialog->NumberOfListBoxItems();
	if (currentItem>numTasks-1)
		currentItem=numTasks-1;
	iTaskListDialog->SetCurrentItemIndex(currentItem);
	listBox->UpdateScrollBarsL();
	iTaskListDialog->ListBox()->DrawNow();
	}

void CEikServAppUi::HandleKeyEventL(const TKeyEvent& aKeyEvent,TEventCode /*aType*/)
	//
	// Exit
	//
	{
    if (aKeyEvent.iCode==CTRL('e'))
        CBaActiveScheduler::Exit();
	}

void CEikServAppUi::HandleWsEventL(const TWsEvent& aEvent,CCoeControl* aDestination)
	{
	switch (aEvent.Type())
		{
	case EEventPassword:	   //should disable the link
		{
		iPasswordControl->ShowPasswordScreen();	
		break;
		}
	case EEventErrorMessage:
		HandleErrorMessageEvent(*(aEvent.ErrorMessage()));
		break;
	default:
		CCoeAppUi::HandleWsEventL(aEvent,aDestination);
		}
	}

void CEikServAppUi::HandleErrorMessageEvent(const TWsErrorMessage& aErrorMessage)
	//
	// Handle an error message from the window server
	//
	{
	TUint err=aErrorMessage.iError;
	switch (aErrorMessage.iErrorCategory)
		{
	case TWsErrorMessage::EDrawingRegion:
		HandleOomEvent();
		break;
	case TWsErrorMessage::EBackLight:
		HandleBacklightError(err);
		break;
	case TWsErrorMessage::ELogging:
		HandleWservLoggingError(err);
		break;
	default:
		break; // intentionally ignored
		}
	}

void CEikServAppUi::HandleSwitchOnEventL(CCoeControl* /*aDestination*/)
	//
	// check the battery states and update any alarm snooze time
	//
	{
	iAlarmAlertServer->HandleSwitchOnEvent();
	if (iPasswordControl->IsVisible())
		return; // wait for password to be entered
    TSupplyInfoV1Buf sbuf;
    UserHal::SupplyInfo(sbuf);
    TSupplyInfoV1& supplyInfo=*(TSupplyInfoV1*)sbuf.Ptr();
	TInt resId=0;
	if (supplyInfo.iMainBatteryStatus<=EVeryLow)
		resId=R_EIKSERV_REPLACE_MAIN_BATTERIES;
	if (supplyInfo.iBackupBatteryStatus<=EVeryLow)
		{
		if (resId)
			resId=R_EIKSERV_REPLACE_BOTH_BATTERIES;
		else
			resId=R_EIKSERV_REPLACE_BACKUP_BATTERY;
		}
	if (resId)
		{
		TBuf<64> msg;
		iEikonEnv->ReadResource(msg, resId);
		iNotifyServer->DisplayInfoPrint(msg);
		}
	}

void CEikServAppUi::HandleSystemEventL(const TWsEvent& aEvent)
	{
	TInt event=*((TInt*)aEvent.EventData());
	switch (event)
		{
	case EEikServExit:
		CBaActiveScheduler::Exit();
		break;
	case EEikServChangePasswordMode:
		iPasswordControl->SetPasswordMode();
		break;
	case EEikServShowTaskList:
		LaunchTaskListL();
		break;
	default:
		break;
		}
	}

void CEikServAppUi::HandleApplicationSpecificEventL(TInt /*aType*/, const TWsEvent& /*aEvent*/)
	{
	// !! check command/number or whatever first
	NotifyAlarmServerOfTaskChange();
	}

CEikServAppUi::~CEikServAppUi()
	{
	RWindowGroup& groupWin=iEikonEnv->RootWin();
	groupWin.DisableErrorMessages();
	groupWin.DisableOnEvents();
	groupWin.CancelCaptureKey(iHelpKey);
	groupWin.CancelCaptureKey(iScreenCaptureKey);
	iOffScreenGroupWin.Close();
	iAlertGroupWin.Close();
	delete iAppbarWindow;
	delete iSidebarWindow;
	delete iTaskListDialog;
	delete iNotifyServer;
	delete iBackupRestoreServer;
	delete iAlarmAlertServer;
	delete iPasswordControl;
	delete iUndertaker;
	delete iServerRestarter;
    iCoeEnv->DeleteResourceFile(iResourceFileOffset);
	}

void CEikServAppUi::SetSystemTime() const
	{
	TTime time;
	time.HomeTime();
	TDateTime dateTime=time.DateTime();
	if (dateTime.Year() > 1980)
		return;	// assume time has already been set
	dateTime.Set(1997, EJanuary, 0, 10, 10, 0, 0); // 1st Jan 1997 10:10:00.0
	User::SetHomeTime(TTime(dateTime));
	}

void CEikServAppUi::EnsureExternalKeyHandlerAppStreamExistsL()
	//
	// checks to see if there is a designated external key handler app and if not defaults to RECORD.APP
	//
	{
	CDictionaryStore* sysIniStore=CDictionaryFileStore::SystemLC(iEikonEnv->FsSession());
	TBool commit=EFalse;
	if (!(sysIniStore->IsPresentL(KUidExternalKeyHandlerAppStream)))
		{
		// need to create default stream with RECORD.APP
		RDictionaryWriteStream stream;
		stream.AssignLC(*sysIniStore, KUidExternalKeyHandlerAppStream);
		stream << __EXTERNAL_KEY_HANDLER_APP_PATH; 
		stream.CommitL();
		CleanupStack::PopAndDestroy(); // stream 
		commit=ETrue;
		}
	if (!(sysIniStore->IsPresentL(KUidDictaphoneFileStream)))
		{
		// need to create default stream with location of default file
		RDictionaryWriteStream stream;
		stream.AssignLC(*sysIniStore, KUidDictaphoneFileStream);
		TFileName fileName;
		iEikonEnv->ReadResource(fileName, R_EIK_TBUF_DEFAULT_DICTAPHONE_FILE_PATH);
		stream << fileName; 
		stream.CommitL();
		CleanupStack::PopAndDestroy(); // stream 
		commit=ETrue;
		}
	if (commit)
		sysIniStore->CommitL();
	CleanupStack::PopAndDestroy(); // sysIniStore
	}

void CEikServAppUi::HandleOomEvent()
	//
	// Respond to an out of memory event from the window server
	//
	{
	TBuf<80> msg1;
	TBuf<80> msg2;
	iEikonEnv->ReadResource(msg1, R_EIKSRV_OOM_EVENT_TOP);
	iEikonEnv->ReadResource(msg2, R_EIKSRV_OOM_EVENT_BOT);
	CEikMover* title=iEikonEnv->Alert()->Title();
	CONST_CAST(CEikAlert*,iEikonEnv->Alert())->SetGloballyCapturing(ETrue);
	title->SetActive(EFalse);
	iEikonEnv->AlertWin(msg1, msg2);
	title->SetActive(ETrue);
	CONST_CAST(CEikAlert*,iEikonEnv->Alert())->SetGloballyCapturing(EFalse);
	}

void CEikServAppUi::HandleBacklightError(TInt aError)
	//
	// Respond to an error from the backlight (battery too low)
	//
	{
	if (aError==KErrNotSupported)
		return; // spec decided to do nothing here
	else if (aError!=KErrNone) // exact error code to be decided - treat all as low batteries for now
		{
		// need to use notifiers info msg window group since environment group win is in bg and 
		// if we bring to fg we don't know when info msg has finished to send it back again
		TBuf<80> msg;
		iEikonEnv->ReadResource(msg, R_EIKSRV_BACKLIGHT_BATTERY_LOW);
		iNotifyServer->DisplayInfoPrint(msg);
		}
	}

void CEikServAppUi::HandleWservLoggingError(TInt aError)
	//
	// Respond to a logging error from wserv (for use by developers)
	//
	{
	TBuf<80> temp;
	iEikonEnv->ReadResource(temp, R_EIKSRV_WSERV_LOGGING_ERROR);
	TBuf<80> msg;
	msg.Format(temp, aError);
	iEikonEnv->AlertWin(msg);
	}

void CEikServAppUi::BringAlertGroupWinForwards(TBool aForwards)
	//
	// Bring to foreground or send to background appropriately
	//
	{
	if (aForwards)
		{
		if (!iAlertGroupForwardsCount++)
    		iAlertGroupWin.SetOrdinalPosition(0,KMaxTInt); 
		}
	else if (--iAlertGroupForwardsCount==0)
   		iAlertGroupWin.SetOrdinalPosition(0,ECoeWinPriorityNeverAtFront); 
	}

//
// Main
//

GLDEF_C TInt E32Dll(TDllReason)
	{
	return(KErrNone);
	}
