sl@0: // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: @test sl@0: @internalComponent - Internal Symbian test code sl@0: */ sl@0: sl@0: #include sl@0: #include "tcompositionbackend.h" sl@0: #include sl@0: sl@0: const TInt KNotificationsAtTime = 10; //how many notifications could be processed at a time, varies from 1... sl@0: sl@0: CTContentUpdateReceiver::CTContentUpdateReceiver(TInt aScreen) : sl@0: iScreen(aScreen), iVisible(ETrue) sl@0: { sl@0: RThread thread; sl@0: iReceiverThreadId = thread.Id(); sl@0: } sl@0: sl@0: CTContentUpdateReceiver::~CTContentUpdateReceiver() sl@0: { sl@0: if(iPeriodic) sl@0: iPeriodic->Cancel(); sl@0: delete iPeriodic; sl@0: iLock.Close(); sl@0: iPriorityLock.Close(); sl@0: } sl@0: sl@0: void CTContentUpdateReceiver::ConstructL() sl@0: { sl@0: TCallBack callback(CallBack); sl@0: callback.iPtr = this; sl@0: User::LeaveIfError(iLock.CreateLocal()); sl@0: User::LeaveIfError(iPriorityLock.CreateLocal(0)); sl@0: iPeriodic= CPeriodic::NewL(CPeriodic::EPriorityStandard); sl@0: iPeriodic->Start(TTimeIntervalMicroSeconds32(0),TTimeIntervalMicroSeconds32(KCompositionInterval), callback); sl@0: } sl@0: sl@0: CTContentUpdateReceiver* CTContentUpdateReceiver::NewL(TInt aScreen) sl@0: { sl@0: CTContentUpdateReceiver* receiver = new (ELeave) CTContentUpdateReceiver(aScreen); sl@0: CleanupStack::PushL(receiver); sl@0: receiver->ConstructL(); sl@0: CleanupStack::Pop(); sl@0: return receiver; sl@0: } sl@0: sl@0: TInt CTContentUpdateReceiver::Extension_(TUint aExtensionId, TAny*& aRetIface, TAny* a1) sl@0: { sl@0: switch (aExtensionId) sl@0: { sl@0: case MCompositionSurfaceUpdate::ETypeId: sl@0: aRetIface= static_cast(this); sl@0: return KErrNone; sl@0: sl@0: default: ; sl@0: } sl@0: return CExtensionContainer::Extension_(aExtensionId,aRetIface,a1); sl@0: } sl@0: sl@0: TInt CTContentUpdateReceiver::CallBack(TAny *aAny) sl@0: { sl@0: return (static_cast (aAny))->CheckNewNotifications(); sl@0: } sl@0: sl@0: void CTContentUpdateReceiver::Stop() sl@0: { sl@0: iLock.Wait(); sl@0: iStop = ETrue; sl@0: iLock.Signal(); sl@0: } sl@0: sl@0: EXPORT_C void CTContentUpdateReceiver::SetVisible(TBool aVisible) sl@0: { sl@0: iLock.Wait(); sl@0: iVisible = aVisible; sl@0: iLock.Signal(); sl@0: } sl@0: sl@0: TInt CTContentUpdateReceiver::CheckNewNotifications() sl@0: { sl@0: iLock.Wait(); sl@0: if(iStop && (iNumberElements <= 0)) sl@0: { sl@0: iLock.Signal(); sl@0: CActiveScheduler::Stop(); sl@0: return 0;//the return value is irrelevant for CPeriodic function sl@0: } sl@0: if(iSetInternalPriority) sl@0: { sl@0: TRAPD(res, DoSetInternalPriorityL()); sl@0: iLock.Signal(); sl@0: __ASSERT_ALWAYS(res ==KErrNone, User::Panic(_L("CheckNewNotifications"), KErrGeneral)); sl@0: return 0;//the return value is irrelevant for CPeriodic function sl@0: } sl@0: TInt index = 0; sl@0: RThread thread; sl@0: TInt res = thread.Open(iThreadId); sl@0: __ASSERT_ALWAYS(res ==KErrNone, User::Panic(_L("CheckNewNotifications"), KErrGeneral)); sl@0: sl@0: //we will check only one limited amount of requests at the time sl@0: for(TInt iteration = 0; (iNumberElements > index) && (iteration < KNotificationsAtTime); iteration++) sl@0: { sl@0: if(iArray[index].iType == EReqDisplayed) sl@0: { sl@0: *(iArray[index].iTimeStamp) = User::FastCounter(); sl@0: if(iCompositionOrder) sl@0: { sl@0: iCompositionOrder->SetOrder(EOrderComposition); sl@0: } sl@0: } sl@0: else if(iArray[index].iType == EReqDisplayedXTimes) sl@0: { sl@0: iArray[index].iDisplayedXTimes--; sl@0: if(iArray[index].iDisplayedXTimes > 0) sl@0: { sl@0: index++; sl@0: continue; sl@0: } sl@0: } sl@0: TRequestStatus* status = iArray[index].iStatus; sl@0: res = iVisible ? KErrNone : KErrNotVisible; sl@0: Remove(index); sl@0: thread.RequestComplete(status, res); sl@0: } sl@0: thread.Close(); sl@0: iLock.Signal(); sl@0: return 0;//the return value is irrelevant for CPeriodic function sl@0: } sl@0: sl@0: void CTContentUpdateReceiver::DoSetInternalPriorityL() sl@0: { sl@0: RThread thread; sl@0: User::LeaveIfError(thread.Open(iReceiverThreadId)); sl@0: thread.SetPriority(iInternalPriority); sl@0: thread.Close(); sl@0: TInt compositionInterval = KCompositionInterval; sl@0: CPeriodic::TPriority priority = CPeriodic::EPriorityStandard; sl@0: if(iInternalPriority < EPriorityNormal) sl@0: { sl@0: priority = CPeriodic::EPriorityIdle; sl@0: compositionInterval = KCompositionIntervalLong; sl@0: } sl@0: else if (iInternalPriority > EPriorityNormal) sl@0: { sl@0: priority = CPeriodic::EPriorityHigh; sl@0: compositionInterval = KCompositionIntervalShort; sl@0: } sl@0: sl@0: TCallBack callback(CallBack); sl@0: callback.iPtr = this; sl@0: iPeriodic->Cancel(); sl@0: delete iPeriodic; sl@0: iPeriodic= CPeriodic::NewL(priority); sl@0: iPeriodic->Start(TTimeIntervalMicroSeconds32(compositionInterval),TTimeIntervalMicroSeconds32(compositionInterval), callback); sl@0: iSetInternalPriority = EFalse; sl@0: iPriorityLock.Signal(); sl@0: } sl@0: sl@0: EXPORT_C TInt CTContentUpdateReceiver::SetInternalPriority(TThreadPriority aInternalPriority) sl@0: { sl@0: iLock.Wait(); sl@0: iInternalPriority = aInternalPriority; sl@0: iSetInternalPriority = ETrue; sl@0: iLock.Signal(); sl@0: sl@0: //wait for the priority changes takes place sl@0: iPriorityLock.Wait(); sl@0: return KErrNone; sl@0: } sl@0: sl@0: void CTContentUpdateReceiver::ContentUpdated(const TSurfaceId& aId, sl@0: TInt aBuffer, sl@0: const TRegion* aRegion, sl@0: TRequestStatus* aStatusAvailable, sl@0: TRequestStatus* aStatusDisplayed, TUint32* aTimeStamp, sl@0: TRequestStatus* aStatusDisplayedXTimes, TInt* aDisplayedXTimes) sl@0: { sl@0: (TAny)&aId; sl@0: (TAny)aBuffer; sl@0: (TAny)aRegion; sl@0: sl@0: iLock.Wait(); sl@0: if(iStop) sl@0: { sl@0: if(aStatusAvailable) sl@0: { sl@0: User::RequestComplete(aStatusAvailable, KErrDied); sl@0: } sl@0: if(aStatusDisplayed) sl@0: { sl@0: User::RequestComplete(aStatusDisplayed, KErrDied); sl@0: } sl@0: if(aStatusDisplayedXTimes) sl@0: { sl@0: User::RequestComplete(aStatusDisplayedXTimes, KErrDied); sl@0: } sl@0: iLock.Signal(); sl@0: return; sl@0: } sl@0: sl@0: RThread thread; sl@0: iThreadId = thread.Id(); sl@0: sl@0: if(aStatusAvailable) sl@0: { sl@0: Add(aStatusAvailable, EReqAvailable); sl@0: } sl@0: if(aStatusDisplayed) sl@0: { sl@0: Add(aStatusDisplayed, EReqDisplayed, 0, aTimeStamp); sl@0: } sl@0: if(aStatusDisplayedXTimes) sl@0: { sl@0: Add(aStatusDisplayedXTimes, EReqDisplayedXTimes, *aDisplayedXTimes); sl@0: } sl@0: iLock.Signal(); sl@0: } sl@0: sl@0: /** sl@0: Add notification to the list. The function is called from the SUS thread. sl@0: The client of this API must use a lock mechanizm to preserve data integrity. sl@0: */ sl@0: TInt CTContentUpdateReceiver::Add(TRequestStatus *aStatus, RequestType aType, sl@0: TInt aDisplayedXTimes, TUint32* aTimeStamp) sl@0: { sl@0: TInt index = iNumberElements; sl@0: TInt max = sizeof(iArray) / sizeof(iArray[0]) - 1; sl@0: if(index >= max) sl@0: return KErrOverflow; sl@0: sl@0: iArray[index].iStatus = aStatus; sl@0: iArray[index].iType = aType; sl@0: iArray[index].iDisplayedXTimes = aDisplayedXTimes; sl@0: iArray[index].iTimeStamp = aTimeStamp; sl@0: sl@0: iNumberElements++; sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Remove notification from the list. sl@0: The function is called from the backend thread. sl@0: The client of this API must use a lock mechanizm to preserve data integrity. sl@0: */ sl@0: void CTContentUpdateReceiver::Remove(TInt aIndex) sl@0: { sl@0: TInt max = sizeof(iArray) / sizeof(iArray[0]) - 1; sl@0: if((aIndex < 0) || (aIndex >= max)) sl@0: return; sl@0: sl@0: iNumberElements--; sl@0: if(aIndex < iNumberElements) sl@0: { sl@0: Mem::Move(&iArray[aIndex], &iArray[aIndex + 1], (iNumberElements - aIndex) * sizeof(RequestObject)); sl@0: iArray[iNumberElements].iType= EReqEmpty; sl@0: } sl@0: else sl@0: { sl@0: iArray[aIndex].iType = EReqEmpty; sl@0: } sl@0: } sl@0: sl@0: TInt CTContentUpdateReceiver::ThreadFunction(TAny* aAny) sl@0: { sl@0: // get clean-up stack sl@0: CTrapCleanup* cleanup=CTrapCleanup::New(); sl@0: RThread thread; sl@0: _LIT(KTestReceiver, "TestReceiver"); sl@0: __ASSERT_ALWAYS(cleanup!=NULL, thread.Panic( KTestReceiver, KErrNoMemory)); sl@0: sl@0: // create an active scheduler and server sl@0: CActiveScheduler *pA = new CActiveScheduler; sl@0: __ASSERT_ALWAYS(pA != NULL, thread.Panic( KTestReceiver, KErrNoMemory)); sl@0: sl@0: //Install the active scheduler sl@0: CActiveScheduler::Install(pA); sl@0: sl@0: CTContentUpdateReceiver *pCB = NULL; sl@0: TInt screen = * (static_cast (aAny)); sl@0: TRAPD(err, pCB = CTContentUpdateReceiver::NewL(screen)); sl@0: __ASSERT_ALWAYS(err == KErrNone, thread.Panic( KTestReceiver, err)); sl@0: sl@0: *(static_cast (aAny)) = pCB; sl@0: sl@0: // Let everyone know that we are ready to sl@0: // deal with requests. sl@0: RThread::Rendezvous(KErrNone); sl@0: // And start fielding requests from client(s). sl@0: CActiveScheduler::Start(); sl@0: sl@0: // Tidy up... sl@0: delete pCB; sl@0: delete pA; sl@0: delete cleanup; sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: _LIT(KMaskBackend, "CompositionBackend_%d"); sl@0: const TUint KDefaultHeapSize=0x10000; sl@0: sl@0: EXPORT_C TInt StartTestUpdateReceiver(CTContentUpdateReceiver*& aReceiver, TInt aScreen) sl@0: { sl@0: RThread compositionThread; sl@0: TInt res = KErrGeneral; sl@0: TBuf<64> contentUpdateReceiverThreadName; sl@0: TBuf<64> contentUpdateReceiverThreadMask; sl@0: sl@0: // Guarantee uniqueness of thread name by using timestamp sl@0: TTime tm; sl@0: TBuf<32> timeStamp; sl@0: tm.UniversalTime(); sl@0: TRAP(res, tm.FormatL(timeStamp, _L("_%H%T%S%C"))); sl@0: if(res != KErrNone) sl@0: { sl@0: return res; sl@0: } sl@0: sl@0: contentUpdateReceiverThreadName.Format(KMaskBackend, aScreen); sl@0: contentUpdateReceiverThreadName.Append(timeStamp); sl@0: contentUpdateReceiverThreadMask = contentUpdateReceiverThreadName; sl@0: contentUpdateReceiverThreadMask.Insert(0, _L("*")); sl@0: TFindThread findThread(contentUpdateReceiverThreadMask); sl@0: TFullName name; sl@0: // Need to check that the thread exists. sl@0: if (findThread.Next(name)!=KErrNone) sl@0: { sl@0: aReceiver = reinterpret_cast (aScreen); sl@0: sl@0: // Create the thread for the server. sl@0: res = compositionThread.Create(contentUpdateReceiverThreadName, sl@0: CTContentUpdateReceiver::ThreadFunction, sl@0: KDefaultStackSize, sl@0: KDefaultHeapSize, sl@0: KDefaultHeapSize, sl@0: (TAny*) &aReceiver sl@0: ); sl@0: sl@0: // The thread has been created OK so get it started - however sl@0: // we need to make sure that it has started before we continue. sl@0: if (res==KErrNone) sl@0: { sl@0: TRequestStatus rendezvousStatus; sl@0: compositionThread.SetPriority(EPriorityNormal); sl@0: compositionThread.Rendezvous(rendezvousStatus); sl@0: compositionThread.Resume(); sl@0: User::WaitForRequest(rendezvousStatus); sl@0: res = rendezvousStatus.Int(); sl@0: } sl@0: } sl@0: compositionThread.Close(); sl@0: return res; sl@0: } sl@0: sl@0: EXPORT_C void CloseTestUpdateReceiver(CTContentUpdateReceiver* aReceiver) sl@0: { sl@0: if(!aReceiver) sl@0: return; sl@0: sl@0: TBuf<64> contentUpdateReceiverThreadName; sl@0: contentUpdateReceiverThreadName.Format(KMaskBackend, aReceiver->Screen()); sl@0: TBuf<64> contentUpdateReceiverThreadMask; sl@0: contentUpdateReceiverThreadMask = contentUpdateReceiverThreadName; sl@0: contentUpdateReceiverThreadMask.Insert(0, _L("*")); sl@0: contentUpdateReceiverThreadMask.Append('*'); sl@0: TFindThread findThread(contentUpdateReceiverThreadMask); sl@0: TFullName name; sl@0: RThread thread; sl@0: if((findThread.Next(name)!=KErrNone) || sl@0: (thread.Open(findThread) != KErrNone)) sl@0: { sl@0: thread.Close(); sl@0: return; sl@0: } sl@0: TRequestStatus status; sl@0: thread.Logon(status); sl@0: if(aReceiver) sl@0: aReceiver->Stop(); sl@0: User::WaitForRequest(status); sl@0: thread.Close(); sl@0: }