profilesservices/ProfileEngine/EngSrc/CProfileEngineImplDynamicProfiles.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 15:29:50 +0300
branchRCL_3
changeset 53 8ee96d21d9bf
parent 25 3b47783fdf16
child 54 7e0eff37aedb
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* Copyright (c) 2002 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: Implementation of the CProfileEngineImpl.
*
*/



// INCLUDE FILES
#include "CProfileEngineImpl.h"
#include "CProfilesNamesArrayImpl.h"
#include "CProfileImpl.h"
#include "CProfileNameImpl.h"
#include "ProfileEngUtils.h"
#include "ProfileEng.hrh"
#include "ProfileEngPanic.h"
#include "ProfileEnginePrivateCRKeys.h"
#include <bautils.h>
#include <barsc.h>
#include <featmgr.h>
#include <settingsinternalcrkeys.h>
#include <sysutil.h>
#include <accessoriescrkeys.h>

#include <ProfileEng.rsg>
#include <TProfileToneSettings.h>
#include <MProfileTones.h>
#include <MProfileSetName.h>
#include <ProfileEngineConstants.h>

namespace
    {
    const TInt KProfileGeneratedNameTailLength( 4 );
    _LIT( KFirstParenthesis, "(" );
    }

// ============================= LOCAL FUNCTIONS ===============================

void GenerateProfileName( TDes& aProfileName, const MProfilesNamesArray& aProfileNames )
    {
    _LIT( KEndParenthesis, ")" );
    _LIT( KZero, "0" );
    TInt counter( 1 );
    TBuf<KProfileMaxNameLength> rootName( aProfileName );
    while( aProfileNames.FindByName( aProfileName ) != KErrNotFound &&
           counter <= KProfilesMaxNumberOfDynamicProfiles )
        {
        aProfileName.Copy( rootName );
        aProfileName.Append( KFirstParenthesis );
        if( counter < 10 )
            {
            aProfileName.Append( KZero );
            }
        TBuf<KProfilesMaxTIntLength> number;
        number.Num( counter );
        aProfileName.Append( number );
        aProfileName.Append( KEndParenthesis );
        ++counter;
        }
    }

// -----------------------------------------------------------------------------
// HandleProfileRemoved
//
// Updates the given central repository value from the given file, when a
// profile is removed. This is used for those central repository keys that
// contain a profile id as a value, and if a deleted profile is
// currently assigned to the central repository value, it is resetted to the
// given default value.
// -----------------------------------------------------------------------------
//
void HandleProfileRemoved( const TInt aRemovedProfileId,
                            const TInt aValuePlusDelta,
                            CRepository& aCenRep,
                            const TUint aKey,
                            const TInt aDefaultValue )
    {
    if ( ( aValuePlusDelta ) == aRemovedProfileId )
        {
        aCenRep.Set( aKey, aDefaultValue );
        }
    }

// -----------------------------------------------------------------------------
// CreateIntSettingForNewProfileL
//
// Creates a new integer Central Repository key for the new profile and
// initialises it by copying the default value to it.
//
// -----------------------------------------------------------------------------
//
void CreateIntSettingForNewProfileL( CRepository& aRepository, TInt aSettingId,
                                     TInt aProfileId )
    {
    TInt val;
    User::LeaveIfError(
            aRepository.Get( 
            ProfileEngUtils::ResolveKey( aSettingId,
            KProEngDefaultProfileId ), val ) );
    TInt err(
            aRepository.Create( 
            ProfileEngUtils::ResolveKey( aSettingId, aProfileId ),
            val ) );
    if( ( err != KErrNone ) && ( err != KErrAlreadyExists ) )
        {
        User::Leave( err );
        }
    }

// -----------------------------------------------------------------------------
// CreateStringSettingForNewProfileL
//
// Creates a new string Central Repository key for the new profile and
// initialises it by copying the default value to it.
//
// -----------------------------------------------------------------------------
//
void CreateStringSettingForNewProfileL( CRepository& aRepository,
                                        TInt aSettingId, TInt aProfileId,
                                        const TDesC& aNewProfileName,
                                        TPtr& aStringPtr ) 
    {
    if( aSettingId != KProEngProfileName )
        {
        User::LeaveIfError(
                aRepository.Get( 
                ProfileEngUtils::ResolveKey( aSettingId,
                KProEngDefaultProfileId ), aStringPtr ) );
        }
    else
        {
        aStringPtr = aNewProfileName;
        }
    TInt err(
            aRepository.Create( 
            ProfileEngUtils::ResolveKey( aSettingId, aProfileId ),
            aStringPtr ) );
    if( ( err != KErrNone ) && ( err != KErrAlreadyExists ) )
        {
        User::Leave( err );
        }
    }

// -----------------------------------------------------------------------------
// CreateBinSettingForNewProfileL
//
// Creates a new binary Central Repository key for the new profile and
// initialises it by copying the default value to it.
//
// -----------------------------------------------------------------------------
//
void CreateBinSettingForNewProfileL( CRepository& aRepository, TInt aSettingId,
                                     TInt aProfileId, TPtr8& aBinPtr )
    {
    User::LeaveIfError(
            aRepository.Get( 
            ProfileEngUtils::ResolveKey( aSettingId,
            KProEngDefaultProfileId ), aBinPtr ) );
    TInt err(
            aRepository.Create( 
            ProfileEngUtils::ResolveKey( aSettingId, aProfileId ),
            aBinPtr ) );
    if( ( err != KErrNone ) && ( err != KErrAlreadyExists ) )
        {
        User::Leave( err );
        }
    }

// -----------------------------------------------------------------------------
// GetSettingsForProfile
//
// Gets all the settings of the profile with given id from Central Repository.
// -----------------------------------------------------------------------------
//
TInt GetSettingsForProfile( CRepository& aRepository,
                            RArray<TUint32>& aSettings,
                            TInt aId )
    {
    const TUint32 KId( aId << 24 );
    const TUint32 KMask( 0xFF000000 );
    TInt error( 0 );
    TRAP( error, error = aRepository.FindL( KId, KMask, aSettings ) );
    return error;
    }

// -----------------------------------------------------------------------------
// DeleteSettingsForProfile
//
// Deletes all the settings of the profile with given id from Central Repository
// Tries to delete all without checking if a deletion fails.
// -----------------------------------------------------------------------------
//
void DeleteSettingsForProfile( CRepository& aRepository,
                               RArray<TUint32>& aSettings )
    {
    for( TInt i( aSettings.Count() - 1 ); i >= 0; --i )
        {
        aRepository.Delete( aSettings[i] ); // ignore errors
        }
    }

// -----------------------------------------------------------------------------
// CreateSettingsForNewProfileL
//
// Creates new Central Repository keys for the new profile and initialises them
// by copying the default values to them.
//
// -----------------------------------------------------------------------------
//
void CreateSettingsForNewProfileL( CRepository& aRepository, TInt aProfileId,
                                   const TDesC& aNewProfileName,
                                   TResourceReader& aReader )
    {
    User::LeaveIfError( aRepository.StartTransaction(
                        CRepository::EReadWriteTransaction ) );

    // This only be used after normal RFS(restore factory settings), If there was
    // user created profile before normal RFS, and the normal RFS only restore
    // KProEngUsedIds, the settings of user created profile are in CenRep still.
    // So we should delete the remain settings and create new one.
    RArray<TUint32> settings;
    if ( !GetSettingsForProfile( aRepository, settings, aProfileId ) )
    	{
    	DeleteSettingsForProfile( aRepository, settings );
    	}
    settings.Close();

    HBufC* stringVal = HBufC::NewL(
            NCentralRepositoryConstants::KMaxUnicodeStringLength );
    CleanupStack::PushL( stringVal );
    TPtr stringValPtr = stringVal->Des();
    HBufC8* binVal = HBufC8::NewL(
            NCentralRepositoryConstants::KMaxBinaryLength );
    CleanupStack::PushL( binVal );
    TPtr8 binValPtr = binVal->Des();

    TInt numOfElements( aReader.ReadInt16() );

    for( TInt i( 0 ) ; i < numOfElements ; ++i )
        {
        TInt settingId( aReader.ReadInt32() );
        TInt keyType( aReader.ReadInt32() );
        switch( keyType )
            {
            case EProfileSettingKeyTypeInt:
                {
                CreateIntSettingForNewProfileL( aRepository, settingId,
                                                aProfileId );
                break;
                }
            case EProfileSettingKeyTypeString:
                {
                CreateStringSettingForNewProfileL( aRepository, settingId,
                                                   aProfileId,
                                                   aNewProfileName,
                                                   stringValPtr );
                break;
                }
            case EProfileSettingKeyTypeBin:
                {
                CreateBinSettingForNewProfileL( aRepository, settingId,
                                                aProfileId, binValPtr );
                                                
                break;
                }
            case EProfileSettingKeyTypeReal: // no settings of this type
            default:
                {
                break;
                }
            }
        }

    CleanupStack::PopAndDestroy( 2 ); // stringVal, binVal
 
    // Update the used ids value (this is done last so that we can get the
    // repository back in a legal state (by deleting the settings just 
    // created)).
    TBuf8< KProfilesMaxNumberOfDynamicProfiles > idBuf;
    ProfileEngUtils::GetBinarySettingL( aRepository, KProEngUsedIds, idBuf );
    idBuf.Append( aProfileId );
    User::LeaveIfError( aRepository.Set( KProEngUsedIds, idBuf ) );

    TUint32 ignore( 0 );
    User::LeaveIfError( aRepository.CommitTransaction( ignore ) );
    }

// -----------------------------------------------------------------------------
// DeleteProfileIdFromList
//
// -----------------------------------------------------------------------------
//
void DeleteProfileIdFromList( CRepository& aRepository, TInt aId, TDes8& aIdBuf )
    {
    TInt numOfIds = aIdBuf.Length();
    for( TInt idx( 0 ); idx < numOfIds; ++idx )
        {
        if( aIdBuf[ idx ] == aId )
            {
            aIdBuf.Delete( idx, 1 );
            aRepository.Set( KProEngUsedIds, aIdBuf );
            break;
            }
        }
    }

void DoDeleteProfileL( CRepository& aCenRep, TInt aId )
    {
    RArray<TUint32> settings;
    User::LeaveIfError( GetSettingsForProfile( aCenRep, settings, aId ) );

    TBuf8< 4 * KProfilesMaxNumberOfDynamicProfiles > idBuf; // One id is 4-bytes long
    ProfileEngUtils::GetBinarySettingL( aCenRep, KProEngUsedIds, idBuf );

    User::LeaveIfError( aCenRep.StartTransaction(
                        CRepository::EReadWriteTransaction ) );
    DeleteSettingsForProfile( aCenRep, settings );
    settings.Reset();
    DeleteProfileIdFromList( aCenRep, aId, idBuf );

    TInt headsetVal( 0 );
    TInt loopsetVal( 0 );
    TInt ttyVal( 0 );
    TInt btVal( 0 );
    TUint32 ignore( 0 );
    TRAPD( error,
          CRepository* cr = CRepository::NewL( KCRUidProfileSettings );
          CleanupStack::PushL( cr );
          User::LeaveIfError( cr->Get( KSettingsHeadsetDefaultProfile, headsetVal ) );
          User::LeaveIfError( cr->Get( KSettingsLoopsetDefaultProfile, loopsetVal ) );
          User::LeaveIfError( cr->Get( KSettingsTTYDefaultProfile, ttyVal ) );
          User::LeaveIfError( cr->Get( KSettingsBTDefaultProfile, btVal ) );
          User::LeaveIfError( cr->StartTransaction(
                              CRepository::EReadWriteTransaction ) );
          // -1 is a mystery, consult general settings team:
          // 0 ( = general profile ) is the default profile used with all the
          // accessories:
          HandleProfileRemoved( aId, headsetVal-1, *cr,
                                KSettingsHeadsetDefaultProfile, 0 );
          HandleProfileRemoved( aId, loopsetVal-1, *cr,
                                KSettingsLoopsetDefaultProfile, 0 );
          HandleProfileRemoved( aId, ttyVal-1, *cr,
                                KSettingsTTYDefaultProfile, 0 );
          HandleProfileRemoved( aId, btVal-1, *cr,
                                KSettingsBTDefaultProfile, 0 );
          User::LeaveIfError( cr->CommitTransaction( ignore ) );

          CleanupStack::PopAndDestroy(); // delete cr:
        );

    if( error )
        {
        aCenRep.RollbackTransaction(); // ignore error
        User::Leave( error );
        }

    User::LeaveIfError( aCenRep.CommitTransaction( ignore ) );
    }

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

// -----------------------------------------------------------------------------
// CProfileEngineImpl::DeleteProfileL
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CProfileEngineImpl::DeleteProfileL( TInt aId )
    {
    iMutex.Wait();
    TInt activeProfileId( ActiveProfileId() );

    if( activeProfileId < 0 )
        {
        iMutex.Signal();
        User::Leave( activeProfileId );
        }

    // Do not allow delete active profile
    if( aId == activeProfileId )
        {
        iMutex.Signal();
        return KErrAbort;
        }
    // Do not allow delete default profile
    if( IsDefaultProfile( aId ) )
        {
        iMutex.Signal();
        return KErrAbort;
        }

    TRAPD( error, DoDeleteProfileL( *iCenRep, aId ) );
    iMutex.Signal();
    User::LeaveIfError( error );
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CProfileEngineImpl::CreateProfileL
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
MProfileExtended* CProfileEngineImpl::CreateProfileL()
    {
    if( SysUtil::FFSSpaceBelowCriticalLevelL( iFs ) )
        {
        User::Leave( KErrDiskFull );
        }

    // Create profile ID
    CProfilesNamesArrayImpl* profileNameArray = CProfilesNamesArrayImpl::NewLC();

    iMutex.Wait();
    TRAPD( error, ReadProfilesNamesL( profileNameArray ) );
    if( error )
        {
        iMutex.Signal();
        User::Leave( error );
        }

    if( profileNameArray->MdcaCount() -         // current profile count
        iProfileLocalisedNames->MdcaCount() >=  // default profile count
        KProfilesMaxNumberOfDynamicProfiles )   // max dynamic profiles
        {
        // Max number of dynamic profiles
        CleanupStack::PopAndDestroy();  // profileNameArray
        iMutex.Signal();
        return NULL;
        }

    TInt profileId( KErrNotFound );
    // Find first free id
    TInt lastDynamicProfileId( KProfileBaseDynamicProfileId + 
                               KProfilesMaxNumberOfDynamicProfiles );

    for( TInt i( KProfileBaseDynamicProfileId ); i < lastDynamicProfileId; ++i )
        {
        TInt index( profileNameArray->FindById( i ) );
        if( index == KErrNotFound )
            {
            profileId = i;
            break;
            }
        }

    if( profileId == KErrNotFound )
        {
        CleanupStack::PopAndDestroy();  // profileNameArray
        iMutex.Signal();
        return NULL;
        }

    TBuf<KProfileMaxNameLength> profileName;
    TRAP( error,
          ReadNewProfileNameFromResourceL( R_NEW_PROFILE, profileName ) );
    if( error )
        {
        iMutex.Signal();
        User::Leave( error );
        }

    GenerateProfileName( profileName, *profileNameArray );
    CleanupStack::PopAndDestroy();  // profileNameArray

    TResourceReader rsReader;
    CProfileImpl* newProfile = NULL;
    TRAP( error,
          ReadResourceInBufferLC( R_PROFILE_SETTINGS, rsReader );
          CreateSettingsForNewProfileL( *iCenRep, profileId,
                                        profileName, rsReader );
          CleanupStack::PopAndDestroy();  // ReadResourceInBufferLC

          // Create and store new profile
          newProfile = CProfileImpl::NewLC( *iFs );
          newProfile->InternalizeL( *iCenRep, profileId );
                
          CleanupStack::Pop();    // newProfile
          );
 
    iMutex.Signal();
    User::LeaveIfError( error );

    return newProfile;
    }

// -----------------------------------------------------------------------------
// CProfileEngineImpl::ReadNewProfileNameFromResourceL
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CProfileEngineImpl::ReadNewProfileNameFromResourceL( TInt aResourceId,
                                                          TDes& aProfileName )
    {
    TResourceReader rsReader;
    ReadResourceInBufferLC( aResourceId, rsReader );

    TPtrC profileName( rsReader.ReadTPtrC() );
    aProfileName.Copy( profileName );

    CleanupStack::PopAndDestroy(); // ReadResourceInBufferLC
    }

// -----------------------------------------------------------------------------
// CProfileEngineImpl::ReadNewProfileNameFromResourceL
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CProfileNameImpl* CProfileEngineImpl::ReadNewProfileNameFromResourceLC()
    {
    TBuf<KProfileMaxNameLength> profileName;
    ReadNewProfileNameFromResourceL( R_NEW_PROFILE, profileName ); 

    TBuf<KProfileMaxNameLength> shortName;
    ReadNewProfileNameFromResourceL( R_NEW_PROFILE_SHORT, shortName ); 

    TBuf<KProfileMaxNameLength> naviName;
    ReadNewProfileNameFromResourceL( R_NEW_PROFILE_NAVI, naviName ); 

    TBuf<KProfileMaxNameLength> titleName;
    ReadNewProfileNameFromResourceL( R_NEW_PROFILE_TITLE, titleName );

    CProfileNameImpl* localizedName =
        CProfileNameImpl::NewLC( 0, profileName, shortName,
                                 naviName, titleName );

    return localizedName;
    }

// -----------------------------------------------------------------------------
// CProfileEngineImpl::ReadDynamicProfilesNamesL
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CProfileEngineImpl::ReadDynamicProfilesNamesL(
        CProfilesNamesArrayImpl* aProfilesNames,
        CProfileNameImpl& aNameTemplate )
    {
    TBuf8< NCentralRepositoryConstants::KMaxBinaryLength > idBuf;
    ProfileEngUtils::GetBinarySettingL( *iCenRep, KProEngUsedIds, idBuf );
    TInt len = idBuf.Length();

    if( len == 0 )
        {
        return; // No user-created profiles, just return
        }

    CProfileNameImpl* localizedName = ReadNewProfileNameFromResourceLC();

    for( TInt i( 0 ); i < len; ++i )
        {
        aNameTemplate.InternalizeL( *iCenRep, idBuf[i] );
        if( !aNameTemplate.IsProfileNameChanged() )
            {
            TInt idxOfParenthesis(
                    aNameTemplate.Name().Find( KFirstParenthesis ) );
            if( idxOfParenthesis != KErrNotFound )
                {
                TBuf<KProfileGeneratedNameTailLength> uniquePart =
                        aNameTemplate.Name().Mid( idxOfParenthesis,
                        KProfileGeneratedNameTailLength );
                aNameTemplate.SetLocalizedProfileNameL( *localizedName,
                                                        uniquePart );
                }
            else
                {
                aNameTemplate.SetLocalizedProfileNameL( *localizedName,
                                                        KNullDesC() );
                }
            }

        CProfileNameImpl* nameImpl =
            CProfileNameImpl::NewLC( aNameTemplate );

        User::LeaveIfError( aProfilesNames->InsertInOrder( nameImpl ) );
        CleanupStack::Pop();    // nameImpl
        }

    CleanupStack::PopAndDestroy( localizedName );
    }

// -----------------------------------------------------------------------------
// CProfileEngineImpl::SetLocalizedNameForDynamicProfileL
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CProfileEngineImpl::SetLocalizedNameForDynamicProfileL(
        CProfileImpl& aProfile )
    {
    CProfileNameImpl* localizedName = ReadNewProfileNameFromResourceLC();

    TInt idxOfParenthesis(
            aProfile.ProfileName().Name().Find( KFirstParenthesis ) );
    if( idxOfParenthesis != KErrNotFound )
        {
        TBuf<KProfileGeneratedNameTailLength> uniquePart =
                aProfile.ProfileName().Name().Mid( idxOfParenthesis,
                KProfileGeneratedNameTailLength );
        aProfile.SetLocalizedProfileNameL( *localizedName, uniquePart );
        }
    else
        {
        aProfile.SetLocalizedProfileNameL( *localizedName,
                                           KNullDesC() );
        }

    CleanupStack::PopAndDestroy( localizedName );
    }

//  End of File