graphicscomposition/surfaceupdate/tsrc/tsurfaceupdateinteg.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 16:31:06 +0300
branchRCL_3
changeset 163 bbf46f59e123
parent 0 5d03bc08d59c
permissions -rw-r--r--
Revision: 201029 Kit: 201035

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

#include <e32std.h>
#include <hal.h>
#include <u32hal.h>
#include <limits.h>
#include <e32const.h>
#include <graphics/surfaceupdateclient.h>
#include <graphics/suerror.h>
#include <graphics/wstestscreencapture.h>
#include <graphics/testscreencapture.h>
#include "surfaceupdatetest.h"
#include "tsurfaceupdateinteg.h"
#include "twindows.h"
#include "tredrawhandler.h"
#include "tsurfacehelper.h"

const TSize windowSize(160, 100);
const TSize windowHalfSize(windowSize.iWidth / 2, 100);
const TPoint windowTopLeft(10,10);
const TPoint windowTopMiddle(windowTopLeft.iX + windowSize.iWidth / 2, windowTopLeft.iY);


CTSurfaceUpdateInteg::CTSurfaceUpdateInteg(CTestStep* aStep) :
	CTGraphicsBase(aStep)
	{
	}

CTSurfaceUpdateInteg::~CTSurfaceUpdateInteg()
	{
	iWindows.ResetAndDestroy();
	iGroups.ResetAndDestroy();

	iWsDevs.ResetAndDestroy();
	iGcs.ResetAndDestroy();
	
	delete iRedrawHandler;
	iSurfaceUpdate.Close();
	delete iSurfaceHelper;
	iBitmaps.ResetAndDestroy();

	delete iGraphicsContext;
	delete iBitmapDevice;
	delete iRefBitmap;
	
	iWs.Close();
	}

/**
 * Create a screen device, drawing context and a window for each screen.
 * Create surfaces, open connection to the SUS.
 */
void CTSurfaceUpdateInteg::ConstructL()
	{
	INFO_PRINTF1(_L("Test case construction"));
	User::LeaveIfError(iWs.Connect());
	iNumOfScreens = iWs.NumberOfScreens();
	iSurfaceHelper = CSurfaceHelper::NewL();
	const TInt stride = windowSize.iWidth * 4;
	const TInt stride1 = windowHalfSize.iWidth * 4;
	iSurface = iSurfaceHelper->CreateSurfaceL(windowSize, EUidPixelFormatXRGB_8888, stride,1);
	iSurfaceDoubleBuffered = iSurfaceHelper->CreateSurfaceL(windowSize, EUidPixelFormatXRGB_8888, stride,2);
	iSurfaceAbove = iSurfaceHelper->CreateSurfaceL(windowHalfSize, EUidPixelFormatXRGB_8888, stride1, 1);
	iSurfaceAbove1 = iSurfaceHelper->CreateSurfaceL(windowSize, EUidPixelFormatXRGB_8888, stride, 1);
	INFO_PRINTF1(_L("The surfaces have been created"));

	iRefBitmap = new (ELeave)CFbsBitmap();
	User::LeaveIfError(iRefBitmap->Create(windowSize,EColor16MU));
	iBitmapDevice = CFbsBitmapDevice::NewL(iRefBitmap);
	User::LeaveIfError(iBitmapDevice->CreateContext(iGraphicsContext));

	//fill the whole surfaces with different color
	iSurfaceHelper->FillRectangleL(iSurfaceAbove, TPoint(), windowHalfSize, KRgbYellow);
	iSurfaceHelper->FillRectangleL(iSurfaceAbove1, TPoint(), windowSize, KRgbYellow);
	iSurfaceHelper->FillRectangleL(iSurface, TPoint(), windowSize, KRgbGreen);
	iSurfaceHelper->FillRectangleL(iSurfaceDoubleBuffered, TPoint(), windowSize, KRgbCyan);
	FillRefBitmap(KRgbGreen);
	INFO_PRINTF1(_L("The surfaces and a reference bitmap have been filled with color"));
	
	User::LeaveIfError(iSurfaceUpdate.Connect());
	
	iRedrawHandler = new (ELeave) CTRedrawHandler(iWs); //will deal with all redrawing command
	iRedrawHandler->Start();

	//create windows and assign surfaces to them
	for(TInt ii = 0; ii < 2; ii++)
		{
		CWsScreenDevice* wsDev = new (ELeave) CWsScreenDevice(iWs);
		iWsDevs.AppendL(wsDev);
		User::LeaveIfError(wsDev->Construct(ii));
		CWindowGc* gc = NULL;
		User::LeaveIfError(wsDev->CreateContext(gc));
		iGcs.AppendL(gc);

		CTWindowGroup* defaultGroup = CreateGroupL(wsDev);
		CTWindow* windowSingle = CTWindow::NewL(iWs, *defaultGroup, *gc);
		RegisterWindowL(windowSingle);
		windowSingle->Window()->SetExtent(windowTopLeft, windowSize);
		windowSingle->Window()->SetBackgroundSurface(iSurface);
		windowSingle->Window()->Activate();
		
		CTWindow* windowDouble = CTWindow::NewL(iWs, *defaultGroup, *gc);
		RegisterWindowL(windowDouble);
		windowDouble->Window()->SetExtent(windowTopLeft, windowSize);
		windowDouble->Window()->SetBackgroundSurface(iSurfaceDoubleBuffered);
		windowDouble->Window()->SetVisible(EFalse);
		windowDouble->Window()->Activate();

		CTWindow* windowAbove = CTWindow::NewL(iWs, *iGroups[ii], *iGcs[ii]);
		RegisterWindowL(windowAbove);
		windowAbove->Window()->SetExtent(windowTopLeft, windowHalfSize);
		windowAbove->Window()->SetBackgroundSurface(iSurfaceAbove);
		windowAbove->Window()->SetVisible(EFalse);
		windowAbove->Window()->Activate();
		if(ii == 0)
			{
			iWindowAbove11 = CTWindow::NewL(iWs, *iGroups[ii], *iGcs[ii]);
			RegisterWindowL(iWindowAbove11);
			iWindowAbove11->Window()->SetExtent(windowTopLeft, windowSize);
			iWindowAbove11->Window()->SetBackgroundSurface(iSurfaceAbove1);
			iWindowAbove11->Window()->SetVisible(EFalse);
			iWindowAbove11->Window()->Activate();

			iWindowAbove1 = windowAbove;
			iWindowSingleBuffured1 = windowSingle;
			iWindowDoubleBuffured1 = windowDouble;
			}
		else
			{
			iWindowAbove2 = windowAbove;
			iWindowSingleBuffured2 = windowSingle;
			iWindowDoubleBuffured2 = windowDouble;
			}

	    TPixelsTwipsAndRotation sizeAndRotation;
	    iWsDevs[ii]->GetDefaultScreenSizeAndRotation(sizeAndRotation);
	    CFbsBitmap* bitmap = new (ELeave)CFbsBitmap();
	    iBitmaps.AppendL(bitmap);
	    User::LeaveIfError(bitmap->Create(sizeAndRotation.iPixelSize, EColor16MU));
        INFO_PRINTF4(_L("Bitmap with size: %d, %d was created to match the size of the screen %d"), sizeAndRotation.iPixelSize.iWidth, sizeAndRotation.iPixelSize.iHeight, ii);
		}
	INFO_PRINTF1(_L("The windows have been created"));
	
	iWs.Finish();
	}

/**
 * Create the window group for the given screen device and put it into the list.
 */
CTWindowGroup* CTSurfaceUpdateInteg::CreateGroupL(CWsScreenDevice* aScreenDevice)
	{
	CTWindowGroup* group = CTWindowGroup::NewL(iWs, aScreenDevice);
	CleanupStack::PushL(group);
	iGroups.AppendL(group);
	CleanupStack::Pop();
	return group;
	}

/**
 * Append a window into the list for retrawing it and destroying in the future.
 */
void CTSurfaceUpdateInteg::RegisterWindowL(CTWindowTreeNode* aWindow)
	{
	CleanupStack::PushL(aWindow);
	iWindows.AppendL(aWindow);
	CleanupStack::Pop(aWindow);
	}

/**
 * Go through all screens and compare the whole surface area with the reference bitmap.
 * 
 * @return ETrue, if the surface is exactly the same as the reference bitmap or EFalse otherwise. 
 */
TBool CTSurfaceUpdateInteg::CompareAllScreens()
	{
	TBool res = ETrue;
	TRect rc(windowTopLeft, windowSize);
	for(TInt ii = 0; (ii < iNumOfScreens) && res; ii++)
		{
		res = Compare(ii, rc, iRefBitmap);
		}
	return res;
	}

/**
 * Compare part of the screen with the reference bitmap.
 * 
 * @param aScreenNumber Screen number.
 * @param aRectSrc The area of the screen to be compared.
 * @param aRefBitmap Bitmap for comparison.
 * @return ETrue, if given part of the screen is exactly the same as the reference bitmap or EFalse otherwise. 
 */
TBool CTSurfaceUpdateInteg::Compare(TInt aScreenNumber, const TRect& aRectSrc, CFbsBitmap* aRefBitmap)
	{
	MTestScreenCapture* csc = static_cast<MTestScreenCapture*> (iWsDevs[aScreenNumber]->GetInterface(MTestScreenCapture::KUidTestScreenCaptureIf));
	if(!csc) //shouldn't happen, as we have checked this before
		{
		return EFalse;
		}
	
	TBool res = ETrue;
	TInt ret = csc->ComposeScreen(*(iBitmaps[aScreenNumber]));
	if(ret != KErrNone)
		{
		INFO_PRINTF2(_L("Composition screen failure, err = %d"), ret);
		res = EFalse;
		}
	//Go through all pixels in screen bitmap for specified area and check that they are 
	//identical to corresponding pixels in reference bitmap
	for(TInt ii = 0; (ii < aRectSrc.Height()) && res; ii++)
		{
		for(TInt jj = 0; (jj < aRectSrc.Width()) && res; jj++)
			{
			TRgb refCol;
			aRefBitmap->GetPixel(refCol, TPoint(jj, ii));
			TRgb col;
			(iBitmaps[aScreenNumber])->GetPixel(col, TPoint(jj, ii) + aRectSrc.iTl);
			if(refCol != col)
				{
				res = EFalse;
				}
			}
		}
	//useful for debugging
#ifdef TEST_COMPARE_PARTLY_UPDATED_SCREEN 	
	if(!res)
		{
		iBitmap->Save(_L("c:\\bitmap.mbm"));
		aRefBitmap->Save(_L("c:\\ref.mbm"));
		}
#endif
	
	return res;
	}

/**
 * Fill reference bitmap with color specified.
 * 
 */
void CTSurfaceUpdateInteg::FillRefBitmap(TRgb aColor)
	{
	TRect rect = TRect(iRefBitmap->SizeInPixels());
	iGraphicsContext->SetBrushColor(aColor);
	iGraphicsContext->SetPenColor(aColor);
	iGraphicsContext->SetBrushStyle(CGraphicsContext::ESolidBrush);
	iGraphicsContext->DrawRect(rect);
	}

/**
  @SYMTestCaseID  GRAPHIC-SURFACEUPDATE-0026
  	
  @SYMCR CR1650

  @SYMREQ REQ11596

  @SYMTestCaseDesc 
  	SubmitUpdate() to cope with Global Updates with surface on various 
  	screens when the dirty region to update may not be visible on all screens

  @SYMTestPriority High

  @SYMTestStatus Implemented
	
  @SYMTestActions The test consists of a single surface, visible on 
  screens A (master), B.
	1.	Submit a global update for the surface, passing a null dirty region.
	2.	Submit a global update for the surface, passing a dirty region 
	that is only visible on screens A  (that particular region for the 
	surface is not visible on B).
	3.	Submit a global update for the surface, passing a dirty region 
	that is only visible on screens B (that particular region for the 
	surface is not visible on A).
	4.	Submit a global update for the surface, passing a dirty 
	region that is not visible on any of the screens.
  
  @SYMTestExpectedResults 
  	1.	TRequestStatus signals KErrNone in all cases. Timestamps must 
  	be valid. The surface gets updated on all screens.
	2.	TRequestStatus signals KErrNone in all cases. Timestamps must 
	be valid. The surface gets updated only on screens A. Screen B is unchanged.
	3.	TRequestStatus signals KErrNone in all cases. Timestamps must 
	be valid. The surface gets updated only on screens B. 
	Screen A is unchanged.
	4.	SubmitUpdate() returns KErrNone.
*/
void CTSurfaceUpdateInteg::TestCase1L()
	{
	INFO_PRINTF1(_L("Global Submit Update with/without update region supplied"));
	
	const TInt bufferNumber = 0; 
	TRequestStatus status = KRequestPending;
	TRequestStatus status1 = KRequestPending;
	TRequestStatus status2 = KRequestPending;
	TUint64 timestampComposition = 0;
	TTimeStamp timeStamp; 
	
	//Fill the surface to different colour, submit update for the whole surface 
	//and check that screen is updated correctly
	INFO_PRINTF1(_L("Fill the surface with the blue color"));
	iSurfaceHelper->FillRectangleL(iSurface, TPoint(), windowSize, KRgbBlue);
	FillRefBitmap(KRgbBlue);
	
	INFO_PRINTF1(_L("Updating the whole area of the surface"));
	TUint64 timestampBefore = User::FastCounter();
	iSurfaceUpdate.NotifyWhenAvailable(status);	
	iSurfaceUpdate.NotifyWhenDisplayed(status1, timeStamp);	
	iSurfaceUpdate.NotifyWhenDisplayedXTimes(10, status2);
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurface, bufferNumber);
	User::WaitForRequest(status);
	User::WaitForRequest(status1);
	User::WaitForRequest(status2);
	User::After(TTimeIntervalMicroSeconds32(100000)); //useful for visual checking

	TUint64 timestampAfter = User::FastCounter();
	if(timestampAfter < timestampBefore)
		{
		timestampAfter += UINT_MAX;
		}
	timestampComposition = timeStamp();
	if(timestampComposition < timestampBefore)
		{
		timestampComposition += UINT_MAX;
		}
	
	TEST(status == KErrNone);
	TEST(status1 == KErrNone);
	TEST(status2 == KErrNone);
	TEST(timestampComposition != 0);
	TEST(timestampAfter >= timestampComposition);
	TEST(timestampBefore <= timestampComposition);
	TEST(CompareAllScreens());

	//Fill the surface to different colour; hide the part of the surface on 
	//the screen which is not a master, submit update for the area of the surface 
	//which is only visible on the master. Check that only master screen gets updated.
	INFO_PRINTF1(_L("Hide the part of the surface on the second screen"));
	iWindowAbove1->Window()->SetVisible(EFalse);
	iWindowAbove2->Window()->SetVisible(ETrue);
	iWs.Finish();
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurface, bufferNumber);
	User::After(TTimeIntervalMicroSeconds32(100000)); //useful for visual checking
	
	INFO_PRINTF1(_L("Fill the surface with the green color"));
	iSurfaceHelper->FillRectangleL(iSurface, TPoint(), windowSize, KRgbGreen);
	
	TRect rc(windowHalfSize);
	rc.Shrink(10, 10);
	RRegion region(1, &rc); //this area is hidden if the window above is visible
	timestampBefore = User::FastCounter();
	iSurfaceUpdate.NotifyWhenAvailable(status);	
	iSurfaceUpdate.NotifyWhenDisplayed(status1, timeStamp);	
	iSurfaceUpdate.NotifyWhenDisplayedXTimes(10, status2);
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurface, bufferNumber, &region);
	User::WaitForRequest(status);
	User::WaitForRequest(status1);
	User::WaitForRequest(status2);
	User::After(TTimeIntervalMicroSeconds32(1000000)); //useful for visual checking

	timestampAfter = User::FastCounter();
	if(timestampAfter < timestampBefore)
		{
		timestampAfter += UINT_MAX;
		}
	timestampComposition = timeStamp();
	if(timestampComposition < timestampBefore)
		{
		timestampComposition += UINT_MAX;
		}
	
	TEST(status == KErrNone);
	TEST(status1 == KErrNone);
	TEST(status2 == KErrNone);
	TEST(timestampComposition != 0);
	TEST(timestampAfter >= timestampComposition);
	TEST(timestampBefore <= timestampComposition);
	User::After(TTimeIntervalMicroSeconds32(100000)); //useful for visual checking

	//first screen should be updated, as the surface is visible here
	TRect rectSrc = rc;
	rectSrc.Move(windowTopLeft);
	FillRefBitmap(KRgbGreen);
	TEST(Compare(0, rectSrc, iRefBitmap));
	//check that second screen doesn't update visible part of the surface 
	FillRefBitmap(KRgbYellow);
	TEST(Compare(1, rectSrc, iRefBitmap));

	//Fill the surface to different colour; hide the part of the surface 
	//on the master screen, submit update for the area of the surface 
	//which is only visible on non-master. Check that only non-master screen gets updated.
	INFO_PRINTF1(_L("Hide the part of the surface on the first screen"));
	iWindowAbove1->Window()->SetVisible(ETrue);
	iWindowAbove2->Window()->SetVisible(EFalse);
	iWs.Finish();
	User::After(TTimeIntervalMicroSeconds32(100000)); //useful for visual checking
	
	INFO_PRINTF1(_L("Fill the surface with the blue color"));
	iSurfaceHelper->FillRectangleL(iSurface, TPoint(), windowSize, KRgbBlue);
	
	timestampBefore = User::FastCounter();
	iSurfaceUpdate.NotifyWhenAvailable(status);	
	iSurfaceUpdate.NotifyWhenDisplayed(status1, timeStamp);	
	iSurfaceUpdate.NotifyWhenDisplayedXTimes(10, status2);
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurface, bufferNumber, &region);
	User::WaitForRequest(status);
	User::WaitForRequest(status1);
	User::WaitForRequest(status2);
	User::After(TTimeIntervalMicroSeconds32(1000000)); //useful for visual checking

	timestampAfter = User::FastCounter();
	if(timestampAfter < timestampBefore)
		{
		timestampAfter += UINT_MAX;
		}
	timestampComposition = timeStamp();
	if(timestampComposition < timestampBefore)
		{
		timestampComposition += UINT_MAX;
		}
	
	TEST(status == KErrNone);
	TEST(status1 == KErrNone);
	TEST(status2 == KErrNone);
	TEST(timestampComposition != 0);
	TEST(timestampAfter >= timestampComposition);
	TEST(timestampBefore <= timestampComposition);

	//check that first screen doesn't update visible part of the surface 
	FillRefBitmap(KRgbYellow);
	TEST(Compare(0, rectSrc, iRefBitmap));
	//second screen should be updated, as the surface is visible here
	FillRefBitmap(KRgbBlue);
	TEST(Compare(1, rectSrc, iRefBitmap));
	
	//Fill the surface to different colour; hide the part of the surface on the master screen, 
	//submit update for the area of the surface which is not visible on any screen. 
	//Check that all screens have not been updated.
	INFO_PRINTF1(_L("Hide partly the surface on two screens"));
	iWindowAbove1->Window()->SetVisible(ETrue);
	iWindowAbove2->Window()->SetVisible(ETrue);
	iWs.Finish();
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurface, bufferNumber);
	User::After(TTimeIntervalMicroSeconds32(1000000)); //useful for visual checking
	
	INFO_PRINTF1(_L("Fill the surface with the green color"));
	iSurfaceHelper->FillRectangleL(iSurface, TPoint(), windowSize, KRgbGreen);
	FillRefBitmap(KRgbGreen);
	
	timestampBefore = User::FastCounter();
	iSurfaceUpdate.NotifyWhenAvailable(status);	
	iSurfaceUpdate.NotifyWhenDisplayed(status1, timeStamp);	
	iSurfaceUpdate.NotifyWhenDisplayedXTimes(10, status2);
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurface, bufferNumber, &region);
	User::WaitForRequest(status);
	User::WaitForRequest(status1);
	User::WaitForRequest(status2);
	User::After(TTimeIntervalMicroSeconds32(1000000)); //useful for visual checking

	timestampAfter = User::FastCounter();
	if(timestampAfter < timestampBefore)
		{
		timestampAfter += UINT_MAX;
		}
	timestampComposition = timeStamp();
	if(timestampComposition < timestampBefore)
		{
		timestampComposition += UINT_MAX;
		}
	
	TEST(status == KErrNone);
	TEST(status1 == KErrNone);
	TEST(status2 == KErrNone);
	TEST(timestampComposition != 0);
	TEST(timestampAfter >= timestampComposition);
	TEST(timestampBefore <= timestampComposition);
	User::After(TTimeIntervalMicroSeconds32(100000)); //useful for visual checking
	
	//both first and second screen shouldn't be updated, as the surface is not visible here
	FillRefBitmap(KRgbYellow);
	TEST(Compare(0, rectSrc, iRefBitmap));
	TEST(Compare(1, rectSrc, iRefBitmap));

	INFO_PRINTF1(_L("Return to the initial state"));
	iWindowAbove1->Window()->SetVisible(EFalse);
	iWindowAbove2->Window()->SetVisible(EFalse);
	iWs.Finish();
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurface, bufferNumber);
	User::After(TTimeIntervalMicroSeconds32(1000000)); //useful for visual checking
	
	FillRefBitmap(KRgbGreen);
	TEST(CompareAllScreens());
	}

/**
  @SYMTestCaseID GRAPHIC-SURFACEUPDATE-0031

  @SYMCR CR1650

  @SYMREQ REQ11598

  @SYMTestCaseDesc NotifyWhenAvailable() to deal with global updates and be signalled 
 	correctly when screen is unplugged.
 	
  @SYMTestPriority 	High

  @SYMTestStatus Implemented
	
  @SYMTestActions 
 	The test consists of a double-buffered surface, visible on screens A 
 	(master) and B,
	1	Make global submit update with notify when available for the buffer 1.
	2	Unplug screen A (notification is still in a progress )
	3	Make global submit update with notify when available for the 
	buffer 2 to trigger notification.
	4	Make global submit update with notify when available for the 
	buffer 1.
	5	Plug in screen A. (notification is still in a progress )
	6	Make global submit update with notify when available for 
	the buffer 2.
  
  @SYMTestExpectedResults 
  	After step 3, notification is received with KErrNone (this is 
  	triggered by the Receiver for screen B).
	After step 6, notification is received with KErrNone (this is 
	triggered by the Receiver for screen A).
*/
void CTSurfaceUpdateInteg::TestCase2L()
	{
	INFO_PRINTF1(_L("Exercising NotifyWhenAvailable while some screens are disconnected."));

	//hide single-buffered surface and show a double buffered-surface
	iWindowSingleBuffured1->Window()->SetVisible(EFalse);
	iWindowSingleBuffured2->Window()->SetVisible(EFalse);
	iWindowDoubleBuffured1->Window()->SetVisible(ETrue);
	iWindowDoubleBuffured2->Window()->SetVisible(ETrue);
	iWs.Finish();
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurface, 0);
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurfaceDoubleBuffered, 0);
	FillRefBitmap(KRgbCyan);
	TEST(CompareAllScreens());
	User::After(TTimeIntervalMicroSeconds32(100000)); //useful for visual checking
	
	INFO_PRINTF1(_L("Fill the surface with the blue color"));
	iSurfaceHelper->FillRectangleL(iSurfaceDoubleBuffered, TPoint(), windowSize, KRgbBlue);
	
	INFO_PRINTF1(_L("Disconnect the screen while notify when available request is still in a progress")); 
	TRequestStatus status;
	TSwitchDisplayAndReleaseBuffer param;
	param.iBuffer = 0;
	param.iScreen = 0;
	param.iSurfaceId=iSurfaceDoubleBuffered;
	CCommandDispatcher commandDispatcher(CCommandDispatcher::EDisconnectDisplayAndReleaseBuffer, &param);
	
	//Command dispatcher will be running in the separate thread. 
	//The requirement for this caused by the fact that for dubble-buffered surfaces 
	//the content update receiver will postpone completion of the request for availability until 
	//client sends SubmitUpdate for another buffer. 
	iSurfaceUpdate.NotifyWhenAvailable(status);	
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurfaceDoubleBuffered, 1);
	TInt res = commandDispatcher.Start();  //kickoff another thread, which SubmitUpdate 
											//for buffer 1 and disconnects the first screen
	TEST(res == KErrNone);
	User::WaitForRequest(status);//At that point we are blocked until command dispatcher sends SubmitUpdate for the buffer number 1
	TEST(status == KErrNone);
	
	//connect the screen
	INFO_PRINTF1(_L("Connect the screen while notify when available request is still in a progress")); 
	CCommandDispatcher commandDispatcher1(CCommandDispatcher::EConnectDisplayAndReleaseBuffer, &param);
	iSurfaceUpdate.NotifyWhenAvailable(status);	
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurfaceDoubleBuffered, 0);
	res = commandDispatcher.Start();//kickoff another thread, which SubmitUpdate 
										//for buffer 1 and connects the first screen

	TEST(res == KErrNone);
	User::WaitForRequest(status);
	TEST(status == KErrNone);

	//restore the original state
	iWindowSingleBuffured1->Window()->SetVisible(ETrue);
	iWindowSingleBuffured2->Window()->SetVisible(ETrue);
	iWindowDoubleBuffured1->Window()->SetVisible(EFalse);
	iWindowDoubleBuffured2->Window()->SetVisible(EFalse);
	iWs.Finish();
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurface, 0);
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurfaceDoubleBuffered, 0);
	FillRefBitmap(KRgbGreen);
	TEST(CompareAllScreens());
	}

/**
  @SYMTestCaseID GRAPHIC-SURFACEUPDATE-0032
  	
  @SYMCR CR1650

  @SYMREQ REQ11599, REQ11600, REQ11601

  @SYMTestCaseDesc NotifyWhenDisplayedXTimes() to deal with global 
  updates and be signalled correctly when screen is unplugged.
	
  @SYMTestPriority 	High

  @SYMTestStatus Implemented
	
  @SYMTestActions 
  	The test consists of a single-buffered surface, S1, visible on 
  	screens A (master) and B.

	Screens are ordered in the following priority: A > B
		1	Make global submit update for surface S1 with notify 
		when notify when displayed X times. X should be approximately 10 
		seconds.
		2	Unplug screen A while display XTimes is still in progress.
		3	After receiving notification, plug in screen A
		4	Make global submit update with notify when displayed X times. 
		X should be approximately 10 seconds.
		5	Make global submit update for surface S1, with notify when 
		displayed X times. X should be approximately 10 seconds.
		6	Unplug screen B while display XTimes is still in progress.
        7   Make global submit update for surface S1, with notify when 
        displayed X times. X should be approximately 10 seconds.		
		8	Unplug screen A as well whilst display XTimes is still in progress.
		9   Reconnect both screens
  	
  @SYMTestExpectedResults
  	After the 10 seconds have elapsed from step 1, notification is 
  	received (step 3) with KErrNone (this is triggered by the Receiver 
  	for screen B).
	After 10 seconds have elapsed from step 4, notification is received 
	with KErrNone (this is triggered by the Receiver for screen A).
	After step 8 (which must occur before 10 seconds) notification will 
	be received with KErrNotVisible (ie. The surface is not visible on 
	any screen).
*/
void CTSurfaceUpdateInteg::TestCase3()
	{
	INFO_PRINTF1(_L("Exercising NotifyWhenDisplayedXTimes while some screen is disconnected."));

	TRequestStatus status;
	TInt count = 100 * 2; 
	iSurfaceUpdate.NotifyWhenDisplayedXTimes(count, status);	
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurface, 0);
	
	INFO_PRINTF1(_L("Disconnect the screen when notification when displayed X times request is still in a progress")); 
	TInt displayState = EDisconnect;
	TInt disconnectedScreenNo = 0;
	TInt res = UserSvr::HalFunction(EHalGroupDisplay | (disconnectedScreenNo<<16), EDisplayHalSetDisplayState, &displayState, NULL);
	TEST(res == KErrNone);
	User::WaitForRequest(status); //The content update receiver will complete notification when “count” number of display refreshes has occurred.  
									//We are not blocked here indefinitely, so there is no point to use a command dispatcher
	TEST(status == KErrNone);

	//restore the first screen 
	INFO_PRINTF1(_L("Connect the screen when notification when displayed X times request is still in a progress")); 
	displayState = ENormalResolution;
	res = UserSvr::HalFunction(EHalGroupDisplay | (disconnectedScreenNo<<16), EDisplayHalSetDisplayState, &displayState, NULL);
	TEST(res == KErrNone);

	iSurfaceUpdate.NotifyWhenDisplayedXTimes(count, status);	
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurface, 0);
	User::WaitForRequest(status);
	TEST(status == KErrNone);
	
	// Make sure other surface is not visible
	iWindowAbove11->Window()->SetVisible(EFalse);
	iWs.Finish();
	User::After(TTimeIntervalMicroSeconds32(100000)); //useful for visual checking
	
	// above1 surface should not be visible because window is not visible
	TTimeStamp timeStamp; 
	iSurfaceUpdate.NotifyWhenDisplayed(status, timeStamp);	
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurfaceAbove1, 0);
	User::WaitForRequest(status);
	TEST(status == KErrNotVisible);
	
	//disconnect the secondary screen - surface still visible on primary
	INFO_PRINTF1(_L("Disconnect the secondary screen - surface still visible on primary")); 
	displayState = EDisconnect;
	disconnectedScreenNo = 1;
	iSurfaceUpdate.NotifyWhenDisplayedXTimes(count, status);	
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurface, 0);
	
	res = UserSvr::HalFunction(EHalGroupDisplay | (disconnectedScreenNo<<16), EDisplayHalSetDisplayState, &displayState, NULL);
	TEST(res == KErrNone);
	User::WaitForRequest(status);
	TEST(status == KErrNone);
	User::After(TTimeIntervalMicroSeconds32(100000)); //useful for visual checking

   //disconnect the primary screen - surface now not visible on any screen
    INFO_PRINTF1(_L("Disconnect the primary screen - surface not visible on any screen")); 
    displayState = EDisconnect;
    disconnectedScreenNo = 0;
    iSurfaceUpdate.NotifyWhenDisplayedXTimes(count, status);    
    iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurface, 0);
    
    res = UserSvr::HalFunction(EHalGroupDisplay | (disconnectedScreenNo<<16), EDisplayHalSetDisplayState, &displayState, NULL);
    TEST(res == KErrNone);
    User::WaitForRequest(status);
    TEST(status == KErrNotVisible); // not visible raised if primary is disconnected
    User::After(TTimeIntervalMicroSeconds32(100000)); //useful for visual checking
        

    //restore initial state 
    disconnectedScreenNo = 0;
    displayState = ENormalResolution;
    res = UserSvr::HalFunction(EHalGroupDisplay | (disconnectedScreenNo<<16), EDisplayHalSetDisplayState, &displayState, NULL);
    TEST(res == KErrNone);
    disconnectedScreenNo = 1;
    res = UserSvr::HalFunction(EHalGroupDisplay | (disconnectedScreenNo<<16), EDisplayHalSetDisplayState, &displayState, NULL);
    TEST(res == KErrNone);

    
	iWs.Finish();	
	iSurfaceUpdate.SubmitUpdate(KAllScreens, iSurface, 0);
	User::After(TTimeIntervalMicroSeconds32(100000)); //useful for visual checking
	TEST(CompareAllScreens());
	}

void CTSurfaceUpdateInteg::RunTestCaseL(TInt aCurTestCase)
	{
	((CTSurfaceUpdateIntegStep*)iStep)->SetTestStepID(KUnknownSYMTestCaseIDName);
	switch(aCurTestCase)
		{
	case 1:
		{
		
		if((static_cast <CTSurfaceUpdateIntegStep*> (iStep)) -> IsScreenCaptureSupported()  && (iNumOfScreens > 1))
			{
			((CTSurfaceUpdateIntegStep*)iStep)->SetTestStepID(_L("GRAPHIC-SURFACEUPDATE-0026"));
			INFO_PRINTF1(_L("TestCase1"));
			TestCase1L();
			}
		else
			{
			((CTSurfaceUpdateIntegStep*)iStep)->SetTestStepID(KNotATestSYMTestCaseIDName);
			INFO_PRINTF3(_L("The test will be skipped as the environment is not ready: Number of screen : %d, Is screen capture supported: %d"), 
					iNumOfScreens, (static_cast <CTSurfaceUpdateIntegStep*> (iStep)) -> IsScreenCaptureSupported());
			TestComplete();		
			}	
		break;
		}
#ifdef __WINS__
	case 2:
		{
		((CTSurfaceUpdateIntegStep*)iStep)->SetTestStepID(_L("GRAPHIC-SURFACEUPDATE-0031"));
		INFO_PRINTF1(_L("TestCase2"));
		TestCase2L();
		break;
		}
	case 3:
		{
		((CTSurfaceUpdateIntegStep*)iStep)->SetTestStepID(_L("GRAPHIC-SURFACEUPDATE-0032"));
		INFO_PRINTF1(_L("TestCase3"));
		TestCase3();
		break;
		}
#endif		
	default:
		((CTSurfaceUpdateIntegStep*)iStep)->SetTestStepID(KNotATestSYMTestCaseIDName);
		((CTSurfaceUpdateIntegStep*)iStep)->CloseTMSGraphicsStep();
		TestComplete();		
		break;
		}
	((CTSurfaceUpdateIntegStep*)iStep)->RecordTestResultL();
	}
//--------------
_LIT(KCommandDispatcher, "CommandDispatcher");
const TUint KDefaultHeapSize=0x10000;

/**
 * Launch the command thread.
 */
TInt CCommandDispatcher::Start()
	{
	RThread commandThread;
	TInt res = KErrGeneral;
	TBuf<64> commandThreadName;
	TBuf<64> commandThreaMask;
	
	// Guarantee uniqueness of thread name by using timestamp
	TTime tm;
	TBuf<32> timeStamp;
	tm.UniversalTime();
	TRAP(res, tm.FormatL(timeStamp, _L("_%H%T%S%C")));
	if(res != KErrNone)
		{
		return res;
		}

	commandThreadName.Append(KCommandDispatcher);
	commandThreadName.Append(timeStamp);
	commandThreaMask = commandThreadName;
	commandThreaMask.Insert(0, _L("*"));
	TFindThread findThread(commandThreaMask);
	TFullName name;
	  // Need to check that the thread exists.
	if (findThread.Next(name)!=KErrNone)
		{
		  // Create the thread for the server.
		res = commandThread.Create(commandThreadName,
			CCommandDispatcher::ThreadFunction,
			KDefaultStackSize,
			KDefaultHeapSize,
			KDefaultHeapSize,
			this
			);
			
          // The thread has been created OK so get it started - however
          // we need to make sure that it has started before we continue.
		if (res==KErrNone)
			{
			TRequestStatus rendezvousStatus;
			commandThread.SetPriority(EPriorityNormal);
			commandThread.Rendezvous(rendezvousStatus);
			commandThread.Resume();
			}
		}
	commandThread.Close();
	return res;
	}

TInt CCommandDispatcher::ThreadFunction(TAny* aAny)
	{
	  // get clean-up stack
	CTrapCleanup* cleanup=CTrapCleanup::New();
	CCommandDispatcher* commandDispatcher = (CCommandDispatcher*) aAny;
	TRAPD(res, commandDispatcher->ExecuteCommandL());
	delete cleanup; 
	return res;
	}

/**
 * Run commands in a thread different to the thread where the instance 
 * of the class was initialized.
 */
void CCommandDispatcher::ExecuteCommandL()
	{
	switch(iCommandName)
		{
	case EDisconnectDisplayAndReleaseBuffer:
		{
		RSurfaceUpdateSession surfaceUpdate;
		User::LeaveIfError(surfaceUpdate.Connect());
		CleanupClosePushL(surfaceUpdate);
		TSwitchDisplayAndReleaseBuffer* param = static_cast<TSwitchDisplayAndReleaseBuffer*>(iParam); 
		if(!param)
			{
			User::Leave(KErrArgument);
			}
		TInt displayState = EDisconnect;
		TInt screenNumber = param->iScreen;
		TInt bufferNumber = param->iBuffer;
		User::LeaveIfError(UserSvr::HalFunction(EHalGroupDisplay | (screenNumber<<16), EDisplayHalSetDisplayState, &displayState, NULL));
		//Submit Update to unblock the main client thread 
		User::LeaveIfError(surfaceUpdate.SubmitUpdate(KAllScreens, param->iSurfaceId, bufferNumber));
		CleanupStack::PopAndDestroy(&surfaceUpdate);
		break;
		}
	case EConnectDisplayAndReleaseBuffer:
		{
		RSurfaceUpdateSession surfaceUpdate;
		User::LeaveIfError(surfaceUpdate.Connect());
		CleanupClosePushL(surfaceUpdate);
		TSwitchDisplayAndReleaseBuffer* param = static_cast<TSwitchDisplayAndReleaseBuffer*>(iParam); 
		if(!param)
			{
			User::Leave(KErrArgument);
			}
		TInt displayState = ENormalResolution;
		TInt screenNumber = param->iScreen;
		TInt bufferNumber = param->iBuffer;
		User::LeaveIfError(UserSvr::HalFunction(EHalGroupDisplay | (screenNumber<<16), EDisplayHalSetDisplayState, &displayState, NULL));
		//Submit Update to unblock the main client thread 
		User::LeaveIfError(surfaceUpdate.SubmitUpdate(KAllScreens, param->iSurfaceId, bufferNumber));
		CleanupStack::PopAndDestroy(&surfaceUpdate);
		break;
		}
	default:
		User::Leave(KErrNotSupported);
		break;
		}
	}

//--------------
__CONSTRUCT_STEP__(SurfaceUpdateInteg)

/**
 * Retrieve screen capturing plug-in, if succeed set a flag.
 */
void CTSurfaceUpdateIntegStep::TestSetupL()
	{
//	check if the screen capture plug-in presents in the system
	RWsSession ws;
	User::LeaveIfError(ws.Connect());
	CleanupClosePushL(ws);

	TInt numOfScreens = ws.NumberOfScreens();
	if(numOfScreens < 2)
		{
		ERR_PRINTF2(_L("Environment is not ready, the number of the screens in the system for this test should be 2 or more, the current number is: %d"), numOfScreens);
		User::Leave(KErrNotReady);
		}
	
	CWsScreenDevice* wsDev = new (ELeave) CWsScreenDevice(ws);
	CleanupStack::PushL(wsDev);
	User::LeaveIfError(wsDev->Construct(0));
	TDisplayMode dispMode = wsDev->DisplayMode();
	INFO_PRINTF2(_L("Screen device display mode is: %d."), dispMode);
	
	MTestScreenCapture* csc = static_cast<MTestScreenCapture*> (wsDev->GetInterface(MTestScreenCapture::KUidTestScreenCaptureIf));
	if(csc)
		{
		INFO_PRINTF1(_L("Screen capture plug-in presents in the system."));
		iScreenCapture = ETrue;
		}
	else
		{
		INFO_PRINTF1(_L("Screen capture plug-in is not installed in the system, to make automated checking screen capture rendering stage is required, \
see graphics\\wserv_std_plugins\\screencapture"));
		}
	
	CleanupStack::PopAndDestroy(2, &ws); //ws, wsDev
	}
	
void CTSurfaceUpdateIntegStep::TestClose()
	{
	}