uifw/AvKon/src/AknEcs.cpp
changeset 0 2f259fa3e83a
child 4 8ca85d2f0db7
child 21 558113899881
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/uifw/AvKon/src/AknEcs.cpp	Tue Feb 02 01:00:49 2010 +0200
@@ -0,0 +1,708 @@
+/*
+* Copyright (c) 2002-2007 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>
+
+
+// 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
+            };
+    public:
+        /**
+        * C++ constructor
+        */
+        CAknMatchingCharacterQueue( CPhCltEmergencyCall* aPhCltEmergencyCall );
+
+        /**
+        * 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;
+
+    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.
+
+        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 ) 
+        : iPhCltEmergencyCall( aPhCltEmergencyCall )
+    {
+    Reset();
+    }
+
+CAknMatchingCharacterQueue::~CAknMatchingCharacterQueue( )
+    {
+    }
+
+void CAknMatchingCharacterQueue::ConstructL()
+    {
+    }
+
+void CAknMatchingCharacterQueue::Reset()
+    {
+    iMatchPosition = 0;
+    iCharBuffer.Zero();
+    }
+
+void CAknMatchingCharacterQueue::AddChar( TText aNewChar )
+    {    
+    TInt length = iCharBuffer.Length();
+    TInt maxLenght = iCharBuffer.MaxLength();
+    if (length >= maxLenght)
+        {
+        iCharBuffer = iCharBuffer.Right(length - 1);
+        }
+    iCharBuffer.Append( aNewChar );
+    UpdateStatus( EFalse );
+    }
+
+void CAknMatchingCharacterQueue::SetBuffer( const TDesC& aNewBuffer )
+    {    
+    TInt maxLenght = iCharBuffer.MaxLength();
+    TInt length = aNewBuffer.Length();
+    if ( length > maxLenght )
+        {
+        length = maxLenght;
+        }
+    iCharBuffer = aNewBuffer.Left( length );
+    UpdateStatus( ETrue );
+    }
+
+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 )
+    {
+    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
+        {
+        iMatchPosition = cbLength;
+        iStatus = ENoMatch;
+        }
+    }
+
+
+//
+//
+// Implementation of CAknEcsDetector
+//  (Emergency Call Support Detector)
+//
+//
+
+EXPORT_C CAknEcsDetector::CAknEcsDetector()
+    {
+    iCoeEnv = CCoeEnv::Static();
+    iState = ENotFullyConstructed;
+    }
+
+EXPORT_C CAknEcsDetector::~CAknEcsDetector()
+    {
+    // 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;
+    }
+
+EXPORT_C void CAknEcsDetector::ConstructL()
+    {
+    iEmergencyCallObserver = new (ELeave) CPhCltEmergencyCallObserver( this );
+    // Phone client interface
+    iPhCltEmergencyCall = CPhCltEmergencyCall::NewL( iEmergencyCallObserver );
+    iQueue = new (ELeave) CAknMatchingCharacterQueue(iPhCltEmergencyCall);
+    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);
+    }
+
+EXPORT_C CAknEcsDetector* CAknEcsDetector::NewL()
+    { // static
+    CAknEcsDetector* self = new (ELeave) CAknEcsDetector();
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop(); //self
+    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  */)
+    {
+    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
+        }    
+    }
+
+
+EXPORT_C void CAknEcsDetector::AddChar( TText aNewChar )
+    {
+    iKeyTimeoutTimer->Cancel(); // there might be pending timeout; clear it
+    if ( aNewChar == EStdKeyYes || aNewChar ==EKeyPhoneSend )
+        {
+        if ( State() == ECompleteMatch )
+            {
+            SetState( ECompleteMatchThenSendKey );
+            }
+        // else do nothing with it...
+        }
+    else
+        {
+        TText scanCode = aNewChar;
+#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 ) );
+        }
+    }
+
+
+void CAknEcsDetector::DetermineState()
+    {
+    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;
+            default:
+                __ASSERT_DEBUG( 0, Panic(EAknEcsPanicBadState) );
+                break;
+            }
+        SetState(bestState);
+        }
+    }
+
+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 )
+    {
+    iKeyTimeoutTimer->Cancel(); // there might be pending timeout; clear it
+    iQueue->Reset();
+    iQueue->SetBuffer(aNewBuffer);
+    DetermineState();
+    if ( State() == ECompleteMatch )
+        {
+        iKeyTimeoutTimer->Start( KEcsInterKeyTimeout,
+            KEcsInterKeyTimeout, TCallBack( CancelMatch, this ) );
+        }
+    }
+
+EXPORT_C void CAknEcsDetector::SetState( TState 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 )
+                    {
+                    AttemptEmergencyCall();
+                    }
+                else
+                    {  // Pass through this state immediately
+                    iQueue->Reset();
+                    SetState( EEmpty );
+                    }
+                }
+            break;
+
+        default:
+            break;
+
+        }
+    }
+
+EXPORT_C void CAknEcsDetector::Reset()
+    {
+    iQueue->Reset();
+    SetState( EEmpty );
+    }
+
+/**
+* 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()
+    {
+#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;
+        }
+    }
+
+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
+    REINTERPRET_CAST(CAknEcsDetector*,aSelf)->SetState( ECallAttempted );
+#ifdef AVKON_RDEBUG_INFO
+    _LIT(KDebugCallAttemptedCallback, "CallAttemptedCallback");
+    RDebug::Print(KDebugCallAttemptedCallback);
+#endif
+    return 0;
+    }
+
+TInt CAknEcsDetector::CancelMatch(TAny* aThis)
+    {
+    static_cast<CAknEcsDetector*>(aThis)->Reset();
+    static_cast<CAknEcsDetector*>(aThis)->iKeyTimeoutTimer->Cancel();
+    return 0; // Do not repeat the operation
+    }
+
+// End of File