profilesapplication/Profiles/ProfileApp/SettingsViewSrc/CProfileToneHandler.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 25 May 2010 12:42:45 +0300
branchRCL_3
changeset 14 232e127a1fe4
parent 11 bc161388e3ce
permissions -rw-r--r--
Revision: 201019 Kit: 2010121

/*
* Copyright (c) 2002-2006 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  A helper interface to be used by S60 applications for
*                setting ringing and alert tones for different profiles.
*                Registers DRM protected tones as automated content
*                and removes old content from automated content list.
*                Shows a content activation query if necessary.
*
*/



// CLASS HEADER
#include    "cprofiletonehandler.h"

// INTERNAL INCLUDES
#include	"ProfileMmfInfoUtility.h"

// EXTERNAL INCLUDES
#include 	<centralrepository.h>
#include    <ProfileEngineDomainCRKeys.h> // KProEngRingingToneMaxSize
#include    <bautils.h> // BaflUtils
#include    <apgcli.h> // RApaLsSession
#include    <coemain.h> // CCoeEnv
#include    <aknnotewrappers.h> // CAknInformationNote
#include    <ConeResLoader.h> // RConeResourceLoader
#include	<StringLoader.h>
#include    <MProfileEngineExtended.h>
#include    <MProfilesLocalFeatures.h>
#include    <MProfileExtended.h>
#include    <MProfileSetExtraTones.h>
#include    <MProfileSetTones.h>
#include    <MProfileExtraTones.h>
#include    <MProfileTones.h>
#include    <MProfilesNamesArray.h>
#include    <MProfileName.h>
#include    <MProfileUtilitySingleton.h>
#include    <profilesettingsview.rsg>
#include    <AknGlobalNote.h>
#include    <f32file.h>

namespace
	{
	// CONSTANTS
	_LIT( KProfileSilentTone,     "Z:No_Sound.wav" );
	_LIT( KProfileAudioMimeType,  "audio" );
	_LIT( KProfileRngMimeType,    "application/vnd.nokia.ringing-tone" );

	_LIT( KProfileCommonVideoType, "video/*" );
	_LIT( KProfileRMVideoMimeType, "application/vnd.rn-realmedia" );
	_LIT( KProfileRMVideoMimeType2, "application/x-pn-realmedia" );
	_LIT( KProfileSDPVideoMimeType, "application/sdp" );
	_LIT( KProfilePlainTextType, "text/plain" );
	// The filename of the resource file
	_LIT( KProfileResourceFileName, "Z:ProfileSettingsView.RSC" );
	}



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

// -----------------------------------------------------------------------------
// CProfileToneHandler::CProfileToneHandler
// C++ default constructor can NOT contain any code, that might leave.
// -----------------------------------------------------------------------------
//
CProfileToneHandler::CProfileToneHandler()
    {
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CProfileToneHandler::ConstructL()
    {
    DrmConstructL();
    GetMaxToneFileSizeL();
    User::LeaveIfError( iFs.Connect() );
    iProfileEngine = CreateProfileEngineExtendedL( &iFs );
    // NB. Singleton must be released in the destructor:
    iProfilesFeatures = &( ProfileUtilityInstanceL().ProfilesLocalFeatures() );
        
    User::LeaveIfError( iSSSettings.Open() );
    iSSSettings.Get( ESSSettingsAls, iAlternateLineSetting ); // ignore errors
    iSSSettings.Register( ESSSettingsAls, *this ); // ignore errors
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::NewLC
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CProfileToneHandler* CProfileToneHandler::NewLC()
    {
    CProfileToneHandler* self = new( ELeave ) CProfileToneHandler();
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CProfileToneHandler* CProfileToneHandler::NewL()
    {
    CProfileToneHandler* self = CProfileToneHandler::NewLC();
    CleanupStack::Pop( self );
    return self;
    }

// Destructor
CProfileToneHandler::~CProfileToneHandler()
    {
    iSSSettings.Close();
    iFs.Close();
    if( iProfileEngine )
        {
        iProfileEngine->Release();
        }
        
    if ( iProfilesFeatures )
        {
        ReleaseProfileUtility();    
        }
    
    ReleaseDrm();
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::SetActiveProfileRingingToneL
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CProfileToneHandler::SetActiveProfileRingingToneL(
    const TDesC& aFileName )
    {
    // Find out the ID of the active profile
    TInt activeProfileId(
        User::LeaveIfError( iProfileEngine->ActiveProfileId() ) );

    return SetProfileToneL(
        activeProfileId, EProfileRingingToneSetting, aFileName );
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::SetProfileToneL
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CProfileToneHandler::SetProfileToneL( TInt aProfileId,
    TProfileTones aToneSetting, const TDesC& aFileName )
    {
    // Check the file which is tried to set as ringing or alert tone.
    TInt returnValue( CheckFileL( aFileName ) );
    returnValue = CheckResultAndProtectionL( returnValue, aFileName );
    if( returnValue != KErrNone )
        {
        return returnValue;
        }

    DoSetProfileToneL( aProfileId, aToneSetting, aFileName );
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::SetProfileToneNotCheckL
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CProfileToneHandler::SetProfileToneNotCheckL( TInt aProfileId,
                TProfileTones aToneSetting, const TDesC& aFileName )
    {
    DoSetProfileToneL( aProfileId, aToneSetting, aFileName );
    return KErrNone;    
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::SetToneForAllProfilesL
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CProfileToneHandler::SetToneForAllProfilesL(
    TProfileTones aToneSetting, const TDesC& aFileName )
    {
    // Check the file which is tried to set as ringing or alert tone.
    TInt returnValue( CheckFileL( aFileName ) );
    returnValue = CheckResultAndProtectionL( returnValue, aFileName );
    if( returnValue != KErrNone )
        {
        return returnValue;
        }

    const MProfilesNamesArray* idArray = iProfileEngine->ProfilesNamesArrayLC();
    TInt arrayCount( idArray->MdcaCount() );
    TInt arrayIndex( 0 );
    TInt profileId( 0 );
    TInt activeId( iProfileEngine->ActiveProfileId() );

    // Go through profiles and update tone
    while( arrayIndex < arrayCount )
        {
        profileId = idArray->ProfileName( arrayIndex )->Id();
        // Updating of the active profile will be done last to make sure that
        // UI gets the new value of the ringing tone if settings view is active
        // and it is containing settings of another than active profile
        if( profileId != activeId )
            {
            TRAPD(r, DoSetProfileToneL( profileId, aToneSetting, aFileName ));
            // Filter situation when profile is not allowed to be changed
            // e.g. Drive-profile
            if( ( r != KErrNone ) && ( r != KErrAccessDenied ) )
                {
                User::Leave( r );
                }
            }
        arrayIndex++;
        }
    CleanupStack::PopAndDestroy(); // idArray

    // Update the active profile:
    TRAPD(r, DoSetProfileToneL( activeId, aToneSetting, aFileName ));
    // Filter situation when profile is not allowed to be changed
    // e.g. Drive-profile
    if( ( r != KErrNone ) && ( r != KErrAccessDenied ) )
        {
        User::Leave( r );
        }

    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::PhoneSettingChanged
// Callback method inherited from MSSSettingsObserver for getting events if
// Alternate Line Service status changes.
// -----------------------------------------------------------------------------
//
void CProfileToneHandler::PhoneSettingChanged(
    TSSSettingsSetting aSetting, TInt aNewValue )
    {
    if( aSetting == ESSSettingsAls )
        {
        iAlternateLineSetting = aNewValue;
        }
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::DoSetProfileToneL
// -----------------------------------------------------------------------------
//
void CProfileToneHandler::DoSetProfileToneL( TInt aProfileId,
    TProfileTones aToneSetting, const TDesC& aFileName )
    {
    // Read the settings of the profile in question
    MProfileExtended* profile = iProfileEngine->ProfileLC( aProfileId );

    // Get the old tone in order to remove it from the automated content list
    TFileName oldTone( ReadToneL( *profile, aToneSetting ) );

	TFileName fileName( aFileName );
	if( fileName.Length() == 0 )
        {
        // If no filename is given, replace it with "No_sound.wav". This way
        // it's possible to e.g. play vibra during incoming call.
		TParse* fp = new(ELeave) TParse();
		fp->Set(KProfileSilentTone, &KDC_RESOURCE_FILES_DIR, NULL);
		fileName.Copy( fp->FullName() );
		delete fp;
        }

    // Replace the old tone with the new tone
    SetToneL( *profile, aToneSetting, fileName );

    // Commit changes. Write the new settings to the Profiles Engine
    iProfileEngine->CommitChangeL( *profile );

    // Register file as automated content
    TInt err( SetAutomated( aToneSetting, fileName ) );
    if( err == KErrNone )
        {
        // Remove old tone from the automated content list
        RemoveAutomated( oldTone );
        }
    else
        {
        // Put the old tone back into Profiles:
        TRAP_IGNORE(
                SetToneL( *profile, aToneSetting, oldTone );
                iProfileEngine->CommitChangeL( *profile );
                );
        }

    CleanupStack::PopAndDestroy(); // profile
    User::LeaveIfError( err );
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::SetToneL
// -----------------------------------------------------------------------------
//
void CProfileToneHandler::SetToneL( MProfileExtended& aProfile,
    TProfileTones aToneSetting, const TDesC& aFileName )
    {
    MProfileSetExtraTones& setExtraTones = aProfile.ProfileSetExtraTones();
    MProfileSetTones& setTones = aProfile.ProfileSetTones();

    switch( aToneSetting )
        {
        case EProfileRingingToneSetting:
            {
            if( iAlternateLineSetting == ESSSettingsAlsAlternate )
                {
                // Alternate Line Service is supported and alternate line is
                // selected. Set as ringing tone for line 2.
                setTones.SetRingingTone2L( aFileName );
                }
            else
                {
                // Alternate Line Service is not supported or primary line is
                // selected. Set as ringing tone for line 1.
                setTones.SetRingingTone1L( aFileName );
                }
            break;
            }
        case EProfileVideoCallToneSetting:
            {
            setExtraTones.SetVideoCallRingingToneL( aFileName );
            break;
            }
        case EProfileMessageAlertToneSetting:
            {
            setTones.SetMessageAlertToneL( aFileName );
            break;
            }
        case EProfileInstantMessageAlertToneSetting:
            {
            setExtraTones.SetIMMessageAlertToneL( aFileName );
            break;
            }
        case EProfileEmailAlertToneSetting:
            {
            setExtraTones.SetEmailAlertToneL( aFileName );
            break;
            }
        default:
            {
            User::Leave( KErrArgument );
            break;
            }
        }
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::ReadToneL
// -----------------------------------------------------------------------------
//
const TDesC& CProfileToneHandler::ReadToneL( const MProfileExtended& aProfile,
    TProfileTones aToneSetting ) const
    {
    const MProfileExtraTones& extraTones = aProfile.ProfileExtraTones();
    const MProfileTones& tones = aProfile.ProfileTones();

    switch( aToneSetting )
        {
        case EProfileRingingToneSetting:
            {
            if( iAlternateLineSetting == ESSSettingsAlsAlternate )
                {
                // Alternate Line Service is supported and alternate line is
                // selected.
                return tones.RingingTone2();
                }
            else
                {
                // Alternate Line Service is not supported or primary line is
                // selected.
                return tones.RingingTone1();
                }
            }
        case EProfileVideoCallToneSetting:
            {
            return extraTones.VideoCallRingingTone();
            }
        case EProfileMessageAlertToneSetting:
            {
            return tones.MessageAlertTone();
            }
        case EProfileInstantMessageAlertToneSetting:
            {
            return extraTones.IMMessageAlertTone();
            }
        case EProfileEmailAlertToneSetting:
            {
            return extraTones.EmailAlertTone();
            }
        default:
            {
            User::Leave( KErrArgument );
            break;
            }
        }
    return KNullDesC;
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::CheckFileL
// -----------------------------------------------------------------------------
//
TInt CProfileToneHandler::CheckFileL( const TDesC& aFileName )
    {
    if( aFileName.Length() == 0 )
        {
        // The filename is empty, ok.
        // It will be changed to "No_sound.wav" when writing to Profiles Engine.
        return KErrNone;
        }

    if( !BaflUtils::FileExists( iFs, aFileName ) )
        {
        // The file does not exist. No good (start the dance).
        return KErrNotFound;
        }

   	TBool isAudio( EFalse );
	TBool isVideo( EFalse );

    // The file exists. Check its data (MIME) type.
    TBuf<KMaxDataTypeLength> dataType( DataTypeL( aFileName ) );
    if( ( dataType.Left( KProfileAudioMimeType()
    .Length() ).CompareF( KProfileAudioMimeType ) == 0 ) ||
		( dataType.CompareF( KProfileRngMimeType ) == 0 ) )
    	{
    	isAudio = ETrue;
    	}

    if( dataType.MatchF( KProfileCommonVideoType ) == 0 ||
		dataType.CompareF( KProfileRMVideoMimeType ) == 0 ||
		dataType.CompareF( KProfileRMVideoMimeType2 ) == 0 ||
		dataType.CompareF( KProfileSDPVideoMimeType ) == 0 )
        {
#ifdef RD_VIDEO_AS_RINGING_TONE	
        isVideo = ETrue;
#else
        isVideo = EFalse;
#endif
        }

	if( (!isAudio) && (!isVideo) && (dataType.CompareF(KProfilePlainTextType) != 0) )
		{
	    // The data type does not start with "audio" or video and it's not RNG file.
    	return KErrNotSupported;
		}
		
	// Check whether file is supported by MMF
	TBuf8<KMaxDataTypeLength> tempDataType;
	tempDataType.Copy( dataType );
    if (!ProfileMmfInfoUtility::IsMimeTypeSupportedL(tempDataType)
			&& !ProfileMmfInfoUtility::IsHeaderDataSupportedL(aFileName))
		{
		// File is not supported by MMF
		return KErrNotSupported;
		}
    
	// Operator requirement. Check if the tones of this data type are blocked:
    if( iProfilesFeatures->IsBlockedType( dataType ) ||
        iProfilesFeatures->IsExcludedType( dataType ) )
        {
        User::Leave( KErrArgument );
        }

	// Check if the tone is WMDRM protected
	if( IsFileWMDRMProtectedL( aFileName ) )
		{
		return KErrPermissionDenied;
		}

    TInt result( KErrNone );
    if( IsProtected( aFileName ) )
        {
        // In certain variants tones of certain MIME-types are not allowed as
        // alert tones if they are DRM-protected, check if this is one:
        if( iProfilesFeatures->IsBlockedProtectedType( dataType ) )
            {
            return KErrArgument;
            }
        result = CheckProtectedFileL( aFileName );
        }
    else
        {
        result = iProfilesFeatures->IsBlockedUnprotectedType( dataType ) ?
                 KErrPermissionDenied : KErrNone;
        }
    return result;
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::CheckResultAndProtectionL
// Find out the mime type of the file
// -----------------------------------------------------------------------------
//
TInt CProfileToneHandler::CheckResultAndProtectionL( TInt aResult,
    const TDesC& aFileName )
    {
    if( aResult == KErrPermissionDenied || aResult == KErrNotSupported ||
        aResult == KErrNotFound )
        {
        User::Leave( aResult );
        }
    else if( aResult != KErrNone )
        {
        return aResult;
        }

    // If tone file size is limited,
    // check if this file's size exceeds this limit.
    if ( iMaxSizeKB )
        {
        if ( CheckToneFileSizeL( aFileName, iMaxSizeKB ) != KErrNone )
            {
            ShowSizeErrorNoteL( iMaxSizeKB );
            return KErrTooBig;
            }
        }

    if( IsProtected( aFileName ) )
        {
        if( !CanSetAutomated( aFileName ) )
            {
            // DRM v2 content should be caught here
            ShowErrorNoteL( R_PROFILE_TEXT_DRM_PREV_RIGHTS_SET );
            return KErrGeneral;
            }

        // If the file in question is unactivated protected content,
        // ask user if he/she wants to activate it.
        if( AskAutomated( aFileName ) == KErrCancel )
            {
            // User doesn't want to activate unactivated protected content.
            return KErrCancel;
            }
        }
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::DataType
// Find out the mime type of the file
// -----------------------------------------------------------------------------
//
TBuf<KMaxDataTypeLength> CProfileToneHandler::DataTypeL(
    const TDesC& aFileName ) const
    {
    RApaLsSession apaLsSession;
    User::LeaveIfError( apaLsSession.Connect() );
    CleanupClosePushL( apaLsSession );

    TUid dummyUid = { 0 }; // instantiate as zero
    TDataType dataType( dummyUid );
    User::LeaveIfError(
        apaLsSession.AppForDocument( aFileName, dummyUid, dataType ) );

    CleanupStack::PopAndDestroy(); // apaLsSession.Close()
    return dataType.Des();
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::ShowErrorNoteL
// -----------------------------------------------------------------------------
//
void CProfileToneHandler::ShowErrorNoteL( TInt aResourceId ) const
    {
    CCoeEnv* coeEnv = CCoeEnv::Static();
    RConeResourceLoader resourceLoader( *coeEnv );
	CleanupClosePushL( resourceLoader );

	TParse* fp = new(ELeave) TParse();
	fp->Set(KProfileResourceFileName, &KDC_RESOURCE_FILES_DIR, NULL);
	TFileName localizedFileName( fp->FullName() );
	delete fp;

    resourceLoader.OpenL( localizedFileName );

    HBufC* errorText = StringLoader::LoadLC( aResourceId );
    CAknInformationNote* note = new( ELeave ) CAknInformationNote( EFalse );
    note->ExecuteLD( *errorText );

	// errorText
    CleanupStack::PopAndDestroy( errorText );
	// resourceLoader
	CleanupStack::PopAndDestroy( );
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::ShowSizeErrorNoteL
// -----------------------------------------------------------------------------
//
void CProfileToneHandler::ShowSizeErrorNoteL( TInt aSizeLimitKB )
    {
    CCoeEnv* coeEnv = CCoeEnv::Static();
    RConeResourceLoader resourceLoader( *coeEnv );
	CleanupClosePushL( resourceLoader );

	TParse* fp = new(ELeave) TParse();
	CleanupStack::PushL( fp );
	fp->Set( KProfileResourceFileName, &KDC_RESOURCE_FILES_DIR, NULL);
	
	TFileName* fileName = new( ELeave ) TFileName();
	fileName->Copy( fp->FullName() );
	CleanupStack::PushL( fileName );
    resourceLoader.OpenL( *fileName );
    CleanupStack::PopAndDestroy( fileName );

    HBufC* errorText = StringLoader::LoadLC(  R_PROFILE_TEXT_TONE_MAXSIZE_ERROR, aSizeLimitKB );
    CAknInformationNote* note = new( ELeave ) CAknInformationNote( EFalse );
    note->ExecuteLD( *errorText );

    CleanupStack::PopAndDestroy( errorText );
    CleanupStack::PopAndDestroy( fp );
	CleanupStack::PopAndDestroy( &resourceLoader );
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::GetMaxToneFileSizeL
// -----------------------------------------------------------------------------
//
void CProfileToneHandler::GetMaxToneFileSizeL()
    {
	CRepository* cenrep = CRepository::NewL( KCRUidProfileEngine );
	CleanupStack::PushL( cenrep );
	TInt error = cenrep->Get( KProEngRingingToneMaxSize, iMaxSizeKB );
	CleanupStack::PopAndDestroy( cenrep );
	if ( error != KErrNone )
    	{
        iMaxSizeKB = 0;
    	}
	if ( iMaxSizeKB < 0 )
	    {
	     iMaxSizeKB = 0;
	    }
    }

// -----------------------------------------------------------------------------
// CProfileToneHandler::CheckToneFileSizeL
// -----------------------------------------------------------------------------
//
TInt CProfileToneHandler::CheckToneFileSizeL( const TDesC& aFile,
                                              TInt aSizeLimitKB )
    {
    // Get file size
    TInt size = 0;
    TInt error = KErrNone;

    TEntry entry;
    if ( iFs.Entry( aFile, entry ) == KErrNone )
        {
        size = entry.iSize;        
        }

	// Check. NOTE: now if file size couldn't be determined, check fails.
	aSizeLimitKB *= KKilo;
	if ( aSizeLimitKB  &&  size > aSizeLimitKB )
		{
		error = KErrTooBig;
		}

    return error;
    }


//  End of File