--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gssettingsuis/Gs/GSFramework/src/GSPluginLoader.cpp Wed Sep 01 12:20:44 2010 +0100
@@ -0,0 +1,989 @@
+/*
+* Copyright (c) 2005-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: GS plugin loader.
+*
+*/
+
+
+// INCLUDE FILES
+#include <gspluginloader.h>
+#include <gsplugininterface.h>
+#include <gsprivatepluginproviderids.h>
+#include "GsLogger.h"
+#include "GSBaseDocument.h"
+#include "GSPluginWrapper.h"
+#include "GSPluginAndViewIdCache.h"
+#include <mgswatchdog.h>
+
+#include <aknViewAppUi.h>
+#include <AknIconArray.h>
+#include <aknlists.h> // CAknSingleLargeStyleListbox
+#include <eikclbd.h> // CColumnListBoxData
+#include <gulicon.h> // For CGulIcon
+#include <utf.h> // CnvUtfConverter
+#include <basched.h>
+#include <AknInfoPopupNoteController.h>
+
+//Flag for enabling/disablign compare by category feature
+#undef RD_GS_COMPARE_BY_CATEGORY
+
+// ================= MEMBER FUNCTIONS =======================
+
+#ifdef _DEBUG
+ #pragma message("-----_DEBUG ACTIVATED IN GS!-----")
+#endif //_GEBUG
+
+#ifdef _GS_PERFORMANCE_TRACES
+ #pragma message("-GS plugin load performance measurements activated-")
+#endif // _GS_PERFORMANCE_TRACES
+
+const TInt KGSCaptionSize = 256;
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::NewL
+//
+// EPOC two-phased constructor
+// ----------------------------------------------------------------------------
+//
+EXPORT_C CGSPluginLoader* CGSPluginLoader::NewL( CAknViewAppUi* aAppUi )
+ {
+ CGSPluginLoader* self = new( ELeave ) CGSPluginLoader;
+ CleanupStack::PushL( self );
+ self->ConstructL( aAppUi );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::CGSPluginLoader
+//
+// C++ default constructor can NOT contain any code, that
+// might leave.
+//
+// Uses low priority for Active Object so that more bandwith is available for
+// the most important pluginloaders.
+// ----------------------------------------------------------------------------
+//
+CGSPluginLoader::CGSPluginLoader()
+ : CActive( EPriorityLow ),
+ iRequestedPriority( EPriorityLow )
+ {
+ __GSLOGSTRING( "[GSPlgLoader] CGSPluginLoader()" );
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::ConstructL
+//
+// EPOC default constructor can leave.
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CGSPluginLoader::ConstructL( CAknViewAppUi* aAppUi )
+ {
+ __GSLOGSTRING( "[GSPlgLoader] ConstructL()" );
+ iAppUi = aAppUi;
+ iDocument = static_cast<CGSBaseDocument*>( iAppUi->Document() );
+ iImplInfoArray = iDocument->GetImplInfo();
+
+ CActiveScheduler* scheluder = CActiveScheduler::Current();
+ __GSLOGSTRING1( "[GSPlgLoader] Current CActiveScheduler:0x%X", scheluder );
+ __GSLOGSTRING1( "[GSPlgLoader] CActiveScheduler stackdepth: %d",
+ scheluder->StackDepth() );
+
+ CActiveScheduler::Add( this );
+
+ iWatchDog = iDocument->WatchDog();
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::~CGSPluginLoader
+//
+// Destructor
+// ----------------------------------------------------------------------------
+//
+EXPORT_C CGSPluginLoader::~CGSPluginLoader()
+ {
+ __GSLOGSTRING( "[GSPlgLoader] ~CGSPluginLoader()" );
+ AbortAsyncLoad();
+ Cancel();
+
+ if( iErrorPopup )
+ {
+ iErrorPopup->HideInfoPopupNote();
+ delete iErrorPopup;
+ iErrorPopup = NULL;
+ }
+ //iPluginArray is not owned and therefore not deleted.
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::LoadAsync
+//
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CGSPluginLoader::LoadAsyncL(
+ TUid aInterfaceUid,
+ TUid aParentUid,
+ CArrayPtrFlat<CGSPluginInterface>* aPluginArray )
+ {
+ iPluginArray = aPluginArray;
+ iParentUid = aParentUid;
+
+ __GSLOGSTRING3(
+ "[GSPlgLoader] LoadAsync(). aInterfaceUid:0x%X aParentUid:0x%X, aPluginArray:0x%X",
+ aInterfaceUid, aParentUid, aPluginArray );
+ // Reset iterator:
+ iImplInfoArrayIterator = 0;
+
+ __GSLOGSTRING1( "[GSPlgLoader] Implementation info count: %d",
+ iImplInfoArray.Count() );
+
+ NotifyProgress();
+
+ //Begin CActive asynchronous loop.
+ CompleteOwnRequest();
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::LoadSyncL
+//
+//
+// ----------------------------------------------------------------------------
+//
+CGSPluginInterface& CGSPluginLoader::LoadSyncL( TUid aInterfaceUid,
+ TUid aImplementationUid )
+ {
+ Cancel();
+ CGSPluginInterface* ret = NULL;
+
+ // Get a list of all implementations, even though we only want one specific.
+ // There appears to be no way to otherwise extract a specific implementation
+ // info object :(
+ // Search for the implementation that matches aImplementationUid
+ const TInt impCount = iImplInfoArray.Count();
+ for( TInt i=0; i<impCount; i++ )
+ {
+ const CImplementationInformation* info = iImplInfoArray[ i ];
+ if ( info->ImplementationUid() == aImplementationUid )
+ {
+ ret = &CreatePluginInstanceL( *info );
+ break;
+ }
+ }
+
+ if ( !ret )
+ {
+ User::Leave( KErrNotFound );
+ }
+ return *ret;
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::AbortAsyncLoad
+//
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CGSPluginLoader::AbortAsyncLoad()
+ {
+ __GSLOGSTRING( "[GSPlgLoader] AbortAsyncLoad()" );
+ Cancel();
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::RunL
+//
+//
+// ----------------------------------------------------------------------------
+//
+void CGSPluginLoader::RunL()
+ {
+ iRunLDebugCount++;
+
+ // This must be done only in RunL or otherwise request might be
+ // outstanding.
+ if( iRequestedPriority != Priority() )
+ {
+ __GSLOGSTRING3(
+ "[CGSPluginLoader::RunL] 0x%X original priority:%d requested priority:%d",
+ iParentUid.iUid,
+ Priority(),
+ iRequestedPriority );
+
+ SetPriority( iRequestedPriority );
+ }
+
+ LoadNextPluginL();
+
+ // Check if there are still more plugins to be loaded:
+ if ( iImplInfoArrayIterator < iImplInfoArray.Count() )
+ {
+ NotifyProgress();
+ // Continue CActive asynchronous loop.
+ CompleteOwnRequest();
+ }
+ else
+ {
+ // All plugins loaded:
+ __GSLOGSTRING( "[GSPlgLoader] Loading plugins finished." );
+ NotifyFinished();
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// CScGenreItemConstructionConductor::CompleteOwnRequest
+//
+// Issue request complete notification.
+// ---------------------------------------------------------------------------
+void CGSPluginLoader::CompleteOwnRequest()
+ {
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete( status, KErrNone );
+ SetActive();
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::RunError
+//
+//
+// ----------------------------------------------------------------------------
+//
+TInt CGSPluginLoader::RunError( TInt aError )
+ {
+ // This method is called when a plugin loading fails.
+ // Always "fake" the return value so that ActiveSchedule
+ // keeps running and later plugins are continued to be loaded.
+ // Check if still plugins to be loaded:
+ if( iImplInfoArrayIterator < iImplInfoArray.Count() )
+ {
+ NotifyProgress();
+
+ //Continue CActive asynchronous loop.
+ CompleteOwnRequest();
+ }
+ else // All plugins loaded:
+ {
+ NotifyFinished();
+ }
+
+ if ( aError == KLeaveExit )
+ {
+ return KLeaveExit;
+ }
+
+ return KErrNone;
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::DoCancel
+//
+//
+// ----------------------------------------------------------------------------
+//
+void CGSPluginLoader::DoCancel()
+ {
+
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::NotifyProgress
+//
+//
+// ----------------------------------------------------------------------------
+//
+void CGSPluginLoader::NotifyProgress()
+ {
+ if( iObserver )
+ {
+ iObserver->HandlePluginLoaded( MGSPluginLoadObserver::EGSSuccess);
+ }
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::NotifyFinished
+//
+//
+// ----------------------------------------------------------------------------
+//
+void CGSPluginLoader::NotifyFinished()
+ {
+
+ #ifdef _GS_PLUGINLOADER_FINAL_SORTING_TRACES
+ TRAP_IGNORE( PrintOrderTracesL( iPluginArray ) );
+ #endif // _GS_PLUGINLOADER_FINAL_SORTING_TRACES
+
+ // I have finished loading: No need to keep me in the expensive scheduler
+ // queue.
+ Deque();
+
+ if( iObserver )
+ {
+ iObserver->HandlePluginLoaded( MGSPluginLoadObserver::EGSFinished );
+ }
+
+ __GSLOGSTRING1( "[CGSPluginLoader::NotifyFinished] 0x%X",
+ iParentUid.iUid );
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::SetObserver
+//
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CGSPluginLoader::SetObserver(MGSPluginLoadObserver* aObserver)
+ {
+ __GSLOGSTRING1("[GSPlgLoader] Observer set:0x%X", aObserver);
+ iObserver = aObserver;
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::ParseToUid
+// Parses a UID from descriptor of form '0xNNNNNNNN' where N is hexadecimal.
+//
+// ----------------------------------------------------------------------------
+//
+TInt CGSPluginLoader::ParseToUid( const TDesC8& aSource, TUid& aTarget )
+ {
+ // Remove "0x" from the descriptor if it exists
+ _LIT8(KHexPrefix, "0x");
+
+ TPtrC8 pSource( aSource );
+ const TInt prefixPosition = pSource.Find( KHexPrefix );
+ if ( prefixPosition != KErrNotFound )
+ {
+ pSource.Set( aSource.Mid( prefixPosition + KHexPrefix().Length() ) );
+ }
+
+ // Parse to integer
+ TLex8 lex( pSource );
+ TUint integer = 0;
+
+ // Parse using TRadix::EHex as radix:
+ const TInt err = lex.Val( integer, EHex );
+ aTarget.iUid = integer;
+
+ if( err != KErrNone )
+ {
+ // If parsing parent UID failed, do not load plugin:
+ __GSLOGSTRING1(
+ "[GSPlgLoader] Parsing parent UID failed. Error code:%d",
+ err );
+ }
+ return err;
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::ParseOrderNumber
+//
+//
+// ----------------------------------------------------------------------------
+//
+TInt CGSPluginLoader::ParseOrderNumber( const TDesC8& aSource, TInt& aOrderNumber )
+ {
+ // Parse plugin's order number from opaque_data:
+ TLex8 lex( aSource );
+ const TInt orderErr = lex.Val( aOrderNumber );
+ return orderErr;
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::PrintInfoDebug
+// Print CImplementationInformation to log. Used for debugging.
+//
+// ----------------------------------------------------------------------------
+//
+void CGSPluginLoader::PrintInfoDebugL( const CImplementationInformation& aInfo,
+ TInt aIterator,
+ TInt aPluginCount )
+ {
+
+
+ #pragma message("-CGSPluginLoader verbose traces activated-")
+ __GSLOGSTRING2( "[GSPlgLoader::LoadNextPluginL] %d/%d",
+ aIterator,
+ aPluginCount);
+
+ __GSLOGSTRING1( "[GSPlgLoader] --Plugin 0x%X info--", &aInfo);
+ __GSLOGSTRING1( "[GSPlgLoader] DisplayName:%S", &aInfo.DisplayName() );
+ __GSLOGSTRING1( "[GSPlgLoader] ImplementationUid:0x%X",
+ aInfo.ImplementationUid() );
+
+ const TInt KMaxEComDataLength = 256;
+
+ HBufC* dataType = HBufC::New( KMaxEComDataLength );
+ HBufC* opaqueData = HBufC::New( KMaxEComDataLength );
+
+ dataType->Des().Copy( aInfo.DataType() );
+ opaqueData->Des().Copy( aInfo.OpaqueData() );
+ __GSLOGSTRING1( "[GSPlgLoader] DataType:%S", dataType );
+ __GSLOGSTRING1( "[GSPlgLoader] OpaqueData:%S", opaqueData );
+
+ delete opaqueData;
+ delete dataType;
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::LoadNextPluginL
+// Iterate through iImplInfoArray. Load the plugin if it is eligible for
+// loading. Loaded plugin is added to iPluginArray. Each time a plugin is
+// loaded, iObserver is notified.
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CGSPluginLoader::LoadNextPluginL()
+ {
+ // Iterate through iImplInfoArray. This loop continues between function
+ // calls. Therefore member variable iImplInfoArrayIterator is used as a
+ // counter. Loop will break when match is found and continues on next RunL.
+ for( ; iImplInfoArrayIterator < iImplInfoArray.Count(); )
+ {
+ const CImplementationInformation* info =
+ iImplInfoArray[ iImplInfoArrayIterator ];
+
+ iImplInfoArrayIterator++;
+
+ #ifdef _GS_PLUGINLOADER_VERBOSE_TRACES
+ PrintInfoDebugL( *info, iImplInfoArrayIterator, iImplInfoArray.Count() );
+ #endif //_GS_PLUGINLOADER_VERBOSE_TRACES
+
+ // Parse parent UID from default_data:
+ TUid parentUid;
+ const TInt uidErr = ParseToUid( info->DataType(), parentUid );
+
+ if( uidErr == KErrNone && iParentUid == parentUid )
+ {
+ // If this plugin is OK -> load it:
+ __GSLOGSTRING2( "[GSPlgLoader] %S eligible for parent 0x%X",
+ &info->DisplayName(), iParentUid.iUid );
+ CGSPluginInterface* plugin = NULL;
+ TInt error = KErrCancel;
+ #ifdef GS_ENABLE_WATCH_DOG
+ if( !iWatchDog->IsInBlackList( info->ImplementationUid() ) )
+ #endif
+ {
+ // Only panics move quarantined plugins to blacklist. Leaving is
+ // normal programmatic functionality and therefore does not move
+ // plugin to blacklist.
+ #ifdef GS_ENABLE_WATCH_DOG
+ iWatchDog->QuarantineL( info->ImplementationUid() );
+ #endif
+
+ #ifdef _GS_PERFORMANCE_TRACES
+ TTime timeStart;
+ TTime timeEnd;
+ timeStart.HomeTime();
+ #endif //_GS_PERFORMANCE_TRACES
+
+ // Create plugin. Trap leave for debugging purposes.
+ TRAP( error, plugin = &CreatePluginInstanceL( *info ); );
+
+ #ifdef _GS_PERFORMANCE_TRACES
+ timeEnd.HomeTime();
+ TTimeIntervalMicroSeconds funcDuration = timeEnd.MicroSecondsFrom( timeStart );
+ __GSLOGSTRING2( "[GSPlgLoader::LoadNextPluginL/perf] %Ld (%S)", funcDuration, &info->DisplayName() );
+ #endif //_GS_PERFORMANCE_TRACES
+
+ #ifdef GS_ENABLE_WATCH_DOG
+ TRAP_IGNORE( iWatchDog->RemoveFromQuarantineL( info->ImplementationUid() ); );
+ #endif
+ }
+ if( error == KErrNone )
+ {
+ // Plugin ownership is transfered to iPluginArray
+ InsertPluginInOrderL( plugin, iPluginArray );
+ }
+ else if( error == KLeaveExit )
+ {
+ __GSLOGSTRING( "[GSPlgLoader::LoadNextPluginL] LEAVE: KLeaveExit!!!" );
+ // Must pass KLeaveExit through or otherwise Exit-command will
+ // not be handled.
+ User::Leave( KLeaveExit );
+ }
+ else
+ {
+ // Error note is displayed even if plugin is not loaded
+ // -> plugin is in blacklist -> blacklist note displayed.
+ #ifdef _DEBUG
+ DisplayErrorPopupL( error, info );
+ #endif //_DEBUG
+ }
+ // Wait for next round
+ break;
+ }
+ }
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::DisplayErrorPopupL
+//
+// ----------------------------------------------------------------------------
+//
+void CGSPluginLoader::DisplayErrorPopupL(
+ TInt aError,
+ const CImplementationInformation* aInfo )
+ {
+
+ // Log error:
+ __GSLOGSTRING3( "[GSPlgLoader] %S (0x%X) loading failed with error code %d",
+ &aInfo->DisplayName(),
+ aInfo->ImplementationUid().iUid,
+ aError );
+
+ // Runtime info message used only in _DEBUG builds.
+ // Buffer needs space for about 50 chars for debug text
+ // + 8 chars for hex UID
+ // + DisplayName().Length()
+ // + error code 10 chars...
+ HBufC* buf = HBufC::NewLC( 100 + aInfo->DisplayName().Length() );
+ TPtr ptr = buf->Des();
+
+ if( aError == KErrCancel )
+ {
+ _LIT( KDbgMsgBlacklisted, "Plugin in blacklist:\n%S (0x%X)" );
+ ptr.Format( KDbgMsgBlacklisted,
+ &aInfo->DisplayName(),
+ aInfo->ImplementationUid().iUid );
+ }
+ else
+ {
+ _LIT( KDbgMsg, "Error:\n%S (0x%X)\nloading failed with error code %d" );
+ ptr.Format( KDbgMsg,
+ &aInfo->DisplayName(),
+ aInfo->ImplementationUid().iUid,
+ aError );
+ }
+ if( iErrorPopup )
+ {
+ delete iErrorPopup;
+ iErrorPopup = NULL;
+ }
+ iErrorPopup = CAknInfoPopupNoteController::NewL();
+ iErrorPopup->SetTextL( ptr );
+ CleanupStack::PopAndDestroy( buf );
+ iErrorPopup->ShowInfoPopupNote();
+ }
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::CreatePluginInstanceL
+//
+//
+// ----------------------------------------------------------------------------
+//
+CGSPluginInterface& CGSPluginLoader::CreatePluginInstanceL(
+ const CImplementationInformation& aImpInfo )
+ {
+ // Create a wrapper for the plugin - this will take
+ // care of cleaning up the plugin dll. This must be on
+ // the cleanup stack above the plugin object itself - since
+ // the cleanup stack will first delete the plugin, then the
+ // plugin wrapper will be called to unload the ECOM plugin
+ // dll itself.
+ CGSPluginWrapper* wrapper = iDocument->NewPluginUnloadWrapperLC();
+
+ // Now we can load the plugin
+ const TUid implUid = aImpInfo.ImplementationUid();
+
+ CGSPluginInterface* plugin = CGSPluginInterface::NewL( implUid,
+ iAppUi );// Remove iAppUi
+ CleanupStack::PushL ( plugin );
+
+ // And now its okay to update the wrapper with the plugin's
+ // ECOM destructor info.
+ wrapper->SetDetails( plugin->iDtor_ID_Key );
+
+ // If plugin's resource definition had a valid order number,
+ // set it to plugin.
+ //
+ // If parent is GSAppsPlugin, this is where the ordering
+ // could be changed to follow the to-be-implemented resource file
+ // defining the plugin order.
+
+ // Parse plugin's order number from opaque_data:
+ TInt orderNumber = 0;
+ const TInt orderErr = ParseOrderNumber( aImpInfo.OpaqueData(), orderNumber );
+ if ( orderErr == KErrNone && orderNumber >= 0 )
+ {
+ plugin->iOrder = orderNumber;
+ }
+
+ // When a specific view has been activated externally to GS (e.g
+ // whilst GS is not running) we have to load the view's plugin on-demand.
+ // This means that the plugin is essentially free-floating and is not bound
+ // to a parent's CGSParentPlugin::iPluginArray.
+ //
+ // In this situation, even though we have activated a specific view,
+ // the plugin loader(s) continue to operate in the background.
+ //
+ // Eventually, as the loaders progress, a second attempt will occur to
+ // load the same view (that was activated externally).
+ //
+ // In this situation, we discard the recently loaded instance of the plugin
+ // and instead preserve the view that the user is (presumably) already using.
+ //
+ // However, we must ensure that we synchronous the parent's iPluginArray
+ // with the pre-existing view instance.
+ const TUid viewId = plugin->Id();
+ CGSPluginAndViewIdCache& pluginViewIdCache = iDocument->PluginViewIdCache();
+ const TBool isAlreadyLoaded = pluginViewIdCache.IsPluginLoaded( viewId );
+
+ if ( !isAlreadyLoaded )
+ {
+ // Cache the view uid & ECOM plugin dll uid to enable us
+ // to more quickly handle external view activation requests
+ // when GS is not already running.
+ pluginViewIdCache.RegisterViewAndImplementationAssociationL( viewId, implUid );
+
+ // Prepare to register the plugin with the cache. Pushes a cleanup stack
+ // item in case adding the view should leave.
+ pluginViewIdCache.PrepareToRegisterPluginInstanceLC( viewId );
+
+ // Add loaded view to appUi. At this point, the GS framework
+ // is no longer responsible for the lifetime of the 'plugin'
+ // object.
+ //
+ // However, to ensure sucessful cleanup of deleted
+ // views, we have separated the ECOM plugin dll (controlled by
+ // plugin->iDtor_ID_Key) to a separate object. This object is
+ // owned by the loader.
+ iAppUi->AddViewL( plugin );
+
+ // Pop the cleanup item - all is well now.
+ CleanupStack::Pop(); // cleanup item from PrepareToRegisterPluginInstanceLC
+
+ CleanupStack::Pop( plugin ); // view framework is now responsible for this memory.
+
+ // Document, when it is destroyed, will handle unloading of ECOM dll.
+ CleanupStack::Pop( wrapper );
+
+ // Also register that we have loaded an instance of the specified view
+ // from a plugin.
+ pluginViewIdCache.RegisterPluginInstanceL( viewId, *plugin );
+ }
+ else
+ {
+ // Plugin is already loaded, presumably due to external view activation
+ // request.
+ //
+ // Discard "just loaded" instance and use the pre-loaded one instead.
+ CleanupStack::PopAndDestroy( 2, wrapper );
+ plugin = pluginViewIdCache.PluginInstance( viewId );
+ }
+
+ return *plugin;
+ }
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::SortPluginsL
+//
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CGSPluginLoader::SortPluginsL(
+ CArrayPtrFlat<CGSPluginInterface>* aPlugins )
+ {
+ RPointerArray<CGSPluginInterface> plugins;
+ TLinearOrder<CGSPluginInterface> order( CGSPluginLoader::Compare );
+
+ // Insertion will also order
+ for( TInt i = 0; i < aPlugins->Count(); i++ )
+ {
+ plugins.InsertInOrderL( (*aPlugins)[i], order );
+ }
+
+ // Replace original array content with sorted items
+ aPlugins->Reset();
+ for( TInt i = 0; i < plugins.Count(); i++ )
+ {
+ aPlugins->AppendL( plugins[i] );
+ }
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::Compare
+//
+// Compare two plugins.
+// Precedence:
+// [1. plugin provider category]
+// 2. plugin order number
+// 3. plugin caption
+// Plugin provider gategory is currently disabled (not supported yet).
+// ----------------------------------------------------------------------------
+//
+TInt CGSPluginLoader::Compare( const CGSPluginInterface& aFirst,
+ const CGSPluginInterface& aSecond )
+ {
+ TInt comparison = CompareCategory( aFirst, aSecond );
+ if( comparison == KGSComparisonEqual )
+ {
+ comparison = CompareIndex( aFirst, aSecond );
+ if( comparison == KGSComparisonEqual )
+ {
+ comparison = CompareCaption( aFirst, aSecond );
+ }
+ }
+ return comparison;
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::InsertPluginInOrderL
+//
+// ----------------------------------------------------------------------------
+//
+void CGSPluginLoader::InsertPluginInOrderL(
+ CGSPluginInterface* aPlugin,
+ CArrayPtrFlat<CGSPluginInterface>* aPlugins )
+ {
+ CGSPluginInterface* comparedPlugin;
+ TInt comparison = 0;
+ TBool inserted = EFalse;
+
+ for( TInt i = 0; i < aPlugins->Count(); i++ )
+ {
+ comparedPlugin = (*aPlugins)[i];
+ // Optimization: do not call time consuming Compare() multiple times!
+ comparison = Compare( *aPlugin, *comparedPlugin );
+ if( comparison < 0 )
+ {
+ aPlugins->InsertL( i, aPlugin );
+ inserted = ETrue;
+ break;
+ }
+ else if( comparison == 0 )
+ {
+ aPlugins->InsertL( i+1, aPlugin );
+ inserted = ETrue;
+ break;
+ }
+ }
+ // Plugin was not before any other plugin - make sure it's appended
+ if( !inserted )
+ {
+ aPlugins->AppendL( aPlugin );
+ }
+
+ #ifdef _GS_PLUGINLOADER_ITERATION_SORTING_TRACES
+ PrintOrderTracesL( aPlugins );
+ #endif // _GS_PLUGINLOADER_ITERATION_SORTING_TRACES
+
+ }
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::CompareCategory
+//
+// ----------------------------------------------------------------------------
+//
+void CGSPluginLoader::PrintOrderTracesL(
+ CArrayPtrFlat<CGSPluginInterface>* aPlugins )
+ {
+ __GSLOGSTRING1( "---[CGSPluginLoader] Sorted list for 0x%X---", iParentUid.iUid );
+ HBufC* name = HBufC::New( KGSCaptionSize );
+ CleanupStack::PushL( name );
+
+ TPtr ptr = name->Des();
+ CGSPluginInterface* plg;
+
+ for( TInt i = 0; i < aPlugins->Count(); i++ )
+ {
+ plg = (*aPlugins)[i];
+ plg->GetCaptionL( ptr );
+ __GSLOGSTRING4( "[CGSPluginLoader] Sorted list[%d] Category:%d (0x%X) %S",
+ plg->iOrder,
+ plg->PluginProviderCategory(),
+ plg->Id().iUid,
+ &ptr );
+ }
+ CleanupStack::PopAndDestroy( name );
+
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::CompareCategory
+//
+//
+// ----------------------------------------------------------------------------
+//
+TInt CGSPluginLoader::CompareCategory( const CGSPluginInterface& aFirst,
+ const CGSPluginInterface& aSecond )
+ {
+#ifdef RD_GS_COMPARE_BY_CATEGORY
+ TInt comparison = KGSComparisonBefore;//KGSComparisonEqual;
+
+ // Compare if a is before b:
+ TInt a = aFirst.PluginProviderCategory();
+ TInt b = aSecond.PluginProviderCategory();
+
+ // Cannot use less/greater comparison because int values used in here
+ // (KGSPluginProviderInternal) must not be revealed to 3rd parties.
+ if( a != b )
+ {
+ switch ( a )
+ {
+/* case KGSPluginProviderInternal:
+ if( b != KGSPluginProviderInternal )
+ {
+ comparison = KGSComparisonAfter;
+ }
+ break;*/
+ case CGSPluginInterface::EGSPluginProviderOEM:
+ if( b == KGSPluginProviderInternal )
+ {
+ comparison = KGSComparisonAfter;
+ }
+ break;
+ case CGSPluginInterface::EGSPluginProviderOperator:
+ if( b == KGSPluginProviderInternal ||
+ b == CGSPluginInterface::EGSPluginProviderOEM )
+ {
+ comparison = KGSComparisonAfter;
+ }
+ break;
+ case CGSPluginInterface::EGSPluginProvider3rdParty:
+ if( b == KGSPluginProviderInternal ||
+ b == CGSPluginInterface::EGSPluginProviderOEM ||
+ b == CGSPluginInterface::EGSPluginProviderOperator )
+ {
+ comparison = KGSComparisonAfter;
+ }
+ break;
+ default:
+ comparison = KGSComparisonBefore;
+ break;
+ }
+ }
+ else
+ {
+ comparison = KGSComparisonEqual;
+ }
+
+ return comparison;
+
+#else //RD_GS_COMPARE_BY_CATEGORY
+ #pragma message("Comparing by category DISABLED")
+ // Force comparison to equal so category comparison will not matter. If
+ // comparison by gategory is needed, simply remove the line below:
+ return KGSComparisonEqual;
+#endif //RD_GS_COMPARE_BY_CATEGORY
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::CompareCaption
+//
+//
+// ----------------------------------------------------------------------------
+//
+TInt CGSPluginLoader::CompareCaption( const CGSPluginInterface& aFirst,
+ const CGSPluginInterface& aSecond )
+ {
+ HBufC* firstCaptionBuf = HBufC::New( KGSCaptionSize );
+ HBufC* secondCaptionBuf = HBufC::New( KGSCaptionSize );
+ TPtr firstCaption = firstCaptionBuf->Des();
+ TPtr secondCaption = secondCaptionBuf->Des();
+ TInt comparison = KGSComparisonEqual;
+
+ TRAPD( err, aFirst.GetCaptionL( firstCaption ); );
+ TRAPD( err2, aSecond.GetCaptionL( secondCaption ); );
+
+ if( err == KErrNone && err2 == KErrNone )
+ {
+ // CompareC return value must be converted to KGSComparisonXXX value.
+ TInt result = secondCaption.CompareC( firstCaption );
+ if( result < 0 )
+ {
+ comparison = KGSComparisonAfter;
+ }
+ else if( result > 0 )
+ {
+ comparison = KGSComparisonBefore;
+ }
+ }
+ delete firstCaptionBuf;
+ delete secondCaptionBuf;
+ return comparison;
+ }
+
+
+// ----------------------------------------------------------------------------
+// CGSPluginLoader::CompareIndex
+//
+//
+// ----------------------------------------------------------------------------
+//
+TInt CGSPluginLoader::CompareIndex( const CGSPluginInterface& aFirst,
+ const CGSPluginInterface& aSecond )
+ {
+ TInt comparison = KGSComparisonEqual;
+
+ // The plugin having index is before the one not having one
+
+ if( aFirst.iOrder == KGSPluginNotIndexed &&
+ aSecond.iOrder == KGSPluginNotIndexed )
+ {
+ // Neither have index -> equal
+ comparison = KGSComparisonEqual;
+ }
+ else if( aFirst.iOrder == KGSPluginNotIndexed )
+ {
+ // The plugin having index is before the one not having one
+ comparison = KGSComparisonAfter;
+ }
+ else if( aSecond.iOrder == KGSPluginNotIndexed )
+ {
+ // The plugin having index is before the one not having one
+ comparison = KGSComparisonBefore;
+ }
+ else if( aFirst.iOrder < aSecond.iOrder )
+ {
+ // Compare actual index values
+ comparison = KGSComparisonBefore;
+ }
+ else if( aFirst.iOrder > aSecond.iOrder )
+ {
+ // Compare actual index values
+ comparison = KGSComparisonAfter;
+ }
+
+ return comparison;
+ }
+
+
+
+EXPORT_C void CGSPluginLoader::RequestPriority( CActive::TPriority aPriority )
+ {
+ iRequestedPriority = aPriority;
+ }
+
+
+// End of File