diff -r 000000000000 -r 96612d01cf9f videocollection/hgmyvideos/src/vcxhgmyvideosvideodataupdater.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/videocollection/hgmyvideos/src/vcxhgmyvideosvideodataupdater.cpp Mon Jan 18 20:21:12 2010 +0200 @@ -0,0 +1,685 @@ +/* +* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "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: CVcxHgMyVideosVideoDataUpdater implementation* +*/ + + + + +// INCLUDE FILES +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include // DRM +#include + +#include "IptvDebug.h" +#include +#include "vcxhgmyvideosmodel.h" +#include "vcxhgmyvideosmainview.h" +#include "vcxhgmyvideosvideolist.h" +#include "vcxhgmyvideosvideodataupdater.h" +#include "vcxhgmyvideosindicatorhelper.h" + +const TInt KRefreshTimerInterval( 1000000 ); // 1 second + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::NewL() +// ----------------------------------------------------------------------------- +// +CVcxHgMyVideosVideoDataUpdater* CVcxHgMyVideosVideoDataUpdater::NewL( + CVcxHgMyVideosModel& aModel, + CHgScroller& aScroller, + CVcxHgMyVideosVideoList& aVideoArray ) + { + CVcxHgMyVideosVideoDataUpdater* self = + CVcxHgMyVideosVideoDataUpdater::NewLC( aModel, + aScroller, + aVideoArray ); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::NewLC() +// ----------------------------------------------------------------------------- +// +CVcxHgMyVideosVideoDataUpdater* CVcxHgMyVideosVideoDataUpdater::NewLC( + CVcxHgMyVideosModel& aModel, + CHgScroller& aScroller, + CVcxHgMyVideosVideoList& aVideoArray ) + { + CVcxHgMyVideosVideoDataUpdater* self = + new (ELeave) CVcxHgMyVideosVideoDataUpdater( aModel, + aScroller, + aVideoArray ); + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::CVcxHgMyVideosVideoDataUpdater() +// ----------------------------------------------------------------------------- +// +CVcxHgMyVideosVideoDataUpdater::CVcxHgMyVideosVideoDataUpdater( + CVcxHgMyVideosModel& aModel, + CHgScroller& aScroller, + CVcxHgMyVideosVideoList& aVideoArray ) + : CActive( EPriorityStandard ), + iModel( aModel ), + iScroller( aScroller ), + iVideoArray( aVideoArray ), + iPaused( EFalse ) + { + CActiveScheduler::Add( this ); + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::ConstructL() +// ----------------------------------------------------------------------------- +// +void CVcxHgMyVideosVideoDataUpdater::ConstructL() + { + iRefreshTimer = CPeriodic::NewL( CActive::EPriorityStandard ); + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::InfoArrayChanged() +// ----------------------------------------------------------------------------- +// +void CVcxHgMyVideosVideoDataUpdater::InfoArrayChanged() + { + // Can we optimise this? Many times new video list contains lot of items + // from the old one. But how to make sure there isn't any radical changes... + + CancelAndDeleteFetchArray(); + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::~CVcxHgMyVideosVideoDataUpdater() +// ----------------------------------------------------------------------------- +// +CVcxHgMyVideosVideoDataUpdater::~CVcxHgMyVideosVideoDataUpdater() + { + if ( iRefreshTimer ) + { + // Calling cancel without checking if the timer is active is safe. + iRefreshTimer->Cancel(); + delete iRefreshTimer; + } + + CancelAndDeleteFetchArray(); + delete iTnEngine; + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::SetPausedL() +// ----------------------------------------------------------------------------- +// +void CVcxHgMyVideosVideoDataUpdater::SetPausedL( TBool aPaused ) + { + iPaused = aPaused; + + if ( ! iPaused ) + { + ContinueVideoDataFetchingL(); + } + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::RequestDataL() +// ----------------------------------------------------------------------------- +// +void CVcxHgMyVideosVideoDataUpdater::RequestDataL( TMPXItemId aMPXItemId ) + { + AddItemToFetchArrayL( aMPXItemId ); + ContinueVideoDataFetchingL(); + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::ReleaseData() +// ----------------------------------------------------------------------------- +// +void CVcxHgMyVideosVideoDataUpdater::ReleaseData( TMPXItemId aMPXItemId ) + { + RemoveItem( IndexByMPXItemId( aMPXItemId ) ); + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::RemoveItem() +// ----------------------------------------------------------------------------- +// +void CVcxHgMyVideosVideoDataUpdater::RemoveItem( TInt aIndex ) + { + if ( aIndex >= 0 && aIndex < iFetchArray.Count() ) + { + CancelActivities( aIndex ); + + delete iFetchArray[aIndex]; + iFetchArray[aIndex] = NULL; + iFetchArray.Remove( aIndex ); + } + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::AddItemToFetchArrayL() +// ----------------------------------------------------------------------------- +// +void CVcxHgMyVideosVideoDataUpdater::AddItemToFetchArrayL( TMPXItemId aMPXItemId ) + { + CVcxHgMyVideosVideoData* newItem = CVcxHgMyVideosVideoData::NewLC(); + newItem->SetMPXItemId( aMPXItemId ); + iFetchArray.AppendL( newItem ); + + CleanupStack::Pop( newItem ); + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::CancelActivities() +// ----------------------------------------------------------------------------- +// +void CVcxHgMyVideosVideoDataUpdater::CancelActivities( TInt aIndex ) + { + if ( aIndex >= 0 && aIndex < iFetchArray.Count() ) + { + CVcxHgMyVideosVideoData::TVideoDataState state = iFetchArray[aIndex]->State(); + + if ( state == CVcxHgMyVideosVideoData::EVideoDataStateThumbnailStarted ) + { + // Cancel thumbnail generation. Safe to ignore leave, as the ThumbnailManagerL + // can only leave if iTnEngine is not created yet, so there cannot be + // any outstanding requests either. + TRAP_IGNORE( ThumbnailManagerL()->CancelRequest( + iFetchArray[aIndex]->ThumbnailConversionId() ) ); + } + else if ( state == CVcxHgMyVideosVideoData::EVideoDataStateDrmStarted ) + { + // Cancel DRM checking. + Cancel(); + } + } + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::CancelAndDeleteFetchArray() +// ----------------------------------------------------------------------------- +// +void CVcxHgMyVideosVideoDataUpdater::CancelAndDeleteFetchArray() + { + for ( TInt i = 0; i < iFetchArray.Count(); i++ ) + { + RemoveItem( i ); + } + iFetchArray.ResetAndDestroy(); + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::ContinueVideoDataFetchingL() +// ----------------------------------------------------------------------------- +// +void CVcxHgMyVideosVideoDataUpdater::ContinueVideoDataFetchingL() + { + if ( iFetchArray.Count() >= 1 && ! iPaused && iVideoArray.VideoCount() > 0 ) + { + TBool go = EFalse; + + // If first item is in idle state, we need to start new operation. + if ( iFetchArray[0]->State() == CVcxHgMyVideosVideoData::EVideoDataStateNone ) + { + // It's safe to ignore leave here, because in that case we just use the first index + // of fetch array. + TRAP_IGNORE( SelectNextIndexL() ); + go = ETrue; + } + // If thumbnail generation has finished, start DRM checking. + else if ( iFetchArray[0]->State() == CVcxHgMyVideosVideoData::EVideoDataStateThumbnailFinished ) + { + go = ETrue; + } + // If first item has completed all operations, remove it and start with second one. + else if ( iFetchArray[0]->State() == CVcxHgMyVideosVideoData::EVideoDataStateDrmFinished ) + { + UpdateVideoDataToUiL( *( iFetchArray[0] ) ); + RemoveItem( 0 ); + + if ( iFetchArray.Count() >= 1 ) + { + TRAP_IGNORE( SelectNextIndexL() ); + go = ETrue; + } + } + + if ( go ) + { + if ( iFetchArray[0]->State() == CVcxHgMyVideosVideoData::EVideoDataStateNone ) + { + CMPXMedia* media = iVideoArray.MPXMediaByMPXItemId( iFetchArray[0]->MPXItemId() ); + + if ( media && media->IsSupported( KMPXMediaGeneralUri ) ) + { + HBufC* mimeType = NULL; + if ( media->IsSupported( KMPXMediaGeneralMimeType ) ) + { + mimeType = media->ValueText( KMPXMediaGeneralMimeType ).AllocLC(); + } + else + { + mimeType = HBufC::NewLC( 1 ); + } + + CThumbnailObjectSource* source = CThumbnailObjectSource::NewLC( + media->ValueText( KMPXMediaGeneralUri ), + *mimeType ); + iFetchArray[0]->SetThumbnailConversionId( + ThumbnailManagerL()->GetThumbnailL( *source ) ); + CleanupStack::PopAndDestroy( source ); + CleanupStack::PopAndDestroy( mimeType ); + + IPTVLOGSTRING3_LOW_LEVEL( + "MPX My Videos UI # GetThumbnailL() called thumbID %d for %S.", + iFetchArray[0]->ThumbnailConversionId(), + &media->ValueText( KMPXMediaGeneralUri ) ); + + iRefreshTimer->Cancel(); + iRefreshTimer->Start( KRefreshTimerInterval, + KRefreshTimerInterval, + TCallBack( RefreshTimerCallBack, this ) ); + + iFetchArray[0]->SetState( + CVcxHgMyVideosVideoData::EVideoDataStateThumbnailStarted ); + } + } + else if ( iFetchArray[0]->State() == + CVcxHgMyVideosVideoData::EVideoDataStateThumbnailFinished ) + { + if ( ! IsActive() ) + { + SetActive(); + iStatus = KRequestPending; + TRequestStatus* stat = &iStatus; + User::RequestComplete(stat, KErrNone); + + iFetchArray[0]->SetState( + CVcxHgMyVideosVideoData::EVideoDataStateDrmStarted ); + } + } + } + } + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::UpdateVideoDataToUiL() +// ----------------------------------------------------------------------------- +// +void CVcxHgMyVideosVideoDataUpdater::UpdateVideoDataToUiL( CVcxHgMyVideosVideoData& videoData ) + { + TInt index = iVideoArray.IndexByMPXItemId( videoData.MPXItemId() ); + + if ( index >= 0 && index < iScroller.ItemCount() ) + { + TBool drmUpdate = videoData.DrmProtected(); + CHgItem& listItem = iScroller.ItemL( index ); + + if ( videoData.Thumbnail() ) + { + CGulIcon* thumbnail = CGulIcon::NewL( videoData.Thumbnail( ETrue ) ); + listItem.SetIcon( thumbnail ); + } + + if ( drmUpdate ) + { + TVcxHgMyVideosIndicatorHelper::TIndicatorDrmStatus drmStatus; + CMPXMedia* media = iVideoArray.MPXMedia( index ); + + if ( media ) + { + TVcxHgMyVideosIndicatorHelper indicatorHelper; + TInt indicator1( 0 ); + TInt indicator2( 0 ); + + if ( videoData.ValidDrmRights() ) + { + drmStatus = TVcxHgMyVideosIndicatorHelper::EIndicatorDrmStatusValid; + } + else + { + drmStatus = TVcxHgMyVideosIndicatorHelper::EIndicatorDrmStatusExpired; + } + + TBool isNewVideo( EFalse ); + if ( media->IsSupported( KMPXMediaGeneralFlags ) ) + { + if ( media->ValueTObjectL( KMPXMediaGeneralFlags ) & + EVcxMyVideosVideoNew ) + { + isNewVideo = ETrue; + } + } + + indicatorHelper.GetIndicatorsForVideoL( + iModel, + isNewVideo, + EFalse, // *Recordings* + media->ValueText( KMPXMediaGeneralUri ), + drmStatus, + indicator1, + indicator2 ); + + if ( indicator1 ) + { + listItem.SetFlags( indicator1 ); + } + if ( indicator2 ) + { + listItem.SetFlags( indicator2 ); + } + } + } + + if ( ListRefreshNeeded( index ) ) + { + RefreshScreen(); + } + } + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::IndexByMPXItemId() +// ----------------------------------------------------------------------------- +// +TInt CVcxHgMyVideosVideoDataUpdater::IndexByMPXItemId( TMPXItemId aMPXItemId ) + { + for ( TInt i = 0; i < iFetchArray.Count(); i++ ) + { + if ( iFetchArray[i]->MPXItemId() == aMPXItemId ) + { + return i; + } + } + return KErrNotFound; + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::SelectNextIndexL() +// ----------------------------------------------------------------------------- +// +void CVcxHgMyVideosVideoDataUpdater::SelectNextIndexL() + { + TInt firstIndexOnScreen = iScroller.FirstIndexOnScreen(); + + if ( firstIndexOnScreen < 0 ) + { + firstIndexOnScreen = 0; + } + + TInt lastIndexOnScreen = firstIndexOnScreen + iScroller.ItemsOnScreen(); + + if ( lastIndexOnScreen >= iScroller.ItemCount() ) + { + lastIndexOnScreen = iScroller.ItemCount() - 1; + } + + // If visible items not found, updater takes object from 0 index. + for ( TInt i = firstIndexOnScreen; i <= lastIndexOnScreen; i++ ) + { + TInt index( KErrNotFound ); + TMPXItemId mpxItemId; + CGulIcon* icon( NULL ); + + // Skip if list item already have a thumbnail. + icon = iScroller.ItemL( i ).Icon(); + if ( !icon ) + { + mpxItemId = iVideoArray.ArrayIndexToMpxItemIdL( i ); + index = IndexByMPXItemId( mpxItemId ); + + if ( index > 0 ) + { + // Move selected index to first index of the fetch array. + iFetchArray.Insert( iFetchArray[index], 0 ); + iFetchArray.Remove( index + 1 ); + break; + } + } + } + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::RefreshTimerCallBack() +// ----------------------------------------------------------------------------- +// +TInt CVcxHgMyVideosVideoDataUpdater::RefreshTimerCallBack( TAny* aAny ) + { + CVcxHgMyVideosVideoDataUpdater* self = static_cast( aAny ); + self->iRefreshTimer->Cancel(); + if ( self->iListRefreshIsDelayed ) + { + self->iListRefreshIsDelayed = EFalse; + if ( !self->iPaused ) + { + self->RefreshScreen(); + } + } + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::RefreshScreen() +// ----------------------------------------------------------------------------- +// +void CVcxHgMyVideosVideoDataUpdater::RefreshScreen() + { + IPTVLOGSTRING_LOW_LEVEL( "MPX My Videos UI # CVcxHgMyVideosVideoDataUpdater::RefreshScreen()" ); + iScroller.DrawDeferred(); + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::ListRefreshNeeded() +// ----------------------------------------------------------------------------- +// +TBool CVcxHgMyVideosVideoDataUpdater::ListRefreshNeeded( TInt aIndex ) + { + TBool modifiedIndexOnScreen( EFalse ); + TInt firstIndexOnScreen( iScroller.FirstIndexOnScreen() ); + + if ( firstIndexOnScreen < 0 ) + { + firstIndexOnScreen = 0; + } + + TInt lastIndexOnScreen = firstIndexOnScreen + iScroller.ItemsOnScreen(); + + if ( lastIndexOnScreen >= iScroller.ItemCount() ) + { + lastIndexOnScreen = iScroller.ItemCount() - 1; + } + + if ( aIndex >= firstIndexOnScreen && aIndex <= lastIndexOnScreen ) + { + modifiedIndexOnScreen = ETrue; + } + + TBool timerHasExpired( ! iRefreshTimer->IsActive() ); + TBool refreshNeeded( EFalse ); + + if ( ( iListRefreshIsDelayed && !modifiedIndexOnScreen ) + || iFetchArray.Count() <= 1 || timerHasExpired ) + { + iListRefreshIsDelayed = EFalse; + refreshNeeded = ETrue; + } + else if ( modifiedIndexOnScreen ) + { + iListRefreshIsDelayed = ETrue; + } + + return refreshNeeded; + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::ThumbnailManagerL() +// ----------------------------------------------------------------------------- +// +CThumbnailManager* CVcxHgMyVideosVideoDataUpdater::ThumbnailManagerL() + { + if ( !iTnEngine ) + { + IPTVLOGSTRING_LOW_LEVEL( + "MPX My Videos UI # CVcxHgMyVideosVideoDataUpdater::ThumbnailManagerL: Creating thumbnail manager." ); + + iTnEngine = CThumbnailManager::NewL( *this ); + iTnEngine->SetThumbnailSizeL( EVideoListThumbnailSize ); + iTnEngine->SetDisplayModeL( EColor16M ); + } + + return iTnEngine; + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::ThumbnailPreviewReady() +// From MThumbnailManagerObserver, not used in Video Center. +// ----------------------------------------------------------------------------- +// +void CVcxHgMyVideosVideoDataUpdater::ThumbnailPreviewReady( MThumbnailData& /*aThumbnail*/, + TThumbnailRequestId /*aId*/ ) + { + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::ThumbnailReady() +// From MThumbnailManagerObserver +// ----------------------------------------------------------------------------- +// +void CVcxHgMyVideosVideoDataUpdater::ThumbnailReady( TInt aError, + MThumbnailData& aThumbnail, + TThumbnailRequestId aId ) + { + IPTVLOGSTRING3_LOW_LEVEL( + "MPX My Videos UI # ThumbnailReady(error=%d, thumbID=%d)", aError, aId ); + + if ( iFetchArray.Count() > 0 ) + { + if ( aError == KErrNone + && aId == iFetchArray[0]->ThumbnailConversionId() ) + { + // Never delete this, ownership gone to Ganes list + iFetchArray[0]->SetThumbnail( aThumbnail.DetachBitmap() ); + } + else + { + iFetchArray[0]->SetThumbnail( NULL ); + } + + iFetchArray[0]->SetState( CVcxHgMyVideosVideoData::EVideoDataStateThumbnailFinished ); + } + + TRAP_IGNORE( ContinueVideoDataFetchingL() ); + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::RunL() +// From CActive +// ----------------------------------------------------------------------------- +// +void CVcxHgMyVideosVideoDataUpdater::RunL() + { + if ( iFetchArray.Count() > 0 ) + { + CMPXMedia* media = iVideoArray.MPXMediaByMPXItemId( iFetchArray[0]->MPXItemId() ); + + if ( media ) + { + if ( media->IsSupported( KMPXMediaGeneralUri ) ) + { + TUint32 flags = 0; + if ( media->IsSupported( KMPXMediaGeneralFlags ) ) + { + flags = media->ValueTObjectL( KMPXMediaGeneralFlags ); + } + + if ( flags & EVcxMyVideosVideoDrmProtected ) + { + ContentAccess::CData* cData = NULL; + + iFetchArray[0]->SetDrmProtected( ETrue ); + iFetchArray[0]->SetValidDrmRights( EFalse ); + + TRAPD( trapError, + cData = CData::NewL( + (TVirtualPathPtr) media->ValueText( KMPXMediaGeneralUri ), + EPeek, + EContentShareReadWrite ) ); + + if ( cData ) + { + if ( trapError == KErrNone ) + { + TInt intentResult = cData->EvaluateIntent( ContentAccess::EPlay ); + + // Not valid rights should return KErrCANoRights, KErrCANoPermission, + // or in rare cases KErrCAPendingRights. But we don't trust those and + // just compare against KErrNone. + if ( intentResult == KErrNone ) + { + iFetchArray[0]->SetValidDrmRights( ETrue ); + } + } + delete cData; + } + } + } + } + + iFetchArray[0]->SetState( CVcxHgMyVideosVideoData::EVideoDataStateDrmFinished ); + } + + ContinueVideoDataFetchingL(); + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::RunError() +// From CActive +// ----------------------------------------------------------------------------- +// +TInt CVcxHgMyVideosVideoDataUpdater::RunError( TInt aError ) + { + IPTVLOGSTRING2_LOW_LEVEL( "MPX My Videos UI # CVcxHgMyVideosVideoDataUpdater::RunError, aError = %d", aError ); + + if ( aError != KErrNone ) + { + // Remove current item from fetch array + RemoveItem( 0 ); + } + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CVcxHgMyVideosVideoDataUpdater::DoCancel() +// From CActive +// ----------------------------------------------------------------------------- +// +void CVcxHgMyVideosVideoDataUpdater::DoCancel() + { + }