/*
* Copyright (c) 2009-2010 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 CSsmLocaleObserverSup class.
*
*/
#include <bacntf.h>
#include <bautils.h>
#include <connect/sbdefs.h>
#include <s32file.h>
#include <e32reg.h>
#include "ssmmapperutilitystatic.h"
#include "ssmlocaleobserversup.h"
#include "trace.h"
/**
* Directory to store user-specific locale data files.
* Private directory of SSM Utility Server.
*/
_LIT( KLocaleDataDir, "\\private\\2000d766\\localedata\\" );
/** Name is RegionData.Dnn */
_LIT( KFileName, "RegionData.D" );
/**
* Version number from 1..255 to indicate data
* format of the file. To make dynamic data format fixes possible we need
* version ID.
*/
const TInt KCurrentVersionNumber = 2; // For fixing TChar r/w
/** The maximum number of regions to be appended to the hash set. */
const TInt KMaxNumberOfRegions = 56;
// ======== LOCAL FUNCTIONS ========
// ---------------------------------------------------------------------------
// EnvChangeNotifierCallbackL
// ---------------------------------------------------------------------------
//
static TInt EnvChangeNotifierCallback( TAny* aThis )
{
CSsmLocaleObserverSup* self = static_cast<CSsmLocaleObserverSup*>( aThis );
ASSERT_TRACE( self );
TRAPD( err, self->EnvChangeOccurredL() );
ERROR( err, "Failed to handle environment change" );
return err;
}
// ---------------------------------------------------------------------------
// MakeFileNameL
// ---------------------------------------------------------------------------
//
static HBufC* MakeFileNameL( const TDesC& aPath, const TDesC& aName, const TInt aCode )
{
FUNC_LOG;
INFO_3( "Region data dir: %S, file name base: %S, region code: %d", &aPath, &aName, aCode );
TInt length = aPath.Length();
// Reserve spave for language code also
HBufC* buffer = HBufC::NewL( length + aName.Length() + 10 );
TPtr ptr = buffer->Des();
ptr.Append( aPath );
if ( length > 0 && aPath[ length - 1 ] != KPathDelimiter )
{
ptr.Append( KPathDelimiter );
}
ptr.Append( aName );
if ( aCode < 10 )
{
ptr.AppendNum( 0 ); // add leading zero to the extention
}
ptr.AppendNum( aCode );
INFO_1( "Region data file: %S", buffer );
return buffer;
}
inline TUint32 HashLangRegionMappingFunction(const TLanguageRegion& aMapping)
{
return aMapping.iLanguage;
}
inline TBool HashLangRegionMappingIdentityRelation(const TLanguageRegion& aMapping1,
const TLanguageRegion& aMapping2)
{
return (aMapping1.iLanguage == aMapping2.iLanguage);
}
// ======== MEMBER FUNCTIONS ========
// ---------------------------------------------------------------------------
// CSsmLocaleObserverSup::NewL
// ---------------------------------------------------------------------------
//
EXPORT_C MSsmUtility* CSsmLocaleObserverSup::NewL()
{
CSsmLocaleObserverSup* self = new ( ELeave ) CSsmLocaleObserverSup;
return self;
}
// ---------------------------------------------------------------------------
// CSsmLocaleObserverSup::~CSsmLocaleObserverSup
// ---------------------------------------------------------------------------
//
CSsmLocaleObserverSup::~CSsmLocaleObserverSup()
{
FUNC_LOG;
Cancel();
iLangRegionMappingHashSet.Close();
delete iEnvChangeNotifier;
iFs.Close();
iProperty.Close();
}
// ---------------------------------------------------------------------------
// CSsmLocaleObserverSup::EnvChangeOccurredL
// ---------------------------------------------------------------------------
//
void CSsmLocaleObserverSup::EnvChangeOccurredL()
{
FUNC_LOG;
const TInt changes( iEnvChangeNotifier->Change() );
INFO_2( "Env data changed: 0x%08x, restore active: %d",
changes, iRestoreActive );
if ( !iRestoreActive && ( changes & EChangesLocale ) )
{
TParsePtrC parse( KLocaleDataDir );
SaveRegionL( parse.FullName() );
}
if( changes & EChangesSystemTime )
{
INFO( "Persisting HAL settings" );
// Changes by writing to HAL
TInt err = BaflUtils::PersistHAL();
ERROR( err, "BaflUtils::PersistHAL failed" );
}
}
// ---------------------------------------------------------------------------
// CSsmLocaleObserverSup::RunL
// ---------------------------------------------------------------------------
//
void CSsmLocaleObserverSup::RunL()
{
FUNC_LOG;
TInt err = iStatus.Int();
ERROR( err, "RSsmStateAdaptation::NotifyCoopSysEvent completed with error" );
if ( err != KErrServerTerminated )
{
Activate();
}
if ( err == KErrNone )
{
TInt status( 0 );
err = iProperty.Get( status );
ERROR( err, "Failed to get backup status from P&S" );
if ( err == KErrNone )
{
TInt type = status & conn::KBURPartTypeMask;
if ( type == conn::EBURRestoreFull ||
type == conn::EBURRestorePartial )
{
INFO( "Restore started" );
iRestoreActive = ETrue;
}
else if ( type == conn::EBURNormal && iRestoreActive )
{
INFO( "Restore finished" );
iRestoreActive = EFalse;
TParsePtrC parse( KLocaleDataDir );
TRAP( err, LoadRegionL( parse.FullName() ) );
ERROR( err, "Failed to load locale" );
// Cannot do anything about the error - just continue.
}
}
}
}
// ---------------------------------------------------------------------------
// CSsmLocaleObserverSup::DoCancel()
// ---------------------------------------------------------------------------
//
void CSsmLocaleObserverSup::DoCancel()
{
FUNC_LOG;
iProperty.Cancel();
}
// ---------------------------------------------------------------------------
// CSsmLocaleObserverSup::InitializeL()
// ---------------------------------------------------------------------------
//
void CSsmLocaleObserverSup::InitializeL()
{
FUNC_LOG;
TInt err = iFs.Connect();
ERROR( err, "Failed to connect to file server" );
User::LeaveIfError( err );
InitializeRegionMappingL();
TRAP( err, iEnvChangeNotifier = CEnvironmentChangeNotifier::NewL(
CActive::EPriorityStandard,
TCallBack( EnvChangeNotifierCallback, this ) ) );
ERROR( err, "Failed to create environment change notifier" );
User::LeaveIfError( err );
}
// ---------------------------------------------------------------------------
// CSsmLocaleObserverSup::StartL()
// ---------------------------------------------------------------------------
//
void CSsmLocaleObserverSup::StartL()
{
FUNC_LOG;
TParsePtrC parse( KLocaleDataDir );
TRAPD_ERR( err, LoadRegionL( parse.FullName() ) );
ERROR( err, "Failed to load region data the first time" );
if ( iEnvChangeNotifier )
{
iEnvChangeNotifier->Start();
}
TInt err1 = iProperty.Attach( SsmMapperUtility::PsUid( KUidSystemCategory ), conn::KUidBackupRestoreKey );
ERROR( err1, "Failed to attach to KUidBackupRestoreKey" );
Activate();
}
// ---------------------------------------------------------------------------
// CSsmLocaleObserverSup::Release()
// ---------------------------------------------------------------------------
//
void CSsmLocaleObserverSup::Release()
{
FUNC_LOG;
delete this;
}
// ---------------------------------------------------------------------------
// CSsmLocaleObserverSup::CSsmLocaleObserverSup
// ---------------------------------------------------------------------------
//
CSsmLocaleObserverSup::CSsmLocaleObserverSup()
: CActive( EPriorityNormal ),
iRestoreActive( EFalse ),
iLangRegionMappingHashSet( &::HashLangRegionMappingFunction, &::HashLangRegionMappingIdentityRelation )
{
FUNC_LOG;
CActiveScheduler::Add( this );
}
// ---------------------------------------------------------------------------
// CSsmLocaleObserverSup::Activate
// ---------------------------------------------------------------------------
//
void CSsmLocaleObserverSup::Activate()
{
FUNC_LOG;
ASSERT_TRACE( !IsActive() );
iProperty.Subscribe( iStatus );
SetActive();
}
// ---------------------------------------------------------------------------
// CSsmLocaleObserverSup::SaveRegionL
// ---------------------------------------------------------------------------
//
void CSsmLocaleObserverSup::SaveRegionL( const TDesC& aPath )
{
FUNC_LOG;
INFO( "Saving region data" );
TInt region = MappedRegionL(User::Language());
HBufC* fName = MakeFileNameL( aPath, KFileName, region);
CleanupStack::PushL( fName );
RFileWriteStream fStream;
CleanupClosePushL( fStream );
// According to documentation RFileWriteStream
// keeps written data in RAM until CommitL has been
// called.
TInt err = iFs.MkDirAll( *fName ); // Ignore errors
err = fStream.Create( iFs, *fName, EFileWrite );
if ( err == KErrAlreadyExists )
{
// Override
err = fStream.Open( iFs, *fName, EFileWrite );
ERROR_1( err, "Failed to open stream %S", fName );
}
User::LeaveIfError( err );
// Write first the version number to enable
// support for file format changes.
fStream.WriteInt8L( KCurrentVersionNumber );
TLocale locale; // copy current values
fStream.WriteInt16L( locale.CountryCode() );
fStream.WriteInt16L( 0 ); // reserved
fStream.WriteInt8L( locale.DateFormat() );
fStream.WriteInt8L( locale.TimeFormat() );
fStream.WriteInt8L( locale.CurrencySymbolPosition() );
fStream.WriteInt8L( locale.CurrencySpaceBetween() );
fStream.WriteInt8L( locale.CurrencyDecimalPlaces() );
fStream.WriteInt8L( locale.CurrencyNegativeInBrackets() );
fStream.WriteInt8L( locale.CurrencyTriadsAllowed() );
fStream.WriteUint32L( locale.ThousandsSeparator() );
fStream.WriteUint32L( locale.DecimalSeparator() );
fStream.WriteInt8L( KMaxDateSeparators ); // restoring this constant. It might chance.
TInt counter( 0 );
for ( counter = 0; counter < KMaxDateSeparators; counter++ )
{
fStream.WriteUint32L( locale.DateSeparator( counter ) );
}
fStream.WriteInt8L( KMaxTimeSeparators ); // restoring this constant. It might chance.
for ( counter = 0; counter < KMaxTimeSeparators; counter++ )
{
fStream.WriteUint32L( locale.TimeSeparator( counter ) );
}
fStream.WriteInt8L( locale.AmPmSpaceBetween() );
fStream.WriteInt8L( locale.AmPmSymbolPosition() );
// DaylightSaving and HomeDaylightSavingZone are not part of TLocale
// any more, zeros are written to LocaleData.Dxx to keep file structure
// as it was.
fStream.WriteInt32L( 0 );
fStream.WriteUint32L( 0 );
fStream.WriteUint8L( locale.WorkDays() );
fStream.WriteInt8L( locale.StartOfWeek() );
fStream.WriteInt8L( locale.ClockFormat() );
fStream.WriteInt8L( locale.UnitsGeneral() );
fStream.WriteInt8L( locale.UnitsDistanceShort() );
fStream.WriteInt8L( locale.UnitsDistanceLong() );
fStream.WriteInt8L( locale.NegativeCurrencyFormat() );
fStream.WriteInt8L( locale.NegativeLoseSpace() );
fStream.WriteInt8L( locale.NegativeCurrencySymbolOpposite() );
fStream.WriteInt16L( locale.DigitType() );
// If CommitL leaves it means probably full disk.
// It is here assumed that data has not been changed if this leaves.
fStream.CommitL();
CleanupStack::PopAndDestroy( &fStream );
CleanupStack::PopAndDestroy( fName );
}
// ---------------------------------------------------------------------------
// CSsmLocaleObserverSup::LoadRegionL
// ---------------------------------------------------------------------------
//
void CSsmLocaleObserverSup::LoadRegionL( const TDesC& aPath )
{
FUNC_LOG;
INFO( "Loading region data" );
TInt region = MappedRegionL(User::Language());
HBufC* fName = MakeFileNameL( aPath, KFileName, region);
CleanupStack::PushL( fName );
TLocale locale; // copy current values
RFileReadStream fStream;
CleanupClosePushL( fStream );
TInt err = fStream.Open( iFs, *fName, EFileRead );
if ( err != KErrNotFound && err != KErrPathNotFound )
{
ERROR_1( err, "Failed to open stream %S", fName );
// Data file is missing upon the first boot or when switching into a
// language for the first time
}
if ( err == KErrNone )
{
TInt version = fStream.ReadInt8L();
INFO_1( "Region file version: %d", version );
locale.SetCountryCode( fStream.ReadInt16L() );
fStream.ReadInt16L(); // obsolete
locale.SetDateFormat( static_cast< TDateFormat >( fStream.ReadInt8L() ) );
locale.SetTimeFormat( static_cast< TTimeFormat >( fStream.ReadInt8L() ) );
locale.SetCurrencySymbolPosition( static_cast< TLocalePos >( fStream.ReadInt8L() ) );
locale.SetCurrencySpaceBetween( fStream.ReadInt8L() );
locale.SetCurrencyDecimalPlaces( fStream.ReadInt8L() );
locale.SetCurrencyNegativeInBrackets( fStream.ReadInt8L() );
locale.SetCurrencyTriadsAllowed( fStream.ReadInt8L() );
locale.SetThousandsSeparator( fStream.ReadUint32L() );
locale.SetDecimalSeparator( fStream.ReadUint32L() );
TInt dateSeparators = fStream.ReadInt8L();
TInt counter( 0 );
for ( counter = 0; counter < dateSeparators ; counter++ )
{
locale.SetDateSeparator( fStream.ReadUint32L(), counter );
}
TInt timeSeparators = fStream.ReadInt8L();
for ( counter = 0; counter < timeSeparators; counter++ )
{
locale.SetTimeSeparator( fStream.ReadUint32L(), counter );
}
locale.SetAmPmSpaceBetween( fStream.ReadInt8L() );
locale.SetAmPmSymbolPosition( static_cast< TLocalePos >( fStream.ReadInt8L() ) );
// DaylightSaving and HomeDaylightSavingZone are not part of TLocale
// any more, zeros are written to LocaleData.Dxx to keep file structure
// as it was.
fStream.ReadUint32L();
fStream.ReadUint32L();
locale.SetWorkDays( fStream.ReadUint8L() );
locale.SetStartOfWeek( static_cast< TDay >( fStream.ReadInt8L() ) );
locale.SetClockFormat( static_cast< TClockFormat>( fStream.ReadInt8L() ) );
locale.SetUnitsGeneral( static_cast< TUnitsFormat >( fStream.ReadInt8L() ) );
locale.SetUnitsDistanceShort( static_cast< TUnitsFormat >( fStream.ReadInt8L() ) );
locale.SetUnitsDistanceLong( static_cast< TUnitsFormat >( fStream.ReadInt8L() ) );
locale.SetNegativeCurrencyFormat(
static_cast< TLocale::TNegativeCurrencyFormat >( fStream.ReadInt8L() ) );
locale.SetNegativeLoseSpace( fStream.ReadInt8L() );
locale.SetNegativeCurrencySymbolOpposite( fStream.ReadInt8L() );
locale.SetDigitType( static_cast< TDigitType >( fStream.ReadInt16L() ) );
}
// Save changes to the system.
locale.Set();
CleanupStack::PopAndDestroy( &fStream );
CleanupStack::PopAndDestroy( fName );
}
void CSsmLocaleObserverSup::InitializeRegionMappingL()
{
//Reserve the memory for the number of mappings to be appended
iLangRegionMappingHashSet.ReserveL( KMaxNumberOfRegions );
//Insert the Language - Region mapping
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangEnglish, ERegGBR ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangFrench, ERegFRA ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangGerman, ERegDEU ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangSpanish, ERegESP ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangItalian, ERegITA ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangSwedish, ERegSWE ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangDanish, ERegDNK ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangNorwegian, ERegNOR ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangFinnish, ERegFIN ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangAmerican, ERegUSA ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangPortuguese, ERegPRT ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangTurkish, ERegTUR ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangIcelandic, ERegISL ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangRussian, ERegRUS ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangHungarian, ERegHUN ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangDutch, ERegNLD ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangBelgianFlemish, ERegBEL ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangCzech, ERegCZE ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangSlovak, ERegSVK ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangPolish, ERegPOL ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangSlovenian, ERegSVN ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangTaiwanChinese, ERegTWN ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangHongKongChinese, ERegHKG ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangPrcChinese, ERegCHN ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangJapanese, ERegJPN ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangThai, ERegTHA ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangArabic, ERegARE ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangTagalog, ERegPHL ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangBulgarian, ERegBGR ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangCatalan, ERegESP ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangCroatian, ERegHRV ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangEstonian, ERegEST ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangFarsi, ERegIRN ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangCanadianFrench, ERegCAN ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangGreek, ERegGRC ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangHebrew, ERegISR ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangHindi, ERegIND ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangIndonesian, ERegIDN ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangLatvian, ERegLVA ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangLithuanian, ERegLTU ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangMalay, ERegMYS ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangBrazilianPortuguese, ERegBRA ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangRomanian, ERegROU ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangSerbian, ERegSCG ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangLatinAmericanSpanish, ERegMEX ));
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangUkrainian, ERegUKR ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangUrdu, ERegPAK ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangVietnamese, ERegVNM ) );
#ifdef __E32LANG_H__
// 5.0
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangBasque, ERegESP ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangGalician, ERegESP ) );
#endif //__E32LANG_H__
#if !defined(__SERIES60_31__)
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangEnglish_Apac, ERegGBR ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangEnglish_Taiwan, ERegTWN ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangEnglish_HongKong, ERegHKG ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangEnglish_Prc, ERegCHN ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangEnglish_Japan, ERegJPN ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangEnglish_Thailand, ERegTHA ) );
iLangRegionMappingHashSet.InsertL( TLanguageRegion( ELangMalay_Apac, ERegMYS ) );
#endif //!defined(__SERIES60_31__)
}
// ---------------------------------------------------------------------------
// CSsmLocaleObserverSup::MappedRegionL
// ---------------------------------------------------------------------------
//
TInt CSsmLocaleObserverSup::MappedRegionL(const TInt aLanguage)
{
FUNC_LOG;
TLanguageRegion langRegion = iLangRegionMappingHashSet.FindL(TLanguageRegion(aLanguage));
return langRegion.iRegion;
}