breakdeps/AknEcs.cpp
changeset 62 d951a20326d6
child 63 ae68f05b0b2f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/breakdeps/AknEcs.cpp	Fri Oct 15 16:43:47 2010 +0100
@@ -0,0 +1,960 @@
+/*
+* 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
+
+    TRAPD( err, iPhCltEmergencyCall->DialEmergencyCallL( CurrentMatch() ) );
+    __ASSERT_DEBUG( err==KErrNone, Panic( EAknEcsPanicDialLLeft ) );
+    if(err != KErrNone)
+        {
+        err = KErrNone;
+        }
+    _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