upnpframework/upnpfiletransferengine/src/upnpdownloadhandler.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:52:00 +0200
changeset 0 7f85d04be362
permissions -rw-r--r--
Revision: 200947 Kit: 200951

/*
* Copyright (c) 2007 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:  Implementation of the CUpnpDownloadHandler class
*
*/


// INCLUDE FILES
// System
#include <bautils.h>                            // BaflUtils
#include <mmf/common/mmfcontrollerpluginresolver.h>

// upnp stack api
#include <upnpitem.h>                           // CUpnpItem
#include <upnpcontainer.h>                      // CUpnpContainer
#include <upnpstring.h>                         // UpnpString

// upnpframework / avcontroller api
#include "upnpavcontroller.h"                   // MUPnPAVController
#include "upnpavcontrollerfactory.h"            // UPnPAVControllerFactory
#include "upnpavbrowsingsession.h"              // MUPnPAVBrowsingSession
#include "upnpfiledownloadsession.h"            // MUPnPFileDownloadSession

// upnpframework / avcontroller helper api
#include "upnpconstantdefs.h"                   // upnp definitions

// upnpframework / xml parser api
#include "upnpxmlparser.h"                      // CUPnPXMLParser

// upnpframework / internal api's
#include "upnpcommonutils.h"                    // TUPnPItemType

// filetransferengine internal
#include "upnpdownloadhandler.h"
#include "upnpnotehandler.h"
#include "upnpplaylisthandler.h"                // CUpnpPlaylistHandler

_LIT( KComponentLogfile, "filetransferengine.txt");
#include "upnplog.h"

// CONSTANTS
const TInt KBrowseRequestCount =        1;
const TInt KZero =                      0;
const TInt KProgressBaseValue =         100;


// --------------------------------------------------------------------------
// CUpnpDownloadHandler::NewL
// NewL.
// --------------------------------------------------------------------------
//
CUpnpDownloadHandler* CUpnpDownloadHandler::NewL(
                            MUPnPAVBrowsingSession* aBrowsingSession )
    {
    __LOG( "[UpnpDownloadHandler] CUpnpDownloadHandler: NewL" );

    // Check that the browsing session is valid and has target device set.
    if( !aBrowsingSession )
        {
        User::Leave( KErrArgument );
        }

    CUpnpDownloadHandler* self = NULL;
    self = new (ELeave) CUpnpDownloadHandler;
    CleanupStack::PushL( self );
    self->ConstructL( aBrowsingSession );
    CleanupStack::Pop( self );
    __LOG( "[UpnpDownloadHandler] CUpnpDownloadHandler: NewL end" );
    return self;
    }

// --------------------------------------------------------------------------
// Constuctor
// --------------------------------------------------------------------------
//
CUpnpDownloadHandler::CUpnpDownloadHandler()
    {
    __LOG( "[UpnpDownloadHandler] Constructor" );
    iContainerCopy = EFalse;
    iBrowsePosition = -1;
    iFirstBrowse = ETrue;

    iDownloadedCount = KZero;
    __LOG( "[UpnpDownloadHandler] Constructor -end" );
    }

// --------------------------------------------------------------------------
// Destructor
// --------------------------------------------------------------------------
//
CUpnpDownloadHandler::~CUpnpDownloadHandler()
    {
    __LOG( "[UpnpDownloadHandler] Destructor" );

    // If download session is running, stop it
    if( iAvController &&
        iDownloadSession )
        {
        iAvController->StopDownloadSession( *iDownloadSession );
        }

    // Delete the note handler.
    delete iNoteHandler;

    // delete the UpnpAvControllerClient
    delete iAvController;
    
    // delete the container id
    delete iContainerId;
    
    delete iPlaylistHandler;
    iCopyItems.ResetAndDestroy();
    iCopyItems.Close();
    //iCopyItem.ResetAndDestroy();
    // Restore the browse session observer
    if( iBrowsingSession &&
        iBrowsingSessionObserverBackup )
        {
        iBrowsingSession->RemoveObserver();
        iBrowsingSession->SetObserver( *iBrowsingSessionObserverBackup );
        }
    __LOG( "[UpnpDownloadHandler] Destructor -end" );    
    }

// --------------------------------------------------------------------------
// CUpnpDownloadHandler::ConstructL
// Second phase constructor
// --------------------------------------------------------------------------
//
void CUpnpDownloadHandler::ConstructL(
                                MUPnPAVBrowsingSession* aBrowsingSession )
    {
    __LOG( "[UpnpDownloadHandler] ConstructL" );

    if( !aBrowsingSession )
        {
        User::Leave( KErrArgument );
        }

    // Store the browsing session
    iBrowsingSession = aBrowsingSession;

    // Create UpnpAvControllerClient
    iAvController = UPnPAVControllerFactory::NewUPnPAVControllerL();

    // Create download session
    iDownloadSession = &iAvController->StartDownloadSessionL(
                                            iBrowsingSession->Device() );

    // Set this object to be the download session observer
    iDownloadSession->SetObserver( *this );

    // Backup the browse session observer and set this object as an observer.
    iBrowsingSessionObserverBackup = iBrowsingSession->Observer();
    iBrowsingSession->RemoveObserver();
    iBrowsingSession->SetObserver( *this );

    iNoteHandler = CUpnpNoteHandler::NewL( this );
    
    iPlaylistHandler = CUpnpPlaylistHandler::NewL();
    __LOG( "[UpnpDownloadHandler] ConstructL -end" );
    }

// --------------------------------------------------------------------------
// CUpnpDownloadHandler::DownloadItemsL
// Downloads the given objects to the handset, into the default target folder
// (setting in the Home Media application).
// --------------------------------------------------------------------------
//
void CUpnpDownloadHandler::DownloadItemsL( CDesC8ArrayFlat* aObjectIds  )
    {
    
    __LOG( "[UpnpDownloadHandler] DownloadItemsL" );
    // Check parameter
    if( !aObjectIds ||
        aObjectIds->Count() <= KZero )
        {
        User::Leave( KErrArgument );
        }

    iTotalCount = aObjectIds->Count();
    iObjectsToCopy = aObjectIds;

    // Initialise values
    iCopyPosition = -1;
    iCopyCompleteness = KZero;

    iStatusCode = KErrNone;

    // Start fetching the object metadata
    StartDownload();

    if( iStatusCode == KErrNone )
        {
        iNoteHandler->RunProgressNoteL( EUpnpCopyProgressNote );
        }
        
    // Leave if there was an error
    if( iStatusCode != KErrNone )
        {
        iDownloadSession->CancelAllTransfers();
        User::Leave( iStatusCode );
        }
    else
        {
        if( iContainerCopy )
            {
            // If no files were copied, change the copy status code
            if( iPlaylistHandler->AudioItemCount() <= 0 &&
                iPlaylistHandler->ImageItemCount() <= 0 &&
                iPlaylistHandler->VideoItemCount() <= 0 &&
                iStatusCode == KErrNone )
                {
                iStatusCode = KErrNotFound;
                }

            // If files were copied, create playlists, albums and notify
            // Media Gallery
            else
                {
                // If audio files were copied, and the operation was to
                // copy a playlist, then create a MPX playlist
                if( iPlaylistHandler->AudioItemCount() > 0 && iPlayList )
                    {
                    iPlaylistHandler->CreateMusicPlaylistL();
                    }

                // If image files were copied, create an image album
                if( iPlaylistHandler->ImageItemCount() > 0 )
                    {
                    iPlaylistHandler->CreateImageAlbumL();
                    }

                // If video files were copied, create a video album
                if( iPlaylistHandler->VideoItemCount() > 0 )
                    {
                    iPlaylistHandler->CreateVideoAlbumL();
                    }
                }

            // Reset the playlist handler
            iPlaylistHandler->Reset();
            }    
        }
    __LOG( "[UpnpDownloadHandler] DownloadItemsL -end" );    
    }

// --------------------------------------------------------------------------
// CUpnpDownloadHandler::DialogDismissedL
// ProgressDialog call back method. Get's called when a dialog is
// dismissed.
// --------------------------------------------------------------------------
//
void CUpnpDownloadHandler::DialogDismissedL( )
    {
    __LOG( "[UpnpDownloadHandler] DialogDismissedL" );
    // Update the status code
    if( iStatusCode == KErrNone )
        {
        iStatusCode = KErrCancel;
        }
    iBrowsingSession->CancelBrowse();
    iDownloadSession->CancelAllTransfers();
    __LOG( "[UpnpDownloadHandler] DialogDismissedL -end" );
    }
    
// --------------------------------------------------------------------------
// CUpnpDownloadHandler::MediaServerDisappeared
// Notifies that the Media Server we have a session with has disappeared. 
// Session is now unusable and must be closed.
// --------------------------------------------------------------------------
//
void CUpnpDownloadHandler::MediaServerDisappeared(
                                TUPnPDeviceDisconnectedReason aReason )
    {
    __LOG( "[UpnpDownloadHandler]\t MediaServerDisappeared()" );

    // Update the status code
    if( aReason == EDisconnected )
        {
        iStatusCode = KErrSessionClosed;
        }
    else if( aReason == EWLANLost )
        {
        iStatusCode = KErrDisconnected;
        }
    else
        {
        iStatusCode = KErrUnknown;
        }

    // Finish the progress note
    iNoteHandler->FinishProgressNote();
    
    __LOG( "[UpnpDownloadHandler]\t MediaServerDisappeared() -end" );
    }

// --------------------------------------------------------------------------
// CUpnpDownloadHandler::BrowseResponse
// Returns unprocessed browse results received from a Media Server.
// --------------------------------------------------------------------------
//
void CUpnpDownloadHandler::BrowseResponse( const TDesC8& aBrowseResponse,
                                           TInt aError,
                                           TInt /*aMatches*/,
                                           TInt  aTotalCount,
                                           const TDesC8& /*aUpdateId*/ )
    {
    __LOG( "[UpnpDownloadHandler] BrowseResponse()" );
    
    if( aBrowseResponse != KNullDesC8 &&
        aError == KErrNone )
        {
        TRAP( aError, BrowseResponseL( aBrowseResponse, 
                                       aTotalCount ) );
        }
    else if( aBrowseResponse == KNullDesC8 && KErrNone!= aError )
        {
        aError = KErrArgument;
        }
    
    // If parsing or sending the download action failed, exit
    if( aError != KErrNone )
        {
        
        if( KErrCompletion == aError )
            {
            iStatusCode = KErrNone;
            }
        else
            {
            iStatusCode = aError;    
            }
        iNoteHandler->FinishProgressNote();
        }

    
    
    __LOG( "[UpnpDownloadHandler] BrowseResponse() -end" );
    }
    
// --------------------------------------------------------------------------
// CUpnpDownloadHandler::BrowseResponseL
// Returns unprocessed browse results received from a Media Server.
// --------------------------------------------------------------------------
//
void CUpnpDownloadHandler::BrowseResponseL( const TDesC8& aBrowseResponse,
                                            TInt aTotalCount )
                                           
    {
    __LOG( "[UpnpDownloadHandler] BrowseResponseL()" );

    //get the number of items in the container copy
    if( !iFirstBrowse && iContainerCopy )
        {
        iTotalCount = aTotalCount;
        if( !iProgressBarMaxValueSet )
            {
            iProgressBarMaxValueSet = ETrue;
            iNoteHandler->SetMaxValue( iTotalCount * KProgressBaseValue );
            }
        
        }
        // Parse the result
        
    RPointerArray<CUpnpObject> array;
    CleanupResetAndDestroyPushL( array );
    
    CUPnPXMLParser* parser = NULL;
    parser = CUPnPXMLParser::NewLC();        
    
    
    parser->ParseResultDataL( array, aBrowseResponse );
    CleanupStack::PopAndDestroy( parser );
    
    /**
     * Seldomly the aError is KErrNone, but no object in array
     * if this is for the container copying, return KErrArgument
     * otherwise, continue to browse the next item
     */
    if( array.Count() > 0 )
        {
        if( array[KZero]->ObjectType() == EUPnPItem )
            { 
            iFirstBrowse = EFalse;
            IsAnyItem = ETrue;
            
            if( !iProgressBarMaxValueSet )
                {
                iProgressBarMaxValueSet = ETrue;
                iNoteHandler->SetMaxValue( iTotalCount * KProgressBaseValue );
                }
            
            CUpnpItem* tempItem = NULL;
            tempItem = CUpnpItem::NewL();
            tempItem->CopyL( *array[KZero] );
             
            CleanupStack::PushL( tempItem );
             
            iCopyItems.AppendL( tempItem ); //transfer ownership
            CleanupStack::Pop( tempItem );
            
            // Start downloading the next object
            StartDownload();
            }
        else if( array[KZero]->ObjectType() == EUPnPContainer )
            {
            //To get the parent container Id
            if( iFirstBrowse )
                {                
                CUpnpContainer* sourseContainer = NULL;
                sourseContainer = ( CUpnpContainer* )array[KZero];
                iPlayList = UPnPCommonUtils::IsPlaylistContainerL( 
                                            *sourseContainer);
                        
                iPlaylistHandler->Reset();
                
                // Convert the container title to playlist name
                HBufC* titleUnicode = NULL;
                titleUnicode = UpnpString::ToUnicodeL( sourseContainer->Title() );
                CleanupStack::PushL( titleUnicode );
                iPlaylistHandler->SetPlaylistNameL( *titleUnicode );
                CleanupStack::PopAndDestroy( titleUnicode );
                
                iContainerCopy = ETrue;
                iBrowsePosition = -1; //reset the browes position
                iFirstBrowse = EFalse;
                delete iContainerId; iContainerId = NULL;
                iContainerId = array[KZero]->Id().AllocL();
                }
            }
        } //if( array[KZero] > 0 )
    else //if no items
        {
        if( iFirstBrowse )
            {
            User::LeaveIfError( KErrArgument );
            }
        }
    
    CleanupStack::PopAndDestroy( &array );    
    
    //try to start browsing next object
    if( iTotalCount > ++iBrowsePosition )
        {
        if( !iContainerCopy )
            {
            iBrowsingSession->BrowseL( iObjectsToCopy->MdcaPoint( 
                                       iBrowsePosition ),
                                       KFilterFull(),
                                       MUPnPAVBrowsingSession::EMetadata,
                                       iBrowsePosition,
                                       KBrowseRequestCount,
                                       KSortCriteria() );
            }
         else
            {
            // if we are copying a container, 
            // browse the next item
            if( iContainerId )
                {
                iBrowsingSession->BrowseL( 
                              *iContainerId,
                              KFilterFull(),
                              MUPnPAVBrowsingSession::EDirectChildren,
                              iBrowsePosition,
                              KBrowseRequestCount,
                              KSortCriteria() );
                }                                    
            }
        } //if( iTotalCount > ++iBrowsePosition )
    else //if there is no item in a container
        {
        if( iContainerCopy && !IsAnyItem )
            {
            iNoteHandler->FinishProgressNote();
            }
        }             
    __LOG( "[UpnpDownloadHandler] BrowseResponseL() -end" );
    }

// --------------------------------------------------------------------------
// CUpnpDownloadHandler::TransferStarted
// --------------------------------------------------------------------------
//
void CUpnpDownloadHandler::TransferStarted( TInt aKey,
                                            TInt aStatus )
    {
    __LOG( "[UpnpDownloadHandler] TransferStarted()" );

    // If the transfer failed to start, exit
    
    if( aStatus != KErrNone)
        {
        iStatusCode = aStatus;    
        }
    else if( aKey < 0 || aKey > iCopyPosition )
        {
        iStatusCode = KErrGeneral;
        }
    
    if( KErrServerBusy == iStatusCode )
        {
        iBrowsePosition--;
        iCopyPosition--;
        iStatusCode = KErrNone;
        }
        
    if( KErrNone != iStatusCode )
        {
        iNoteHandler->FinishProgressNote(); //this is sychro. call    
        }
    else
        {
        TRAP_IGNORE( iDownloadSession->StartTrackingProgressL( aKey ) );    
        }    
    
    __LOG( "[UpnpDownloadHandler] TransferStarted() -end" );
    }

// --------------------------------------------------------------------------
// CUpnpDownloadHandler::TransferProgress
// --------------------------------------------------------------------------
//
void CUpnpDownloadHandler::TransferProgress( TInt aKey,
                                             TInt aBytes,
                                             TInt aTotalBytes )
    {
    __LOG( "[UpnpDownloadHandler] TransferProgress()" );
    if( aKey < 0 || aKey > iCopyPosition )
        {
        iStatusCode = KErrGeneral;
        iNoteHandler->FinishProgressNote();
        }
    else
        {
        float progress = ((float)aBytes / aTotalBytes) * 100;
        iNoteHandler->SetValue( iCopyCompleteness + (TInt)progress);    
        }    
    
    __LOG( "[UpnpDownloadHandler] TransferProgress() -end" );
    }
    
// --------------------------------------------------------------------------
// CUpnpDownloadHandler::TransferCompleted
// --------------------------------------------------------------------------
//
void CUpnpDownloadHandler::TransferCompleted( TInt aKey,
                                              TInt aStatus,
                                              const TDesC& aFilePath )
    {
    __LOG( "[UpnpDownloadHandler] TransferCompleted()" );
    
    
    iStatusCode = aStatus;
    iDownloadedCount++;
    
    if( KErrNone != iStatusCode || ( aKey < 0 || aKey > iCopyPosition ) ||
        iTotalCount <= iDownloadedCount )
        {
        iNoteHandler->FinishProgressNote();
        }
    else    
        {
        // Update the download completeness percentage value
        iCopyCompleteness = iDownloadedCount * KProgressBaseValue;
            // Update the progress note
        iNoteHandler->SetValue( iCopyCompleteness );
        
        if( iCopyItems.Count() > aKey )
            {
            CUpnpItem* obj = NULL;
            obj = (CUpnpItem*)iCopyItems[aKey];
            if( obj )
                {
                TRAP_IGNORE( NotifyMPXL( *obj, aFilePath ) );        
            
                delete iCopyItems[aKey];
                iCopyItems[aKey] = NULL;
                }
            }
         
        }
    __LOG( "[UpnpDownloadHandler] TransferCompleted() -end" );    
    }

// --------------------------------------------------------------------------
// CUpnpDownloadHandler::NotifyMPXL
// Notify MPX when download is complete
// --------------------------------------------------------------------------
//
void CUpnpDownloadHandler::NotifyMPXL( 
                        const CUpnpItem& aObject, const TDesC& aFilePath )
    {
    __LOG( "[UpnpDownloadHandler] NotifyMPXL()" );
    TUPnPItemType itemType = ETypeOther;
    itemType = UPnPCommonUtils::ResolveFileTypeL( aFilePath );
    
    // Nofity MPX of a new file
    if( itemType == ETypeAudio )
        {
        if( iContainerCopy )
            {
            iPlaylistHandler->AddAudioItemL( aFilePath );
            }
        iPlaylistHandler->NotifyNewAudioFileL( aFilePath, aObject );
        }
    
    if( iContainerCopy )
        {
        if( itemType == ETypeVideo )
            {
            iPlaylistHandler->AddVideoItemL( aFilePath);
            }
        else if( itemType == ETypeImage )
            {
            iPlaylistHandler->AddImageItemL( aFilePath);
            }
        }
    __LOG( "[UpnpDownloadHandler] NotifyMPXL() end" );    
    }


// --------------------------------------------------------------------------
// CUpnpDownloadHandler::StartDownload
// Start download a file
// --------------------------------------------------------------------------
//
void CUpnpDownloadHandler::StartDownload()
    {
    __LOG( "[UpnpDownloadHandler] StartDownload()" );
    if( iStatusCode == KErrNone )
        {
        TRAP( iStatusCode, StartDownloadL() );    
        }
    
    
    // If the downloading of the next file failed (browse failed or there
    // are no more files), exit
    
    if( iStatusCode!= KErrNone )
        {
        if( iStatusCode == KErrCompletion )
            {
            iStatusCode = KErrNone;
            }
        iNoteHandler->FinishProgressNote();     
        }
    __LOG( "[UpnpDownloadHandler] StartDownload() end" );
    }

// --------------------------------------------------------------------------
// CUpnpDownloadHandler::StartDownloadL
// Starts the next download. Leaves (KErrCompletion) if there are no more
// objects to download.
// --------------------------------------------------------------------------
//
void CUpnpDownloadHandler::StartDownloadL()
    {
    __LOG( "[UpnpDownloadHandler] StartDownloadL()" );

    if( !iFirstBrowse )
        {
        //start downloading
        // check if there are any CUpnpObject left in the array
        if( iCopyItems.Count() > ++iCopyPosition )
            {
            iDownloadSession->
                    StartDownloadL( *(CUpnpItem*)iCopyItems[iCopyPosition],
                                    iCopyPosition );
            }
        else
            {
            User::Leave( KErrCompletion );
            }
        }
    else //this is called only once at the beginning of copying
        {
        //start browsing
        iBrowsePosition++;

        iBrowsingSession->BrowseL( 
                        iObjectsToCopy->MdcaPoint( iBrowsePosition ),
                        KFilterFull(),
                        MUPnPAVBrowsingSession::EMetadata,
                        iBrowsePosition,
                        KBrowseRequestCount,
                        KSortCriteria() );
        
        }
    __LOG( "[UpnpDownloadHandler] StartDownloadL() -end" );
    }

// --------------------------------------------------------------------------
// CUpnpDownloadHandler::GetNumCopiedFiles
// --------------------------------------------------------------------------
//
TInt CUpnpDownloadHandler::GetNumCopiedFiles() const
    {
    return iDownloadedCount;
    }
// End of file