breakdeps/AknEcs.cpp
author William Roberts <williamr@symbian.org>
Mon, 25 Oct 2010 17:26:54 +0100
changeset 80 3ab0df073c86
parent 63 ae68f05b0b2f
permissions -rw-r--r--
Add support for "slim", which is "stem" + removal of some exports and checking of import details For this to work, the static_dependencies.txt file needs to contain the augmented dependency information. To help with this, it can now consume a mixture of both rom_content.csv lines and static_dependencies.txt lines: the best way to update the information would be something like (edit rom_content.csv to add "slim" to XXX.dll) findstr /i "xxx.dll" rom_content.csv > slim.txt findstr /i "xxx.dll" static_dependencies.txt >> slim.txt perl ..\tools\static_dependencies.pl -u static_dependencies.txt slim.txt > new_dependencies.txt This will notice the "slim" marking for xxx.dll, and record the detailed import and export lists for xxx.dll and everything which links to it. The new information will look something like sys\bin\xxx.dll /epoc32/release/armv5/urel/stem_xxx.dll exports=1-98.100-102:euser[100039e5].dll sys\bin\yyy.dll /epoc32/release/armv5/urel/yyy.dll euser[100039e5].dll:xxx[102750c7].dll@2.4-5.77.104-106:scppnwdl.dll sys\bin\zzz.dll /epoc32/release/armv5/urel/zzz.dll euser[100039e5].dll:xxx[102750c7].dll@23.25.74-77:scppnwdl.dll Only executables for which there is a "slim" marking will have this level of detail. The filtering script now does the detailed cross-checking of imports to exports for "slim" executables. In this case, it will observe the stem_xxx.dll does not export ordinal 104, and so the filtering will include deleting sys\bin\yyy.dll (xxx.dll Missing ordinal 104) sys\bin\zzz.dll will be acceptable, because it only uses ordinals which are still present in stem_xxx.dll

/*
* Copyright (c) 2002-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:   Support for Emergency Calls. Class Implementations.
*   Pressed keys are tracked in a buffer and CEmergencyNumberUtils
*   is used to find out if the buffer matches to emergency number.
*   Observers, if registered are called to notify them.
*
*
*/



// INCLUDES
#include <e32std.h>
#include "aknenv.h"
#include "aknappui.h"
#include "AknEcs.h"
#include <featmgr.h>
#include "AknDebug.h"

#include <CPhCltEmergencyCall.h>
#include <MPhCltEmergencyCallObserver.h>
#include <PhCltTypes.h>
#include <AvkonInternalCRKeys.h>
#include <PtiDefs.h>
#include <e32property.h>
#include <AiwCommon.hrh>
#include <aiwdialdata.h>
#include <AiwServiceHandler.h>
#include <centralrepository.h>

#include "akntrace.h"

const TInt KAknKeyScanCodeBegin = 33;
const TInt KAknKeyScanCodeEnd   = 126;

// CLASS DECLARATIONS

/** Class for getting emergency call events */
NONSHARABLE_CLASS(CPhCltEmergencyCallObserver) : public CBase,
                                                 public MPhCltEmergencyCallObserver
    {
    public:
        /** Constructor */
        CPhCltEmergencyCallObserver(CAknEcsDetector* aParent);
        
        /** Destructor */
        ~CPhCltEmergencyCallObserver( );
        
       /**
         * This method is called when client's dial request is completed.
         *
         * @param aStatus error code of the success of the operation.
         */       
        virtual void HandleEmergencyDialL( const TInt aStatus );
    private:
        /** Pointer to the parent object that really handles the events. */
        CAknEcsDetector* iParent;
    };
    
    
CPhCltEmergencyCallObserver::CPhCltEmergencyCallObserver(CAknEcsDetector* aParent)
    :iParent(aParent)
    {
    }
    
CPhCltEmergencyCallObserver::~CPhCltEmergencyCallObserver()
    {
    }
    
void CPhCltEmergencyCallObserver::HandleEmergencyDialL( const TInt /*aStatus*/ )
    {
#ifdef AVKON_RDEBUG_INFO
    _LIT(KDebugDialRequestCompleted, "Dial request is completed");
    RDebug::Print(KDebugDialRequestCompleted);
#endif
    iParent->CallAttemptedCallback( iParent );    
    }
       
/**
* Class to hold the queue of keys (TText characters) provided to the emergency call detector.
*
* Performs matching of an emergency number with the current queue.
*
* No memory is allocated after its complete construction
*
*/
NONSHARABLE_CLASS(CAknMatchingCharacterQueue) : public CBase
    {
    public:
        /**
        * These statuses are returned by MatchText
        */
        enum TStatus
            {
            ENoMatch,
            ECompleteMatch,
            EServiceNumMatch
            };
    public:
        /**
        * C++ constructor
        *
        * @param aPhCltEmergencyCall  Emergency call client
        * @param aServiceCallEnabled  Is service call feature enabled during device or key lock.
        */
        CAknMatchingCharacterQueue( CPhCltEmergencyCall* aPhCltEmergencyCall, TBool aServiceCallEnabled );

        /**
        * C++ destructor
        */
        ~CAknMatchingCharacterQueue( );

        /**
        * 2nd phase constructor
        */
        void ConstructL();

        /**
        * Method to reset the buffer by resetting the pointers.
        *
        */
        void Reset();

        /**
        * Adds the passed character code to the queue. All codes append to the queue;
        * none are ignored.
        *
        * @param aNewChar New char to the queue.
        */
        void AddChar( TText aNewChar );


        /**
        * Set the entire contents of the queue. If the new buffer is longer than
        * the queue, rest are stripped.
        *
        * @param aNewBuffer New content to the queue.
        */
        void SetBuffer( const TDesC& aNewBuffer );

        /**
        * The number of characters in the queue.  Resets to 0. Increases as characters are added
        * up to and equal to KAknEcsMaxMatchingLength
        *
        * @return   the number of characters queued and available for match.
        *
        */
        TInt Count() const;

        /**
        * Returns the status of the queue (which is automatically updated when AddChar and other non-const
        * API is called)
        * @return The status of the match. Nothing matching returns ENoMatch; 
        *         The whole sequence matching returns ECompleteMatch.
        */
        TStatus Status() const;

        /**
        * Returns a pointer to the current matching number. 
        *
        * @return A ptr descriptor into the currently matching text
        */
        TPtrC CurrentMatch() const;

        /**
        * Returns an index to the current character buffer where the emergency number
        * match begins.  This value is between 0 and KAknEcsMaxMatchingLength, even if
        * there have been a large number characters input to the FIFO. Thus, it does not
        * take account of characters that have fallen out of the FIFO.
        *
        * @return the index in the current buffer where the match starts
        */
        TInt IndexOfCurrentMatch() const;

        /**
        * Validates the service number.
        *
        * @param aNumber Service number to be validated from CenRep.
        *
        * @return Returns ETrue if aNumber is a service number, EFalse if not.
        */
        TBool ValidateServiceNumberL( const TDesC& aNumber );

    private:
        /**
        * Update the status of the queue
        */
        void UpdateStatus( TBool aBufferMode );

    private:
        // Emergency number buffer is as long as maximum sequence
        TBuf<KAknEcsMaxMatchingLength> iCharBuffer;

        /** Pointer to phone client interface of emergency call. Not owned */
        CPhCltEmergencyCall* iPhCltEmergencyCall; 
        TStatus iStatus;      // Holds the status;
        TInt iMatchPosition;  // Position in iCharBuffer from where the match starts.
        TBool iServiceCallFeature;  // True if service call feature is enabled.

        TAny* iSpare;
    };




// CLASS IMPLEMENTATIONS

/**
 * Local Panic Function and Panic Codes
 */

enum TAknEcsPanicCodes
    {
    EAknEcsPanicDialLLeft = 1,
    EAknEcsPanicBadState
    };

GLDEF_C void Panic(TAknEcsPanicCodes aPanic)
    {
    _LIT(KPanicCat,"AknEcs");
    User::Panic(KPanicCat, aPanic);
    }

//
// Queue used for storing and matching the keys used in emergency number detection
//
//


CAknMatchingCharacterQueue::CAknMatchingCharacterQueue( CPhCltEmergencyCall* aPhCltEmergencyCall, TBool aServiceCallEnabled )
        : iPhCltEmergencyCall( aPhCltEmergencyCall ), iServiceCallFeature( aServiceCallEnabled )
    {
    _AKNTRACE_FUNC_ENTER;
    Reset();
    _AKNTRACE_FUNC_EXIT;
    }

CAknMatchingCharacterQueue::~CAknMatchingCharacterQueue( )
    {
    }

void CAknMatchingCharacterQueue::ConstructL()
    {
    }

void CAknMatchingCharacterQueue::Reset()
    {
    _AKNTRACE_FUNC_ENTER;
    iMatchPosition = 0;
    iCharBuffer.Zero();
    _AKNTRACE_FUNC_EXIT;
    }

void CAknMatchingCharacterQueue::AddChar( TText aNewChar )
    {    
    _AKNTRACE_FUNC_ENTER;
    _AKNTRACE( "[%s][%s] aNewChar: %s", "CAknMatchingCharacterQueue", 
        		__FUNCTION__,&aNewChar);
    
    TInt length = iCharBuffer.Length();
    TInt maxLenght = iCharBuffer.MaxLength();
    if (length >= maxLenght)
        {
        iCharBuffer = iCharBuffer.Right(length - 1);
        }
    iCharBuffer.Append( aNewChar );
    UpdateStatus( EFalse );
    _AKNTRACE_FUNC_EXIT;
    }

void CAknMatchingCharacterQueue::SetBuffer( const TDesC& aNewBuffer )
    {    
    _AKNTRACE_FUNC_ENTER;
    _AKNTRACE( "[%s][%s] aNewBuffer: %s", "CAknMatchingCharacterQueue", 
            		__FUNCTION__,&aNewBuffer);
    
    TInt maxLenght = iCharBuffer.MaxLength();
    TInt length = aNewBuffer.Length();
    if ( length > maxLenght )
        {
        length = maxLenght;
        }
    iCharBuffer = aNewBuffer.Left( length );
    UpdateStatus( ETrue );
    _AKNTRACE_FUNC_EXIT;
    }

TInt CAknMatchingCharacterQueue::Count() const
    {
    return iCharBuffer.Length();
    }

CAknMatchingCharacterQueue::TStatus CAknMatchingCharacterQueue::Status() const
    {
    return iStatus;
    }

TPtrC CAknMatchingCharacterQueue::CurrentMatch() const
    {
    return TPtrC(iCharBuffer.Right(iCharBuffer.Length() - iMatchPosition));
    }

TInt CAknMatchingCharacterQueue::IndexOfCurrentMatch() const
    {
    return iMatchPosition;
    }

void CAknMatchingCharacterQueue::UpdateStatus( TBool aBufferMode )
    {
    _AKNTRACE_FUNC_ENTER;
    TBool isEmergency = EFalse;
    TInt err = KErrNone;
    TPhCltTelephoneNumber buffer = iCharBuffer;
    if (iPhCltEmergencyCall)
        {
        //err = iPhCltEmergencyCall->FindEmergencyPhoneNumber(buffer, isEmergency);        
        }
    if ( err != KErrNone )
        {
        isEmergency = EFalse;
        }

    TInt cbLength = iCharBuffer.Length();
    TInt bLength = buffer.Length();

    if ( aBufferMode && isEmergency && ( cbLength != bLength ) )
        {
        isEmergency = EFalse;
        }

    if ( isEmergency )
        {
        iMatchPosition = cbLength - bLength;
        iStatus = ECompleteMatch;
        }
    else if ( iServiceCallFeature && cbLength >= KAknServiceCallMinLength )
        {
        // Check if this is a service call
        TBool isServiceNum = EFalse;
        TRAP_IGNORE( isServiceNum = ValidateServiceNumberL( iCharBuffer ) );

        if ( isServiceNum )
            {
            iMatchPosition = 0;
            iStatus = EServiceNumMatch;
            }
        else
            {
            iMatchPosition = cbLength;
            iStatus = ENoMatch;
            }
        }
    else
        {
        iMatchPosition = cbLength;
        iStatus = ENoMatch;
        }
    _AKNTRACE( "[%s][%s] iStatus: %d", "CAknMatchingCharacterQueue", 
                		__FUNCTION__,iStatus );
    _AKNTRACE_FUNC_EXIT;
    }

// -----------------------------------------------------------------------------
// CAknMatchingCharacterQueue::ValidateServiceNumber
// 
// Validates the service phone number.
// -----------------------------------------------------------------------------
//
TBool CAknMatchingCharacterQueue::ValidateServiceNumberL( const TDesC& aNumber )
    {
    _AKNTRACE_FUNC_ENTER;
	TBool isServiceNum = EFalse;
    HBufC* serviceNum = HBufC::NewLC( KAknEcsMaxMatchingLength );
    CRepository* cenRep = CRepository::NewLC( KCRUidAvkon );
    TPtr bufPtr = serviceNum->Des();

    if( cenRep->Get( KAknServiceCallNumber, bufPtr ) != KErrNone )
        {
        CleanupStack::PopAndDestroy( cenRep );
        CleanupStack::PopAndDestroy( serviceNum );
        return EFalse;
        }

    // Check if aNumber matches serviceNum
    if ( aNumber.Compare( *serviceNum ) == 0 )
        {
        isServiceNum = ETrue;
		}

    CleanupStack::PopAndDestroy( cenRep );
    CleanupStack::PopAndDestroy( serviceNum );
    _AKNTRACE_FUNC_EXIT;
    return isServiceNum;
    }

//
//
// Implementation of CAknEcsDetector
//  (Emergency Call Support Detector)
//
//

EXPORT_C CAknEcsDetector::CAknEcsDetector()
    {
    _AKNTRACE_FUNC_ENTER;
    iCoeEnv = CCoeEnv::Static();
    iState = ENotFullyConstructed;
    _AKNTRACE_FUNC_EXIT;
    }

EXPORT_C CAknEcsDetector::~CAknEcsDetector()
    {
    _AKNTRACE_FUNC_ENTER;
    // Must close this in order to remove any observers from the AppUi's monitor
    CloseEventSource();
    delete iPhCltEmergencyCall;
    delete iEmergencyCallObserver;
    delete iQueue;
    delete iIdler;
    delete iKeyTimeoutTimer;
    _AKNTRACE_FUNC_EXIT;
    }

EXPORT_C void CAknEcsDetector::ConstructL()
    {
    _AKNTRACE_FUNC_ENTER;
    iEmergencyCallObserver = new (ELeave) CPhCltEmergencyCallObserver( this );
    // Phone client interface
    //iPhCltEmergencyCall = CPhCltEmergencyCall::NewL( iEmergencyCallObserver );

    // Check if service call is allowed during device and key lock
    iServiceCallEnabled = 
        FeatureManager::FeatureSupported( KFeatureIdFfServiceCallWhilePhoneLocked );

    iQueue = new (ELeave) CAknMatchingCharacterQueue( iPhCltEmergencyCall, iServiceCallEnabled );
    iQueue->ConstructL();

    DetermineState();

    // Idler for delaying the change of state to Call Attempted
    iIdler = CIdle::NewL( CActive::EPriorityLow );

    // Timer for timing the timeout between keys
    iKeyTimeoutTimer = CPeriodic::NewL( CActive::EPriorityLow);
    _AKNTRACE_FUNC_EXIT;
    }

EXPORT_C CAknEcsDetector* CAknEcsDetector::NewL()
    { // static
    _AKNTRACE_FUNC_ENTER;
    CAknEcsDetector* self = new (ELeave) CAknEcsDetector();
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop(); //self
    _AKNTRACE_FUNC_EXIT;
    return self;
    }

EXPORT_C TBool CAknEcsDetector::ConnectToEventSource()
    {
    if ( iFlags.IsClear( EEventSourceConnected ) )
        {
        TRAPD( err, iAvkonAppUi->EventMonitor()->AddObserverL(this) );
        iFlags.Assign( EEventSourceConnected, ( err == KErrNone ) );
        return ( err == KErrNone );
        }
    else
        {
        return ETrue;
        }
    }

EXPORT_C void CAknEcsDetector::CloseEventSource()
    {
    if (iFlags.IsSet( EEventSourceConnected ) )
        {
        CAknWsEventMonitor* eventMonitor = iAvkonAppUi->EventMonitor();
        eventMonitor->RemoveObserver(this);
        iFlags.Clear( EEventSourceConnected );
        }
    }

EXPORT_C void CAknEcsDetector::HandleWsEventL(const TWsEvent& aEvent, CCoeControl* /* aDestination  */)
    {
    _AKNTRACE_FUNC_ENTER;
    _AKNTRACE( "[%s][%s] aEvent.type(): %d, aEvent.Key()->iScanCode :%d", "CAknEcsDetector", 
                            		__FUNCTION__,aEvent.Type(),aEvent.Key()->iScanCode );
    if ( aEvent.Type() == EEventKeyDown || 
        // EKeyPhoneEnd/EKeyNo doesn't send EEVentKeyDown events, so EEventKey is used instead
       ( ( aEvent.Key()->iScanCode == EStdKeyNo ) && ( aEvent.Type() == EEventKey ) ) )
        {
        AddChar( (TText)(aEvent.Key()->iScanCode ) ); // top 16 ( in Unicode build) bits removed
        }

    if ( iServiceCallEnabled )
        {
        // When Cancel is pressed we need to clear the queue
        if ( iState == EServiceNumMatch && aEvent.Type() == EEventPointer && 
        	   aEvent.Pointer()->iType == TPointerEvent::EButton1Down )
            {
            // Clear the queue, set state to EEmpty, and cancel any pending timeout
            Reset();
            iKeyTimeoutTimer->Cancel();
            }
        }
    _AKNTRACE_FUNC_EXIT;
    }


EXPORT_C void CAknEcsDetector::AddChar( TText aNewChar )
    {
    _AKNTRACE_FUNC_ENTER;
    _AKNTRACE( "[%s][%s] aNewChar: %s", "CAknEcsDetector", 
                                		__FUNCTION__, &aNewChar );

    if (aNewChar == EKeyQwertyOn || aNewChar == EKeyQwertyOff)
        { 
        _AKNTRACE_FUNC_EXIT;
        return;   // return directly if the aNewChar is slide open/closed.
        }
	
    iKeyTimeoutTimer->Cancel(); // there might be pending timeout; clear it
    if ( aNewChar == EStdKeyYes || aNewChar == EKeyPhoneSend )
        {
        if ( iServiceCallEnabled )
            {
            if ( iState == ECompleteMatch || iState == EServiceNumMatch )
                {
                _AKNTRACE( "[%s][%s] SetState( ECompleteMatchThenSendKey )", "CAknEcsDetector", 
                                            		    __FUNCTION__ );
                SetState( ECompleteMatchThenSendKey );
                }
            }
        else
            {
            if ( iState == ECompleteMatch )
                {
                _AKNTRACE( "[%s][%s] SetState( ECompleteMatchThenSendKey )", "CAknEcsDetector", 
                                                        __FUNCTION__ );
                SetState( ECompleteMatchThenSendKey );
                }
            }
        // else do nothing with it...
        }
    else
        {
        TText scanCode = aNewChar;

        if ( scanCode < KAknKeyScanCodeBegin || scanCode > KAknKeyScanCodeEnd )
            {
            // Just return since it is an invalid character
            return;
            }

#ifdef RD_INTELLIGENT_TEXT_INPUT 
        // Convert scan code to number value here 
        // for 4*10, 3*11, half-qwerty key pad
        // The convert value is referenced from KeymapBuilder.pl in ptienginev2
        // Note: if the product change the scancode defintion,pls change the following 
        // map rules.
        TInt keyboardLayout = EPtiKeyboardNone;
        TInt errCode = RProperty::Get( KCRUidAvkon, KAknKeyBoardLayout, keyboardLayout );
        if ( errCode == KErrNone &&  ( keyboardLayout == EPtiKeyboardQwerty4x10 
            || keyboardLayout == EPtiKeyboardQwerty3x11 ) )
            {
            // using same conventor rule for 3x11 & 4x10
            if ( scanCode == EPtiKeyQwertyQ )
                {
                scanCode = EPtiKeyQwerty1;
                }
            else if ( scanCode == EPtiKeyQwertyW )
                {
                scanCode = EPtiKeyQwerty2;
                }
            else if ( scanCode == EPtiKeyQwertyE )
                {
                scanCode = EPtiKeyQwerty3;
                }        
            else if ( scanCode == EPtiKeyQwertyR )
                {
                scanCode = EPtiKeyQwerty4;
                }
            else if ( scanCode == EPtiKeyQwertyT )
                {
                scanCode = EPtiKeyQwerty5;
                }
            else if ( scanCode == EPtiKeyQwertyY )
                {
                scanCode = EPtiKeyQwerty6;
                }
            else if ( scanCode == EPtiKeyQwertyU )
                {
                scanCode = EPtiKeyQwerty7;
                }
            else if ( scanCode == EPtiKeyQwertyI )
                {
                scanCode = EPtiKeyQwerty8;
                }
            else if ( scanCode == EPtiKeyQwertyO )
                {
                scanCode = EPtiKeyQwerty9;
                }
            else if ( scanCode == EPtiKeyQwertyP )
                {
                scanCode = EPtiKeyQwerty0;
                }    
            }
        else if ( errCode == KErrNone && keyboardLayout == EPtiKeyboardHalfQwerty )
            {
            if ( scanCode == EPtiKeyQwertyE )
                {
                scanCode = EPtiKeyQwerty1;
                }
            else if ( scanCode == EPtiKeyQwertyT )
                {
                scanCode = EPtiKeyQwerty2;
                }
            else if ( scanCode == EPtiKeyQwertyU )
                {
                scanCode = EPtiKeyQwerty3;
                }        
            else if ( scanCode == EPtiKeyQwertyD )
                {
                scanCode = EPtiKeyQwerty4;
                }
            else if ( scanCode == EPtiKeyQwertyG )
                {
                scanCode = EPtiKeyQwerty5;
                }
            else if ( scanCode == EPtiKeyQwertyJ )
                {
                scanCode = EPtiKeyQwerty6;
                }
            else if ( scanCode == EPtiKeyQwertyU )
                {
                scanCode = EPtiKeyQwertyC;
                }
            else if ( scanCode == EPtiKeyQwertyB )
                {
                scanCode = EPtiKeyQwerty8;
                }
            else if ( scanCode == EPtiKeyQwertyM )
                {
                scanCode = EPtiKeyQwerty9;
                }
            else if ( scanCode == EPtiKeyQwertySpace )
                {
                scanCode = EPtiKeyQwerty0;
                }    
            }
#endif   //RD_INTELLIGENT_TEXT_INPUT    
        
        iQueue->AddChar( scanCode );
        DetermineState();
        iKeyTimeoutTimer->Start( KEcsInterKeyTimeout, KEcsInterKeyTimeout, TCallBack( CancelMatch, this ) );
        }
    _AKNTRACE_FUNC_EXIT;
    }


void CAknEcsDetector::DetermineState()
    {
    _AKNTRACE_FUNC_ENTER;
    TState bestState = ENoMatch;

    if ( iQueue->Count() == 0 )
        {
        bestState = EEmpty;
        }
    else
        {
        CAknMatchingCharacterQueue::TStatus matchStatus = iQueue->Status();

        switch ( matchStatus )
            {
            case CAknMatchingCharacterQueue::ENoMatch:
                bestState = ENoMatch;
                break;
            case CAknMatchingCharacterQueue::ECompleteMatch:
                bestState = ECompleteMatch;
                break;
            case CAknMatchingCharacterQueue::EServiceNumMatch:
                if ( iServiceCallEnabled )
                    {
                    bestState = EServiceNumMatch;
                    break;
                    }
                // Fall through to default case if service call feature is off
            default:
                __ASSERT_DEBUG( 0, Panic(EAknEcsPanicBadState) );
                break;
            }
        SetState(bestState);
        }
    _AKNTRACE( "[%s][%s] bestState: %d", "CAknEcsDetector", 
                                    		__FUNCTION__, bestState );
    _AKNTRACE_FUNC_EXIT;
    }

EXPORT_C void CAknEcsDetector::ReportEvent(TState aNewState )
    {
    if (iObserver)
        {
        iObserver->HandleEcsEvent( this, aNewState );
        }
    }


EXPORT_C TPtrC CAknEcsDetector::CurrentMatch() const
    {
    return iQueue->CurrentMatch();
    }

TInt CAknEcsDetector::IndexOfCurrentMatch() const
    {
    return iQueue->IndexOfCurrentMatch();
    }

EXPORT_C CAknEcsDetector::TState CAknEcsDetector::State()
    {
    return iState;
    }
EXPORT_C void CAknEcsDetector::SetBuffer( const TDesC& aNewBuffer )
    {
    _AKNTRACE_FUNC_ENTER;
    _AKNTRACE( "[%s][%s] aNewBuffer: %s", "CAknEcsDetector", 
                                        		__FUNCTION__, &aNewBuffer );
        
    iKeyTimeoutTimer->Cancel(); // there might be pending timeout; clear it
    iQueue->Reset();
    iQueue->SetBuffer(aNewBuffer);
    DetermineState();

    if ( iServiceCallEnabled )
        {
        if ( iState == ECompleteMatch || iState == EServiceNumMatch )
            {
            iKeyTimeoutTimer->Start( KEcsInterKeyTimeout,
                KEcsInterKeyTimeout, TCallBack( CancelMatch, this ) );
            }
        }
    else
        {
        if ( iState == ECompleteMatch )
            {
            _AKNTRACE( "[%s][%s] State() == ECompleteMatch ", "CAknEcsDetector", 
                                                		    __FUNCTION__ );
            iKeyTimeoutTimer->Start( KEcsInterKeyTimeout,
                KEcsInterKeyTimeout, TCallBack( CancelMatch, this ) );
            }
        }
    _AKNTRACE_FUNC_EXIT;
    }

EXPORT_C void CAknEcsDetector::SetState( TState aNewState )
    {
    _AKNTRACE_FUNC_ENTER;
    _AKNTRACE( "[%s][%s] aNewState: %d", "CAknEcsDetector", 
                                            		__FUNCTION__, aNewState );
    ReportEvent( aNewState );

    TInt oldState = iState;
    iState = aNewState;

    switch ( oldState )
        {
        // All these are OK to go to the next state without transition action:
        case ENotFullyConstructed:
        case EEmpty:
        case ECallAttempted:
        case ENoMatch:
        case ECompleteMatchThenSendKey:
            break;

        case ECompleteMatch:
            if ( aNewState == ECompleteMatchThenSendKey )
                {
                RelinquishCapturedKeys();

                TBool proceedWithCall = ETrue;
                proceedWithCall = OfferEmergencyCall();
                if ( proceedWithCall )
                    {
                    _AKNTRACE( "[%s][%s] Attempt Emergency Call", "CAknEcsDetector", 
                                                                		__FUNCTION__);
                    AttemptEmergencyCall();
                    }
                else
                    {  // Pass through this state immediately
                    _AKNTRACE( "[%s][%s] Reset", "CAknEcsDetector", __FUNCTION__);
                    iQueue->Reset();
                    SetState( EEmpty );
                    }
                }
            break;

        case EServiceNumMatch:
            if ( iServiceCallEnabled )
                {
                if ( aNewState == ECompleteMatchThenSendKey )
                    {
                    RelinquishCapturedKeys();
                    _AKNTRACE( "[%s][%s] Make Service Call", "CAknEcsDetector", 
                                                                		__FUNCTION__);
                    TRAP_IGNORE( MakeServiceCallL() );
                    }
                }
            break;

        default:
            break;

        }
    _AKNTRACE_FUNC_EXIT;
    }

EXPORT_C void CAknEcsDetector::Reset()
    {
    _AKNTRACE_FUNC_ENTER;
    iQueue->Reset();
    SetState( EEmpty );
    _AKNTRACE_FUNC_EXIT;
    }

/**
* This may be re-implemented to add a confirm query. Re-implementation must not leave
*
*/
EXPORT_C TBool CAknEcsDetector::OfferEmergencyCall()
    {
    return ETrue;
    }

void CAknEcsDetector::CaptureKeys()
    {
    // Capture Send Key
    RWindowGroup& groupWin=iCoeEnv->RootWin();
    iCapturedKey=groupWin.CaptureKey( EStdKeyYes, 0, 0);
    }

void CAknEcsDetector::RelinquishCapturedKeys()
    {
    RWindowGroup& groupWin=iCoeEnv->RootWin();
    groupWin.CancelCaptureKey( iCapturedKey );
    }

void CAknEcsDetector::AttemptEmergencyCall()
    {
    _AKNTRACE_FUNC_ENTER;
#ifdef AVKON_RDEBUG_INFO
    _LIT(KDebugAttemptEmergencyCall, "Attempt Emergency Call From Detector");
    RDebug::Print(KDebugAttemptEmergencyCall);
#endif

#if 0
    TRAPD( err, iPhCltEmergencyCall->DialEmergencyCallL( CurrentMatch() ) );
    __ASSERT_DEBUG( err==KErrNone, Panic( EAknEcsPanicDialLLeft ) );
    if(err != KErrNone)
        {
        err = KErrNone;
        }
#endif
    _AKNTRACE_FUNC_EXIT;
    }

void CAknEcsDetector::MakeServiceCallL()
    {
    _AKNTRACE_FUNC_ENTER;
    if ( iServiceCallEnabled )
        {
        CAiwServiceHandler* aiwServiceHandler = CAiwServiceHandler::NewLC();
        RCriteriaArray interest;
        CleanupClosePushL( interest );

        CAiwCriteriaItem* criteria = CAiwCriteriaItem::NewLC( KAiwCmdCall,
                                         KAiwCmdCall, _L8( "*" ) );
        TUid base;
        base.iUid = KAiwClassBase;
        criteria->SetServiceClass( base );
        User::LeaveIfError( interest.Append( criteria ) );
        aiwServiceHandler->AttachL( interest );

        CAiwDialData* dialData = CAiwDialData::NewLC();
        dialData->SetCallType( CAiwDialData::EAIWForcedCS );
        dialData->SetPhoneNumberL( CurrentMatch() );
        dialData->SetWindowGroup( AIWDialData::KAiwGoToIdle );

        CAiwGenericParamList& paramList = aiwServiceHandler->InParamListL();
        dialData->FillInParamListL( paramList );

        TRAPD( err, aiwServiceHandler->ExecuteServiceCmdL( KAiwCmdCall, paramList,
                    aiwServiceHandler->OutParamListL(), 0, NULL ) );
        __ASSERT_DEBUG( err == KErrNone, Panic( EAknEcsPanicDialLLeft ) );

        //reset the queue
        iQueue->Reset();

        CleanupStack::PopAndDestroy( dialData );
        CleanupStack::PopAndDestroy( criteria );
        CleanupStack::PopAndDestroy( &interest );
        CleanupStack::PopAndDestroy( aiwServiceHandler );

        if( err != KErrNone )
            {
            User::Leave( err );
            }
        }
    _AKNTRACE_FUNC_EXIT;
    }

EXPORT_C void CAknEcsDetector::SetObserver( MAknEcsObserver* aObserver )
    {
    iObserver = aObserver;
    }

    /**
     * It is called whenever status is retrieved (by the client).
     *
     * @param aStatus It is the status of the phone.
     */
void CAknEcsDetector::HandlePhoneStatusL( const TInt /* aStatus */ )
    {
    }

    /**
    * This is meant to be called asynchronously in order for the Observer to destroy itself
    *
    */
TInt CAknEcsDetector::CallAttemptedCallback(TAny* aSelf)
    { // static
    _AKNTRACE_FUNC_ENTER;
    REINTERPRET_CAST(CAknEcsDetector*,aSelf)->SetState( ECallAttempted );
#ifdef AVKON_RDEBUG_INFO
    _LIT(KDebugCallAttemptedCallback, "CallAttemptedCallback");
    RDebug::Print(KDebugCallAttemptedCallback);
#endif
    _AKNTRACE_FUNC_EXIT;
    return 0;
    }

TInt CAknEcsDetector::CancelMatch(TAny* aThis)
    {
    _AKNTRACE_FUNC_ENTER;
    static_cast<CAknEcsDetector*>(aThis)->Reset();
    static_cast<CAknEcsDetector*>(aThis)->iKeyTimeoutTimer->Cancel();
    _AKNTRACE_FUNC_EXIT;
    return 0; // Do not repeat the operation
    }

// End of File