diff -r dbfb5e38438b -r 305818acdca4 taskswitcher/server/src/tsdatalist.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/taskswitcher/server/src/tsdatalist.cpp Mon Sep 13 13:26:33 2010 +0300 @@ -0,0 +1,620 @@ +/* + * Copyright (c) 2008 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: File containing application list classes + * + */ + +//INCLUDES: +#include // for CleanupResetAndDestroyPushL +#include +#include +#include +#include // avkon +#include // fbsbitmap +#include +#include +#include +#include +#include + +#include "tsdatalist.h" +#include "tsentrykeygenerator.h" +#include "tsscreenshotmsg.h" +#include "tsunregscreenshotmsg.h" +#include "tsvisibilitymsg.h" + +// size for the created app icons +const TInt KAppIconWidth = 128; +const TInt KAppIconHeight = 128; + +//uids to be hidden +const TUid KHsApplicationUid = { 0x20022F35 }; + +// ================= MEMBER FUNCTIONS ======================= + +// -------------------------------------------------------------------------- +/** + * Two-phased constructor. + */ +CTsDataList* CTsDataList::NewL( MTsResourceManager& aResources, + MTsWindowGroupsMonitor& aMonitor, + MTsDataObserver& aObserver ) + { + CTsDataList* self = new (ELeave) CTsDataList( aResources, + aMonitor, + aObserver ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// -------------------------------------------------------------------------- +/** + * Constructor. + */ +CTsDataList::CTsDataList(MTsResourceManager& aResources, + MTsWindowGroupsMonitor &aMonitor, + MTsDataObserver& aObserver ) +: + CTsWindowGroupsObserver( aMonitor ), + iResources( aResources ), + iObserver( aObserver ) + { + } + +// -------------------------------------------------------------------------- +/* + * Destructor + */ +CTsDataList::~CTsDataList() + { + iData.ResetAndDestroy(); + iVisibleData.Close(); + iHiddenUids.Close(); + RFbsSession::Disconnect(); + RAknIconSrvClient::Disconnect(); + delete iDefaultIcon; + } + +// -------------------------------------------------------------------------- +/** + * Performs 2nd phase construction. + */ +void CTsDataList::ConstructL() + { + BaseConstructL(); + iHiddenUids.AppendL( KHsApplicationUid ); + User::LeaveIfError(RFbsSession::Connect()); + RAknIconSrvClient::Connect(); + QT_TRYCATCH_LEAVING( + iDefaultIcon = HbIcon2CFbsBitmap( HbIcon("qtg_large_application") );) + } + +// -------------------------------------------------------------------------- +/** + * Returns a reference to the current content. + * Also performs sanity checks, e.g. associates application icons + * when no screenshot has been received. + * @return ref to content array + */ +const RTsFswArray& CTsDataList::Data() const + { + return iVisibleData; + } + +// -------------------------------------------------------------------------- +/** + * Interface implementation + * @see MTsWindowGroupsObserver HandleWindowGroupChanged + */ +void CTsDataList::HandleWindowGroupChanged( + MTsResourceManager &, + const TArray& aWgList) + { + TRAP_IGNORE(RDebug::Print(_L("[TaskSwitcher] processing started")); + RTsFswArray newAppsList; + CleanupResetAndDestroyPushL(newAppsList); + CollectAppsL(newAppsList, aWgList); + RDebug::Print(_L("[TaskSwitcher] gathered app info")); + FitDataToListL(newAppsList); + CleanupStack::PopAndDestroy(&newAppsList); + RDebug::Print(_L("[TaskSwitcher] processing finished")); + ); + } + +// -------------------------------------------------------------------------- +/** + * Adds running apps to the list. + * @param aAppsList array to add to + */ +void CTsDataList::CollectAppsL(RTsFswArray& aAppsList, + const TArray &aWgList) + { + for( TInt i(0); i < aWgList.Count(); ++i ) + { + TTsEntryKey key; + TInt err = TsEntryKeyGeneraror::Generate(key, aWgList[i].iId, aWgList); + //skip this entry if it is already on list or generate key failed + if( err!=KErrNone || FindEntry( aAppsList, key ) >= 0 ) + { + continue; + } + + // get window group name + CApaWindowGroupName* windowName = + CApaWindowGroupName::NewLC( iResources.WsSession(), + key.WindowGroupId() ); + TUid appUid = windowName->AppUid(); + + // get screen number (-1=console, 0=main screen, 1=cover ui) + TInt appScreen = 0; + TInt scrNumErr = + iResources.ApaSession().GetDefaultScreenNumber( appScreen, + appUid ); + + if( appUid.iUid && + !windowName->Hidden() && + (appScreen == 0 || appScreen == -1) && + scrNumErr == KErrNone ) + { + AddEntryL( key, appUid, windowName, aAppsList ); + } + + CleanupStack::PopAndDestroy( windowName ); + } + } + +// -------------------------------------------------------------------------- +/** + * Called from CollectTasksL for each entry in the task list. + * @param aKey entry key + * @param aAppUid application uid + * @param aWgName window group name or NULL + * @param aNewList list to add to + */ +void CTsDataList::AddEntryL( const TTsEntryKey& aKey, + const TUid& aAppUid, + CApaWindowGroupName* aWgName, + RTsFswArray& aNewList ) + { + CTsEntry* entry = CTsEntry::NewLC( aKey, iObserver ); + // check if present in old list and if yes then take some of the old data + TBool found = ConsiderOldDataL( aKey ); + // if not present previously then find out app name + // and check if screenshot is already available + if( !found ) + { + entry->SetAppUid(aAppUid); + HBufC* name = FindAppNameLC( aWgName, aAppUid, aKey.WindowGroupId() ); + entry->SetAppNameL(*name); + CleanupStack::PopAndDestroy( name ); + //transfer ownership to entry + entry->SetAppIcon( GetAppIconL( aAppUid ) ); + } + if(aWgName) + { + entry->SetCloseableApp( !aWgName->IsSystem() ); + } + // add to new list, ownership is transferred + aNewList.AppendL( entry ); + CleanupStack::Pop( entry ); + } + +// -------------------------------------------------------------------------- +/** + * Checks if there is an entry for same app in the content list. + * If yes then it takes some of the data for the entry that + * will correspond to the same app in the refreshed content list. + * @param aKey new key in content list + * @return ETrue if app was found + */ +TBool CTsDataList::ConsiderOldDataL( const TTsEntryKey& aKey ) + { + for(TInt entryIdx = 0, oldCount = iData.Count(); entryIdx < oldCount; ++entryIdx) + { + if (iData[entryIdx]->Key() == aKey) + { + return ETrue; + } + } + return EFalse; + } + +// -------------------------------------------------------------------------- +/** + * Finds out the application name. + * @param aWindowName window group name or NULL + * @param aAppUId application uid + * @param aWgId window group id + * @return application name, ownership transferred to caller + */ +HBufC* CTsDataList::FindAppNameLC( CApaWindowGroupName* aWindowName, + const TUid& aAppUid, + TInt aWgId ) + { + //Retrieve the app name + TApaAppInfo info; + iResources.ApaSession().GetAppInfo( info, aAppUid ); + TPtrC caption = info.iShortCaption; + + HBufC* tempName( 0 ); + if (!caption.Length() && aWindowName) // if not set - use thread name instead + { + if (aWindowName->Caption().Length()) + { + tempName = aWindowName->Caption().AllocLC(); + } + else + { + TThreadId threadId; + if(KErrNone == iResources.WsSession().GetWindowGroupClientThreadId( aWgId, threadId ) ) + { + RThread thread; + CleanupClosePushL( thread ); + if( KErrNone == thread.Open( threadId ) ) + { + tempName = thread.Name().AllocL(); // codescanner::forgottoputptroncleanupstack + } + // tempName put on cleanupstack after the if + CleanupStack::PopAndDestroy( &thread ); + if(tempName) + { + CleanupStack::PushL(tempName); + } + } + } + } + else + { + tempName = caption.AllocLC(); + } + if( 0 == tempName ) + { + tempName = KNullDesC16().AllocLC(); + } + return tempName; + } + +// -------------------------------------------------------------------------- +/** + * Fit existing class contained data list into give one. + * Data is being changed with application type consideration that is based + * on aConsiderWidgets param. + * Function removes or add entries into data depend on given list. + * @param aListToFit list with actual data + */ +void CTsDataList::FitDataToListL( RTsFswArray& aListToFit ) + { + TBool changed = EFalse; + TInt dataCount = iData.Count(); + + //remove items that dont't exists in newly collected list + for (TInt i = dataCount - 1; i >= 0; --i) + { + if( !CheckIfExists( *iData[i], aListToFit ) ) + { + delete iData[i]; + iData.Remove( i ); + changed = ETrue; + } + } + RArray allKeys; + + //add new items at start + for(TInt i = aListToFit.Count() - 1; i >= 0; --i) + { + User::LeaveIfError( allKeys.Insert(aListToFit[i]->Key(), 0) ); + if( !CheckIfExists( *aListToFit[i], iData ) ) + { + HideEntryIfNotAllowed( aListToFit[i] ); + User::LeaveIfError( iData.Insert( aListToFit[i], 0 ) ); + TTime currentTimestamp; + currentTimestamp.UniversalTime(); + iData[0]->SetTimestamp( currentTimestamp ); + aListToFit[i] = 0; + changed = ETrue; + } + } + //establish order + TBool orderChanged = EstablishOrder( allKeys ); + //update entries data + TBool dataChanged = UpdateEntryData( aListToFit ); + RebuildVisibleDataListL(); + if( changed || orderChanged || dataChanged ) + { + iObserver.DataChanged(); + } + allKeys.Close(); + } + +// -------------------------------------------------------------------------- +/** + * Checks if there is an entry for same app in the given list. + * @param aEntry entry + * @param aList ref to list + * @return ETrue if app was found + */ + +TBool CTsDataList::CheckIfExists( const CTsEntry& aEntry, + const RTsFswArray& aList ) const + { + return 0 <= FindEntry( aList, aEntry.Key() ); + } + +// -------------------------------------------------------------------------- +/** + * Retrieves the bitmap for the icon of the given app. + * @param aAppUid application uid + * @return app CFbsBitmap + */ +CFbsBitmap* CTsDataList::GetAppIconL( const TUid& aAppUid ) + { + + CFbsBitmap* iconBitmap(0); + TRAPD(errNo, + QT_TRYCATCH_LEAVING( + const QSize size(KAppIconWidth, KAppIconHeight); + HbIcon icon = CaMenuIconUtility::getApplicationIcon( aAppUid.iUid, size); + iconBitmap = HbIcon2CFbsBitmap( icon );) + User::LeaveIfNull(iconBitmap); ) + if( KErrNone != errNo ) + { + iconBitmap = new(ELeave) CFbsBitmap; + CleanupStack::PushL(iconBitmap); + User::LeaveIfError( iconBitmap->Duplicate( iDefaultIcon->Handle() ) ); + CleanupStack::Pop(iconBitmap); + } + return iconBitmap; + } + +// -------------------------------------------------------------------------- +/** + * Converts HbIcon to CFbsBitmap + * @param aIcon icon to be coverted + * @return CFbsBitmap + */ +CFbsBitmap* CTsDataList::HbIcon2CFbsBitmap( const HbIcon& aIcon ) + { + CFbsBitmap* retValue(0); + QIcon qicon = aIcon.qicon(); + QPixmap pixmap = qicon.pixmap(QSize(KAppIconWidth, KAppIconHeight)); + if( !pixmap.isNull() ) + { + retValue = pixmap.toSymbianCFbsBitmap(); + } + return retValue; + } +// -------------------------------------------------------------------------- +TBool CTsDataList::IsSupported( TInt aFunction ) const + { + return ( RegisterScreenshotMessage == aFunction || + UnregisterScreenshotMessage == aFunction || + VisibilityChange == aFunction || + WindowGroupToBackgroundMessage == aFunction ); + } + +// -------------------------------------------------------------------------- +void CTsDataList::HandleDataL( TInt aFunction, RReadStream& aDataStream ) + { + switch( aFunction ) + { + case RegisterScreenshotMessage: + RegisterScreenshotL( aDataStream ); + break; + case UnregisterScreenshotMessage: + UnregisterScreenshotL( aDataStream ); + break; + case VisibilityChange: + ChangeVisibilityL( aDataStream ); + break; + case WindowGroupToBackgroundMessage: + UpdateTaskTimestampL( aDataStream ); + break; + } + } + +// -------------------------------------------------------------------------- +void CTsDataList::RegisterScreenshotL( RReadStream& aDataStream ) + { + CTsScreenshotMsg* msg = CTsScreenshotMsg::NewLC( aDataStream ); + const TInt pos = FindEntry( iData, GenerateKeyL(msg->WindowGroupId() ) ); + User::LeaveIfError(pos); + iData[pos]->SetScreenshotL( msg->Screenshot(), msg->Priority(), msg->Rotation() ); + CleanupStack::PopAndDestroy(msg); + } +// -------------------------------------------------------------------------- +void CTsDataList::UnregisterScreenshotL(RReadStream& aDataStream) +{ + CTsUnregisterScreenshotMsg* msg = + CTsUnregisterScreenshotMsg::NewLC(aDataStream); + const TInt pos = FindEntry( iData, GenerateKeyL(msg->windowGroupId() ) ); + User::LeaveIfError(pos); + iData[pos]->RemoveScreenshotL(); + CleanupStack::PopAndDestroy(msg); +} +// -------------------------------------------------------------------------- +void CTsDataList::ChangeVisibilityL( RReadStream& aDataStream ) + { + CTsVisibilitMsg* msg = CTsVisibilitMsg::NewLC(aDataStream); + const TInt pos = FindEntry( iData, GenerateKeyL( msg->windowGroupId() ) ); + User::LeaveIfError(pos); + + msg->visibility() == iData[pos]->GetVisibility() ? + User::Leave( KErrInUse ) : + iData[pos]->SetVisibility( msg->visibility() ); + + CleanupStack::PopAndDestroy(msg); + RebuildVisibleDataListL(); + iObserver.DataChanged(); + } +// -------------------------------------------------------------------------- +void CTsDataList::UpdateTaskTimestampL( RReadStream& aDataStream ) + { + const TInt wgId = aDataStream.ReadInt32L(); + const TInt pos = FindEntry( iData, GenerateKeyL( wgId ) ); + User::LeaveIfError( pos ); + + TTime currentTimestamp; + currentTimestamp.UniversalTime(); + iData[pos]->SetTimestamp( currentTimestamp ); + + iObserver.DataChanged(); + } + +// -------------------------------------------------------------------------- +/** + * Checks if given uid is on hidden list + * @param aUid uid to be checked + * @return ETrue if uid is on hidden list + */ +TBool CTsDataList::IsHiddenUid( TUid aUid ) + { + return 0 < iHiddenUids.Find( aUid ); + } + +// -------------------------------------------------------------------------- +/** + * Finds entry in array + * @param aList list to find + * @param aKey finding key + * @return position or KErrNotFound + */ +TInt CTsDataList::FindEntry( const RTsFswArray& aList, + const TTsEntryKey& aKey ) const + { + TInt pos(KErrNotFound); + for(TInt entryIdx = 0; + entryIdx < aList.Count() && KErrNotFound == pos; + ++entryIdx) + { + if (aList[entryIdx]->Key() == aKey) + { + pos = entryIdx; + } + } + return pos; + } + +// -------------------------------------------------------------------------- +/** + * Establish entry order accridung to aKeyList, all keys MUST be in iData + * @param aKeyList reference key list + * @return ETrue if changes occured + */ +TBool CTsDataList::EstablishOrder( const RArray& aKeyList ) + { + TBool changed( EFalse ); + TInt lastChangedItem( KErrNotFound ); + __ASSERT_ALWAYS( iData.Count() == aKeyList.Count(), User::Panic(_L("EstablishOrder 1"), KErrBadHandle) ); + for (TInt i = 0; i < aKeyList.Count(); i++) + { + const TTsEntryKey& currentdataKey = iData[i]->Key(); + const TTsEntryKey& referenceKey = aKeyList[i]; + if( !(currentdataKey == referenceKey) ) + { + TInt foundPos = FindEntry( iData, referenceKey ); + __ASSERT_ALWAYS(foundPos>=0, User::Panic(_L("EstablishOrder 2"), KErrBadHandle)); + CTsEntry* entry = iData[foundPos]; + iData.Remove( foundPos ); + iData.Insert( entry, i ); + changed = ETrue; + lastChangedItem = i; + } + } + TTime currentTimestamp; + currentTimestamp.UniversalTime(); + for (TInt i = lastChangedItem; i >= 0; --i) + { + iData[i]->SetTimestamp(currentTimestamp); + } + return changed; + } + +// -------------------------------------------------------------------------- +/** + * Updates entry data on mData according to list + * @param aList reference entires list + * @return ETrue if changes occured + */ +TBool CTsDataList::UpdateEntryData( const RTsFswArray& aList ) +{ + __ASSERT_ALWAYS( iData.Count() == aList.Count(), + User::Panic(_L("UpdateEntryData 1"), KErrBadHandle) ); + TBool changed( EFalse ); + for( TInt i=0; iKey() == aList[i]->Key(), + User::Panic(_L("UpdateEntryData 2"), KErrBadHandle)); + if( iData[i]->CloseableApp() != aList[i]->CloseableApp() ) + { + iData[i]->SetCloseableApp(aList[i]->CloseableApp()); + changed = ETrue; + } + } + } + return changed; +} + +// -------------------------------------------------------------------------- +/** + * Function generate task key using window group id + * @param wgId - window group id of running application + * @param entry key + */ +TTsEntryKey CTsDataList::GenerateKeyL( TInt aWgId ) + { + RArray allWgIds; + CleanupClosePushL( allWgIds ); + User::LeaveIfError( iResources.WsSession().WindowGroupList( 0, &allWgIds ) ); + TTsEntryKey key; + User::LeaveIfError(TsEntryKeyGeneraror::Generate(key, aWgId, allWgIds.Array())); + CleanupStack::PopAndDestroy( &allWgIds ); + return key; + } + +// -------------------------------------------------------------------------- +/** + * Hides entrie if exist on mHiddenUids + * @param entry + */ +void CTsDataList::HideEntryIfNotAllowed( CTsEntry* aEntry ) + { + if( iHiddenUids.Find( aEntry->AppUid() ) >= 0 ) + { + aEntry->SetVisibility(Invisible); + } + } + +void CTsDataList::RebuildVisibleDataListL() + { + iVisibleData.Reset(); + RArray visibleItems(iData.Count() ? iData.Count() : 1); + CleanupClosePushL(visibleItems); + for( TInt iter = 0; iter < iData.Count(); ++iter ) + { + if( Visible == iData[iter]->GetVisibility() ) + { + visibleItems.AppendL(iter); + } + } + for( TInt iter = 0; iter < visibleItems.Count(); ++iter ) + { + iVisibleData.AppendL( iData[visibleItems[iter]] ); + } + CleanupStack::PopAndDestroy(&visibleItems); + } +// end of file