mpxmusicplayer/app/src/mpxrestorepath.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 11 May 2010 16:10:56 +0300
branchRCL_3
changeset 26 70a8526f03f2
parent 0 ff3acec5bc43
permissions -rw-r--r--
Revision: 201017 Kit: 201019

/*
* 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:  Saves/restores current playback path
*
*/


// INCLUDE FILES
#include <bldvariant.hrh>
#include <s32file.h>

#include <eikenv.h>
#include <mpxcollectionframeworkdefs.h>
#include <mpxcollectionmessage.h>
#include <mpxcollectionutility.h>
#include <mpxcollectionplaylist.h>
#include <mpxcollectionpath.h>
#include <mpxcollectionuihelper.h>
#include <mpxcollectionhelperfactory.h>
#include <mpxplaybackutility.h>
#include <mpxplaybackmessage.h>
#include <mpxplaybackpluginobserver.h>
#include <mpxmessagegeneraldefs.h>
#include <mpxplaybackmessagedefs.h>
#include <mpxcollectionopenutility.h>
#include <mpxsubscription.h>
#include <mpxviewutility.h>
#include <mpxmusicplayerviewplugin.hrh>

#include "mpxrestorepath.h"
#include <mpxconstants.h>
#include "mpxlog.h"

// CONSTANTS
_LIT( KMPXCollectionPathFileName, "c:\\system\\data\\mpxcollectionpath.dat" );
const TInt KIncrementalFetchCount = 400;
const TInt KIncrementalNullOffset = 0;
const TInt KIncrementalLoadDelay = 1000000; // 1 second in ms
#define KMPXPdSbPlaybackViewImplementationId    0x10207BD0

// ============================ MEMBER FUNCTIONS ==============================

// ----------------------------------------------------------------------------
// Two-phased constructor.
// ----------------------------------------------------------------------------
//
CMPXRestorePath* CMPXRestorePath::NewL(MMPXPlaybackUtility* aPlaybackUtility,
                                       MMPXCollectionUiHelper* aCollectionUiHelper)
    {
    CMPXRestorePath* self = NewLC(aPlaybackUtility, aCollectionUiHelper);
    CleanupStack::Pop(self);
    return self;
    }

// ----------------------------------------------------------------------------
// Two-phased constructor.
// ----------------------------------------------------------------------------
//
CMPXRestorePath* CMPXRestorePath::NewLC(MMPXPlaybackUtility* aPlaybackUtility,
                                        MMPXCollectionUiHelper* aCollectionUiHelper )
    {
    CMPXRestorePath* self = new (ELeave) CMPXRestorePath(aPlaybackUtility,
                                                         aCollectionUiHelper);
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }

// ----------------------------------------------------------------------------
// C++ constructor can NOT contain any code that might leave.
// ----------------------------------------------------------------------------
//
CMPXRestorePath::CMPXRestorePath(MMPXPlaybackUtility* aPlaybackUtility,
                                 MMPXCollectionUiHelper* aCollectionUiHelper ):
                                             iPlaybackUtility(aPlaybackUtility),
                                             iCollectionUiHelper( aCollectionUiHelper ),
                                             iPathInitialized(0),
                                             iIsInitializing(EFalse),
                                             iInitCanceled(EFalse),
                                             iLoadSavedPath(EFalse),
                                             iRootPathId( KNullUid )
    {
    }

// ----------------------------------------------------------------------------
// Destructor.
// ----------------------------------------------------------------------------
//
CMPXRestorePath::~CMPXRestorePath()
    {
    if ( iCollectionUtility )
        {
        iCollectionUtility->Close();
        }

    delete iIncOpenUtil;
    }

// ----------------------------------------------------------------------------
// Symbian 2nd phase constructor can leave.
// ----------------------------------------------------------------------------
//
void CMPXRestorePath::ConstructL()
    {
    iCollectionUtility = MMPXCollectionUtility::NewL( this, KMcModeIsolated );

#ifdef __USE_MESSAGE_SUBSCRIPTION
    // Subscribe to only a few messages from collection utility
    CMPXSubscription* subscription( CMPXSubscription::NewL() );
    CleanupStack::PushL( subscription );
    CMPXSubscriptionItem* subItem1( CMPXSubscriptionItem::NewL() );
    CleanupStack::PushL( subItem1 );
    subItem1->SetTObjectValueL( KMPXMessageGeneralId, KMPXMessageGeneral );
    subItem1->SetTObjectValueL( KMPXMessageGeneralEvent, TMPXCollectionMessage::EBroadcastEvent );
    subscription->AddItemL( *subItem1 );
    CMPXSubscriptionItem* subItem2( CMPXSubscriptionItem::CopyL( *subItem1 ));
    CleanupStack::PushL( subItem2 );
    subItem2->SetTObjectValueL( KMPXMessageGeneralEvent, TMPXCollectionMessage::EPathChanged );
    subItem2->SetTObjectValueL( KMPXMessageGeneralType, EMcPathChangedByOpen );
    subItem2->SetTObjectValueL( KMPXMessageGeneralData, EMcItemOpened );
    subscription->AddItemL( *subItem2 );
    iCollectionUtility->Collection().AddSubscriptionL( *subscription );
    CleanupStack::PopAndDestroy( subItem2 );
    CleanupStack::PopAndDestroy( subItem1 );
    CleanupStack::PopAndDestroy( subscription );
#endif

    iIncOpenUtil = CMPXCollectionOpenUtility::NewL( this, KMcModeIsolated );
    iMTPStarted = EFalse;
    }

// -----------------------------------------------------------------------------
// Load from file
// -----------------------------------------------------------------------------
//
void CMPXRestorePath::LoadPathL()
    {
    MPX_FUNC("CMPXRestorePath::LoadPathL()");
    if (iIsInitializing) // avoid reenter
        return;
    iDefaultPath = EFalse;

    RFs& fs = CEikonEnv::Static()->FsSession();
    fs.MkDirAll( KMPXCollectionPathFileName );
    TParse parsedName;

    fs.Parse( KMPXCollectionPathFileName, parsedName );
    CFileStore* store( NULL );
    MPX_TRAPD( error, store = CDirectFileStore::OpenL(fs,
                                                 parsedName.FullName(),
                                                 EFileRead ); );

    // If we can internalize a collection path from file, we use that to
    // create a collection playlist. Otherwise, we construct the default
    // path using the collection helper.
    //
    CMPXCollectionPath* cpath( NULL );
    if ( error == KErrNone )
        {
        CleanupStack::PushL( store );

        RStoreReadStream stream;
        stream.OpenLC( *store, store->Root() );

        // Recreate the collection path that we were browsing
        cpath = CMPXCollectionPath::NewL(stream);
        CleanupStack::PushL(cpath);
        if( cpath->Levels() )
            {
            iRootPathId = TUid::Uid( cpath->Id( 0 ) );
            }
        TInt selection = stream.ReadInt32L();

        // bounds checking
        if( selection >=0 && selection < cpath->Count() )
            {
            cpath->Set( selection );

            // Find out what we were selecting
            iSelectionId = cpath->Id();
            iSelectionIndex = cpath->Index();

            MPX_DEBUG1("CMPXRestorePath::LoadPathL -- Opening Path in collection");

            // Rebrowse collection path of the container
            // We re-select the item when the container is opened and
            // in turn open the song
            //
            if( cpath->Levels() )
                {
                cpath->Back();
                }
            DoIncrementalOpenL( *cpath, iSelectionIndex, KIncrementalLoadDelay );
            }
        else
            {
            // Bad collection path, restore to default
            MPX_DEBUG1("CMPXRestorePath::LoadPathL -- bad collection path found");
            LoadDefaultPathL( KIncrementalLoadDelay );
            }

        CleanupStack::PopAndDestroy( cpath);
        CleanupStack::PopAndDestroy(&stream);

        CleanupStack::PopAndDestroy(store);
        }
    else
        {
        delete store;
        cpath = iCollectionUiHelper->CreateDefaultPlaylistPathLC();

        iDefaultPath = ETrue;
        iSelectionId = KMPXInvalidItemId;
        iSelectionIndex = 0;

        DoIncrementalOpenL( *cpath, iSelectionIndex, KIncrementalLoadDelay );
        CleanupStack::PopAndDestroy( cpath );
        }
    }

// ---------------------------------------------------------------------------
// Create the default path and load it in collection
// ---------------------------------------------------------------------------
//
void CMPXRestorePath::LoadDefaultPathL( TInt aDelay )
    {
    MPX_DEBUG1("CMPXRestorePath::LoadDefaultPathL");
    CMPXCollectionPath* cpath = iCollectionUiHelper->CreateDefaultPlaylistPathLC();

    if (!iIsInitializing)
        {
        // Get incremental utility to open the path
        //
        DoIncrementalOpenL( *cpath, KIncrementalNullOffset, aDelay );

        iPathInitialized = EFalse;
        iIsInitializing = ETrue;
        iInitCanceled = EFalse;
        iDefaultPath = ETrue;
        iSelectionId = KMPXInvalidItemId;
        }
    CleanupStack::PopAndDestroy( cpath );
    }

// ---------------------------------------------------------------------------
// Save the currently playing playlist path
// ---------------------------------------------------------------------------
//
void CMPXRestorePath::SavePathL()
    {
    RFs& fs = CEikonEnv::Static()->FsSession();
    fs.MkDirAll( KMPXCollectionPathFileName );
    TParse parsedName;

    fs.Parse( KMPXCollectionPathFileName, parsedName );
    CFileStore* store( NULL );
    MPX_TRAPD( error, store = CDirectFileStore::ReplaceL(fs,
                                                 parsedName.FullName(),
                                                 EFileWrite ); );

    if( error == KErrNone )
        {
        CleanupStack::PushL( store );
        store->SetTypeL(store->Layout());

        RStoreWriteStream wStream;
        TStreamId stream = wStream.CreateLC( *store );
        store->SetRootL( stream );

        MMPXSource* source = iPlaybackUtility->Source();
        CMPXCollectionPlaylist* pl( NULL );
        TInt levels(0);

        // Make sure we have a source, a playlist, and a valid path
        // Playback engine path could be invalid (0 levels) but have
        // a source and playlist if the currently playing playlist
        // is deleted.
        //
        if( source )
            {
            pl = source->PlaylistL();
            if (pl)
                {
                CleanupStack::PushL( pl );
                const CMPXCollectionPath& path = pl->Path();
                levels = path.Levels();
                if( levels > 0 )
                    {
                    wStream << path;
                    wStream.WriteInt32L( path.Index( path.Levels() - 1 ) );
                    wStream.CommitL();
                    }
                CleanupStack::PopAndDestroy( pl );
                }
            }

        CleanupStack::PopAndDestroy( &wStream );
        CleanupStack::PopAndDestroy( store );

        // Delete if source was invalid. Have to do it here
        // because store owned a file handle to the file
        //
        if( !source || !pl || !levels )
            {
            fs.Delete( KMPXCollectionPathFileName );
            }
        }
    else
        {
        // File cannot be opened, so try to delete it so that when
        // music player tries to load the path next time it'll use
        // the default path
        //
        fs.Delete( KMPXCollectionPathFileName );
        }
    }

// ---------------------------------------------------------------------------
// Check the initialized flag
// ---------------------------------------------------------------------------
//
TBool CMPXRestorePath::Initialized()
    {
    return iPathInitialized;
    }

// ---------------------------------------------------------------------------
// Check the iIsInitializing flag
// ---------------------------------------------------------------------------
//
TBool CMPXRestorePath::IsInitializing()
    {
    return iIsInitializing;
    }

// ---------------------------------------------------------------------------
// Set the initialized flag
// ---------------------------------------------------------------------------
//
void CMPXRestorePath::SetInitialized( TBool aInit )
    {
    iPathInitialized = aInit;
    iIsInitializing = EFalse;
    }

// ---------------------------------------------------------------------------
// Cancels the initialize operation
// ---------------------------------------------------------------------------
//
void CMPXRestorePath::CancelInit()
    {
    iInitCanceled = ETrue;
    SetInitialized( ETrue );
    }

// ---------------------------------------------------------------------------
// From MMPXCollectionObserver.
// Handle media properties.
// ---------------------------------------------------------------------------
//
void CMPXRestorePath::HandleCollectionMediaL(
    const CMPXMedia& /*aMedia*/,
    TInt /*aError*/ )
    {
    // Do nothing
    }

// ---------------------------------------------------------------------------
// From MMPXCollectionObserver.
// Handle collection message.
// ---------------------------------------------------------------------------
//
void CMPXRestorePath::HandleCollectionMessage(
    CMPXMessage* aMessage, TInt aError )
    {
    if ( aError == KErrNone && aMessage )
        {
        TRAP_IGNORE( DoHandleCollectionMessageL( *aMessage ) );
        }
    }

// ---------------------------------------------------------------------------
// From MMPXCollectionObserver.
// Handles the collection entries being opened.
// ---------------------------------------------------------------------------
//
void CMPXRestorePath::HandleOpenL(
    const CMPXMedia& /* aEntries */,
    TInt /* aIndex */,
    TBool /* aComplete */,
    TInt aError )
    {
    // OpenL() callback from trying to open the default Music Menu -> All Songs
    // or from opening a container
    //
    MPX_DEBUG1("CMPXRestorePath::HandleOpenL -- Passing path to playback engine");

    // Stop the incremental open algorithm. We are only interested in fetcing
    // a single block containing the item we want to play. This will speed up the
    // initalization procedure. Once the playlist is created, the playlist
    // takes over the rest of the incremental open operation
    //
    iIncOpenUtil->Stop();
    if ( aError == KErrNone )
        {

        CMPXCollectionPath* cPath = iIncOpenUtil->PathL();
        CleanupStack::PushL( cPath );

        if( iSelectionId != KMPXInvalidItemId )
            {
            // Find the Index first
            TInt index = cPath->IndexOfId( iSelectionId );

            // If the item still exists in the path, we open it to init playback
            if( index != KErrNotFound )
                {
                cPath->Set( index );
                iCollectionUtility->Collection().OpenL( *cPath );
                }
            else
                {
                LoadDefaultPathL();
                }
            iSelectionId = KMPXInvalidItemId;
            }
        else  // Opening the default path
            {
            InitPlaybackEngineL( *cPath );
            }
        CleanupStack::PopAndDestroy( cPath );
        }
    else
        {
        if( iDefaultPath )
            {
            MPX_DEBUG1("CMPXRestorePath::HandleOpenL - Failed to open default path");
            // Failed to open default path, set to initialized
            // "No songs view"
            //
            iDefaultPath = EFalse;
            iPathInitialized = ETrue;
            iIsInitializing = EFalse;
            }
        else
            {
            MPX_DEBUG1("CMPXRestorePath::HandleOpenL - Opening default Path");
            iIsInitializing = EFalse;
            // Try opening default
            LoadDefaultPathL();
            }
        }
    }

// ---------------------------------------------------------------------------
// Handle playback message.
// ---------------------------------------------------------------------------
//
void CMPXRestorePath::HandlePlaybackMessage(
    CMPXMessage* aMessage, TInt aError )
    {
    if ( aError == KErrNone && aMessage )
        {
        TRAP_IGNORE( DoHandlePlaybackMessageL( *aMessage ) );
        }
    }


// ---------------------------------------------------------------------------
// From MMPXCollectionObserver.
// Handles the item being opened.
// ---------------------------------------------------------------------------
//
void CMPXRestorePath::HandleOpenL(
    const CMPXCollectionPlaylist& aPlaylist,
    TInt aError )
    {
    MPX_FUNC("CMPXRestorePath::HandleOpenL");
    if( aError == KErrNone )
        {
        if ( !iInitCanceled )
            {
            MPX_DEBUG1( "CMPXRestorePath::HandleOpenL - Opening playlist" );

            // toggle repeat and shuffle to off if podcast playlist
            if(KMPXUidPodcastDBPlugin == TUid::Uid((TInt)aPlaylist.Path().Id(0)))
                {
                CMPXCollectionPlaylist* tmp =
                                CMPXCollectionPlaylist::NewL( aPlaylist );
                CleanupStack::PushL( tmp );
                tmp->SetRepeatEnabled( EFalse );
                tmp->SetShuffleEnabledL( EFalse );
                iPlaybackUtility->InitL( *tmp, EFalse );
                CleanupStack::PopAndDestroy( tmp );
                }
            else
                {
                iPlaybackUtility->InitL( aPlaylist, EFalse );
                }
            }
        else
            {
            MPX_DEBUG1( "CMPXRestorePath::HandleOpenL - Init canceled, do nothing" );
            }
        }
    else
        {
        if( iDefaultPath )
            {
            // Failed to open default path, set to initialized
            // "No songs view"
            //
            iDefaultPath = EFalse;
            iPathInitialized = ETrue;
            iIsInitializing = EFalse;
            }
        else
            {
            // Try opening default
            LoadDefaultPathL();
            }
        }
    }

// ---------------------------------------------------------------------------
// Initialize the playback engine with a collection path
// ---------------------------------------------------------------------------
//
void CMPXRestorePath::InitPlaybackEngineL( CMPXCollectionPath& aPath )
    {
    MPX_FUNC( "CMPXRestorePath::InitPlaybackEngineL" );
    // Do not load a playlist if USB started, this
    // could happen if the user switches mode from MTP to USB
    // which would lose the playback playlist
    //
    if( !iUSBOngoing && !iInitCanceled )
        {
        CMPXCollectionPlaylist* playlist = CMPXCollectionPlaylist::NewL( aPath );
        CleanupStack::PushL( playlist );
        iPlaybackUtility->InitL( *playlist, EFalse );
        CleanupStack::PopAndDestroy( playlist );
        }
    else
        {
        iIsInitializing = EFalse;
        iPathInitialized = ETrue;
        iInitCanceled = EFalse;
        }
    }

// -----------------------------------------------------------------------------
// Handle playback message
// -----------------------------------------------------------------------------
//
void CMPXRestorePath::DoHandlePlaybackMessageL( const CMPXMessage& aMessage )
    {
    MPX_FUNC( "CMPXRestorePath::DoHandlePlaybackMessageL" );
    TMPXMessageId id( aMessage.ValueTObjectL<TMPXMessageId>( KMPXMessageGeneralId ) );
    if ( KMPXMessageGeneral == id )
        {
        TInt event( aMessage.ValueTObjectL<TInt>( KMPXMessageGeneralEvent ) );
        MPX_DEBUG2( "CMPXRestorePath::DoHandlePlaybackMessageL(%d)", event );

        switch ( event )
            {
            default:
                {
                // ignore other messages
                break;
                }
            }
        }
    }

// -----------------------------------------------------------------------------
// Handle collection message
// -----------------------------------------------------------------------------
//
void CMPXRestorePath::DoHandleCollectionMessageL( const CMPXMessage& aMessage )
    {
    MPX_FUNC( "CMPXRestorePath::DoHandleCollectionMessageL" );
    TMPXMessageId id( aMessage.ValueTObjectL<TMPXMessageId>( KMPXMessageGeneralId ) );
    if ( KMPXMessageGeneral == id )
        {
        TInt event( aMessage.ValueTObjectL<TInt>( KMPXMessageGeneralEvent ) );
        TInt type( aMessage.ValueTObjectL<TInt>( KMPXMessageGeneralType ) );
        TInt data( aMessage.ValueTObjectL<TInt>( KMPXMessageGeneralData ) );
        MPX_DEBUG3( "CMPXRestorePath::DoHandleCollectionMessageL Event = %d, Type() = %d",
            event, type );

        // When OpenL( *path ) is done we get a path changed msg
        //
        if ( event == TMPXCollectionMessage::EPathChanged &&
            type == EMcPathChangedByOpen &&
            data == EMcItemOpened )
            {
            MPX_DEBUG1("CMPXRestorePath::DoHandleCollectionMessageL -- opening new path");
            iCollectionUtility->Collection().OpenL();
            }
        else if( event == TMPXCollectionMessage::EBroadcastEvent )
            {
            // Restore default path after refresh or end of mtp
            //
            if( type == EMcMsgRefreshEnd )
                {
                MPX_DEBUG1( "CMPXRestorePath::DoHandleCollectionMessageL -- Refresh End" );
                if( iLoadSavedPath )
                    {
                    MPX_DEBUG1("  ---> Loading a saved path");
                    LoadPathL();
                    }
                else
                    {
                    MPX_DEBUG1("  ---> Loading a default path");
                    LoadDefaultPathL();
                    }
                iLoadSavedPath = EFalse;
                }
            else if ( type == EMcMsgUSBMTPEnd )
            	{
                if ( iMTPStarted )
                    {
                    MPX_DEBUG1( "CMPXRestorePath::DoHandleCollectionMessageL -- MTP End" );
                    if( iLoadSavedPath )
                        {
                        MPX_DEBUG1("  ---> Loading a saved path");
                        LoadPathL();
                        }
                    else
                        {
                        MPX_DEBUG1("  ---> Loading a default path");
                        LoadDefaultPathL();
                        }
                    iLoadSavedPath = EFalse;   
                    iMTPStarted = EFalse;
                    }
            	}
            // Disk inserted, we try to keep playback playlist at the
            // currently selected song after the automatic refresh
            //
            // USB mass storage dismounts the disk, but in that case
            // we do want to revert back to first song of all songs
            //
			//if refresh started save the path info
			//
            else if( ( type == EMcMsgDiskInserted || EMcMsgRefreshStart ) &&
                     !iUSBOngoing )
                {
                SavePathL();
                iLoadSavedPath = ETrue;
                }
            else if( type == EMcMsgUSBMassStorageStart )
                {
                iUSBOngoing = ETrue;
                }
            else if( type == EMcMsgUSBMassStorageEnd )
                {
                iUSBOngoing = EFalse;
                }
            else if( type == EMcMsgDiskRemoved
                     && !iUSBOngoing )
                {
                MPX_DEBUG1("  ---> Save the current path and restore it");
                SavePathL();
                LoadPathL();
                }
            else if( type == EMcMsgFormatEnd )
                {
                MPX_DEBUG1(" --> Loading a default path after formatting ");
                LoadDefaultPathL();
                }
            else if ( type == EMcMsgUSBMTPStart )
                {
                iMTPStarted = ETrue;
                }
            }
        else if ( event == TMPXCollectionMessage::ECollectionChanged && !iInitCanceled )
            {
            //To Handle the case when path is restored and we are in playback view.
            //This will switch to the right playback view to prevent podcast playback on music playback view.
            MMPXViewUtility* viewUtility = MMPXViewUtility::UtilityL();
            if (viewUtility->ActiveViewType() == TUid::Uid( KMPXPluginTypePlaybackUid ) && 
                    viewUtility->ActiveViewImplementationUid() != TUid::Uid(KMPXPdSbPlaybackViewImplementationId))
                {
                MMPXPlayer* player = iPlaybackUtility->PlayerManager().CurrentPlayer();
                if ( player )
                    {
                    RArray<TUid> array;
                    CleanupClosePushL( array );
                    array.AppendL( player->UidL() );
                    array.AppendL(TUid::Uid(data));
                    viewUtility->ActivateViewL( array );
                    CleanupStack::PopAndDestroy( &array );
                    }
                }
            viewUtility->Close();
            }
        else
            {
            // Ignore all other messages
            }
        }
    }

// -----------------------------------------------------------------------------
// Start the incremental reading operation at an offset
// -----------------------------------------------------------------------------
//
void CMPXRestorePath::DoIncrementalOpenL( CMPXCollectionPath& aPath,
                                          TInt aIndex,
                                          TInt aDelay )
    {
    RArray<TMPXAttribute> attrs;
    CleanupClosePushL( attrs );
    TArray<TMPXAttribute> ary = attrs.Array();
    iIncOpenUtil->Stop();
    iIncOpenUtil->SetDelay( aDelay );
    iIncOpenUtil->StartL( aPath, ary, KIncrementalFetchCount,
                          aIndex, CMPXCollectionOpenUtility::EFetchNormal );
    CleanupStack::PopAndDestroy( &attrs );
    }

// -----------------------------------------------------------------------------
// Get the Uid of the root path 
// -----------------------------------------------------------------------------
//
TUid CMPXRestorePath::RooPathId()
    {
    return iRootPathId;
    }
// End of File