mpx/commonframework/common/src/mpxpluginhandlerbase.cpp
changeset 0 a2952bb97e68
child 50 762d760dcfdf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mpx/commonframework/common/src/mpxpluginhandlerbase.cpp	Thu Dec 17 08:55:47 2009 +0200
@@ -0,0 +1,1109 @@
+/*
+* Copyright (c) 2006 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:  Base plugin handler
+*
+*  CMPXPluginHandlerBase instantiates and owns a CMPXPluginMonitor to monitor
+*  plugins for the designated plugin interface. When a plugin for that plugin
+*  interface is added/removed, PluginsChangedL is called. This base plugin
+*  handler provides a default implementation for PluginsChangedL which requests
+*  child class to perform plugin resolution.
+*
+*  CMPXPluginHandlerBase also provides plugin selection plugin APIs. These
+*  methods set up the selection criteria and then request child class to
+*  resolve these selection criteria to a plugin via ResolvePluginL.
+*
+*
+*/
+
+
+
+#include <bamdesca.h>
+#include <badesca.h>
+#include <uri16.h>
+#include <apgcli.h>
+
+#include <mpxlog.h>
+#include <mpxuser.h>
+#include <mpxpluginmonitor.h>
+#include <mpxcmn.h>
+#include <mpxplugininfo.h>
+#include "mpxpluginhandlerobserver.h"
+#include "mpxpluginhandlerbase.h"
+
+// CONSTANTS
+
+// ============================ LOCAL FUNCTIONS ==============================
+
+// ---------------------------------------------------------------------------
+// Local function to cleanup an array
+// ---------------------------------------------------------------------------
+//
+static void CleanupPluginInfoArray(
+    TAny* item)
+    {
+    ((RPointerArray<CMPXPluginInfo>*)item)->ResetAndDestroy();
+    ((RPointerArray<CMPXPluginInfo>*)item)->Close();
+    }
+
+// ============================ MEMBER FUNCTIONS ==============================
+
+// ----------------------------------------------------------------------------
+// Constructor.
+// ----------------------------------------------------------------------------
+//
+EXPORT_C CMPXPluginHandlerBase::CMPXPluginHandlerBase(
+    TUid aInterfaceUid,
+    TPluginSelection aSelection,
+    TInt aSelectionType,
+    MMPXPluginHandlerObserver& aObserver,
+    CMPXPluginMonitor* aPluginMonitor/*=NULL*/)
+:   iObserver(aObserver),
+    iInterfaceUid(aInterfaceUid),
+    iPluginMonitor(aPluginMonitor),
+    iSelection(aSelection),
+    iSelectedType(aSelectionType)
+    {
+    iOwnedPluginMonitor = iPluginMonitor ? EFalse : ETrue;
+    }
+
+// ----------------------------------------------------------------------------
+// 2nd phase constructor.
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::BaseConstructL()
+    {
+    CreatePluginListL();
+    if (iOwnedPluginMonitor)
+        {
+        iPluginMonitor = CMPXPluginMonitor::NewL(iInterfaceUid);
+        }
+    iPluginMonitor->AddObserverL(*this);
+    }
+
+// ----------------------------------------------------------------------------
+// Destructor.
+// ----------------------------------------------------------------------------
+//
+EXPORT_C CMPXPluginHandlerBase::~CMPXPluginHandlerBase()
+    {
+    if ( iPluginMonitor )
+        {
+        TRAP_IGNORE( iPluginMonitor->RemoveObserverL( *this ) );
+        }
+    if (iOwnedPluginMonitor)
+        {
+        delete iPluginMonitor;
+        }
+    delete iDataType;
+    delete iScheme;
+    delete iExt;
+
+    iPluginInfoArray.ResetAndDestroy();
+    }
+// ----------------------------------------------------------------------------
+// Select this specific plugin
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::SelectPluginL(const TUid& aPluginUid)
+    {
+    MPX_DEBUG2("CMPXPluginHandlerBase::SelectPluginL(Uid 0x%08x)", aPluginUid.iUid);
+
+    ClearSelectionCriteria();
+
+    iSelection=ESelectionUid;
+    iSelectedUid=aPluginUid;
+
+    ResolvePluginL();
+    MPX_DEBUG1("<--CMPXPluginHandlerBase::SelectPluginL() exits");
+    }
+
+// ----------------------------------------------------------------------------
+// select the plugin with the specified name
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::SelectPluginL(const TDesC& aPluginName)
+    {
+    MPX_DEBUG2("CMPXPluginHandlerBase::SelectPluginL(PluginName %S)", &aPluginName);
+
+    SelectPluginL( PluginUid( aPluginName ) );
+    MPX_DEBUG1("<--CMPXPluginHandlerBase::SelectPluginL() exits");
+    }
+
+// ----------------------------------------------------------------------------
+// Set up selection criteria, e.g. data type, extension, and scheme and then
+// resolve plugin
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::SelectPluginL(
+    const TDesC& aUri,
+    const TDesC8& aDataType)
+    {
+    MPX_FUNC("CMPXPluginHandlerBase::PluginL");
+
+    delete iScheme;
+    iScheme=NULL;
+    delete iExt;
+    iExt=NULL;
+    delete iDataType;
+    iDataType=NULL;
+
+    TPtrC fullpath;
+    TUriParser up;
+    TParse fp;
+    //
+    // Is it a valid URI, or even full path (e.g. c:\\data\test.mp3")
+    //
+    if (up.Parse(aUri)==KErrNone)
+        {
+        const TDesC& uriScheme=up.Extract(EUriScheme);
+        //
+        // Could be just drive letter if path
+        // which isn't really a scheme
+        //
+        if (uriScheme.Length()>1)
+             {
+             iScheme=MPXUser::Alloc8L(uriScheme);
+             }
+         else if (fp.Set(aUri,NULL,NULL)==KErrNone) // Must be a full path
+             {
+             fullpath.Set(fp.FullName());
+             }
+         else
+             {
+             User::Leave(KErrArgument);
+             }
+        //
+        // Get the extension
+        //
+        iExt=MPXUser::Alloc8L(fp.Ext());
+        }
+    if (aDataType.Length())
+        {
+        iDataType=aDataType.AllocL();
+        }
+    else if (fullpath.Length())
+        {
+        RApaLsSession aps;
+        TInt error  = aps.Connect(); // always fail in console test
+        if (KErrNone == error)
+            {
+            CleanupClosePushL(aps);
+            TDataType dataType;
+            TUid ignore;
+            if(aps.AppForDocument(fullpath,ignore,dataType)==KErrNone)
+                {
+                iDataType=dataType.Des8().AllocL();
+                }
+            CleanupStack::PopAndDestroy(&aps);
+            } // else APPARC is not working in Console environment,
+              // Always find plugin by scheme & etension
+        }
+    else
+        {
+        if ( !iScheme ) // last valid case
+            {
+            User::Leave(KErrArgument);
+            }
+        }
+
+    ResolvePluginL();
+    }
+
+// ----------------------------------------------------------------------------
+// Select a plugin with the specific type
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::SelectPluginL(TInt aPluginType)
+    {
+    MPX_DEBUG2("CMPXPluginHandlerBase::SelectPluginL(PluginType %x)", aPluginType);
+
+    ClearSelectionCriteria();
+    iSelectedType=aPluginType;
+    ResolvePluginL();
+    MPX_DEBUG1("<--CMPXPluginHandlerBase::SelectPluginL() exits");
+    }
+
+// ----------------------------------------------------------------------------
+// select plug-in appropriate for a file
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::SelectPluginL(const RFile& aFile)
+    {
+    MPX_FUNC("CMPXPluginHandlerBase::SelectPluginL(RFile)");
+
+    TFileName fn;
+    User::LeaveIfError(aFile.FullName(fn));
+    SelectPluginL(fn, KNullDesC8);
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXPluginHandlerBase::UsePlugin
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::UsePlugin(
+    const TUid& aPluginUid)
+    {
+    MPX_FUNC_EX("CMPXPluginHandlerBase::UsePlugin");
+
+    TInt index(IndexOf(aPluginUid));
+    if (index != KErrNotFound)
+        {
+        iPluginInfoArray[index]->ReferenceCount()++;
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXPluginHandlerBase::ReleasePlugin
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TBool CMPXPluginHandlerBase::ReleasePlugin(
+    const TUid& aPluginUid)
+    {
+    MPX_FUNC_EX("CMPXPluginHandlerBase::ReleasePlugin");
+
+    TBool unload(EFalse);
+    TInt index(IndexOf(aPluginUid));
+    if (index != KErrNotFound)
+        {
+        TInt& refCount = iPluginInfoArray[index]->ReferenceCount();
+        refCount--;
+
+        if (!refCount)
+            {
+            UnloadPlugin(aPluginUid);
+            unload = ETrue;
+            }
+        }
+
+    return unload;
+    }
+
+// ----------------------------------------------------------------------------
+// Get current selection criteria
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::GetSelectionCriteria(
+    TPluginSelection& aPluginSelection,
+    TInt& aPluginType,
+    TUid& aPluginUid,
+    TPtrC8& aDataType,
+    TPtrC8& aScheme,
+    TPtrC8& aExtension)
+    {
+    aPluginSelection=iSelection;
+    aPluginType=iSelectedType;
+    aPluginUid=iSelectedUid;
+
+    aDataType.Set(*iDataType);
+    aScheme.Set(*iScheme);
+    aExtension.Set(*iExt);
+    }
+
+// ----------------------------------------------------------------------------
+// Clear current selection criteria
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::ClearSelectionCriteria()
+    {
+    iSelection=ESelectionType;
+    iSelectedType=0; // unknown type. this info is unknown
+    iSelectedUid=KNullUid;
+
+    delete iScheme;
+    iScheme=NULL;
+    delete iExt;
+    iExt=NULL;
+    delete iDataType;
+    iDataType=NULL;
+    }
+
+// ----------------------------------------------------------------------------
+// Resolve a plugin, based on properties (iDataType, iExt and iScheme)
+// and selection criteria. If selection is by type, then there is always a
+// plug-in resolved (if there are any of that type).
+// TO-DO: Room for optimisation
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::DoResolvePluginL(
+    TUid& aPluginUid,
+    TInt& aIndex,
+    TPtrC& aDisplayName,
+    TInt& aPluginType)
+    {
+    MPX_DEBUG2("===>CMPXPluginHandlerBase::DoResolvePluginL 0x%08x", this);
+    TInt index=KErrNotFound;
+    if (iSelection==ESelectionUid)
+        {
+        index=IndexOf(iSelectedUid);
+        }
+    else // if (iSelection==ESelectionType)
+        {
+        TInt score=0;
+        TInt maxScore=0;
+
+        TInt count(iPluginInfoArray.Count());
+        for(TInt i = 0; i < count; ++i)
+            {
+            // Must scan from beginning of plugin info array, because plugins
+            // sorted by priority descendingly
+            score=0;
+
+            //
+            // First, try scheme then data type, then extension
+            // and total up the points
+            //
+            HBufC* hbuf = NULL;
+            TInt pos(0);
+            const CDesCArray& schemas = iPluginInfoArray[i]->SupportedSchemas();
+            if (schemas.MdcaCount() && iScheme)
+                {
+                if (iScheme->Length())
+                    {
+                    hbuf = MPXUser::AllocL(*iScheme);
+                    if (!schemas.FindIsq(*hbuf, pos))
+                        { // schema supported by the plugin
+                        score+=4;
+                        }
+                    delete hbuf;
+                    hbuf=NULL;
+                    }
+                } // else schema not supported
+
+            if (iDataType)
+                {
+                hbuf = MPXUser::AllocL(*iDataType);
+                if (!iPluginInfoArray[i]->SupportedMimeTypes().FindIsq(*hbuf, pos))
+                    { // mime type supported by the plugin
+                    score+=3;
+                    }
+                delete hbuf;
+                hbuf=NULL;
+                }
+
+            if (iExt)
+                {
+                hbuf = MPXUser::AllocL(*iExt);
+                if (!iPluginInfoArray[i]->SupportedExtensions().FindIsq(*hbuf, pos))
+                    { // extension supported by the plugin
+                    score+=2;
+                    }
+                delete hbuf;
+                hbuf=NULL;
+                }
+
+            if (iSelectedType == iPluginInfoArray[i]->PluginType().iUid)
+                {
+                score+=1; // Just for being the right "type"
+                }
+
+            if (score > maxScore)
+                {
+                maxScore=score;
+                index=i;
+                }
+            }
+        }
+
+    if (index==KErrNotFound)
+        {
+        User::Leave(KErrNotSupported);
+        }
+
+    //
+    // set return values
+    //
+    aPluginUid = iPluginInfoArray[index]->ImplementationUid();
+    aIndex = index;
+    aDisplayName.Set(iPluginInfoArray[index]->DisplayName());
+    aPluginType = iPluginInfoArray[index]->PluginType().iUid;
+
+#ifdef _DEBUG
+    PrintPluginInfo();
+#endif
+
+    MPX_DEBUG5("<===CMPXPluginHandlerBase::DoResolvePluginL 0x%08x (aPluginUid 0x%08x, aIndex %d, aDisplayName %S)",
+               this, aPluginUid.iUid, aIndex, &aDisplayName);
+    }
+
+// ----------------------------------------------------------------------------
+// Handles request completion event
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::PluginsChangedL()
+    {
+    MPX_DEBUG2("===> CMPXPluginHandlerBase::PluginsChangedL 0x%08x", this);
+    CreatePluginListL();
+    ResolvePluginL();
+    MPX_DEBUG2("<=== CMPXPluginHandlerBase::PluginsChangedL 0x%08x", this);
+    }
+
+// ----------------------------------------------------------------------------
+// Handles a plugin unload request
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::HandlePluginUnload(
+    const TUid& aPluginUid)
+    {
+    UnloadPlugin(aPluginUid);
+    }
+
+// ----------------------------------------------------------------------------
+// Resolve a plugin
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::ResolvePluginL()
+    {
+    // Do nothing in base class
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXPluginHandlerBase::IsPluginLoaded
+// This method had to be made virtual (and not pure virtual) because
+// the playlist engine instantiates the base class.
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TBool CMPXPluginHandlerBase::IsPluginLoaded(
+    const TUid& /* aPluginUid */)
+    {
+    return EFalse;
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXPluginHandlerBase::LoadPluginL
+// This method had to be made virtual (and not pure virtual) because
+// the playlist engine instantiates the base class.
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::LoadPluginL(
+    const TUid& /* aPluginUid */)
+    {
+    // do nothing
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXPluginHandlerBase::UnloadPlugin
+// This method had to be made virtual (and not pure virtual) because
+// the playlist engine instantiates the base class.
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::UnloadPlugin(
+    const TUid& /* aPluginUid */)
+    {
+    // do nothing
+    }
+
+// ----------------------------------------------------------------------------
+// Return a new instance of the plugin info class
+// ----------------------------------------------------------------------------
+//
+EXPORT_C CMPXPluginInfo* CMPXPluginHandlerBase::ConstructPluginInfoLC(
+                                     const CImplementationInformation& aData  )
+    {
+    return CMPXPluginInfo::NewLC( aData );
+    }
+
+
+// ----------------------------------------------------------------------------
+// Return plugin name which supports the specified type
+// ----------------------------------------------------------------------------
+//
+EXPORT_C const TDesC& CMPXPluginHandlerBase::PluginName(
+    TInt aPluginType) const
+    {
+    const TDesC* name=&KNullDesC;
+    for ( TInt i=iPluginInfoArray.Count(); --i >= 0 ; )
+        {
+        if ( aPluginType == iPluginInfoArray[i]->PluginType().iUid )
+            {
+            name = &(iPluginInfoArray[i]->DisplayName());
+            break;
+            }
+        }
+    return *name;
+    }
+
+// ----------------------------------------------------------------------------
+// Return plugin name which supports the specified uid
+// ----------------------------------------------------------------------------
+//
+EXPORT_C const TDesC& CMPXPluginHandlerBase::PluginName(const TUid& aUid) const
+    {
+    const TDesC* name=&KNullDesC;
+    TInt index(IndexOf(aUid));
+    MPX_ASSERT(KErrNotFound!=index && index<iPluginInfoArray.Count());
+    name = &iPluginInfoArray[index]->DisplayName();
+    return *name;
+    }
+
+// ----------------------------------------------------------------------------
+// Return a list of plugin names
+// ----------------------------------------------------------------------------
+//
+EXPORT_C CDesCArray* CMPXPluginHandlerBase::PluginNamesL()
+    {
+    CDesCArray* desArray = new(ELeave)CDesCArrayFlat(KMPXArrayGranularity);
+    CleanupStack::PushL(desArray);
+    for(TInt i=iPluginInfoArray.Count(); --i>=0 ;)
+        {
+        HBufC* item = iPluginInfoArray[i]->DisplayName().AllocLC();
+
+        //ignore leave when insert the same item
+        TRAP_IGNORE(desArray->InsertIsqL(*item));
+        CleanupStack::PopAndDestroy(item);
+        }
+    CleanupStack::Pop(desArray);
+    return desArray;
+    }
+
+// ----------------------------------------------------------------------------
+// returns a list of plugin types
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::GetPluginTypes(RArray<TInt>& aTypes) const
+    {
+    aTypes.Reset();
+    TInt count(iPluginInfoArray.Count());
+    for(TInt i=0; i<count; ++i)
+        {
+        aTypes.Append(iPluginInfoArray[i]->PluginType().iUid);
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// Return the list of UIDs of all plugins
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::GetPluginUids(RArray<TUid>& aUids) const
+    {
+    aUids.Reset();
+    TInt count(iPluginInfoArray.Count());
+    for(TInt i=0; i<count; ++i)
+        {
+        aUids.Append(iPluginInfoArray[i]->ImplementationUid());
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// Get plugin list with the specific type
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::GetPluginUidsL(
+    RArray<TUid>& aPlugins,
+    TInt aPluginType) const
+    {
+    aPlugins.Reset();
+    for(TInt i=iPluginInfoArray.Count(); --i>=0 ;)
+        {
+        if (aPluginType == iPluginInfoArray[i]->PluginType().iUid)
+            {
+            aPlugins.Append(iPluginInfoArray[i]->ImplementationUid());
+            }
+        }
+    }
+
+// ----------------------------------------------------------------------------
+// Get plugin UID with the specified display name
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TUid CMPXPluginHandlerBase::PluginUid(const TDesC& aPluginName) const
+    {
+    TUid uid( KNullUid );
+
+    for(TInt i=iPluginInfoArray.Count();--i>=0;)
+        {
+        if ( aPluginName.Compare(iPluginInfoArray[i]->DisplayName()) == 0 )
+            {
+            uid = iPluginInfoArray[i]->ImplementationUid();
+            break;
+            }
+        }
+
+    return uid;
+    }
+
+// ----------------------------------------------------------------------------
+// returns the index of the specified plugin
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TInt CMPXPluginHandlerBase::IndexOf(const TUid& aPluginUid) const
+    {
+    TInt ret(KErrNotFound);
+    TInt count(iPluginInfoArray.Count());
+    for(TInt i=0; i<count; ++i)
+        {
+        if (iPluginInfoArray[i]->ImplementationUid()==aPluginUid)
+            {
+            ret = i;
+            break;
+            }
+        }
+    return ret;
+    }
+
+// ----------------------------------------------------------------------------
+// Return a list of mime types supported by the plugins
+// ----------------------------------------------------------------------------
+//
+EXPORT_C CDesCArray* CMPXPluginHandlerBase::SupportedMimeTypesL()
+    {
+    CDesCArray* descArray = new(ELeave)CDesCArrayFlat(KMPXArrayGranularity);
+    for(TInt i=iPluginInfoArray.Count();--i>=0;)
+        {
+        if( iPluginInfoArray[i] )
+        	{
+			MPXUser::MergeArray(iPluginInfoArray[i]->SupportedMimeTypes(),
+				                *descArray);
+        	}
+        }
+    return descArray;
+    }
+
+// ----------------------------------------------------------------------------
+// Return a list of extensions supported by the plugins
+// ----------------------------------------------------------------------------
+//
+EXPORT_C CDesCArray* CMPXPluginHandlerBase::SupportedExtensionsL()
+    {
+    CDesCArray* descArray = new(ELeave)CDesCArrayFlat(KMPXArrayGranularity);
+    for(TInt i=iPluginInfoArray.Count();--i>=0;)
+        {
+        MPXUser::MergeArray(iPluginInfoArray[i]->SupportedExtensions(),
+                            *descArray);
+        }
+    return descArray;
+    }
+
+// ----------------------------------------------------------------------------
+// Get plugin type for a given implementation UID
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TUid CMPXPluginHandlerBase::PluginType( const TUid& aUid ) const
+    {
+    TUid ret( KNullUid );
+    TInt count( iPluginInfoArray.Count() );
+    for( TInt i = 0; i < count; ++i )
+        {
+        if ( iPluginInfoArray[i]->ImplementationUid() == aUid )
+            {
+            ret = iPluginInfoArray[i]->PluginType();
+            break;
+            }
+        }
+    return ret;
+    }
+
+// ----------------------------------------------------------------------------
+// Get supported app uid for a given implementation UID
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TUid CMPXPluginHandlerBase::SupportedAppUid( const TUid& aUid ) const
+    {
+    TUid ret( KNullUid );
+    TInt count( iPluginInfoArray.Count() );
+    for( TInt i = 0; i < count; ++i )
+        {
+        if ( iPluginInfoArray[i]->ImplementationUid() == aUid )
+            {
+            ret = iPluginInfoArray[i]->SupportedAppUid();
+            MPX_DEBUG2("SupportedAppUid = %d", ret);
+            break;
+            }
+        }
+    return ret;
+    }
+
+// ----------------------------------------------------------------------------
+// Get plugin type for a given implementation UID
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TUint CMPXPluginHandlerBase::PluginFlagsL( const TUid& aUid ) const
+    {
+    TUint ret( 0 );
+    TInt count( iPluginInfoArray.Count() );
+    TBool found( EFalse );
+    for( TInt i = 0; !found && i < count; ++i )
+        {
+        if ( iPluginInfoArray[i]->ImplementationUid() == aUid )
+            {
+            ret = iPluginInfoArray[i]->Flags();
+            found = ETrue;
+            }
+        }
+    if ( !found )
+        {
+        User::Leave( KErrNotFound );
+        }
+    return ret;
+    }
+
+// ----------------------------------------------------------------------------
+// Return a list of schemas supported by the plugins
+// ----------------------------------------------------------------------------
+//
+EXPORT_C CDesCArray* CMPXPluginHandlerBase::SupportedSchemasL()
+    {
+    CDesCArray* descArray = new(ELeave)CDesCArrayFlat(KMPXArrayGranularity);
+    for(TInt i=iPluginInfoArray.Count();--i>=0;)
+        {
+        MPXUser::MergeArray(iPluginInfoArray[i]->SupportedSchemas(),
+                            *descArray);
+        }
+    return descArray;
+    }
+
+// ----------------------------------------------------------------------------
+// Return a list of mime types supported by the plugins
+// ----------------------------------------------------------------------------
+//
+EXPORT_C CDesCArray* CMPXPluginHandlerBase::SupportedMimeTypesL(const TUid& aUid)
+    {
+    CDesCArray* descArray = new(ELeave)CDesCArrayFlat(KMPXArrayGranularity);
+    CleanupStack::PushL(descArray);
+    for(TInt i=iPluginInfoArray.Count();--i>=0;)
+        {
+        if (aUid == iPluginInfoArray[i]->ImplementationUid())
+            {
+            MPXUser::CopyArrayL(iPluginInfoArray[i]->SupportedMimeTypes(),
+                            *descArray);
+            break;
+            }
+        }
+    CleanupStack::Pop(descArray);
+    return descArray;
+    }
+
+// ----------------------------------------------------------------------------
+// Return a list of extensions supported by the plugins
+// ----------------------------------------------------------------------------
+//
+EXPORT_C CDesCArray* CMPXPluginHandlerBase::SupportedExtensionsL(const TUid& aUid)
+    {
+    CDesCArray* descArray = new(ELeave)CDesCArrayFlat(KMPXArrayGranularity);
+    CleanupStack::PushL(descArray);
+    for(TInt i=iPluginInfoArray.Count();--i>=0;)
+        {
+        if (aUid == iPluginInfoArray[i]->ImplementationUid())
+            {
+            MPXUser::CopyArrayL(iPluginInfoArray[i]->SupportedExtensions(),
+                            *descArray);
+            break;
+            }
+        }
+    CleanupStack::Pop(descArray);
+    return descArray;
+    }
+
+// ----------------------------------------------------------------------------
+// Recreates the list of plugins. Handles the scenarios of plugin update,
+// addition and removal by comparing the previous list with the current one.
+// In case any change is detected to the plugin list the observer interface is
+// used to notify the owner.
+//
+// NOTE: ECOM takes care of versioning for us. When two plugins that implement
+// the same interface and have the same implementation UID are detected, it loads
+// the one with the higher version. There is no way to have two implementations
+// of the same interface that share the implementation UID returned by
+// REComSession::ListImplementationsL.
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::CreatePluginListL()
+    {
+    MPX_DEBUG_THREAD("CMPXPluginHandlerBase::CreatePluginListL");
+    // Get the current list of plugins that implement the interface
+    // The ECOM versioning mechanism is appied here.
+    // Auto destroy array, no need to call ResetAndDestroy and Close
+    RMPXPointerArray<CImplementationInformation> implInfoArray;
+    REComSession::ListImplementationsL(iInterfaceUid, implInfoArray);
+
+    // Temporary array to store the new plugin infos.
+    RPointerArray<CMPXPluginInfo> tempInfoArray;
+    CleanupStack::PushL(TCleanupItem(CleanupPluginInfoArray, &tempInfoArray));
+
+    // Reused variables
+    CMPXPluginInfo* prevInfo(NULL);
+    TBool loaded(EFalse);
+
+    // Iterate the new plugins
+    // It is expected that when the loop ends the temporary array will contain
+    // all current plugins and iPluginInfoArray will contain the plugins that
+    // have been removed
+    TInt count(implInfoArray.Count());
+    MPX_DEBUG3("CMPXPluginHandlerBase::CreatePluginListL numbers of the plugin 0x%08x %d",
+                this, count);
+    TInt index(0);
+    CMPXPluginInfo* info(NULL);
+    for (; index < count; ++index)
+        {
+        // Convert to an internal plugin info instance
+        info = ConstructPluginInfoLC(*implInfoArray[index]);
+        const TUid& uid = info->ImplementationUid();
+
+        // Check if the plugin existed in the previous list
+        TInt prevIndex = IndexOf(uid);
+        if (prevIndex != KErrNotFound)
+            {
+            // The plugin existed before the update
+            prevInfo = iPluginInfoArray[prevIndex];
+            MPX_DEBUG5("Process the existing plugin 0x%08x uid 0x%08x, old version %d new version %d",
+                       this, uid.iUid, prevInfo->Version(), info->Version());
+            // Copy the reference count
+            info->ReferenceCount() = prevInfo->ReferenceCount();
+
+            // Compare the versions
+            if (prevInfo->Version() < info->Version())
+                {
+                // The plugin is being upgraded
+                loaded = IsPluginLoaded(uid);
+
+                // Generate an update start notification
+                iObserver.HandlePluginHandlerEvent(
+                    MMPXPluginHandlerObserver::EPluginUpdateStart, uid, loaded,
+                    info->Version());
+
+                // Check if this plugin was loaded. The plugin is still loaded if this is the first
+                // handler that got notified or it is already unloaded for any otehr handlers.
+                if (info->ReferenceCount())
+                    {
+                    if (loaded)
+                        {
+                        // Unload the old plugin version
+                        MPX_DEBUG2("CMPXPluginHandlerBase::CreatePluginListL unload old plugin 0x%08x", this);
+
+                        // The plugin is loaded - ask the monitor to tell all
+                        // handler instances (including this one) to unload it.
+                        // After the call below all plugin instances owned by
+                        // all monitors are unloaded.
+                        //
+                        // Only make this call if the plugin is still loaded,
+                        // i.e. from the first handler that detects the update.
+                        iPluginMonitor->NotifyUnload(uid);
+                        
+                        // Necessary to ensure version upgrade of ECom plugins
+                        // is successful. This call will unload any garbage
+                        // plugins. 
+                        REComSession::FinalClose();                       
+                        }
+
+                    MPX_DEBUG2("CMPXPluginHandlerBase::CreatePluginListL load new plugin 0x%08x", this);
+                    // Load the new plugin version
+                    LoadPluginL(uid);
+                    MPX_DEBUG2("CMPXPluginHandlerBase::CreatePluginListL load new plugin finished 0x%08x", this);
+                    }
+
+                // Generate an update end notification
+                iObserver.HandlePluginHandlerEvent(
+                    MMPXPluginHandlerObserver::EPluginUpdateEnd, uid, loaded,
+                    info->Version());
+                }
+
+            // Delete the entry from the info array
+            iPluginInfoArray.Remove(prevIndex);
+            delete prevInfo;
+            prevInfo = NULL;
+            }
+        else
+            {
+            MPX_DEBUG2("CMPXPluginHandlerBase::CreatePluginListL found new plugin 0x%08x", this);
+            // A new plugin is being added
+            iObserver.HandlePluginHandlerEvent(
+                MMPXPluginHandlerObserver::EPluginAdd, uid, EFalse, info->Version());
+            }
+
+        // Insert into the temporary array - order by priority, high priority first
+        tempInfoArray.InsertInOrderAllowRepeatsL(info,
+                                    CMPXPluginInfo::ComparePluginInfoByPriority);
+
+        CleanupStack::Pop(info);
+        }
+
+    // What is left in iPluginInfoArray are removed plugins
+    while (iPluginInfoArray.Count())
+        {
+        prevInfo = iPluginInfoArray[0];
+        const TUid& uid = prevInfo->ImplementationUid();
+
+        loaded = IsPluginLoaded(uid);
+        MPX_DEBUG3("CMPXPluginHandlerBase::CreatePluginListL plugin removed 0x%08x uid  0x%08x",
+                   this, uid.iUid);
+        // Generate an remove notification
+        iObserver.HandlePluginHandlerEvent(
+            MMPXPluginHandlerObserver::EPluginRemove, uid, loaded,
+            prevInfo->Version());
+
+        // Check if the plugin is currently loaded
+        if (loaded)
+            {
+            // Unload the plugin
+            UnloadPlugin(uid);
+            }
+
+        iPluginInfoArray.Remove(0);
+        delete prevInfo;
+        prevInfo = NULL;
+        }
+
+    // iPluginInfoArray should be empty and the temp array should contain all new plugins
+    // Copy the pointers to iPluginInfoArray - the ownership is transferred
+    for (index = 0; index < count; ++index)
+        {
+        info = tempInfoArray[0];
+        iPluginInfoArray.AppendL(info);
+        tempInfoArray.Remove(0);
+        // check if this plugin should be pre-loaded and not loaded yet
+        if (info->Flags() & EMPXPluginFlagPreLoad && info->ReferenceCount() == 0)
+            {
+            // pre-load the plugin - have to go through SelectPluginL
+            // to apply the reference counting consistently
+            TRAP_IGNORE(SelectPluginL(info->ImplementationUid()));
+            }
+        }
+
+    // Reset the temp array - this does not delete the plugin info instances pointed to
+    // from the array - these were copied to iPluginInfoArray
+    CleanupStack::Pop(); // TCleanupItem(CleanupPluginInfoArray, &tempInfoArray)
+    tempInfoArray.Close();
+    }
+
+// ----------------------------------------------------------------------------
+// CMPXPluginHandlerBase::SupportUids
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TBool CMPXPluginHandlerBase::SupportUids(
+    const TUid& aPluginId,
+    const TArray<TUid>& aUids) const
+    {
+    TInt index(IndexOf(aPluginId));
+    MPX_ASSERT(index!=KErrNotFound && index < iPluginInfoArray.Count());
+    return iPluginInfoArray[index]->SupportUids(aUids);
+    }
+
+// ----------------------------------------------------------------------------
+// Search a plugin by matching implementation id, supported id and plugin type
+// If two plugins get the same score, high priority plugin's implementation
+// uid will be returned
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TUid CMPXPluginHandlerBase::FindPlugin(const TArray<TUid>& aUids) const
+    {
+	MPX_DEBUG1("#### MPX Plugins ####");
+    TInt count(iPluginInfoArray.Count());
+    for (TInt index = 0; index < count; ++index)
+        {
+        CMPXPluginInfo* info = iPluginInfoArray[index];
+        const TDesC& name = info->DisplayName();
+        MPX_DEBUG5("%S [0x%08X] Priority: %d Ref Count: %d", &name, info->ImplementationUid(),
+            info->Priority(), info->ReferenceCount());
+        MPX_DEBUG2("Version %d", info->Version());
+        }
+
+    TInt lastScore( 0 );
+    CMPXPluginInfo* mostPossiblePluginInfo( NULL );
+    TUid uid = TUid::Null();
+
+    // Find the most suitable plugin
+    for ( TInt i = iPluginInfoArray.Count(); --i >= 0; )
+        {
+        TInt score( 0 );
+        CMPXPluginInfo* info = iPluginInfoArray[i];
+        const TArray<TUid> supportedUids = info->SupportedUids();
+
+        for ( TInt j = aUids.Count(); --j >= 0; )
+            {
+            for (TInt k=supportedUids.Count(); --k >=0;)
+                {
+                if ( aUids[j] ==  supportedUids[k] )
+                   {
+                   // Five scores if in the supported uids list.
+                   score += 5;
+
+                   // We now allow a UID to be repeated multiple times
+                   // for emphasized scoring.
+                   //break;
+                   }
+                }
+            if (info->ImplementationUid() == aUids[j])
+                {
+                score += 100;
+                }
+            if ( info->PluginType() == aUids[j])
+                { // One more if match plugin type
+                score++;
+                }
+            }
+
+        if ( score )
+            {
+            if ( lastScore < score )
+                {
+                lastScore = score;
+                mostPossiblePluginInfo = info;
+                }
+            else if ( lastScore == score )
+                {
+                // Use priority to determine if scores are the same
+                // If same priorities are detected, the first found plugin
+                // will be used.
+                if (mostPossiblePluginInfo->Priority() < info->Priority())
+                    {
+                    mostPossiblePluginInfo = info;
+                    }
+                } // else do nothing
+            }
+        }
+    if (mostPossiblePluginInfo)
+        {
+        uid =  mostPossiblePluginInfo->ImplementationUid();
+        }
+    return uid;
+    }
+
+#ifdef _DEBUG
+
+// ----------------------------------------------------------------------------
+// CMPXPluginHandlerBase::PrintPluginInfo
+// ----------------------------------------------------------------------------
+//
+void CMPXPluginHandlerBase::PrintPluginInfo()
+    {
+    MPX_DEBUG1("#### MPX Plugins ####");
+
+    TInt count(iPluginInfoArray.Count());
+    for (TInt index = 0; index < count; ++index)
+        {
+        CMPXPluginInfo* info = iPluginInfoArray[index];
+        const TDesC& name = info->DisplayName();
+        MPX_DEBUG5("%S [0x%08X] Priority: %d Ref Count: %d", &name, info->ImplementationUid(),
+            info->Priority(), info->ReferenceCount());
+        MPX_DEBUG2("Version %d", info->Version());
+        }
+    }
+
+#endif
+
+#ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
+// ----------------------------------------------------------------------------
+// select plug-in appropriate for a file
+// ----------------------------------------------------------------------------
+//
+EXPORT_C void CMPXPluginHandlerBase::SelectPlugin64L(const RFile64& aFile)
+    {
+    MPX_FUNC("CMPXPluginHandlerBase::SelectPlugin64L(RFile64)");
+
+    TFileName fn;
+    User::LeaveIfError(aFile.FullName(fn));
+    SelectPluginL(fn, KNullDesC8);
+    }
+#endif // SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
+
+// End of file