mpxmusicplayer/activeidle/aiplayerplugin/src/aiplayerplugin.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:45:05 +0200
changeset 0 ff3acec5bc43
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2006-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:  Active Idle player plug-in
*
*/


#include <ecom/implementationproxy.h>
#include <aiutility.h>

#include <AknUtils.h>
#include <StringLoader.h>
#include <bautils.h>
#include <avkon.rsg>

#include <data_caging_path_literals.hrh> 	// KDC_APP_BITMAP_DIR
#include <apgcli.h>           				// RApaLsSession
#include <apacmdln.h>         				// CApaCommandLine
#include <apgtask.h>

#include <mpxlog.h>
#include <mpxconstants.h> 					// KAppUidMusicPlayer
#include <mpxparameter.h>
#include <mpxmusicplayerviewplugin.hrh>
#include <aiplayerpluginresource.rsg>

#include "aiplayerplugin.h"
#include "aiplayerpluginuids.hrh"
#include "aiplayerplugincontentmodel.h"

_LIT(KMPXZeroDurationMark, "--");
const TInt KMPXMinSecSeparatorIndex = 2;
const TInt KMPXOneSecInMicroSecs = 1000000;
const TInt KMPXOneHourInSeconds = 60*60;
const TInt KMPXTimeIndicatorLength = 16;
const TInt KPlayerMusicPlayerParameterGranularity = 50;
_LIT( KMPXAiPlayerRscPath, "z:aiplayerpluginresource.rsc" );

const TInt KMPlayerResumeWaitTime = 1000000; // 1.0s

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

// ----------------------------------------------------------------------------
// CAiPlayerPlugin::ConstructL
// ----------------------------------------------------------------------------
//
void CAiPlayerPlugin::ConstructL()
    {
    MPX_DEBUG1("CAiPlayerPlugin::ConstructL() - begin");

    iInfo.iUid = KUidMusicPlayerPlugin;
    iInfo.iName.Copy(_L8("PlayerPlugin"));

    iContent   = AiUtility::CreateContentItemArrayIteratorL(KAiPlplContent);
    iResources = AiUtility::CreateContentItemArrayIteratorL(KAiPlplResources);
    iEvents    = AiUtility::CreateContentItemArrayIteratorL(KAiPlplEvents);

    // Read time format strings from AVKON resource
    iLongFormatString = StringLoader::LoadL(R_QTN_TIME_DURAT_LONG_WITH_ZERO);
    iShortFormatString = StringLoader::LoadL(R_QTN_TIME_DURAT_MIN_SEC_WITH_ZERO);

    iCoeEnv = CCoeEnv::Static();

    TParse parse;
    parse.Set(KMPXAiPlayerRscPath, &KDC_APP_RESOURCE_DIR, NULL);
    TFileName resourceFile;
    resourceFile.Append(parse.FullName());
    BaflUtils::NearestLanguageFile(iCoeEnv->FsSession(), resourceFile);
    iResourceOffset = iCoeEnv->AddResourceFileL(resourceFile);
    iUnknownArtistText = StringLoader::LoadL(R_MPX_QTN_AIPP_UNKNOWN_ARTIST);

    iPlayStarted = EFalse;
    iCleanTimer = CPeriodic::NewL(CActive::EPriorityStandard);

    MPX_DEBUG1("CAiPlayerPlugin::ConstructL() - end");
    }

// ----------------------------------------------------------------------------
// CAiPlayerPlugin::NewL
// ----------------------------------------------------------------------------
//
CAiPlayerPlugin* CAiPlayerPlugin::NewL()
    {
    CAiPlayerPlugin* self = new (ELeave) CAiPlayerPlugin;
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }

// ----------------------------------------------------------------------------
// CAiPlayerPlugin::CAiPlayerPlugin
// ----------------------------------------------------------------------------
//
CAiPlayerPlugin::CAiPlayerPlugin()
    : iEngine(NULL)
    {
    }

// ----------------------------------------------------------------------------
// CAiPlayerPlugin::~CAiPlayerPlugin()
// ----------------------------------------------------------------------------
//
CAiPlayerPlugin::~CAiPlayerPlugin()
    {
    iObservers.Close();

    Release( iContent );
    Release( iResources );
    Release( iEvents );

    if ( iResourceOffset )
        {
        iCoeEnv->DeleteResourceFile(iResourceOffset);
        }

    delete iEngine;

    delete iLongFormatString;
    delete iShortFormatString;
    delete iUnknownArtistText;

    iCoeEnv = NULL;
    iCleanTimer->Cancel();
    delete iCleanTimer;
    }

// ----------------------------------------------------------------------------
// CAiPlayerPlugin::Resume
// ----------------------------------------------------------------------------
//
void CAiPlayerPlugin::Resume( TAiTransitionReason aReason )
    {
    MPX_DEBUG1("CAiPlayerPlugin::ResumeL");
    if ( !iEngine )
        {
        TRAPD(err, iEngine = CAiPlayerPluginEngine::NewL(*this));
        if ( err == KErrNone )
        	{
			iState = iEngine->PlayerState();
			PlayerStateChanged( iState );
		    if (iState == EMPlayerStatePlaying || iState == EMPlayerStatePaused )
				{
				TrackInfoChanged( iEngine->Title(), iEngine->Artist() );
				VolumeChanged( iEngine->Volume() );
				PlaybackPositionChanged( iEngine->Position() );
				}
			}
        }
     else if ( aReason == EAiGeneralThemeChanged )
        {
        PlayerStateChanged( iEngine->PlayerState() );
        }

    }

// ----------------------------------------------------------------------------
// CAiPlayerPlugin::Suspend
// ----------------------------------------------------------------------------
//
void CAiPlayerPlugin::Suspend( TAiTransitionReason /*aReason*/ )
    {
    MPX_DEBUG1("CAiPlayerPlugin::Suspend");
    }

// ----------------------------------------------------------------------------
// CAiPlayerPlugin::Stop
// ----------------------------------------------------------------------------
//
void CAiPlayerPlugin::Stop( TAiTransitionReason /*aReason*/ )
    {
    MPX_DEBUG1("CAiPlayerPlugin::Stop");
    }

// ----------------------------------------------------------------------------
// CAiPlayerPlugin::SubscribeL
// ----------------------------------------------------------------------------
//
void CAiPlayerPlugin::SubscribeL( MAiContentObserver& aObserver )
    {
    MPX_DEBUG1("CAiPlayerPlugin::SubscribeL");
    return iObservers.AppendL(&aObserver);
    }

// ----------------------------------------------------------------------------
// CAiPlayerPlugin::ConfigureL
// ----------------------------------------------------------------------------
//
void CAiPlayerPlugin::ConfigureL( RAiSettingsItemArray& /*aSettings*/ )
    {
    MPX_DEBUG1("CAiPlayerPlugin::ConfigureL");
    }

// ----------------------------------------------------------------------------
// CAiPlayerPlugin::Extension
// ----------------------------------------------------------------------------
//
TAny* CAiPlayerPlugin::Extension( TUid aUid )
    {
    if (aUid == KExtensionUidProperty)
        {
        return static_cast<MAiPropertyExtension*>(this);
        }
    else if (aUid == KExtensionUidEventHandler)
        {
        return static_cast<MAiEventHandlerExtension*>(this);
        }
    return NULL; // Requested extension not supported
    }

// ----------------------------------------------------------------------------
// CAiPlayerPlugin::GetPropertyL
// ----------------------------------------------------------------------------
//
TAny* CAiPlayerPlugin::GetPropertyL( TInt aProperty )
    {
    switch (aProperty)
        {
        case EAiPublisherInfo:
        return &iInfo;

        case EAiPublisherContent:
        return static_cast<MAiContentItemIterator*>(iContent);

        case EAiPublisherResources:
        return static_cast<MAiContentItemIterator*>(iResources);

        case EAiPublisherEvents:
        return static_cast<MAiContentItemIterator*>(iEvents);
        }

    User::Leave(KErrNotSupported);
    return NULL;
    }

// ----------------------------------------------------------------------------
// CAiPlayerPlugin::SetPropertyL
// ----------------------------------------------------------------------------
//
void CAiPlayerPlugin::SetPropertyL( TInt aProperty, TAny* aValue )
    {
    if (aValue)
        {
        switch (aProperty)
            {
            case EAiPublisherInfo:
                {
                const TAiPublisherInfo* info =
                    static_cast<const TAiPublisherInfo*>(aValue);

                iInfo.iUid.iUid = info->iUid.iUid;
                iInfo.iName.Copy( info->iName );
                }
            break;
            }
        }
    }

// ----------------------------------------------------------------------------
// CAiPlayerPlugin::HandleEvent
// ----------------------------------------------------------------------------
//
void CAiPlayerPlugin::HandleEvent( TInt aEvent, const TDesC& aParam )
    {
    MPX_DEBUG1("CAiPlayerPlugin::HandleEvent");
    TRAPD(err, DoHandleEventL( aEvent, aParam ) );
    if ( err != KErrNone )
    	{
		MPX_DEBUG2("CAiPlayerPlugin::HandleEvent err[%d]", err);
		}
    }

// ----------------------------------------------------------------------------
// CAiPlayerPlugin::DoHandleEventL
// ----------------------------------------------------------------------------
//
void CAiPlayerPlugin::DoHandleEventL( TInt aEvent, const TDesC& aParam )
    {
    MPX_DEBUG2("CAiPlayerPlugin::DoHandleEventL %d", aEvent);

	TInt volume = iEngine->Volume();
    switch (aEvent)
        {
        case EAiPlplEventVolInc:
            {
            iEngine->SetVolumeL(++volume);
            iLastSetVolume = volume;
            }
            break;
        case EAiPlplEventVolDec:
            {
            iEngine->SetVolumeL(--volume);
            iLastSetVolume = volume;
            }
            break;
    	case EAiPlplEventVolSet:
    		{
    		TLex lex;
    		lex.Assign(aParam);
    		if( lex.Val(volume) == KErrNone )
    		    {
        		iEngine->SetVolumeL(volume);
    		    }
            iLastSetVolume = volume;
    		}
        	break;
    	case EAiPlplEventVolMute:
    		{
    		iLastSetVolume = volume;
       		iEngine->SetVolumeL(0);
    		}
	        break;
    	case EAiPlplEventVolRestore:
    		{
    		if( iLastSetVolume == 0 )
    		    {
    		    // So that "muting muted" don't function funky way.
    		    iLastSetVolume = 1;
    		    }
       		iEngine->SetVolumeL(iLastSetVolume);
    		}
	        break;
        case EAiPlplEventLaunchLibrary:
            {
            MPX_DEBUG1("CAiPlayerPlugin::DoHandleEventL() EAiPlplEventLaunchLibrary");
            //Launch player
            TApaTaskList tasList(iEikonEnv->WsSession());
            TApaTask task = tasList.FindApp(KAppUidMusicPlayerX);
            if (task.Exists())
                {
                MPX_DEBUG1("CAiPlayerPlugin::DoHandleEventL() Music app is already launched. Go to Now Playing view.");
                RWsSession& wsSession( iCoeEnv->WsSession() );
                CMPXParameter* param = new ( ELeave ) CMPXParameter();
                CleanupStack::PushL( param );
                param->iType.iUid = KMPXPluginTypePlaybackUid;
                param->iCmdForward = EMPXCmdFwdNowPlaying;

                MPX_DEBUG1( "CAiPlayerPlugin::DoHandleEventL start Externalize" );
                CBufBase* buffer = CBufFlat::NewL( KPlayerMusicPlayerParameterGranularity );
                CleanupStack::PushL( buffer );
                RBufWriteStream writeStream( *buffer );
                CleanupClosePushL( writeStream );
                param->ExternalizeL( writeStream );
                writeStream.CommitL();
                buffer->Compress();
                CleanupStack::PopAndDestroy( &writeStream );

                MPX_DEBUG2( "CAiPlayerPlugin::DoHandleEventL start Send message, message size = %d", buffer->Size() );
                wsSession.SendMessageToWindowGroup( task.WgId(), KAppUidMusicPlayerX, buffer->Ptr( 0 ));
                MPX_DEBUG1( "CAiPlayerPlugin::DoHandleEventL Send message complete" );
                CleanupStack::PopAndDestroy( buffer );
                CleanupStack::PopAndDestroy( param );
                }
            else
                {
				// Launch Music Player Application
                MPX_DEBUG1("CAiPlayerPlugin::DoHandleEventL() Launch Music app for the first time");
				RProcess process;
				TApaAppInfo appInfo;
				RApaLsSession session;
				TInt res = session.Connect(); // Ignore error
				CleanupClosePushL( session );
				TInt err = session.GetAppInfo( appInfo, KAppUidMusicPlayerX );
				if ( !err )
						{
						process.Create( appInfo.iFullName, KNullDesC );// Ignore error
						TRAP( err,
							{
							CApaCommandLine* commandLine = CApaCommandLine::NewLC();
							commandLine->SetDocumentNameL( KNullDesC );
							commandLine->SetExecutableNameL( appInfo.iFullName );
							commandLine->SetProcessEnvironmentL( process );
							session.StartApp( *commandLine ); // Ignore error
							CleanupStack::PopAndDestroy(); // commandLine
							});
						process.Resume();
						process.Close();
						}
				CleanupStack::PopAndDestroy(); // Close RApaLsSession session
                }
            }
            break;
        default:
        	break;
        }
    }

// ----------------------------------------------------------------------------
// CAiPlayerPlugin::ClearL
// ----------------------------------------------------------------------------
//
TInt CAiPlayerPlugin::ClearL(TAny* aPtr)
	{
    MPX_DEBUG1("CAiPlayerPlugin::ClearL");
  	CAiPlayerPlugin* plugin = reinterpret_cast<CAiPlayerPlugin*> (aPtr);
    for (TInt i = 0; i < plugin->iObservers.Count(); i++)
    	{
        MAiContentObserver* observer = plugin->iObservers[i];
        observer->Clean((MAiPropertyExtension&) *plugin, EAiPlplContentArtistCaption, 1);
        observer->Clean((MAiPropertyExtension&) *plugin, EAiPlplContentTitleCaption, 1);
        observer->Clean((MAiPropertyExtension&) *plugin, EAiPlplContentDurationCaption, 1);
        observer->Clean((MAiPropertyExtension&) *plugin, EAiPlplContentElapsedTime,1);
        observer->Clean((MAiPropertyExtension&) *plugin, EAiPlplContentStatus, 1);
        observer->Clean((MAiPropertyExtension&) *plugin, EAiPlplContentVolume,1);
        observer->Commit(0);
    	}
    plugin->iCleanTimer->Cancel();
    return KErrNone;
	}

// -----------------------------------------------------------------------------
// CAiPlayerPlugin::PlayerStateChanged
// -----------------------------------------------------------------------------
//
void CAiPlayerPlugin::PlayerStateChanged( TMPlayerState aState )
    {
    MPX_DEBUG2("CAiPlayerPlugin::PlayerStateChanged [%d]", aState);
    iState = aState;
    for (TInt i = 0; i < iObservers.Count(); i++)
        {
        MAiContentObserver* observer = iObservers[i];
        observer->StartTransaction(reinterpret_cast<TInt32>(this));
        switch(iState)
            {
            case EMPlayerStatePlaying:
                {
       			iPlayStarted = ETrue;
       			iCleanTimer->Cancel();
                observer->Publish(*this,
                                  EAiPlplContentStatus,
                                  EAiPlplResourcePlayIcon,
                                  1);
                }
                break;
            case EMPlayerStatePaused:
                {
       			iPlayStarted = ETrue;
                iCleanTimer->Cancel();
                observer->Publish(*this,
                                  EAiPlplContentStatus,
                                  EAiPlplResourcePauseIcon,
                                  1);
                PlaybackPositionChanged(iEngine->Position());
                }
                break;
            case EMPlayerStateSeeking:
                PlaybackPositionChanged(iEngine->Position());
                break;
            default:    // EMPlayerStateOther
       			if ( iPlayStarted )
       				{
       				iCleanTimer->Start(KMPlayerResumeWaitTime,
       			                        KMPlayerResumeWaitTime,
       			                        TCallBack(ClearL,this));
       				}
       			iPlayStarted = EFalse;
                break;
            }
        observer->Commit(reinterpret_cast<TInt32>(this));
        }
    }

// -----------------------------------------------------------------------------
// CAiPlayerPlugin::TrackInfoChanged
// -----------------------------------------------------------------------------
//
void CAiPlayerPlugin::TrackInfoChanged( const TDesC& aTitle, const TDesC& aArtist )
    {
    MPX_DEBUG1("CAiPlayerPlugin::TrackInfoChanged");
    for (TInt i = 0; i < iObservers.Count(); i++)
        {
        MAiContentObserver* observer = iObservers[i];
        observer->StartTransaction(reinterpret_cast<TInt32>(this));

        if ( &aTitle && aTitle.Length() ) //Check if hte reference exists add if is not empty
            {
            observer->Publish(*this, EAiPlplContentTitleCaption, aTitle, 1);
            }
        if ( &aArtist && aArtist.Length() ) //Check if hte reference exists add if is not empty
            {
            observer->Publish(*this, EAiPlplContentArtistCaption, aArtist, 1);
            }
        else
            {
            observer->Publish(*this, EAiPlplContentArtistCaption, *iUnknownArtistText, 1);
            }
        observer->Commit(reinterpret_cast<TInt32>(this));
        }
    }

// -----------------------------------------------------------------------------
// CAiPlayerPlugin::PlaybackPositionChanged
// -----------------------------------------------------------------------------
//
void CAiPlayerPlugin::PlaybackPositionChanged( TInt aPosition )
    {
    MPX_DEBUG1("CAiPlayerPlugin::PlaybackPositionChanged");

    TBuf<KMPXTimeIndicatorLength> elapsed;
    TBuf<KMPXTimeIndicatorLength> total;

    TInt64 playbackPosInSeconds;
    TInt64 totalLengthInSeconds;

    playbackPosInSeconds = aPosition;
    totalLengthInSeconds = iEngine->Duration();

    TPtrC format = *iShortFormatString;

    if (totalLengthInSeconds >= KMPXOneHourInSeconds)
        {
        // For tracks longer than an hour we use different time format and a
        // slightly different layout which has more space for the time labels.
        format.Set(*iLongFormatString);
        }

    TTime elapsedTime(playbackPosInSeconds * KMPXOneSecInMicroSecs);
    TTime totalTime(totalLengthInSeconds * KMPXOneSecInMicroSecs);

    if (aPosition == 0)
    	{
    	totalLengthInSeconds = 0;
    	}

    // Convert total playing time to texts.
    elapsedTime.FormatL(elapsed, format);

    if (totalLengthInSeconds)
        {
        // Time remaining
        totalTime.FormatL(total, format);
        }
    else
        {
        // Time remaining: --:--
        TLocale locale;
        TBuf<KMPXTimeIndicatorLength> pos;
        TChar separator = locale.TimeSeparator(KMPXMinSecSeparatorIndex);
        total = KMPXZeroDurationMark;
        total.Append(separator);
        total += KMPXZeroDurationMark;
        }

    AknTextUtils::LanguageSpecificNumberConversion(elapsed);
    AknTextUtils::LanguageSpecificNumberConversion(total);

    iElapsedTime.Copy(elapsed);

    iDuration.Copy(elapsed);
    iDuration.Append(_L("/"));
    iDuration.Append(total);

    if ( iState == EMPlayerStatePlaying || iState == EMPlayerStatePaused || iState == EMPlayerStateSeeking )
        {
        for (TInt i = 0; i < iObservers.Count(); i++)
            {
            MAiContentObserver* observer = iObservers[i];
            observer->StartTransaction(reinterpret_cast<TInt32>(this));

            //for (Classic view)
            observer->Publish(*this,
                           EAiPlplContentElapsedTime,
                           iElapsedTime,
                           1);

            //for (Navibar view)
            observer->Publish(*this,
                           EAiPlplContentDurationCaption,
                           iDuration,
                           1);

            observer->Commit(reinterpret_cast<TInt32>(this));
            }
        }
    }

// -----------------------------------------------------------------------------
// CAiPlayerPlugin::VolumeChanged
// -----------------------------------------------------------------------------
//
void CAiPlayerPlugin::VolumeChanged( TInt aVolume )
    {
    MPX_DEBUG1("CAiPlayerPlugin::VolumeChanged");

    for (TInt i = 0; i < iObservers.Count(); i++)
        {
        MAiContentObserver* observer = iObservers[i];
        observer->StartTransaction(reinterpret_cast<TInt32>(this));

        // Order of enum TAiPlplPluginResourceIds is important
        // must stay EAiPlplResourceVol0= 0 ... EAiPlplResourceVol10 = 10
        // for this to work
        if ( aVolume>=0 && aVolume<=10 )
            {
            observer->Publish(*this,
                              EAiPlplContentVolume,
                              aVolume,
                              1);
            }
        observer->Commit(reinterpret_cast<TInt32>(this));
        }
    }

// ======== GLOBAL FUNCTIONS ========

// Provide a key pair value table for ECOM.
// Used to identify the correct construction function for the requested interface.
const TImplementationProxy ImplementationTable[] =
{
    IMPLEMENTATION_PROXY_ENTRY( AI_UID_ECOM_IMPLEMENTATION_CONTENTPUBLISHER_PLAYERPLUGIN,
                                CAiPlayerPlugin::NewL )
};


// Return an instance of the proxy table.
EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
{
    aTableCount = sizeof( ImplementationTable ) / sizeof( TImplementationProxy );
    return ImplementationTable;
}