videocollection/hgmyvideos/src/vcxhgmyvideosvideodataupdater.cpp
branchRCL_3
changeset 57 befca0ec475f
child 64 3eb824b18d67
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/videocollection/hgmyvideos/src/vcxhgmyvideosvideodataupdater.cpp	Wed Sep 01 12:30:28 2010 +0100
@@ -0,0 +1,1048 @@
+/*
+* 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 <mpxmediaarray.h>
+#include <mpxmedia.h>
+#include <mpxmediageneraldefs.h>
+
+#include <ganes/HgScroller.h>
+#include <ganes/HgItem.h>
+
+#include <thumbnailmanager.h>
+#include <thumbnailmanagerobserver.h>
+#include <thumbnailobjectsource.h>
+#include <thumbnaildata.h>
+#include <DRMCommon.h> // DRM
+#include <gulicon.h>
+
+#include "IptvDebug.h"
+#include <myvideosindicator.h>
+#include <vcxmyvideosdefs.h>
+#include "vcxhgmyvideosmodel.h"
+#include "vcxhgmyvideosmainview.h"
+#include "vcxhgmyvideosvideolist.h"
+#include "vcxhgmyvideosvideodataupdater.h"
+#include "vcxhgmyvideosindicatorhelper.h"
+#include "vcxhgmyvideosthumbnailmanager.h"
+
+const TInt KRefreshTimerInterval( 1000000 );    // 1 second
+const TInt KMaxThumbnailReqs( 2 );              // Max count of peek and get reqs combined
+const TInt KMaxThumbnailGetReqs( 1 );           // Max count of get reqs
+const TInt KMaxPredictiveSelect( 10 );          // Max range for selecting items before/after visible area
+const TInt KScrollCheckInterval( 250000 );      // 0.25 seconds
+
+// -----------------------------------------------------------------------------
+// TimeStamp
+// -----------------------------------------------------------------------------
+//
+static TInt64 TimeStamp()
+    {
+    TTime time;
+    time.UniversalTime();
+    return time.Int64();
+    }
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::NewL()
+// -----------------------------------------------------------------------------
+//
+CVcxHgMyVideosVideoDataUpdater* CVcxHgMyVideosVideoDataUpdater::NewL(
+        CVcxHgMyVideosModel& aModel,
+        CHgScroller& aScroller,
+        CVcxHgMyVideosVideoList& aVideoArray,
+        CMyVideosIndicator& aVideosIndicator )
+    {
+    CVcxHgMyVideosVideoDataUpdater* self = 
+        CVcxHgMyVideosVideoDataUpdater::NewLC( aModel,
+                                               aScroller,
+                                               aVideoArray,
+                                               aVideosIndicator );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::NewLC()
+// -----------------------------------------------------------------------------
+//
+CVcxHgMyVideosVideoDataUpdater* CVcxHgMyVideosVideoDataUpdater::NewLC(
+        CVcxHgMyVideosModel& aModel,
+        CHgScroller& aScroller,
+        CVcxHgMyVideosVideoList& aVideoArray,
+        CMyVideosIndicator& aVideosIndicator)
+    {
+    CVcxHgMyVideosVideoDataUpdater* self = 
+        new (ELeave) CVcxHgMyVideosVideoDataUpdater( aModel,
+                                                     aScroller,
+                                                     aVideoArray,
+                                                     aVideosIndicator );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::CVcxHgMyVideosVideoDataUpdater()
+// -----------------------------------------------------------------------------
+//
+CVcxHgMyVideosVideoDataUpdater::CVcxHgMyVideosVideoDataUpdater(
+        CVcxHgMyVideosModel& aModel,
+        CHgScroller& aScroller,
+        CVcxHgMyVideosVideoList& aVideoArray,
+        CMyVideosIndicator& aVideosIndicator )
+  : CActive( EPriorityStandard ),
+    iModel( aModel ),
+    iScroller( aScroller ),
+    iVideoArray( aVideoArray ),
+    iVideosIndicator( aVideosIndicator ),
+    iPaused( EFalse )
+    {
+    CActiveScheduler::Add( this );
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::ConstructL()
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::ConstructL()
+    {
+    iRefreshTimer = CPeriodic::NewL( CActive::EPriorityStandard );
+    iRetryTimer =   CPeriodic::NewL( CActive::EPriorityStandard );
+    iModel.ThumbnailManager().AddObserverL( *this );
+    }
+
+// -----------------------------------------------------------------------------
+// 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()
+    {
+    iModel.ThumbnailManager().RemoveObserver( *this );
+    Cancel();
+    delete iRefreshTimer; // Cancels active timer
+    delete iRetryTimer;
+    iFetchArray.ResetAndDestroy();
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::SetPausedL()
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::SetPausedL( TBool aPaused )
+    {
+    iPaused = aPaused;
+
+    if ( ! iPaused )
+        {
+        ContinueVideoDataFetchingL();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::RequestDataL()
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::RequestDataL( TMPXItemId aMPXItemId )
+    {
+    AddItemToFetchArrayL( aMPXItemId );
+    ContinueVideoDataFetchingL();
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::AddToRequestBufferL()
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::AddToRequestBufferL( TMPXItemId aMPXItemId )
+    {
+    AddItemToFetchArrayL( aMPXItemId );
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::FlushRequestBufferL()
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::FlushRequestBufferL()
+    {
+    ContinueVideoDataFetchingL();
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::ReleaseData()
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::ReleaseData( TMPXItemId aMPXItemId )
+    {
+    TInt index = IndexByMPXItemId( aMPXItemId );
+    if ( index >= 0 )
+        {
+        RemoveItem( index ); 
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::PrepareForMoveOrDelete()
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::PrepareForMoveOrDelete( TMPXItemId aMPXItemId )
+    {
+    TInt index = IndexByMPXItemId( aMPXItemId );
+    if ( index >= 0 )
+        {
+        RemoveAndCancelThumbnailGeneration( index ); 
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::RemoveAndCancelThumbnailGeneration()
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::RemoveAndCancelThumbnailGeneration( TInt aIndex )
+    {
+    if ( aIndex >= 0 && aIndex < iFetchArray.Count() )
+        {
+        // Can be enabled when cancellation of (hd) thumbnail gets faster and
+        // does not hang up UI
+        CancelActivities( aIndex );
+        delete iFetchArray[aIndex];
+        iFetchArray.Remove( aIndex );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::RemoveItem()
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::RemoveItem( TInt aIndex )
+    {
+    if ( aIndex >= 0 && aIndex < iFetchArray.Count() )
+        {    
+        CVcxHgMyVideosVideoData* item = iFetchArray[aIndex];
+        
+        // When scrolling around canceling thumbnail creation is sometimes so slow
+        // that it hangs UI for while. Thumbnail is needed sooner or later anyway.
+        // Therefore let creation get finished in peace. It is possible to fetch already 
+        // created thumbs during creation but not during hang up. 
+        if ( item && !CancelNeeded( *item ) )
+            {
+            delete item;
+            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* item = iFetchArray[aIndex];
+        if ( item && CancelNeeded( *item ) )
+            {
+            iModel.ThumbnailManager().Cancel( item->ThumbnailConversionId() );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::CancelAndDeleteFetchArray()
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::CancelAndDeleteFetchArray()
+    {
+    TInt count = iFetchArray.Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        CancelActivities( i );
+        }
+    iFetchArray.ResetAndDestroy();
+    
+    iPreviousFirstScrollerIndexTime = 0;
+    iPreviousFirstScrollerIndex = iScroller.FirstIndexOnScreen();
+    iPreviousModifiedIndexOnScreen = EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::ContinueVideoDataFetchingL()
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::ContinueVideoDataFetchingL()
+    {
+    iRetryTimer->Cancel();
+    if ( !iPaused && iVideoArray.VideoCount() > 0 && iFetchArray.Count() > 0 )
+        {
+        TInt64 time = TimeStamp();
+        TBool refreshTimerNeeded = EFalse;
+        TInt peekReqs = 0;
+        TInt getReqs = 0;
+        GetActiveRequestCount( peekReqs, getReqs );
+        TInt reqs = peekReqs + getReqs;
+        if ( reqs < KMaxThumbnailReqs )
+            {
+            CVcxHgMyVideosVideoData::TVideoDataState state =
+                        CVcxHgMyVideosVideoData::EVideoDataStateNone;
+            CVcxHgMyVideosVideoData* prevItem = NULL;
+            CVcxHgMyVideosVideoData* item = NULL;
+            do
+                {
+                TInt err = KErrNone;
+                prevItem = item;
+                if ( !SelectNextIndexL( getReqs >= KMaxThumbnailGetReqs ) )
+                    {
+                    // Nothing to be started
+                    if ( !reqs && iFetchArray.Count() > 0 )
+                        {
+                        // To ensure that thumbnail creation continues after
+                        // disabled while scrolling
+                        iRetryTimer->Start( KScrollCheckInterval, KScrollCheckInterval,
+                            TCallBack( RetryTimerCallBack, this ) );
+                        iPreviousFirstScrollerIndexTime = 0; // Force scroll check update
+                        IPTVLOGSTRING_LOW_LEVEL(
+                           "MPX My Videos UI # ContinueVideoDataFetchingL # iRetryTimer start" );
+                        }
+                    break;
+                    }
+                item = iFetchArray[0];
+                state = item->State();
+                if ( state == CVcxHgMyVideosVideoData::EVideoDataStateNone )
+                    {
+                    // Try first a quick peek with thumbnail creation denied
+                    TRAP( err, StartThumbnailL( *item, ETrue ) );
+                    if( err == KErrNone )
+                        {
+                        ++reqs;
+                        refreshTimerNeeded = ETrue;
+                        }
+                    }
+                else if ( state == CVcxHgMyVideosVideoData::EVideoDataStateThumbnailPeekFinished ) 
+                    {
+                    if ( getReqs < KMaxThumbnailGetReqs )
+                        {
+                        // Try then get with thumbnail creation allowed
+                        TRAP( err, StartThumbnailL( *item, EFalse ) );
+                        if ( err == KErrNone )
+                            {
+                            ++reqs;
+                            ++getReqs;
+                            refreshTimerNeeded = ETrue;
+                            }
+                        }
+                    }
+                if ( err != KErrNone )
+                    {
+                    RemoveItem( 0 );
+                    }                
+                }
+            while ( iFetchArray.Count() > 0 && reqs < KMaxThumbnailReqs && prevItem != item );
+            }
+        if ( refreshTimerNeeded && !iRefreshTimer->IsActive() )
+            {
+            iRefreshTimer->Start( KRefreshTimerInterval, KRefreshTimerInterval,
+                TCallBack( RefreshTimerCallBack, this ) );
+            IPTVLOGSTRING_LOW_LEVEL(
+               "MPX My Videos UI # ContinueVideoDataFetchingL # iRefreshTimer start" );
+            }
+        if ( time - iPreviousFirstScrollerIndexTime >= KScrollCheckInterval )
+            {
+            // Store values for scroll direction check
+            iPreviousFirstScrollerIndexTime = time;
+            iPreviousFirstScrollerIndex = iScroller.FirstIndexOnScreen();
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::UpdateVideoDataToUiL()
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::UpdateVideoDataToUiL( CVcxHgMyVideosVideoData& aVideoData )
+    {
+    IPTVLOGSTRING_LOW_LEVEL("CVcxHgMyVideosVideoDataUpdater::UpdateVideoDataToUiL() ENTER" );
+
+    TInt index = iVideoArray.IndexByMPXItemId( aVideoData.MPXItemId() );
+    
+    if ( index >= 0 && index < iScroller.ItemCount() )
+        {       
+        TBool drmUpdate = aVideoData.DrmProtected();
+        CHgItem& listItem = iScroller.ItemL( index );
+                
+        if ( aVideoData.Thumbnail() )
+            {
+            CGulIcon* thumbnail = CGulIcon::NewL( aVideoData.Thumbnail( ETrue ) );
+            listItem.SetIcon( thumbnail );
+            CMPXMedia* media = iVideoArray.MPXMediaByMPXItemId( aVideoData.MPXItemId() );
+            if ( iVideosIndicator.IsIndicatorShown( *media ) )
+                {
+                IPTVLOGSTRING_LOW_LEVEL("CVcxHgMyVideosVideoDataUpdater::UpdateVideoDataToUiL() has icon, has indicator" );
+                listItem.SetFlags( CHgItem::EHgItemFlagsIconOverlayIndicator );
+                }
+            else
+                {
+                IPTVLOGSTRING_LOW_LEVEL("CVcxHgMyVideosVideoDataUpdater::UpdateVideoDataToUiL() has icon, no indicator" );
+                listItem.ClearFlags( CHgItem::EHgItemFlagsIconOverlayIndicator );
+                }
+            }
+        
+        if ( drmUpdate )
+            {
+            TVcxHgMyVideosIndicatorHelper::TIndicatorDrmStatus drmStatus;
+            CMPXMedia* media = iVideoArray.MPXMedia( index );
+            
+            if ( media )
+                {
+                TVcxHgMyVideosIndicatorHelper indicatorHelper;
+                TInt indicator1( 0 );
+                TInt indicator2( 0 );
+
+                if ( aVideoData.ValidDrmRights() )
+                    {
+                    drmStatus = TVcxHgMyVideosIndicatorHelper::EIndicatorDrmStatusValid;
+                    }
+                else
+                    {
+                    drmStatus = TVcxHgMyVideosIndicatorHelper::EIndicatorDrmStatusExpired;
+                    }
+
+                TBool isNewVideo( EFalse );
+                if ( media->IsSupported( KMPXMediaGeneralFlags ) )
+                    {
+                    if ( media->ValueTObjectL<TUint32>( 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();
+            }
+        }
+    IPTVLOGSTRING_LOW_LEVEL("CVcxHgMyVideosVideoDataUpdater::UpdateVideoDataToUiL() RETURN" );
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::IndexByMPXItemId()
+// -----------------------------------------------------------------------------
+//
+TInt CVcxHgMyVideosVideoDataUpdater::IndexByMPXItemId( TMPXItemId aMPXItemId )
+    {   
+    TInt count = iFetchArray.Count();
+    for ( TInt i = 0; i < count; i++ )
+        {
+        if ( iFetchArray[i]->MPXItemId() == aMPXItemId )
+            {
+            return i;
+            }
+        }
+    return KErrNotFound;
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::SelectNextIndexL()
+// -----------------------------------------------------------------------------
+// 
+TBool CVcxHgMyVideosVideoDataUpdater::SelectNextIndexL( TBool aSelectForPeekOnly )
+    {
+    TBool selected = EFalse;
+    if ( iScroller.ItemCount() > 0 )
+        {
+        TInt firstIndexOnScreen = 0;
+        TInt lastIndexOnScreen = 0;
+        TInt lastIndex = 0;
+        GetScrollerArea( firstIndexOnScreen, lastIndexOnScreen, lastIndex );
+
+        // Determine scroll direction for optimal selection
+        TInt maxPredict = KMaxPredictiveSelect;
+        TBool scrollUp = iPreviousFirstScrollerIndex > firstIndexOnScreen;
+        TBool scrollDown = iPreviousFirstScrollerIndex < firstIndexOnScreen;
+        if ( scrollUp || scrollDown )
+            {
+            if ( scrollUp )
+                {
+                IPTVLOGSTRING_LOW_LEVEL(
+                   "MPX My Videos UI # CVcxHgMyVideosVideoDataUpdater # scroll up" );
+                }
+            else
+                {
+                IPTVLOGSTRING_LOW_LEVEL(
+                    "MPX My Videos UI # CVcxHgMyVideosVideoDataUpdater # scroll down" );
+                }
+            aSelectForPeekOnly = ETrue; // Disable thumb creation while scrolling
+            }
+        else
+            {
+            maxPredict /= 2; // Split range when checking both directions
+            }
+
+        if ( !aSelectForPeekOnly || scrollUp )
+            {
+            // Try visible area first with thumb creation disabled to get
+            // already created thumbs as fast as possible
+            selected = TrySelectFromScrollerAreaL( firstIndexOnScreen, 
+                                                   lastIndexOnScreen,
+                                                   ETrue );
+            }
+        if ( !selected && !scrollUp )
+            {
+            // Try visible area and items below
+            TInt end = Min( lastIndexOnScreen + maxPredict, lastIndex );
+            selected = TrySelectFromScrollerAreaL( firstIndexOnScreen, end, 
+                    aSelectForPeekOnly );
+            }
+        if ( !selected && !scrollDown && firstIndexOnScreen > 0 )
+            {
+            // Try items above visible area
+            TInt end = Max( firstIndexOnScreen - maxPredict - 1, 0 );
+            selected = TrySelectFromScrollerAreaL( firstIndexOnScreen - 1, end,
+                    aSelectForPeekOnly );
+            }
+        if ( !selected )
+            {
+            // Try any item
+            TInt count = iFetchArray.Count();
+            for ( TInt i = 0; i < count; i++ )
+                {
+                if ( TrySelectL( i, aSelectForPeekOnly ) )
+                    {
+                    selected = ETrue;
+                    break;
+                    }
+                }
+            }
+        }
+    return selected;
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::RefreshTimerCallBack()
+// -----------------------------------------------------------------------------
+//
+TInt CVcxHgMyVideosVideoDataUpdater::RefreshTimerCallBack( TAny* aAny )
+    {
+    CVcxHgMyVideosVideoDataUpdater* self = static_cast<CVcxHgMyVideosVideoDataUpdater*>( aAny ); 
+    if ( !self->iPaused && self->iFetchArray.Count() > 0 )
+        {
+        // Do refresh only if on screen item has been modified
+        if ( self->iPreviousModifiedIndexOnScreen )
+            {
+            self->iPreviousModifiedIndexOnScreen = EFalse; // Reset refresh checking
+            self->RefreshScreen();
+            }
+        }
+    else
+        {
+        self->iRefreshTimer->Cancel();
+        IPTVLOGSTRING_LOW_LEVEL(
+           "MPX My Videos UI # RefreshTimerCallBack # iRefreshTimer stop" );
+        }
+    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 )
+    {
+    TInt firstIndexOnScreen = 0;
+    TInt lastIndexOnScreen = 0;
+    TInt lastIndex = 0;
+    GetScrollerArea( firstIndexOnScreen, lastIndexOnScreen, lastIndex );
+    
+    TBool modifiedIndexOnScreen = aIndex >= firstIndexOnScreen &&
+        aIndex <= lastIndexOnScreen;
+    TBool refreshNeeded( EFalse );
+
+    // Refresh rules:
+    // 1) Refresh if off screen item is detected after on screen item
+    // 2) Refresh if item is the last
+    if ( ( iPreviousModifiedIndexOnScreen && !modifiedIndexOnScreen ) ||
+         iFetchArray.Count() <= 1 )
+        {
+        // Restart refresh timer if there are items left after current one
+        iRefreshTimer->Cancel();
+        if ( iFetchArray.Count() > 1 )
+            {
+            iRefreshTimer->Start( KRefreshTimerInterval, KRefreshTimerInterval,
+                TCallBack( RefreshTimerCallBack, this ) );
+            IPTVLOGSTRING_LOW_LEVEL(
+               "MPX My Videos UI # ListRefreshNeeded # iRefreshTimer start" );
+            }
+        else
+            {
+            IPTVLOGSTRING_LOW_LEVEL(
+               "MPX My Videos UI # ListRefreshNeeded # iRefreshTimer stop" );
+            }
+        refreshNeeded = ETrue;
+        }
+    iPreviousModifiedIndexOnScreen = modifiedIndexOnScreen;
+    return refreshNeeded;
+    }
+
+// -----------------------------------------------------------------------------
+// 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 );
+
+    TInt count = iFetchArray.Count();
+    for( TInt i = 0; i < count; ++i )
+        {
+        CVcxHgMyVideosVideoData* item = iFetchArray[i];
+        if ( aId == item->ThumbnailConversionId() )
+            {
+            if ( aError == KErrNone ||
+			     aError == KErrCompletion || // Accept blacklisted
+                 item->State() == CVcxHgMyVideosVideoData::EVideoDataStateThumbnailStarted )
+                {
+                // Never delete this, ownership gone to Ganes list
+                item->SetThumbnail( aError == KErrNone ? aThumbnail.DetachBitmap() : NULL );
+                item->SetState( CVcxHgMyVideosVideoData::EVideoDataStateThumbnailFinished );
+                StartFinalActions();
+                }
+            else if ( aError == KErrNotFound &&
+            	item->State() == CVcxHgMyVideosVideoData::EVideoDataStateThumbnailPeekStarted )
+                {
+                // Try getting thumbnail with create allowed when peek failed with not found
+                item->SetState( CVcxHgMyVideosVideoData::EVideoDataStateThumbnailPeekFinished );
+                }
+            else
+                {
+                // Stop thumbnail peek attemps
+                item->SetState( CVcxHgMyVideosVideoData::EVideoDataStateThumbnailFinished );
+                StartFinalActions();
+                }
+
+            TRAPD( err, ContinueVideoDataFetchingL() );
+            if ( err != KErrNone )
+                {
+                IPTVLOGSTRING2_LOW_LEVEL(
+                "MPX My Videos UI # CVcxHgMyVideosVideoDataUpdater::ThumbnailReady, err = %d",
+                err );
+                }
+            break;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::RunL()
+// From CActive
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::RunL()
+    {
+    if ( !iPaused )
+        {
+        TInt i = iFetchArray.Count() - 1;
+        while( i >= 0 )
+            {
+            CVcxHgMyVideosVideoData* item = iFetchArray[i];
+            if ( item->State() == CVcxHgMyVideosVideoData::EVideoDataStateThumbnailFinished )
+                {
+                TRAP_IGNORE(
+                    {
+                    CheckDrmL( *item );
+                    UpdateVideoDataToUiL( *item );
+                    } );				
+                delete item;
+                iFetchArray.Remove(i);
+#if 0
+                if ( iFetchArray.Count() > 0 )
+                    {
+                    // If drm checking is time consuming, proceed finalisation later
+                    StartFinalActions();
+                    break;
+                    }
+#endif
+                }
+            --i;
+            }
+        if ( !iFetchArray.Count() )
+            {
+            // No items left, timers are not needed anymore
+            iRefreshTimer->Cancel();
+            iRetryTimer->Cancel();
+            IPTVLOGSTRING_LOW_LEVEL(
+               "MPX My Videos UI # RunL # iRefreshTimer stop" );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::RunError()
+// From CActive
+// -----------------------------------------------------------------------------
+//
+TInt CVcxHgMyVideosVideoDataUpdater::RunError( TInt aError )
+    {
+    IPTVLOGSTRING2_LOW_LEVEL( "MPX My Videos UI # CVcxHgMyVideosVideoDataUpdater::RunError, aError = %d", aError );
+    
+    if ( aError != KErrNone )
+        {
+        }
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::DoCancel()
+// From CActive
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::DoCancel()
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::CheckDrmL()
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::CheckDrmL( CVcxHgMyVideosVideoData& aVideoData )
+    {
+    CMPXMedia* media = iVideoArray.MPXMediaByMPXItemId( aVideoData.MPXItemId() );
+    if ( media && media->IsSupported( KMPXMediaGeneralUri ) )
+        {
+        TUint32 flags = 0;
+        if ( media->IsSupported( KMPXMediaGeneralFlags ) )
+            {
+            flags = media->ValueTObjectL<TUint32>( KMPXMediaGeneralFlags );
+            }
+        if ( flags & EVcxMyVideosVideoDrmProtected )
+            {
+            aVideoData.SetDrmProtected( ETrue );
+            aVideoData.SetValidDrmRights( EFalse );
+
+            ContentAccess::CData* cData = CData::NewLC( 
+                               (TVirtualPathPtr) media->ValueText( KMPXMediaGeneralUri ),
+                               EPeek,
+                               EContentShareReadWrite );
+            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 )
+                {
+                aVideoData.SetValidDrmRights( ETrue );
+                }
+            CleanupStack::PopAndDestroy( cData );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::GetActiveRequestCount()
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::GetActiveRequestCount(
+        TInt& aPeekRequests, TInt& aGetRequests )
+    {
+    aPeekRequests = 0;
+    aGetRequests = 0;
+    TInt count = iFetchArray.Count();
+    for( TInt i = 0; i < count; ++i )
+        {
+        CVcxHgMyVideosVideoData::TVideoDataState state = iFetchArray[i]->State();
+        if ( state == CVcxHgMyVideosVideoData::EVideoDataStateThumbnailPeekStarted )
+            {
+            ++aPeekRequests;
+            }
+        else if ( state == CVcxHgMyVideosVideoData::EVideoDataStateThumbnailStarted )
+            {
+            ++aGetRequests;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::StartThumbnailL()
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::StartThumbnailL(
+        CVcxHgMyVideosVideoData& aItem, TBool aPeek )
+    {
+    CMPXMedia* media = iVideoArray.MPXMediaByMPXItemId( aItem.MPXItemId() );
+    if ( media && media->IsSupported( KMPXMediaGeneralUri ) )
+        {
+        TPtrC uri = media->ValueText( KMPXMediaGeneralUri ); 
+        TPtrC mime = media->IsSupported( KMPXMediaGeneralMimeType ) ? 
+                        media->ValueText( KMPXMediaGeneralMimeType ) : KNullDesC;
+        TThumbnailRequestId id = 0;
+        if ( aPeek )
+            {
+            CThumbnailObjectSource* source = CThumbnailObjectSource::NewLC(
+                    uri, mime );
+            id = iModel.ThumbnailManager().PeekL( *source );
+            CleanupStack::PopAndDestroy( source );
+            }
+        else
+            {
+            CThumbnailObjectSource* source = CThumbnailObjectSource::NewLC(
+                    uri, mime );
+            id = iModel.ThumbnailManager().GetL( *source );
+            CleanupStack::PopAndDestroy( source ); 
+            }
+        aItem.SetThumbnailConversionId( id );
+
+        IPTVLOGSTRING4_LOW_LEVEL( 
+                "MPX My Videos UI # StartThumbnailL() called thumbID %d for %S (peek %d)",
+                aItem.ThumbnailConversionId(),
+                &media->ValueText( KMPXMediaGeneralUri ),
+                aPeek );
+
+        aItem.SetState( aPeek ?
+                CVcxHgMyVideosVideoData::EVideoDataStateThumbnailPeekStarted :
+                CVcxHgMyVideosVideoData::EVideoDataStateThumbnailStarted );
+        }
+    else
+        {
+        User::Leave( KErrNotFound );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::TrySelectL()
+// -----------------------------------------------------------------------------
+//
+TBool CVcxHgMyVideosVideoDataUpdater::TrySelectL( TInt aIndex, 
+                                                  TBool aSelectForPeekOnly )
+    {
+    // Move selected index to first index of the fetch array
+    TBool selected = EFalse;
+    CVcxHgMyVideosVideoData* item = iFetchArray[aIndex];
+    CVcxHgMyVideosVideoData::TVideoDataState state = item->State();
+    if ( aSelectForPeekOnly )
+        {
+        // Accept item only for peeking
+        if ( state == CVcxHgMyVideosVideoData::EVideoDataStateNone )
+            {
+            iFetchArray.InsertL( item, 0 );
+            iFetchArray.Remove( aIndex + 1 );
+            selected = ETrue;
+            }
+        }
+    else if ( state == CVcxHgMyVideosVideoData::EVideoDataStateNone ||
+              state == CVcxHgMyVideosVideoData::EVideoDataStateThumbnailPeekFinished )
+        {
+        // Accept any item that waits to be fetched
+        iFetchArray.InsertL( item, 0 );
+        iFetchArray.Remove( aIndex + 1 );
+        selected = ETrue;
+        }
+    return selected;
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::TrySelectFromScrollerL()
+// -----------------------------------------------------------------------------
+//
+TBool CVcxHgMyVideosVideoDataUpdater::TrySelectFromScrollerL(
+    TInt aPos, TBool aSelectForPeekOnly )
+    {
+    TBool selected = EFalse;
+    CGulIcon* icon = iScroller.ItemL( aPos ).Icon();
+    TMPXItemId mpxItemId = iVideoArray.ArrayIndexToMpxItemIdL( aPos );
+    TInt index = IndexByMPXItemId( mpxItemId );
+    if ( index >= 0 )
+        {
+		// Skip fetch selection if icon already exist
+        if ( !icon )
+            {
+            if ( TrySelectL( index, aSelectForPeekOnly ) )
+                {
+                selected = ETrue;
+                }
+            }
+        else
+            {
+            iFetchArray[index]->SetState(
+                CVcxHgMyVideosVideoData::EVideoDataStateThumbnailFinished );
+            StartFinalActions();
+            }
+        }
+    return selected;
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::TrySelectFromScrollerAreaL()
+// -----------------------------------------------------------------------------
+//
+TBool CVcxHgMyVideosVideoDataUpdater::TrySelectFromScrollerAreaL( 
+    TInt aStartPos, TInt aEndPos, TBool aSelectForPeekOnly )
+    {
+    TBool selected = EFalse;
+    if ( aEndPos >= aStartPos )
+        {
+        // Search forwards
+        for ( TInt i = aStartPos; i <= aEndPos; i++ )
+            {
+            if ( TrySelectFromScrollerL( i, aSelectForPeekOnly ) )
+                {
+                selected = ETrue;
+                break;
+                }
+            }
+        }
+    else
+        {
+        // Search backwards
+        for ( TInt i = aStartPos; i >= aEndPos; i-- )
+            {
+            if ( TrySelectFromScrollerL( i, aSelectForPeekOnly ) )
+                {
+                selected = ETrue;
+                break;
+                }
+            }
+        }
+    return selected;
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::StartFinalActions()
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::StartFinalActions()
+    {
+    if ( !IsActive() )
+        {
+        SetActive();
+        TRequestStatus* stat = &iStatus;
+        User::RequestComplete( stat, KErrNone );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::CancelNeeded()
+// -----------------------------------------------------------------------------
+//
+TBool CVcxHgMyVideosVideoDataUpdater::CancelNeeded( CVcxHgMyVideosVideoData& aItem )
+    {
+    CVcxHgMyVideosVideoData::TVideoDataState state = aItem.State();
+    return ( state == CVcxHgMyVideosVideoData::EVideoDataStateThumbnailPeekStarted ||
+             state == CVcxHgMyVideosVideoData::EVideoDataStateThumbnailStarted );
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::RetryTimerCallBack()
+// -----------------------------------------------------------------------------
+//
+TInt CVcxHgMyVideosVideoDataUpdater::RetryTimerCallBack( TAny* aAny )
+    {
+    CVcxHgMyVideosVideoDataUpdater* self = static_cast<CVcxHgMyVideosVideoDataUpdater*>( aAny ); 
+    self->iRetryTimer->Cancel();
+    TRAPD( err, self->ContinueVideoDataFetchingL() );
+    if ( err != KErrNone )
+        {
+        IPTVLOGSTRING2_LOW_LEVEL(
+        "MPX My Videos UI # CVcxHgMyVideosVideoDataUpdater::RetryTimerCallBack, err = %d",
+        err );
+        }
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CVcxHgMyVideosVideoDataUpdater::GetScrollerArea()
+// -----------------------------------------------------------------------------
+//
+void CVcxHgMyVideosVideoDataUpdater::GetScrollerArea( TInt& aFirstIndexOnScreen, 
+                                                      TInt& aLastIndexOnScreen, 
+                                                      TInt& aLastIndex )
+    {
+    aLastIndex = Max( iScroller.ItemCount() - 1, 0 );
+    aFirstIndexOnScreen = Max( iScroller.FirstIndexOnScreen(), 0 );
+    aLastIndexOnScreen = Min( aFirstIndexOnScreen + iScroller.ItemsOnScreen(), aLastIndex );
+    }