graphicscomposition/surfaceupdate/tsrc/tsurfaceupdateinteg.cpp
changeset 0 5d03bc08d59c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graphicscomposition/surfaceupdate/tsrc/tsurfaceupdateinteg.cpp	Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,939 @@
+// 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()
+	{
+	}
+