videocollection/hgmyvideos/src/vcxhgmyvideosvideodataupdater.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 25 May 2010 12:44:54 +0300
branchRCL_3
changeset 15 8f0df5c82986
parent 9 5294c000a26d
child 20 2d690156cf8f
permissions -rw-r--r--
Revision: 201019 Kit: 2010121

/*
* 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 <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 )
    {
    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 );
    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 )
    {
    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 ); 
            }
        
        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();
            }
        }
    }

// -----------------------------------------------------------------------------
// 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 );
    }