mmappcomponents/mmmtpdataprovider/mmmtpdpplugins/mediamtpdataprovider/src/cmediamtpdataproviderenumerator.cpp
changeset 0 a2952bb97e68
child 9 bee149131e4b
child 25 d881023c13eb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmappcomponents/mmmtpdataprovider/mmmtpdpplugins/mediamtpdataprovider/src/cmediamtpdataproviderenumerator.cpp	Thu Dec 17 08:55:47 2009 +0200
@@ -0,0 +1,649 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  Enumerator objects
+*
+*/
+
+
+#include <mtp/mmtpdataproviderframework.h>
+#include <mtp/mmtpobjectmgr.h>
+#include <mtp/mmtpstoragemgr.h>
+#include <mtp/cmtpobjectmetadata.h>
+#include <hal.h>
+
+#include "mediamtpdataproviderconst.h"
+#include "cmediamtpdataproviderenumerator.h"
+#include "cmediamtpdataprovider.h"
+#include "mmmtpdplogger.h"
+#include "mmmtpdputility.h"
+#include "cmmmtpdpaccesssingleton.h"
+#include "cmmmtpdpmetadataaccesswrapper.h"
+
+// Unit: microsecond
+const TInt KThresholdOfEnumerationLoopDuration = 1000 * 1000; // microsecond
+
+const TInt KMTPDriveGranularity = 5;
+const TInt KMediaDpArrayGranularity = 2;
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::NewL
+// Two phase constructor
+// -----------------------------------------------------------------------------
+//
+CMediaMtpDataProviderEnumerator* CMediaMtpDataProviderEnumerator::NewL( MMTPDataProviderFramework& aFramework,
+    CMediaMtpDataProvider& aDataProvider )
+    {
+    PRINT( _L( "MM MTP => CMediaMtpDataProviderEnumerator::NewL" ) );
+
+    CMediaMtpDataProviderEnumerator* self = new ( ELeave ) CMediaMtpDataProviderEnumerator( aFramework, aDataProvider );
+
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+
+    PRINT( _L( "MM MTP <= CMediaMtpDataProviderEnumerator::NewL" ) );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::CMediaMtpDataProviderEnumerator
+// Standard C++ Constructor
+// -----------------------------------------------------------------------------
+//
+CMediaMtpDataProviderEnumerator::CMediaMtpDataProviderEnumerator( MMTPDataProviderFramework& aFramework,
+    CMediaMtpDataProvider& aDataProvider ) :
+        CActive( EPriorityLow ), // EPriorityStandard ? sure?
+        iFramework( aFramework ),
+        iObjectMgr( aFramework.ObjectMgr() ),
+        iDataProviderId( aFramework.DataProviderId() ),
+        iDataProvider( aDataProvider ),
+        iDirStack( KMediaDpArrayGranularity ),
+        iStorages( KMediaDpArrayGranularity ),
+        iScanningDir( EFalse )
+    {
+    PRINT1( _L( "MM MTP <> CMediaMtpDataProviderEnumerator::CMediaMtpDataProviderEnumerator, iDataProviderId = %d" ), iDataProviderId );
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::~CMediaMtpDataProviderEnumerator
+// destructor
+// -----------------------------------------------------------------------------
+//
+CMediaMtpDataProviderEnumerator::~CMediaMtpDataProviderEnumerator()
+    {
+    PRINT( _L( "MM MTP => CMediaMtpDataProviderEnumerator::~CMediaMtpDataProviderEnumerator" ) );
+    Cancel();
+    iDir.Close();
+    iDirStack.Close();
+    iStorages.Close();
+
+#if defined(_DEBUG) || defined(MMMTPDP_PERFLOG)
+    delete iPerfLog;
+#endif
+    PRINT( _L( "MM MTP <= CMediaMtpDataProviderEnumerator::~CMediaMtpDataProviderEnumerator" ) );
+    }
+
+// -----------------------------------------------------------------------------
+// MediaMtpDataProviderEnumerator::StartL
+// Kick off the enumeration on the specified storage
+// -----------------------------------------------------------------------------
+//
+void CMediaMtpDataProviderEnumerator::StartL( TUint32 aStorageId )
+    {
+    PRINT1( _L( "MM MTP => CMediaMtpDataProviderEnumerator::StartL aStorageId = 0x%x" ), aStorageId );
+
+    MMTPStorageMgr& storageMgr( iFramework.StorageMgr() );
+    if ( aStorageId == KMTPStorageAll )
+        {
+        // Retrieve the available logical StorageIDs
+        RPointerArray<const CMTPStorageMetaData> storages;
+        CleanupClosePushL( storages ); // + storages
+        TMTPStorageMgrQueryParams params( KNullDesC,
+            CMTPStorageMetaData::ESystemTypeDefaultFileSystem );
+
+        storageMgr.GetLogicalStoragesL( params, storages );
+
+        // Construct the StorageIDs list.
+        for ( TInt i = 0; i < storages.Count(); i++ )
+            {
+            iStorages.AppendL( storages[i]->Uint( CMTPStorageMetaData::EStorageId ) );
+            }
+        CleanupStack::PopAndDestroy( &storages ); // - storages
+        }
+    else if ( aStorageId != KMTPNotSpecified32 )
+        {
+        __ASSERT_DEBUG( storageMgr.ValidStorageId( aStorageId ), User::Invariant() );
+
+        const CMTPStorageMetaData& storage( storageMgr.StorageL( aStorageId ) );
+
+        if ( storage.Uint( CMTPStorageMetaData::EStorageSystemType )
+            == CMTPStorageMetaData::ESystemTypeDefaultFileSystem )
+            {
+            if ( storageMgr.LogicalStorageId( aStorageId ) )
+                {
+                // Logical StorageID.
+                iStorages.AppendL( aStorageId );
+                }
+            else
+                {
+                // Physical StorageID. Enumerate all eligible logical storages.
+                const RArray<TUint>& logicalIds( storage.UintArray( CMTPStorageMetaData::EStorageLogicalIds ) );
+
+                for ( TInt i = 0; i < logicalIds.Count(); i++ )
+                    {
+                    iStorages.AppendL( logicalIds[i] );
+                    }
+                }
+            }
+        }
+
+    iStorageId = aStorageId;
+
+    if ( iStorages.Count() > 0 )
+        {
+        ScanStorageL( iStorages[0] );
+        }
+    else
+        {
+        SignalCompleteL( iDataProvider );
+        }
+
+    PRINT( _L( "MM MTP <= CMediaMtpDataProviderEnumerator::StartL" ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::DoCancel()
+// Cancel the enumeration process
+// -----------------------------------------------------------------------------
+//
+void CMediaMtpDataProviderEnumerator::DoCancel()
+    {
+    iDir.Close();
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::ScanStorageL
+//
+// -----------------------------------------------------------------------------
+//
+void CMediaMtpDataProviderEnumerator::ScanStorageL( TUint32 aStorageId )
+    {
+    const CMTPStorageMetaData& storage( iFramework.StorageMgr().StorageL( aStorageId ) );
+
+    __ASSERT_DEBUG( ( storage.Uint( CMTPStorageMetaData::EStorageSystemType ) == CMTPStorageMetaData::ESystemTypeDefaultFileSystem ),
+        User::Invariant() );
+
+    TFileName root( storage.DesC( CMTPStorageMetaData::EStorageSuid ) );
+    PRINT2( _L("MM MTP <> CMediaMtpDataProviderEnumerator::ScanStorageL aStorageId = 0x%x, StorageSuid = %S"), aStorageId, &root );
+
+    iParentHandle = KMTPHandleNone;
+    iPath.Set( root, NULL, NULL);
+    iDir.Close();
+    User::LeaveIfError( iDir.Open( iFramework.Fs(),
+        iPath.DriveAndPath(),
+        KEntryAttNormal | KEntryAttDir ) );
+    ScanDirL();
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::ScanNextStorageL
+//
+// -----------------------------------------------------------------------------
+//
+void CMediaMtpDataProviderEnumerator::ScanNextStorageL()
+    {
+    // If there are one or more unscanned storages left
+    // (the currently scanned one is still on the list)
+    if ( iStorages.Count() > 1 )
+        {
+        // Round trip suppport
+        const CMTPStorageMetaData& storage( iFramework.StorageMgr().StorageL( iStorages[0] ) );
+        TFileName root( storage.DesC( CMTPStorageMetaData::EStorageSuid ) );
+        GetModifiedContentL( root );
+        iDataProvider.GetWrapperL().UpdateMusicCollectionL();
+
+        iStorages.Remove( 0 );
+        ScanStorageL( iStorages[0] );
+        }
+    else
+        {
+
+        // Round trip suppport
+        const CMTPStorageMetaData& storage( iFramework.StorageMgr().StorageL( iStorages[0] ) );
+        TFileName root( storage.DesC( CMTPStorageMetaData::EStorageSuid ) );
+        GetModifiedContentL( root );
+
+        // We are done
+        iStorages.Reset();
+
+        SignalCompleteL( iDataProvider );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::ScanDirL
+//
+// -----------------------------------------------------------------------------
+//
+void CMediaMtpDataProviderEnumerator::ScanDirL()
+    {
+    PRINT( _L( "MM MTP => CMediaMtpDataProviderEnumerator::ScanDirL" ) );
+
+    StartEnumerationCount();
+
+    iFirstUnprocessed = 0;
+
+    iScanningDir = ETrue;
+    PERFLOGSTART( KDirectoryScan );
+    iDir.Read( iEntries, iStatus );
+    SetActive();
+
+    PRINT( _L( "MM MTP <= CMediaMtpDataProviderEnumerator::ScanDirL" ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::ScanNextDirL
+// Recurse into the next directory on the stack
+// and scan it for entries.
+// -----------------------------------------------------------------------------
+//
+void CMediaMtpDataProviderEnumerator::ScanNextDirL()
+    {
+    TInt count = iDirStack.Count();
+
+    if ( count == 0 )
+        {
+        // No more directories on the stack, try the next storage
+        ScanNextStorageL();
+        }
+    else
+        {
+        TEntry* entry = iDirStack[count - 1];
+        if ( entry != NULL )
+            {
+
+            // Empty TEntry, no more subdirectories in
+            // the current path
+            if ( entry->iName == KNullDesC )
+                {
+                // Remove current dir from path
+                iPath.PopDir();
+                iDirStack.Remove( count - 1 );
+                delete entry;
+                entry = NULL;
+                iDir.Close();
+    
+                // Scan the next directory of the parent
+                ScanNextDirL();
+                }
+            // Going into a subdirectory of current
+            else
+                {
+                // Add directory to path
+                iPath.AddDir( entry->iName );
+                // Remove directory so we don't think it's a subdirectory
+                iDirStack.Remove( count - 1 );
+                delete entry;
+                entry = NULL;
+                ScanNextSubdirL();
+                }
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::ScanNextSubdirL
+// Scan next sub dir
+// -----------------------------------------------------------------------------
+//
+void CMediaMtpDataProviderEnumerator::ScanNextSubdirL()
+    {
+    PRINT( _L( "MM MTP => CMediaMtpDataProviderEnumerator::ScanNextSubdirL" ) );
+
+    // A empty (non-constructed) TEntry is our marker telling us to pop a directory
+    // from iPath when we see this
+    TEntry* entry = new TEntry( TEntry() );
+    
+    User::LeaveIfNull( entry );
+    
+    iDirStack.AppendL( entry );
+
+    // Leave with KErrNotFound if we don't find the object handle since it shouldn't be on the
+    // dirstack if the entry wasn't added
+    TPtrC suid = iPath.DriveAndPath().Left( iPath.DriveAndPath().Length() );
+    // Update the current parenthandle with object of the directory
+    PERFLOGSTART( KObjectManagerObjectUid );
+    iParentHandle = iFramework.ObjectMgr().HandleL( suid );
+    PERFLOGSTOP( KObjectManagerObjectUid );
+    PRINT1( _L( "MM MTP <> iParentHandle = 0x%Lx" ), iParentHandle );
+
+    // Kick-off a scan of the next directory
+    iDir.Close();
+
+    TInt err = iDir.Open( iFramework.Fs(),
+        iPath.DriveAndPath(),
+        KEntryAttNormal | KEntryAttDir );
+
+    PRINT1( _L( "MM MTP <> CMediaMtpDataProviderEnumerator::ScanNextSubdirL, RDir::Open err = %d" ), err );
+
+    if ( err == KErrNone )
+        ScanDirL();
+    else
+        {
+        iEntries = TEntryArray();
+
+        TRequestStatus* status = &iStatus;
+        User::RequestComplete( status, iStatus.Int() );
+        SetActive();
+        }
+
+
+    PRINT( _L( "MM MTP <= CMediaMtpDataProviderEnumerator::ScanNextSubdirL" ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::RunL
+//
+// -----------------------------------------------------------------------------
+//
+void CMediaMtpDataProviderEnumerator::RunL()
+    {
+    if ( iScanningDir )
+        {
+        PERFLOGSTOP( KDirectoryScan );
+        }
+
+    iScanningDir = EFalse;
+    if ( iEntries.Count() == 0 )
+        {
+        // No entries to process, scan next dir or storage
+        ScanNextDirL();
+        }
+    else if ( iFirstUnprocessed < iEntries.Count() )
+        {
+        PRINT1( _L( "MM MTP <> CMediaMtpDataProviderEnumerator::RunL iFirstUnprocessed = %d" ), iFirstUnprocessed);
+        TRAPD( err, ProcessEntriesL(););
+        if ( err != KErrNone )
+            {
+            iFirstUnprocessed++;
+            }
+
+        // Complete ourselves with current TRequestStatus
+        // since we need to run again to either scan a new dir or drive
+        // or process more entries
+        TRequestStatus* status = &iStatus;
+        User::RequestComplete( status, iStatus.Int() );
+        SetActive();
+        }
+    else
+        {
+        switch ( iStatus.Int() )
+            {
+            case KErrNone:
+                // There are still entries left to be read
+                ScanDirL();
+                break;
+
+            case KErrEof:
+                // There are no more entries
+            default:
+                // Error, ignore and continue with next dir
+                ScanNextDirL();
+                break;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::RunError
+//
+// -----------------------------------------------------------------------------
+//
+TInt CMediaMtpDataProviderEnumerator::RunError( TInt aError )
+    {
+    PRINT1( _L( "MM MTP <> CMediaMtpDataProviderEnumerator::RunError with error %d" ), aError );
+
+    TRAP_IGNORE( SignalCompleteL( iDataProvider ) );
+
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::ConstructL
+//
+// -----------------------------------------------------------------------------
+//
+void CMediaMtpDataProviderEnumerator::ConstructL()
+    {
+    CActiveScheduler::Add( this );
+
+    TTimeIntervalMicroSeconds32 tickPeriod = 0;
+    TInt err = UserHal::TickPeriod(tickPeriod);
+
+    PRINT1( _L( "MM MTP <> CMediaMtpDataProviderEnumerator::ConstructL, UserHal::TickPeriod err = %d" ), err);
+    User::LeaveIfError( err );
+    iTickPeriod = tickPeriod.Int();
+
+#if defined(_DEBUG) || defined(MMMTPDP_PERFLOG)
+    iPerfLog = CMmMtpDpPerfLog::NewL( _L( "MediaMtpDataProviderEnumerator" ) );
+#endif
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::SignalCompleteL
+// Called when the enumeration is completed
+// -----------------------------------------------------------------------------
+//
+void CMediaMtpDataProviderEnumerator::SignalCompleteL( MMTPEnumerationCallback& aCallback,
+    TInt aError/* = KErrNone*/)
+    {
+    // Enumeration completed on this drive
+    aCallback.NotifyEnumerationCompleteL( iStorageId, aError );
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::ProcessEntriesL
+// Iterates iEntries adding entries as needed to object manager and iDirStack.
+// -----------------------------------------------------------------------------
+//
+void CMediaMtpDataProviderEnumerator::ProcessEntriesL()
+    {
+    PRINT( _L( "MM MTP => CMediaMtpDataProviderEnumerator::ProcessEntriesL" ) );
+
+    TBuf<KMaxFileName> path = iPath.DriveAndPath();
+
+    while ( !IsOverThreshold() && iFirstUnprocessed < iEntries.Count() )
+        {
+        const TEntry& entry = iEntries[iFirstUnprocessed];
+        path.Append( entry.iName );
+        PRINT1( _L( "MM MTP <> path = %S" ), &path );
+
+        TInt len = entry.iName.Length();
+
+        if ( entry.IsDir() )
+            {
+            path.Append( '\\' );
+            ++len;
+
+            // we don't need to process folder, just remember
+            // the folder
+            TEntry* dirEntry = new TEntry( entry );
+            User::LeaveIfNull( dirEntry );
+            iDirStack.AppendL( dirEntry );
+            }
+        else if ( IsFileAccepted( path ) )
+            {
+            AddEntryL( path );
+            }
+
+        // Remove filename part
+        path.SetLength( path.Length() - len );
+
+        iFirstUnprocessed++;
+        }
+
+    StartEnumerationCount();
+    PRINT( _L( "MM MTP <= CMediaMtpDataProviderEnumerator::ProcessEntriesL" ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::AddEntryL
+// Add a file entry to the object store
+// -----------------------------------------------------------------------------
+//
+void CMediaMtpDataProviderEnumerator::AddEntryL( const TDesC& aFullFileName )
+    {
+    PRINT1( _L( "MM MTP => CMediaDataProviderEnumerator::AddEntryL aFullFileName = %S" ), &aFullFileName );
+
+    CMTPObjectMetaData* object( CMTPObjectMetaData::NewLC( iDataProviderId,
+        iFormatCode,
+        iStorages[0],
+        aFullFileName ) );    // + object
+
+    object->SetUint( CMTPObjectMetaData::EParentHandle, iParentHandle );
+
+    if ( ( iFormatCode == EMTPFormatCodeMP4Container )
+        || ( iFormatCode == EMTPFormatCode3GPContainer )
+        || ( iFormatCode == EMTPFormatCodeASF ) )
+        {
+        TMmMtpSubFormatCode subFormatCode;
+
+        // Note: Delay the file parsing until external enumeration phase to avoid time-out
+        subFormatCode = EMTPSubFormatCodeUnknown;
+
+        object->SetUint( CMTPObjectMetaData::EFormatSubCode, (TUint)subFormatCode );
+        }
+
+    PERFLOGSTART( KObjectManagerInsert );
+    iObjectMgr.InsertObjectL( *object );
+    PERFLOGSTOP( KObjectManagerInsert );
+
+    CleanupStack::PopAndDestroy( object );  // - object
+
+    PRINT1( _L( "MM MTP <= CMediaMtpDataProviderEnumerator::AddEntryL, entry inserted, iFormatCode = 0x%x" ), iFormatCode);
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::GetObjectFormatCode
+// Returns a TMTPFormatCode for the requested object
+// -----------------------------------------------------------------------------
+//
+TMTPFormatCode CMediaMtpDataProviderEnumerator::GetObjectFormatCode( const TDesC& aFullFileName )
+    {
+    PRINT1( _L("MM MTP <> CMediaMtpDataProviderEnumerator::GetObjectFormatCodeL aFullFileName = %S"), &aFullFileName );
+    TMTPFormatCode formatCode = MmMtpDpUtility::FormatFromFilename( aFullFileName );
+    return formatCode;
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::IsFileAccepted
+// Is the file format is supported by this Dp
+// -----------------------------------------------------------------------------
+//
+TBool CMediaMtpDataProviderEnumerator::IsFileAccepted( const TDesC& aFullFileName )
+    {
+    PERFLOGSTART(KFormatFilter);
+    iFormatCode = GetObjectFormatCode( aFullFileName );
+    PRINT1( _L( "MM MTP <> CMediaMtpDataProviderEnumerator::IsFileAcceptedL formatCode = 0x%x" ), iFormatCode );
+    TBool accepted = EFalse;
+    TInt count = sizeof( KMediaMtpDataProviderSupportedFormats ) / sizeof( TUint16 );
+    for ( TInt i = 0; i < count; i++ )
+        {
+        if ( iFormatCode == KMediaMtpDataProviderSupportedFormats[i] )
+            {
+            accepted = ETrue;
+            break;
+            }
+        }
+
+    PERFLOGSTOP(KFormatFilter);
+    return accepted;
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaDpMtpEnumerator::StartEnumerationCount
+// start record system tick
+// -----------------------------------------------------------------------------
+//
+void CMediaMtpDataProviderEnumerator::StartEnumerationCount()
+    {
+    iTickCountBegin = User::TickCount();
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaDpMtpEnumerator::IsOverThreshold
+// Is system tick more than the predefined value?
+// -----------------------------------------------------------------------------
+//
+TBool CMediaMtpDataProviderEnumerator::IsOverThreshold()
+    {
+    TUint tcNow = User::TickCount();
+
+    if ( ( tcNow - iTickCountBegin ) * iTickPeriod >= KThresholdOfEnumerationLoopDuration )
+        {
+        return ETrue;
+        }
+    else
+        {
+        return EFalse;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaDpMtpEnumerator::GetModifiedContentL()
+// Get Modified Content and report to Framework
+// -----------------------------------------------------------------------------
+//
+void CMediaMtpDataProviderEnumerator::GetModifiedContentL( const TDesC& aStorageRoot )
+    {
+    PRINT( _L( "MM MTP => CMediaMtpDataProviderEnumerator::GetModifiedContentL" ) );
+    TInt arrayCount = 0;
+    CDesCArray* modifiedContents = new ( ELeave ) CDesCArrayFlat( KMTPDriveGranularity );
+    CleanupStack::PushL( modifiedContents ); // + modifiedContents
+
+    iDataProvider.GetWrapperL().GetModifiedContentL( aStorageRoot, arrayCount, *modifiedContents );
+
+    if ( arrayCount > 0 )
+        {
+        CMTPObjectMetaData* object = CMTPObjectMetaData::NewLC();   // + object
+        for ( TInt i = 0; i < arrayCount; i++ )
+            {
+
+            if ( iFramework.ObjectMgr().ObjectL( ( *modifiedContents )[i], *object ) )
+                {
+                object->SetUint( CMTPObjectMetaData::EObjectMetaDataUpdate , 1 );
+                iFramework.ObjectMgr().ModifyObjectL( *object );
+                }
+            }
+
+        CleanupStack::PopAndDestroy( object );  // - object
+        }
+
+    CleanupStack::PopAndDestroy( modifiedContents ); // - modifiedContents
+
+    PRINT( _L( "MM MTP <= CMediaMtpDataProviderEnumerator::GetModifiedContentL" ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CMediaMtpDataProviderEnumerator::SessionClosedL
+//
+// -----------------------------------------------------------------------------
+//
+void CMediaMtpDataProviderEnumerator::SessionClosedL()
+    {
+    iDataProvider.GetWrapperL().UpdateMusicCollectionL();
+    iDataProvider.GetWrapperL().CleanupDatabaseL();
+    }
+
+//end of file