/*
* 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: Helper class to handle virtual keypad text labels
*
*/
#include <AknUtils.h>
#include <bautils.h>
#include <barsread.h>
#include <avkon.rsg>
#include <dialer.rsg>
#include <dialerkeypad.rsg>
#include <e32const.h>
#include <e32lang.h>
#include <PtiEngine.h>
#include <AknFepInternalCRKeys.h>
#include <AvkonInternalCRKeys.h>
#include <bacntf.h>
#include "cdialerkeypadlabelmanager.h"
#include "dialercommon.h"
// CONSTANTS
const TInt KKeyCount( 12 );
_LIT( KDialerButton1NumLabel, "1" );
_LIT( KDialerButton2NumLabel, "2" );
_LIT( KDialerButton3NumLabel, "3" );
_LIT( KDialerButton4NumLabel, "4" );
_LIT( KDialerButton5NumLabel, "5" );
_LIT( KDialerButton6NumLabel, "6" );
_LIT( KDialerButton7NumLabel, "7" );
_LIT( KDialerButton8NumLabel, "8" );
_LIT( KDialerButton9NumLabel, "9" );
_LIT( KDialerButton10NumLabel, "*+" );
_LIT( KDialerButton11NumLabel, "0" );
_LIT( KDialerButton12NumLabel, "#" );
_LIT( KDialerKeypadResourceFile, "z:\\resource\\dialerkeypad" );
_LIT( KDialerKeypadResourceFileExt, ".rsc" );
_LIT( KDialerKeypadVariantExtSeparator, "_" );
_LIT( KScriptLatin, "latin" );
_LIT( KScriptCyrillic, "cyrillic" );
_LIT( KScriptGreek, "greek" );
_LIT( KScriptHebrew, "hebrew" );
_LIT( KScriptArabic, "arabic" );
_LIT( KScriptFarsi, "farsi" );
_LIT( KScriptUrdu, "urdu" );
_LIT( KScriptThai, "thai" );
_LIT( KScriptDevanagari, "devanagari" );
_LIT( KScriptChnPinyin, "chn_pinyin" );
_LIT( KScriptChnZhuyin, "chn_zhuyin" );
_LIT( KScriptChnStroke, "chn_stroke" );
_LIT( KScriptChnCangjie, "chn_cangjie" );
enum TScript
{
EScriptLatin = 0,
EScriptCyrillic,
EScriptGreek,
EScriptHebrew,
EScriptArabic,
EScriptFarsi,
EScriptUrdu,
EScriptThai,
EScriptDevanagari,
EScriptChinese, // generic value for all Chinese input modes
EScriptChnPinyin,
EScriptChnZhuyin,
EScriptChnStroke,
EScriptChnCangjie
};
struct TLanguageScriptMapping
{
TLanguage iLang;
TScript iScript;
};
// Following table maps non-Latin languages to corresponding scripts.
// Rest of the languages are asumed to use Latin script.
// The data of the table has been extracted from the header
// \sf\mw\inputmethods\textinput\peninputgenericitut\inc\peninputgenericitutdata.h
const TLanguageScriptMapping KScriptMap[] =
{
{ELangRussian, EScriptCyrillic},
{ELangBulgarian, EScriptCyrillic},
{ELangUkrainian, EScriptCyrillic},
{ELangGreek, EScriptGreek},
{ELangCyprusGreek, EScriptGreek},
{ELangHebrew, EScriptHebrew},
{ELangArabic, EScriptArabic},
{ELangFarsi, EScriptFarsi},
{ELangUrdu, EScriptUrdu},
{ELangThai, EScriptThai},
{ELangHindi, EScriptDevanagari},
{ELangMarathi, EScriptDevanagari},
{ELangTaiwanChinese, EScriptChinese},
{ELangHongKongChinese, EScriptChinese},
{ELangPrcChinese, EScriptChinese}
};
const TInt KScriptMapCount = sizeof( KScriptMap ) / sizeof( TLanguageScriptMapping );
// Values for Chinese adaptive search modes, as documented in AvkonInternalCRKeys.h
enum TChinesePrcMode
{
EChnPrcPinyin = 0,
EChnPrcStroke = 1
};
enum TChineseTwMode
{
EChnTwZhuyin = 0,
EChnTwStroke = 1
};
enum TChineseHkMode
{
EChnHkStroke = 0,
EChnHkCangjie = 1
};
// LOCAL FUNCTION DECLARATIONS
static TScript ScriptForLang( TLanguage aLang );
static const TDesC& ScriptName( TScript aScriptCode );
static TBool ScriptCanSubstituteLatin( TScript aScript );
// MEMBER FUNCTION DEFINITIONS
// ---------------------------------------------------------------------------
// CDialerKeyPadLabelManager::CDialerKeyPadLabelManager
//
// ---------------------------------------------------------------------------
//
CDialerKeyPadLabelManager::CDialerKeyPadLabelManager( CCoeEnv& aCoeEnv,
MDialerKeyPadLabelManagerCallback& aObserver )
: iCoeEnv( aCoeEnv ), iObserver( aObserver )
{
// No implementation required
}
// ---------------------------------------------------------------------------
// CDialerKeyPadLabelManager::~CDialerKeyPadLabelManager
//
// ---------------------------------------------------------------------------
//
CDialerKeyPadLabelManager::~CDialerKeyPadLabelManager()
{
delete iPtiEngine;
delete iAknFepRepository;
delete iAvkonRepository;
if ( iEnvChangeNotifier )
{
iEnvChangeNotifier->Cancel();
delete iEnvChangeNotifier;
}
delete iKeypadNumLabelArray;
delete iKeypadFirstLabelArray;
delete iKeypadSecondLabelArray;
if ( iResourceOffset )
{
iCoeEnv.DeleteResourceFile( iResourceOffset );
}
}
// ---------------------------------------------------------------------------
// CDialerKeyPadLabelManager::NewLC
//
// ---------------------------------------------------------------------------
//
CDialerKeyPadLabelManager* CDialerKeyPadLabelManager::NewLC( CCoeEnv& aCoeEnv,
MDialerKeyPadLabelManagerCallback& aObserver )
{
CDialerKeyPadLabelManager* self =
new (ELeave) CDialerKeyPadLabelManager( aCoeEnv, aObserver );
CleanupStack::PushL( self );
self->ConstructL();
return self;
}
// ---------------------------------------------------------------------------
// CDialerKeyPadLabelManager::NewL
//
// ---------------------------------------------------------------------------
//
CDialerKeyPadLabelManager* CDialerKeyPadLabelManager::NewL( CCoeEnv& aCoeEnv,
MDialerKeyPadLabelManagerCallback& aObserver )
{
CDialerKeyPadLabelManager* self =
CDialerKeyPadLabelManager::NewLC( aCoeEnv, aObserver );
CleanupStack::Pop( self );
return self;
}
// ---------------------------------------------------------------------------
// CDialerKeyPadLabelManager::ConstructL
//
// ---------------------------------------------------------------------------
//
void CDialerKeyPadLabelManager::ConstructL()
{
iPtiEngine = CPtiEngine::NewL();
iAknFepRepository = CDialerCenRepWrapper::NewL( *this, KCRUidAknFep );
iAvkonRepository = CDialerCenRepWrapper::NewL( *this, KCRUidAvkon );
TCallBack envChangeCallback( EnvChangeCallback, this );
iEnvChangeNotifier = CEnvironmentChangeNotifier::NewL(
CActive::EPriorityStandard, envChangeCallback );
iEnvChangeNotifier->Start();
iKeypadNumLabelArray = new ( ELeave ) CDesCArrayFlat( KKeyCount );
iKeypadFirstLabelArray = new ( ELeave ) CDesCArrayFlat( KKeyCount );
iKeypadSecondLabelArray = new ( ELeave ) CDesCArrayFlat( KKeyCount );
UpdateNumLabelsL();
UpdateTextLabelsL();
}
// ---------------------------------------------------------------------------
// CDialerKeyPadLabelManager::ButtonNumLabel
//
// ---------------------------------------------------------------------------
//
TPtrC CDialerKeyPadLabelManager::ButtonNumLabel( TInt aIndex ) const
{
__ASSERT_DEBUG( aIndex < iKeypadNumLabelArray->Count(), DialerPanic(EDialerPanicLabelNotFound) );
TPtrC label( KNullDesC );
if ( aIndex < iKeypadNumLabelArray->Count() )
{
label.Set( (*iKeypadNumLabelArray)[ aIndex ] );
}
return label;
}
// ---------------------------------------------------------------------------
// CDialerKeyPadLabelManager::ButtonFirstAlphaLabel
//
// ---------------------------------------------------------------------------
//
TPtrC CDialerKeyPadLabelManager::ButtonFirstAlphaLabel( TInt aIndex ) const
{
__ASSERT_DEBUG( aIndex < iKeypadFirstLabelArray->Count(), DialerPanic(EDialerPanicLabelNotFound) );
TPtrC label( KNullDesC );
if ( aIndex < iKeypadFirstLabelArray->Count() )
{
label.Set( (*iKeypadFirstLabelArray)[ aIndex ] );
}
return label;
}
// ---------------------------------------------------------------------------
// CDialerKeyPadLabelManager::ButtonSecondAlphaLabel
//
// ---------------------------------------------------------------------------
//
TPtrC CDialerKeyPadLabelManager::ButtonSecondAlphaLabel( TInt aIndex ) const
{
__ASSERT_DEBUG( aIndex < iKeypadSecondLabelArray->Count(), DialerPanic(EDialerPanicLabelNotFound) );
TPtrC label( KNullDesC );
if ( aIndex < iKeypadSecondLabelArray->Count() )
{
label.Set( (*iKeypadSecondLabelArray)[ aIndex ] );
}
return label;
}
// ---------------------------------------------------------------------------
// CDialerKeyPadLabelManager::UpdateTextLabelsL
//
// ---------------------------------------------------------------------------
//
void CDialerKeyPadLabelManager::HandleRepositoryChange(
TUid aRepository, TUint32 aId )
{
if ( (aRepository == KCRUidAknFep && aId == KAknFepInputTxtLang) ||
(aRepository == KCRUidAvkon && aId == KAknAdaptiveSearchChinesePRC) ||
(aRepository == KCRUidAvkon && aId == KAknAdaptiveSearchChineseTW) ||
(aRepository == KCRUidAvkon && aId == KAknAdaptiveSearchChineseHongkong) )
{
// Check if alpabet labels need to be changed
TInt scriptToUse( EScriptLatin );
TRAP_IGNORE( scriptToUse = LabelScriptToUseL() );
if ( iLabelScriptInUse != scriptToUse )
{
TRAP_IGNORE( UpdateTextLabelsL() );
iObserver.KeyLabelsChanged();
}
}
}
// ---------------------------------------------------------------------------
// CDialerKeyPadLabelManager::HandleEnvChange
//
// ---------------------------------------------------------------------------
//
void CDialerKeyPadLabelManager::HandleEnvChange()
{
if ( iEnvChangeNotifier->Change() & EChangesLocale )
{
TLocale locale;
if ( locale.DigitType() != iDigitTypeInUse )
{
TRAP_IGNORE( UpdateNumLabelsL() );
iObserver.KeyLabelsChanged();
}
}
}
// ---------------------------------------------------------------------------
// CDialerKeyPadLabelManager::EnvChangeCallback
//
// ---------------------------------------------------------------------------
//
TInt CDialerKeyPadLabelManager::EnvChangeCallback( TAny* aSelfPtr )
{
CDialerKeyPadLabelManager* self =
static_cast< CDialerKeyPadLabelManager* >( aSelfPtr );
self->HandleEnvChange();
return KErrNone;
}
// ---------------------------------------------------------------------------
// CDialerKeyPadLabelManager::UpdateTextLabelsL
//
// ---------------------------------------------------------------------------
//
void CDialerKeyPadLabelManager::UpdateTextLabelsL()
{
iKeypadFirstLabelArray->Reset();
iKeypadSecondLabelArray->Reset();
// Load the correct keypad resource file
TFileName resourceName;
GetResourceFileNameL( resourceName );
iResourceOffset = iCoeEnv.AddResourceFileL( resourceName );
// Read keypad labels from the resource
TResourceReader reader;
iCoeEnv.CreateResourceReaderLC( reader, R_DIALER_KEYPAD );
TInt16 count = reader.ReadInt16();
for ( TInt i = 0 ; i < count ; ++i )
{
TPtrC firstRow = reader.ReadTPtrC();
iKeypadFirstLabelArray->AppendL( firstRow );
TPtrC secondRow = reader.ReadTPtrC();
iKeypadSecondLabelArray->AppendL( secondRow );
}
CleanupStack::PopAndDestroy(); // reader
// Free resource as it's not usually needed anymore. Ensure that destructor
// won't free it again.
iCoeEnv.DeleteResourceFile( iResourceOffset );
iResourceOffset = 0;
}
// ---------------------------------------------------------------------------
// CDialerKeyPadLabelManager::UpdateNumLabelsL
//
// ---------------------------------------------------------------------------
//
void CDialerKeyPadLabelManager::UpdateNumLabelsL()
{
// Save digit type used. This is to allow us update number labels
// only when digit type is changed and not on all locale changes.
TLocale locale;
iDigitTypeInUse = locale.DigitType();
iKeypadNumLabelArray->Reset();
// Fill number labels array
iKeypadNumLabelArray->AppendL( KDialerButton1NumLabel );
iKeypadNumLabelArray->AppendL( KDialerButton2NumLabel );
iKeypadNumLabelArray->AppendL( KDialerButton3NumLabel );
iKeypadNumLabelArray->AppendL( KDialerButton4NumLabel );
iKeypadNumLabelArray->AppendL( KDialerButton5NumLabel );
iKeypadNumLabelArray->AppendL( KDialerButton6NumLabel );
iKeypadNumLabelArray->AppendL( KDialerButton7NumLabel );
iKeypadNumLabelArray->AppendL( KDialerButton8NumLabel );
iKeypadNumLabelArray->AppendL( KDialerButton9NumLabel );
iKeypadNumLabelArray->AppendL( KDialerButton10NumLabel );
iKeypadNumLabelArray->AppendL( KDialerButton11NumLabel );
iKeypadNumLabelArray->AppendL( KDialerButton12NumLabel );
// Convert num labels to current global number mode
for ( TInt i = 0 ; i < iKeypadNumLabelArray->Count() ; ++i )
{
// A bit of magic is needed to get a modifiable pointer
// descriptor which points to string within the array.
TPtrC roPtr = (*iKeypadNumLabelArray)[i];
TPtr ptr( const_cast<TUint16*>( roPtr.Ptr() ), roPtr.Length(), roPtr.Length() );
AknTextUtils::LanguageSpecificNumberConversion( ptr );
}
}
// ---------------------------------------------------------------------------
// CDialerKeyPadLabelManager::GetResourceFileNameL
//
// ---------------------------------------------------------------------------
//
void CDialerKeyPadLabelManager::GetResourceFileNameL( TDes& aFileName )
{
TFileName resName;
iLabelScriptInUse = LabelScriptToUseL();
// Try to get variated resource name if necessary
if ( iLabelScriptInUse != EScriptLatin )
{
const TDesC& scriptName = ScriptName( static_cast<TScript>(iLabelScriptInUse) );
resName.Copy( KDialerKeypadResourceFile );
resName.Append( KDialerKeypadVariantExtSeparator );
resName.Append( scriptName );
resName.Append( KDialerKeypadResourceFileExt );
BaflUtils::NearestLanguageFile( iCoeEnv.FsSession(), resName );
if ( !BaflUtils::FileExists( iCoeEnv.FsSession(), resName ) )
{
// resource not found, fall back to Latin
iLabelScriptInUse = EScriptLatin;
}
}
// Get the default resource name if Latin script was selected or
// resource file for the selected script was not found.
if ( iLabelScriptInUse == EScriptLatin )
{
resName.Copy( KDialerKeypadResourceFile );
resName.Append( KDialerKeypadResourceFileExt );
BaflUtils::NearestLanguageFile( iCoeEnv.FsSession(), resName );
}
aFileName.Copy( resName );
}
// ---------------------------------------------------------------------------
// CDialerKeyPadLabelManager::LabelScriptToUseL
//
// ---------------------------------------------------------------------------
//
TInt CDialerKeyPadLabelManager::LabelScriptToUseL() const
{
TInt lang( ELangEnglish );
// Get current input language
TInt err = iAknFepRepository->Get( KAknFepInputTxtLang, lang );
__ASSERT_DEBUG( !err, DialerPanic(err) );
TInt script = ScriptForLang( static_cast<TLanguage>(lang) );
// Distinct logic is used to select labels when current input language
// is any version of Chinese. PCS uses different algorith for Chinese.
if ( script == EScriptChinese )
{
script = ChineseScriptToUseL();
}
// If current input language is written in Latin script, then we check
// if some other script of the device could also be shown on the labels.
// Most variated labels include Latin characters as well.
else if ( script == EScriptLatin )
{
RArray<TInt> availableLanguages;
CleanupClosePushL( availableLanguages );
iPtiEngine->GetAvailableLanguagesL( availableLanguages );
// Scirpt of the current UI language is preferred option for
// alternative script. Ensure it's considered first.
TLanguage uiLang = User::Language();
TInt pos = availableLanguages.Find( uiLang );
if ( pos != KErrNotFound )
{
availableLanguages.Remove( pos );
availableLanguages.InsertL( uiLang, 0 );
}
TInt langCount = availableLanguages.Count();
for ( TInt i = 0 ; i < langCount ; ++i )
{
TLanguage altLang = static_cast<TLanguage>( availableLanguages[i] );
TScript altScript = ScriptForLang( altLang );
if ( altScript != EScriptLatin && ScriptCanSubstituteLatin(altScript) )
{
// Suitable alternative script found. Use its labels
// instead of showing only Latin alphabets.
script = altScript;
i = langCount; // to break out
}
}
CleanupStack::PopAndDestroy( &availableLanguages );
}
return script;
}
// ---------------------------------------------------------------------------
// CDialerKeyPadLabelManager::ChineseScriptToUseL
//
// ---------------------------------------------------------------------------
//
TInt CDialerKeyPadLabelManager::ChineseScriptToUseL() const
{
TInt script( EScriptLatin );
TInt lang( ELangPrcChinese );
TInt chnSearchMode( 0 );
TInt err = iAknFepRepository->Get( KAknFepInputTxtLang, lang );
__ASSERT_DEBUG( !err, DialerPanic(EDialerPanicChineseScriptError) );
switch ( lang )
{
case ELangPrcChinese:
{
err = iAvkonRepository->Get( KAknAdaptiveSearchChinesePRC, chnSearchMode );
script = ( chnSearchMode == EChnPrcPinyin ? EScriptChnPinyin : EScriptChnStroke );
}
break;
case ELangTaiwanChinese:
{
err = iAvkonRepository->Get( KAknAdaptiveSearchChineseTW, chnSearchMode );
script = ( chnSearchMode == EChnTwZhuyin ? EScriptChnZhuyin : EScriptChnStroke );
}
break;
case ELangHongKongChinese:
{
err = iAvkonRepository->Get( KAknAdaptiveSearchChineseHongkong, chnSearchMode );
script = ( chnSearchMode == EChnHkStroke ? EScriptChnStroke : EScriptChnCangjie );
}
break;
default:
{
err = KErrUnknown;
}
break;
}
__ASSERT_DEBUG( !err, DialerPanic(EDialerPanicChineseScriptError) );
return script;
}
// LOCAL FUNCTION DEFINITIONS
// ---------------------------------------------------------------------------
// ScriptForLang
//
// ---------------------------------------------------------------------------
//
static TScript ScriptForLang( TLanguage aLang )
{
TScript script( EScriptLatin );
for ( TInt i = 0 ; i < KScriptMapCount ; ++i )
{
if ( aLang == KScriptMap[i].iLang )
{
script = KScriptMap[i].iScript;
i = KScriptMapCount; // to break out
}
}
return script;
}
// ---------------------------------------------------------------------------
// ScriptName
//
// ---------------------------------------------------------------------------
//
static const TDesC& ScriptName( TScript aScriptCode )
{
// Convert script ID to script name
switch ( aScriptCode )
{
case EScriptLatin:
return KScriptLatin;
case EScriptCyrillic:
return KScriptCyrillic;
case EScriptGreek:
return KScriptGreek;
case EScriptHebrew:
return KScriptHebrew;
case EScriptArabic:
return KScriptArabic;
case EScriptFarsi:
return KScriptFarsi;
case EScriptUrdu:
return KScriptUrdu;
case EScriptThai:
return KScriptThai;
case EScriptDevanagari:
return KScriptDevanagari;
case EScriptChnPinyin:
return KScriptChnPinyin;
case EScriptChnZhuyin:
return KScriptChnZhuyin;
case EScriptChnStroke:
return KScriptChnStroke;
case EScriptChnCangjie:
return KScriptChnCangjie;
default:
__ASSERT_DEBUG( EFalse, DialerPanic(EDialerPanicUnknownScript) );
}
return KNullDesC;
}
// ---------------------------------------------------------------------------
// ScriptCanSubstituteLatin
// Return ETrue if labels of given script can be used instead of Latin labels
// when current input language is written with Latin script. This requires
// that the labels include also Latin characters and that labels don't contain
// any characters which would only make sense in some specific input mode.
// ---------------------------------------------------------------------------
//
static TBool ScriptCanSubstituteLatin( TScript aScript )
{
// It would be better to figure this out from the resources but that would
// require opening and parsing several resource files.
return !( aScript == EScriptArabic ||
aScript == EScriptUrdu ||
aScript == EScriptFarsi ||
aScript == EScriptChinese ||
aScript == EScriptChnPinyin ||
aScript == EScriptChnZhuyin ||
aScript == EScriptChnStroke ||
aScript == EScriptChnCangjie );
}
// end of file