// PLEASE NOTE: THIS FILE HAS NOT YET BEEN MIGRATED TO NEW NOTIFIER SYSTEM !!!

/*
* Copyright (c) 2002 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: Avkon KeyLock Notifier
*
*/


#include "AknKeyLockNotifier.h"
#include "AknNotifyPlugin.h"
#include "AknNotifyPlugin.hrh"

#include <aknnotpi.rsg>
#include <eikenv.h>
#include <eikappui.h>
#include <aknkeys.h>
#include <coedef.h>

#include <uikon/eiksrvui.h>
#include <eikon.hrh>
#include <apgwgnam.h>
#include <aknsoundsystem.h>
#include <avkon.rsg>
#include <akndlgshut.h>
#include <eikkeysound.h>
#include <bautils.h>
#include <FeatMgr.h>

#include <aknlayout.lag>
#include <aknutils.h>
#include <eikcba.h>
#include <AknsConstants.h>
#include <aknnotecontrol.h>
#include <AknLayoutScalable_Avkon.cdl.h>

#ifdef __COVER_DISPLAY
#include "AknPublishToCoverUI.h"
#endif // __COVER_DISPLAY

#include <AknNotifySignature.h>

#include <AiwServiceHandler.h>
#include <AiwCommon.hrh>

#include <akntashook.h>
#define KSysApUid TUid::Uid(0x100058F3)

const TInt KAknObserverListGranularity = 4;
const TInt KAknOfferKeyLockTimeout = 6000000; // 6sec

const TInt KNoteCmdFocusLost = 3100;

const TUint KAknAsterisk = '*';
const TUint KAknHash = '#';
const TInt KKeyLockControlAnyKey = 3300;    // phone query

_LIT(KRESOURCEFILE,"z:\\private\\10003a4a\\aknnotpi.rsc");

// CAknLockedNote

CAknLockedNote::CAknLockedNote(TInt& aLocked, MEikCommandObserver* aCommandObserver)
:CAknSleepingNote(aCommandObserver), iLocked(aLocked)
    {
    AKNTASHOOK_ADD( this, "CAknLockedNote" );
    }

TBool CAknLockedNote::OkToExitL(TInt aCommand)
    {
    iLocked = EFalse;

    if (iCommandObserver)
        {
        iCommandObserver->ProcessCommandL(aCommand);
        }

    return ETrue;
    }

CAknLockedNote::~CAknLockedNote()
    {
    AKNTASHOOK_REMOVE();
    iLocked = EFalse;
    }

void CAknLockedNote::CancelNote()
    {
    if ( iTimer )
        iTimer->Cancel();
    CAknNoteControl* ctrl = 0;
    ctrl = NoteControl();
    if ( ctrl )
        { // if there is no animation, just returns KErrGeneral
        ctrl->CancelAnimation();
        }
    ExitSleepingDialog();
    iLocked = EFalse;
    }

void CAknLockedNote::FocusChanged(TDrawNow /*aDrawNow*/)
    {
    if (!IsFocused() &&  iCommandObserver)
        {
        TRAP_IGNORE(iCommandObserver->ProcessCommandL(KNoteCmdFocusLost))
        }
    }


void CAknLockedNote::CEikDialog_Reserved_1()
    {
    }

void CAknLockedNote::CEikDialog_Reserved_2()
    {
    }

void CAknLockedNote::CAknNoteDialog_Reserved()
    {
    }

void CAknLockedNote::CAknSleepingNote_Reserved()
    {
    }


CAknSleepingNote::CAknSleepingNote(MEikCommandObserver* aCommandObserver)
:iCommandObserver(aCommandObserver)
    {
    AKNTASHOOK_ADD( this, "CAknSleepingNote" );
    }


void CAknSleepingNote::ConstructSleepingNoteL(TInt aResourceId)
    {
    iResourceId = aResourceId;
    CAknNoteDialog::ConstructSleepingDialogL(aResourceId);
    // Construct now rather than in PreLayoutDynInit
    delete iTimer;
    iTimer = 0;

    iTimer = CPeriodic::NewL(0);
    }

TInt CAknSleepingNote::ShowNote(const TTimeout aTimeout,const TTone aTone)
    {
    ReportUserActivity();
    iTimeoutInMicroseconds = aTimeout;
    iTone = aTone;
    return RouseSleepingDialog();
    }

TBool CAknSleepingNote::OkToExitL(TInt aCommand)
    {
    if (iCommandObserver)
        {
        iCommandObserver->ProcessCommandL(aCommand);
        }
    return ETrue;
    }

void CAknSleepingNote::HandleResourceChange(TInt aType)
    {
    if( aType == KAknsMessageSkinChange )
        {
        TInt animationRes(0);
        switch (iResourceId)
            {
        case R_KEYLOCK_NOTE_KEYLOCKED:
            animationRes = R_QGN_NOTE_INFO_ANIM;
            break;
        case R_KEYLOCK_NOTE_UNLOCK_CONFIRM:
            animationRes = R_QGN_NOTE_QUERY_ANIM;
            break;
        case R_KEYLOCK_NOTE_UNLOCK_ASTERISK:
            animationRes = R_QGN_NOTE_INFO_ANIM;
            break;
        case R_KEYLOCK_NOTE_LOCK_ON:
            animationRes = R_QGN_NOTE_KEYGUARD_LOCKED_ANIM;
            break;
        case R_KEYLOCK_NOTE_LOCK_OFF:
            animationRes = R_QGN_NOTE_KEYGUARD_OPEN_ANIM;
            break;
        case R_KEYLOCK_OFFER_LOCK_NOTE:
            animationRes = R_QGN_NOTE_QUERY_ANIM;
            break;
        default:
            break;
        } // end of switch

        if (animationRes)
            {
            CAknNoteControl* ctrl = 0;
            ctrl = NoteControl();
            if ( ctrl )
                {
                TRAP_IGNORE( ctrl->SetAnimationL( animationRes ));
                }
            }

        }

    CAknNoteDialog::HandleResourceChange(aType);
    }


void CAknSleepingNote::CEikDialog_Reserved_1()
    {
    }

void CAknSleepingNote::CEikDialog_Reserved_2()
    {
    }

void CAknSleepingNote::CAknNoteDialog_Reserved()
    {
    }

void CAknSleepingNote::CAknSleepingNote_Reserved()
    {
    }


/**
* Private class to implement the emergency number display during keylock
*
*/
class CAknEcsNote: public CAknSleepingNote
    {
public:
    /**
    * Constructor
    */
    CAknEcsNote( MEikCommandObserver* aCommandObserver );
    /**
    * API to set the emergency number to be displayed
    *
    * aMatchedNumber    text to display (e.g. "112" )
    */
    void SetEmergencyNumber( const TDesC& aMatchedNumber );
    /**
    * Dismisses the sleeping note.
    */
    void SleepNote();

    TBool iNoteOnScreen;
    };

CAknEcsNote::CAknEcsNote( MEikCommandObserver* aCommandObserver ) : CAknSleepingNote( aCommandObserver )
    {}

void CAknEcsNote::SetEmergencyNumber( const TDesC& aMatchedNumber )
    {
    TRect screen(iAvkonAppUi->ApplicationRect());
    TAknLayoutRect mainPane;
    mainPane.LayoutRect(screen, AKN_LAYOUT_WINDOW_main_pane(screen, 0, 1, 1));
    TAknLayoutRect popupNoteWindow;
    AknLayoutUtils::TAknCbaLocation cbaLocation( AknLayoutUtils::CbaLocation() );
	TInt variety( 0 );
    if ( cbaLocation == AknLayoutUtils::EAknCbaLocationRight )
		{
		variety = 5;
		}
	else if ( cbaLocation == AknLayoutUtils::EAknCbaLocationLeft )
		{
		variety = 8;
		}
	else
		{
		variety = 2;
		}

    popupNoteWindow.LayoutRect(mainPane.Rect(), AknLayoutScalable_Avkon::popup_note_window( variety ));
    TAknLayoutText textRect;
    textRect.LayoutText(popupNoteWindow.Rect(), AKN_LAYOUT_TEXT_Note_pop_up_window_texts_Line_1(4));

    // Size of a temporary buffer that contains new lines, spaces and 
    // emergency number for a note.
    TBuf16<KAknEcsMaxMatchingLength+80> number;
    number.Append('\n');
    number.Append('\n');

    TInt spaceCharWidthInPixels = textRect.Font()->CharWidthInPixels(' ');
    if (spaceCharWidthInPixels < 1)
        {
        // Avoid divide by zero situation even the space char would have zero length.
        spaceCharWidthInPixels = 1;
        }
    
    TInt length = (textRect.TextRect().Width() - textRect.Font()->TextWidthInPixels(aMatchedNumber))
                    / spaceCharWidthInPixels;

    const TInt matchedNumberLength = aMatchedNumber.Length();
    const TInt numberLength = number.Length();
    const TInt numberMaxLength = number.MaxLength();
    
    if ( numberLength + length + matchedNumberLength > numberMaxLength)
        {
        // To make sure that buffer overflow does not happen.
        length = numberMaxLength - numberLength - matchedNumberLength;
        }
    for (int i = 0; i < length ; i++)
        {
        number.Append(' ');
        }

    number.Append(aMatchedNumber);
    TRAP_IGNORE(SetTextL(number));

    }

void CAknEcsNote::SleepNote()
    {
    if (iNoteOnScreen)
        ExitSleepingDialog(); // Causes flicker to other notes if called when note is not on screen
    iNoteOnScreen = EFalse;
    }

//CaknLockedPhoneQuery
CAknLockedPhoneQuery* CAknLockedPhoneQuery::NewL( TDes& aDataText )
    {
    CAknLockedPhoneQuery* self =
        new(ELeave) CAknLockedPhoneQuery( aDataText );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    AKNTASHOOK_ADDL( self, "CAknLockedPhoneQuery" );
    return self;
    }

CAknLockedPhoneQuery::~CAknLockedPhoneQuery()
    {
    AKNTASHOOK_REMOVE();
    if ( iInactivityTimer )
        {
        iInactivityTimer->Cancel();
        delete iInactivityTimer;
        }
    }

CAknLockedPhoneQuery::CAknLockedPhoneQuery(TDes& aDataText)
    : CAknTextQueryDialog(aDataText)
    {
    }

void CAknLockedPhoneQuery::ConstructL()
    {
    iInactivityTimer = CPeriodic::NewL(CActive::EPriorityUserInput);
    TCallBack callback(InactivityExitL, this);
    iInactivityTimer->Start(KEcsInterKeyTimeout,
        KEcsInterKeyTimeout, callback);
    }

TKeyResponse CAknLockedPhoneQuery::OfferKeyEventL(const TKeyEvent& aKeyEvent,
                                                  TEventCode aType)
    {
    ResetInactivityTimer();
    if(aKeyEvent.iCode == EKeyPhoneSend || aKeyEvent.iCode == EKeyOK)
        {
        TryExitL(EAknSoftkeyCall);
        return EKeyWasConsumed;
        }
    if(aKeyEvent.iCode == EKeyPhoneEnd)
        {
        TryExitL(EAknSoftkeyCancel);
        return EKeyWasConsumed;
        }
    return CAknTextQueryDialog::OfferKeyEventL(aKeyEvent, aType);
    }

void CAknLockedPhoneQuery::ResetInactivityTimer()
    {
    iInactivityTimer->Cancel();
    TCallBack callback(InactivityExitL, this);
    iInactivityTimer->Start(KEcsInterKeyTimeout,
        KEcsInterKeyTimeout, callback);
    }

TInt CAknLockedPhoneQuery::InactivityExitL(TAny *aThis)
    {
    static_cast<CAknLockedPhoneQuery*>(aThis)->DoInactivityExitL();
    return 0;
    }

void CAknLockedPhoneQuery::DoInactivityExitL()
    {
    TryExitL(EEikBidCancel);
    }

//CAknKeyLockControl

CAknKeyLockControl::CAknKeyLockControl()
    {
    AKNTASHOOK_ADD( this, "CAknKeyLockControl" );
    }

CAknKeyLockControl::CAknKeyLockControl(CAknKeyLockNotifierSubject* aNotif):iNotif(aNotif)
    {
    AKNTASHOOK_ADD( this, "CAknKeyLockControl" );
    }

CAknKeyLockControl::~CAknKeyLockControl()
    {
    AKNTASHOOK_REMOVE();
    FeatureManager::UnInitializeLib();
    iEikonEnv->EikAppUi()->RemoveFromStack(this);
    delete iConfirmationNote;
    //Show note "Now press *".
    //Note is shown when user has pressed "Unlock" when keypad is in locked state
    delete iConfirmationNoteAsterisk;
    delete iLockedNote;
    delete iKeypadUnlockedNote;
    delete iKeypadLockedNote;
    delete iEcsDetector;
    delete iKeyLockCba;
    delete iOfferLockNote;
    delete iEcsNote; // Ecs change
    }

void CAknKeyLockControl::ConstructL()
    {
    FeatureManager::InitializeLibL();
    iFeatureKeypadNoSlider =
        FeatureManager::FeatureSupported( KFeatureIdKeypadNoSlider );

    CreateWindowL();
    Window().SetSize(TSize(0,0));

    ActivateL();

    iEikonEnv->EikAppUi()->AddToStackL(this,ECoeStackPriorityEnvironmentFilter+10,ECoeStackFlagRefusesFocus);

    iKeyLockCba = CEikButtonGroupContainer::NewL(CEikButtonGroupContainer::ECba, CEikButtonGroupContainer::EHorizontal, this, R_KEYLOCK_SOFTKEYS_UNLOCK_EMPTY);
    iKeyLockCba->ButtonGroup()->AsControl()->DrawableWindow()->SetOrdinalPosition(ECoeWinPriorityNeverAtFront);
//    const TSize screenSize=TSize(AKN_LAYOUT_WINDOW_screen.iW,AKN_LAYOUT_WINDOW_screen.iH);  // Ok so far. 'screen' layout used.
    const TSize screenSize( iAvkonAppUi->ApplicationRect().Size() );
    iKeyLockCba->MakeVisible(EFalse);
    iKeyLockCba->SetBoundingRect(TRect(screenSize));

    iEcsNote = new (ELeave) CAknEcsNote( this );
    iEcsNote->ConstructSleepingNoteL(R_AVKON_EMERGENCY_CALL_NOTE);
    iEcsNote->ButtonGroupContainer().ButtonGroup()->AsControl()->DrawableWindow()->SetOrdinalPosition(0,2);

    iOfferLockNote = new(ELeave)CAknLockedNote(iOfferLockEnabled, this);
    iOfferLockNote->ConstructSleepingNoteL(R_KEYLOCK_OFFER_LOCK_NOTE);
    iOfferLockNote->ButtonGroupContainer().ButtonGroup()->AsControl()->DrawableWindow()->SetOrdinalPosition(0,2);

    iKeypadLockedNote = new(ELeave)CAknSleepingNote();
    iKeypadLockedNote->ConstructSleepingNoteL(R_KEYLOCK_NOTE_LOCK_ON);
    iKeypadLockedNote->ButtonGroupContainer().ButtonGroup()->AsControl()->DrawableWindow()->SetOrdinalPosition(0,2);

    iKeypadUnlockedNote = new(ELeave)CAknSleepingNote();
    iKeypadUnlockedNote->ConstructSleepingNoteL(R_KEYLOCK_NOTE_LOCK_OFF);
    iKeypadUnlockedNote->ButtonGroupContainer().ButtonGroup()->AsControl()->DrawableWindow()->SetOrdinalPosition(0,2);

    iLockedNote = new (ELeave)CAknLockedNote(iLockedNoteDisplayed);
    iLockedNote->ConstructSleepingNoteL(R_KEYLOCK_NOTE_KEYLOCKED);
    iLockedNote->ButtonGroupContainer().ButtonGroup()->AsControl()->DrawableWindow()->SetOrdinalPosition(0,2);

    iConfirmationNote = new (ELeave) CAknLockedNote(iUnlockConfirmation);
    iConfirmationNote->ConstructSleepingNoteL(R_KEYLOCK_NOTE_UNLOCK_CONFIRM);
    iConfirmationNote->ButtonGroupContainer().ButtonGroup()->AsControl()->DrawableWindow()->SetOrdinalPosition(0,2);

    if ( iFeatureKeypadNoSlider )
        {
        //Show note "Now press *".
        //Note is shown when user has pressed "Unlock" when keypad is in locked state
        iConfirmationNoteAsterisk = new (ELeave) CAknLockedNote(iUnlockConfirmation);
        iConfirmationNoteAsterisk->ConstructSleepingNoteL(R_KEYLOCK_NOTE_UNLOCK_ASTERISK);
        iConfirmationNoteAsterisk->ButtonGroupContainer().ButtonGroup()->AsControl()->DrawableWindow()->SetOrdinalPosition(0,2);
        }
    // Emergency call support
    iEcsDetector = CAknEcsDetector::NewL();
    iEcsDetector->SetObserver( this );

    iPhoneQueryOnScreen = EFalse;
    iPhoneNumber.Zero();
    }


void CAknKeyLockControl::EnableKeylock(TBool aShowNote)
    {
    if (iOfferLockEnabled)
        {
        iOfferLockNote->CancelNote();
        }
    iKeyLockEnabled = ETrue;

    if (!iAutolockEnabled)
        SendMessageToSysAp(EEikKeyLockEnabled);
    iKeyLockCba->MakeVisible(ETrue);

    TBool areWeInIdleState = CEikStatusPaneBase::Current()->PaneCapabilities(TUid::Uid(EEikStatusPaneUidClock)).IsInCurrentLayout();
        if (areWeInIdleState)
        { // idle state
        ((CEikCba*)iKeyLockCba->ButtonGroup())->SetSkinBackgroundId(KAknsIIDQsnBgAreaControlIdle);
        }
        else
            {
        ((CEikCba*)iKeyLockCba->ButtonGroup())->SetSkinBackgroundId(KAknsIIDQsnBgAreaControl);
        }

    iEikonEnv->BringForwards(ETrue);

    if ( aShowNote )
        DisplayLockedNote();
    ShowKeylockCba();
    CaptureSystemKeys();
    iEcsDetector->ConnectToEventSource();

    if ( iNotif )
        {
        iNotif->NotifyStatusChange(EKeyLockEnabled);
        }

    if ( !iSoundsMuted )
        {
        CAknAppUiBase* appUi = iAvkonAppUiBase;
        TRAPD(err, appUi->KeySounds()->PushContextL(R_AVKON_SILENT_SKEY_LIST));
        if ( !err )
            {
            appUi->KeySounds()->BringToForeground();
            appUi->KeySounds()->LockContext();
            iSoundsMuted = ETrue;
            }
        }
    }

void CAknKeyLockControl::DisableKeylock()
    {
    if ( iSoundsMuted )
        {
        CAknAppUiBase* appUi = iAvkonAppUiBase;
        appUi->KeySounds()->ReleaseContext();
        appUi->KeySounds()->PopContext();
        }

    iEcsDetector->CloseEventSource();
    UnCaptureSystemKeys();
    iEikonEnv->BringForwards(EFalse);
    iKeyLockCba->ButtonGroup()->AsControl()->DrawableWindow()->SetOrdinalPosition(ECoeWinPriorityNeverAtFront);
    iKeyLockCba->MakeVisible(EFalse);
    iKeyLockEnabled = EFalse;
    if (!iAutolockEnabled)
        SendMessageToSysAp(EEikKeyLockDisabled);
    if ( iNotif )
        {
        iNotif->NotifyStatusChange(EKeyLockDisabled);
        }
    iAutolockEnabled = EFalse;
    }

void CAknKeyLockControl::SendMessageToSysAp(TInt aMessage)
    {
    RWsSession& ws = iEikonEnv->WsSession();
    TInt wgId=0;
    CApaWindowGroupName::FindByAppUid(KSysApUid, ws, wgId);
    if (wgId)
        {
        TWsEvent event;
        event.SetType(aMessage);
        event.SetTimeNow();
        ws.SendEventToWindowGroup(wgId, event);
        }
    }

void CAknKeyLockControl::OfferKeylock()
    {
    iOfferLockNote->ShowNote((CAknNoteDialog::TTimeout)KAknOfferKeyLockTimeout, CAknNoteDialog::ENoTone);
    iOfferLockEnabled = ETrue;
    }


void CAknKeyLockControl::DisplayLockedNote()
    {
    if ( !iAutolockEnabled )
        {
    iKeypadLockedNote->ShowNote(CAknNoteDialog::EShortTimeout,CAknNoteDialog::ENoTone);
#ifdef __COVER_DISPLAY
#ifdef __SERIES60_30__ // different code for 3.0 and 2.8
        SAknKeyguardNotePS params;
        params.iIsLocked = ETrue;
        params.iTimeout = CAknNoteDialog::EShortTimeout;
        params.iTone = CAknNoteDialog::ENoTone;
        TRAP_IGNORE( AknPublishToCoverUI::PublishKeyguardNoteL( params ) );
#else // 2.8
        SAknKeyguardNotePSParams params;
        params.iIsLocked = ETrue;
        params.iTimeout = CAknNoteDialog::EShortTimeout;
        TRAP_IGNORE( AknPublishToCoverUI::PublishKeyguardNoteL( params ) );
#endif // __SERIES60_30__
#endif // __COVER_DISPLAY
        }
    }

void CAknKeyLockControl::DisplayKeyActiveNote()
    {
    if ( !iAutolockEnabled )
        {
    iKeypadUnlockedNote->ShowNote(CAknNoteDialog::EShortTimeout,CAknNoteDialog::ENoTone);
#ifdef __COVER_DISPLAY
#ifdef __SERIES60_30__ // different code for 3.0 and 2.8
        SAknKeyguardNotePS params;
        params.iIsLocked = EFalse;
        params.iTimeout = CAknNoteDialog::EShortTimeout;
        params.iTone = CAknNoteDialog::ENoTone;
        TRAP_IGNORE( AknPublishToCoverUI::PublishKeyguardNoteL( params ) );
#else // 2.8
        SAknKeyguardNotePSParams params;
        params.iIsLocked = EFalse;
        params.iTimeout = CAknNoteDialog::EShortTimeout;
        TRAP_IGNORE( AknPublishToCoverUI::PublishKeyguardNoteL( params ) );
#endif // __COVER_DISPLAY
#endif // __COVER_DISPLAY
        }
    }

void CAknKeyLockControl::DoUnlock()
    {
    DisableKeylock();
    DisplayKeyActiveNote();
    }

void CAknKeyLockControl::ProcessCommandL(TInt aCommandId)
    {
    if ( aCommandId == KKeyLockControlAnyKey )
        {
        if ( !iPhoneQueryOnScreen )
            {
            iPhoneQueryOnScreen = ETrue;

            // show phone query
            ShowLockPhoneQueryL();
            }
        }
    else if (aCommandId == EAknSoftkeyUnlock)
        {
        iPhoneQueryOnScreen = EFalse;
        if ( iAutolockEnabled )
            {
            TApaTaskList aList(iCoeEnv->WsSession());
            TApaTask aTask = aList.FindApp(TUid::Uid(0x100059B5));
            if ( aTask.Exists() )
                {
                DisableKeylock();
                iNotif->NotifyStatusChange(EHideSoftNotifications);
                TKeyEvent keyEvent;
                keyEvent.iCode = EKeyBell;
                aTask.SendKey(keyEvent);
                SendMessageToSysAp(EEikKeyLockPowerKeyPressed);
                }
            // else we do nothing, Autolock application was not ready yet.
            }
        else
            {
            if ( iFeatureKeypadNoSlider )
                {
                //Show note "Now press *".
                //Note is shown when user has pressed "Unlock" when keypad is in locked state
                iConfirmationNoteAsterisk->ShowNote(
                    CAknNoteDialog::EShortTimeout,CAknNoteDialog::EConfirmationTone);
                }
            else
                {
                iConfirmationNote->ShowNote(
                    CAknNoteDialog::EShortTimeout,CAknNoteDialog::EConfirmationTone);
                }
            iUnlockConfirmation = ETrue;
            }
        }
    else if (aCommandId == EAknSoftkeyLock)
        {
        // Lock keys
        DoExitOfferKeylock();
        EnableKeylock();
        }
    else if (aCommandId == EAknSoftkeyExit)
        {
        // Cancel offer keylock CBA
        DoExitOfferKeylock();
        }
    else if (aCommandId == EAknSoftkeyEmpty)
        {
        if (iKeyLockEnabled)
            {
            ShowLockedNote();
            }
        }
    else if (aCommandId == KNoteCmdFocusLost)
        {
        // Locked note has become unfocusd - get rid of it
        if (iOfferLockEnabled)
            {
            DoExitOfferKeylock();
            }
        }
    }

TInt CAknKeyLockControl::CountComponentControls() const
    {
    if (iKeyLockEnabled)
        return 1;
    else
        return 0;
    }

CCoeControl* CAknKeyLockControl::ComponentControl(TInt /*aIndex*/) const
    {
    if (iKeyLockEnabled)
        return iKeyLockCba;
    else
        return NULL;
    }


TKeyResponse CAknKeyLockControl::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
    {
    if (!iOfferLockEnabled && !iKeyLockEnabled)
        return EKeyWasNotConsumed;


    if ( (aType == EEventKey && aKeyEvent.iRepeats == 0) ||
         (aType == EEventKeyDown && aKeyEvent.iScanCode == EStdKeyDevice2) // Power key
         )
        {
        // If power key pressed, tell SysAp about if
        if(aKeyEvent.iScanCode == EStdKeyDevice2)
            {
            SendMessageToSysAp(EEikKeyLockPowerKeyPressed);
            }

        if (iOfferLockEnabled)
            {
            switch (aKeyEvent.iCode)
                {
                case EKeyOK:
                    {
                    DoExitOfferKeylock();
                    EnableKeylock();
                    }
                case EKeyLeftArrow:
                case EKeyRightArrow:
                case EKeyUpArrow:
                case EKeyDownArrow:
                case EKeyApplication:
                    return EKeyWasConsumed;
                    break;
                default:
            // Normal response - send it to the cba via the control stack
            return EKeyWasNotConsumed;
                }
            }
        else if (iKeyLockEnabled)
            {
            if (iLockedNoteDisplayed)
                {
                // See if 'Unlock' has been pressed
                if (aKeyEvent.iCode == EKeyCBA1)
                    {
                    if ( iFeatureKeypadNoSlider )
                        {
                        iConfirmationNoteAsterisk->ShowNote(
                            CAknNoteDialog::EShortTimeout,
                            CAknNoteDialog::EConfirmationTone);
                        }
                    else
                        {
                        iConfirmationNote->ShowNote(
                            CAknNoteDialog::EShortTimeout,
                            CAknNoteDialog::EConfirmationTone);
                        }

                    iUnlockConfirmation = ETrue;
                    iLockedNote->CancelNote();
                    }
                // Locked note is on-screen - discard key
                return EKeyWasConsumed;
                }
            else if (iUnlockConfirmation)
                {
                // Confirmation note is on-screen - check for OK

                if ( ( aKeyEvent.iCode == KAknAsterisk && iFeatureKeypadNoSlider )
                  || ( aKeyEvent.iCode == EKeyCBA2 && !iFeatureKeypadNoSlider ) )
                    {
                    DoUnlock();
                    if ( iFeatureKeypadNoSlider )
                        {
                        //Show note "Now press *".
                        //Note is shown when user has pressed "Unlock" when keypad is in locked state
                        iConfirmationNoteAsterisk->CancelNote();
                        }
                    else
                        {
                        iConfirmationNote->CancelNote();
                        }
                    }
                else
                    {
                    if ( aKeyEvent.iCode != EKeyCBA1 )
                        ShowLockedNote();
                    }
                }
            else
                {
                // Normal response - send it to the cba
                TKeyResponse cbaResponse = iKeyLockCba->ButtonGroup()->
                    AsControl()->OfferKeyEventL(aKeyEvent, aType);

                if (cbaResponse == EKeyWasNotConsumed)
                    {
                    if ( !iFeatureKeypadNoSlider )
                        {
                        // Selection key causes same action as 'Unlock'
                        if (aKeyEvent.iCode == EKeyOK)
                            {
                            iConfirmationNote->ShowNote(
                                CAknNoteDialog::EShortTimeout,
                                CAknNoteDialog::EConfirmationTone);

                            iUnlockConfirmation = ETrue;
                            }
                        else
                            {
                            ShowLockedNote();
                            }
                        }
                    else
                        {
                        if ( !(iEcsNote->iNoteOnScreen && aKeyEvent.iCode == EKeyYes) )
                            {
                            if ( !iAutolockEnabled )
                                {
                                ShowLockedNote();
                                }
                            else
                                {
                                if(aKeyEvent.iScanCode == EStdKeyDevice2)
                                    {
                                    SendMessageToSysAp(EEikKeyLockPowerKeyPressed);
                                    return EKeyWasConsumed;
                                    }
                                switch ( aKeyEvent.iCode )
                                    {
                                    case EKeyLeftArrow:
                                    case EKeyRightArrow:
                                    case EKeyUpArrow:
                                    case EKeyDownArrow:
                                    case EKeyApplication:
                                    case EKeyCamera:
                                    case EKeyVolumeUp:
                                    case EKeyVolumeDown:
                                    case EKeySide:
                                        return EKeyWasConsumed;
                                    case EKeyOK:
                                    case EKeyPhoneSend:
                                    case EKeyPhoneEnd:
                                    case EKeyBackspace:
                                        if ( !iPhoneQueryOnScreen )
                                        {
                                            return EKeyWasConsumed;
                                        }
                                    default:
                                        break;
                                    }
                                if ( iPhoneQueryOnScreen )
                                    {
                                    return EKeyWasNotConsumed;
                                    }

                                iPhoneNumber.Zero();
                                if (aKeyEvent.iScanCode == EStdKeyHash)
                                    {
                                    iPhoneNumber.Append( KAknHash );
                                    }
                                else
                                    {
                                    iPhoneNumber.Append( aKeyEvent.iScanCode );
                                    }
                                ProcessCommandL( KKeyLockControlAnyKey );
                                }
                            }
                        }
                    }
                }
            }
        }
    return EKeyWasConsumed;
    }


void CAknKeyLockControl::ShowLockedNote()
    {
    if ( !iLockedNoteDisplayed )
        {
        DoShowLockedNote();
        }
    }


void CAknKeyLockControl::DoShowLockedNote()
    {
    if ( !iAutolockEnabled )
        {
        iLockedNote->ShowNote(CAknNoteDialog::EShortTimeout,CAknNoteDialog::ENoTone);
        iLockedNoteDisplayed = ETrue;
        }
    }

void CAknKeyLockControl::ShowKeylockCba()
    {
    RDrawableWindow* cbaWindow = iKeyLockCba->ButtonGroup()->AsControl()->DrawableWindow();
    cbaWindow->SetFaded(EFalse, RWindowTreeNode::EFadeWindowOnly);
    cbaWindow->SetOrdinalPosition(0,1);
    cbaWindow->SetNonFading(ETrue);
    }

void CAknKeyLockControl::CaptureSystemKeys()
    {
    if (!iKeysCaptured)
        {
        RWindowGroup& groupWin=iCoeEnv->RootWin();
        iAppKey = groupWin.CaptureKeyUpAndDowns(EStdKeyApplication0, 0, 0); // Capture app key
        iPowerKey = groupWin.CaptureKeyUpAndDowns(EStdKeyDevice2, 0, 0);      // Capture power key
        iVoiceKey = groupWin.CaptureKeyUpAndDowns(EStdKeyDevice6, 0, 0);      // Capture power key
        iAppKey2 = groupWin.CaptureKey(EKeyApplication0, 0, 0); // Capture app key
        iPowerKey2 = groupWin.CaptureKey(EKeyDevice2, 0, 0);      // Capture power key
        iVoiceKey2 = groupWin.CaptureKey(EKeyDevice6, 0, 0);      // Capture power key
        iLeftSoftKey = groupWin.CaptureKey(EKeyDevice0,0,0);
        iEditKey = groupWin.CaptureKey(EKeyRightShift,0,0);
        iCameraKey = groupWin.CaptureKeyUpAndDowns(EKeyCamera,0,0);
        iVolumeUpKey = groupWin.CaptureKeyUpAndDowns(EStdKeyIncVolume,0,0);
        iVolumeDownKey = groupWin.CaptureKeyUpAndDowns(EStdKeyDecVolume,0,0);
        iCameraKey2 = groupWin.CaptureKey(EKeyDevice7,0,0);
        iVolumeUpKey2 = groupWin.CaptureKey(EKeyVolumeUp,0,0);
        iVolumeDownKey2 = groupWin.CaptureKey(EKeyVolumeDown,0,0);
        iKeysCaptured = ETrue;
        }
    }

void CAknKeyLockControl::UnCaptureSystemKeys()
    {
    if (iKeysCaptured)
        {
        RWindowGroup& groupWin=iCoeEnv->RootWin();
        groupWin.CancelCaptureKeyUpAndDowns(iAppKey);
        groupWin.CancelCaptureKeyUpAndDowns(iPowerKey);
        groupWin.CancelCaptureKeyUpAndDowns(iVoiceKey);
        groupWin.CancelCaptureKey(iAppKey2);
        groupWin.CancelCaptureKey(iPowerKey2);
        groupWin.CancelCaptureKey(iVoiceKey2);
        groupWin.CancelCaptureKey(iLeftSoftKey);
        groupWin.CancelCaptureKey(iEditKey);
        groupWin.CancelCaptureKey(iCameraKey);
        groupWin.CancelCaptureKey(iVolumeUpKey);
        groupWin.CancelCaptureKey(iVolumeDownKey);
        groupWin.CancelCaptureKey(iCameraKey2);
        groupWin.CancelCaptureKey(iVolumeUpKey2);
        groupWin.CancelCaptureKey(iVolumeDownKey2);
        iKeysCaptured = EFalse;
        }
    }

void CAknKeyLockControl::HandleEcsEvent( CAknEcsDetector* aEcsDetector, CAknEcsDetector::TState aState )
    {
    switch ( aState )
        {
        case CAknEcsDetector::ECompleteMatchThenSendKey:
            // Do nothing since note will be removed on ECallAttempted event
            break;
        case CAknEcsDetector::ECompleteMatch:
            if ( !iPhoneQueryOnScreen )
                {
                iEcsNote->SetEmergencyNumber( aEcsDetector->CurrentMatch() );
                iEcsNote->ShowNote( CAknNoteDialog::ENoTimeout,CAknNoteDialog::ENoTone );

                // Tell sysAp to switch lights on
                SendMessageToSysAp(EEikKeyLockPowerKeyPressed);
                iEcsNote->iNoteOnScreen =ETrue;
                }
            break;
        case CAknEcsDetector::EPartialMatch:
            iEcsNote->SleepNote();
            break;
        case CAknEcsDetector::ECallAttempted:
            iEcsNote->SleepNote();
            break;
        case CAknEcsDetector::EEmpty:
            iEcsNote->SleepNote();
            break;
        case CAknEcsDetector::ENoMatch:
            iEcsNote->SleepNote();
            break;
        default:
            break;
        }

    }

void CAknKeyLockControl::DoExitOfferKeylock()
    {
    iOfferLockNote->CancelNote();
    }

void CAknKeyLockControl::OfferTimerExpired()
    {
    DoExitOfferKeylock();
    }

void CAknKeyLockControl::AutolockEnabled(TBool aAutoLockOn)
    {
    iAutolockEnabled = aAutoLockOn;
    }

void CAknKeyLockControl::CallNumberL( TDesC& aNumber )
    {
    CAiwServiceHandler* serviceHandler;
    serviceHandler = CAiwServiceHandler::NewL();
    serviceHandler->AttachL(R_AKNNOTIFYPLUGIN_INTEREST);

    TAiwDialDataV1 dialData = TAiwDialDataV1();
    dialData.SetTelephoneNumber(aNumber);
    dialData.SetCallType(EAiwVoice);
    TAiwDialDataV1Pckg dialDataPckg = TAiwDialDataV1Pckg(dialData);
    CAiwGenericParamList& paramList = serviceHandler->InParamListL();
    TPtrC8 ptr;
    ptr.Set(dialDataPckg);
    TAiwVariant variant(ptr);
    TAiwGenericParam param(EGenericParamCallDialDataV1, variant);
    paramList.AppendL(param);

    serviceHandler->ExecuteServiceCmdL(KAiwCmdCall,
                                        paramList,
                                        serviceHandler->OutParamListL(),
                                        0,
                                        NULL);
    }

void CAknKeyLockControl::ShowLockPhoneQueryL()
    {
    iKeyLockCba->MakeVisible(EFalse);

    HBufC* phoneNumber = HBufC::NewLC(KPhoneNumberMaxLength);
    phoneNumber->Des() = iPhoneNumber;
    TPtr phonePtr(phoneNumber->Des());

    CAknLockedPhoneQuery* phoneQuery = CAknLockedPhoneQuery::NewL(phonePtr);
    TInt queryAction = phoneQuery->ExecuteLD(R_AVKON_LOCK_PHONE_QUERY);
    switch(queryAction)
        {
        case EAknSoftkeyCall:
            CallNumberL(phonePtr);
            break;
        default:
            break;
        }

    iPhoneQueryOnScreen = EFalse;
    CleanupStack::PopAndDestroy(phoneNumber);

    iKeyLockCba->MakeVisible(ETrue);
    }

// CAknKeyLockNotifierSubject

CAknKeyLockNotifierSubject* CAknKeyLockNotifierSubject::NewL()
    {
    CAknKeyLockNotifierSubject* self = new(ELeave)CAknKeyLockNotifierSubject();
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }


void CAknKeyLockNotifierSubject::ConstructL()
    {
    CCoeEnv* environment = CCoeEnv::Static();

    TFileName resourceFile;
    resourceFile.Append(KRESOURCEFILE);
    BaflUtils::NearestLanguageFile(environment->FsSession(),resourceFile);

    iResourceFileOffset = environment->AddResourceFileL(resourceFile);

    iObserverList = new(ELeave)CArrayPtrFlat<MAknKeyLockObserver>(KAknObserverListGranularity);
    iKeyLockControl = new(ELeave)CAknKeyLockControl(this);
    iKeyLockControl->ConstructL();
    // Make sure AppUi has a pointer to this
    STATIC_CAST(CEikServAppUi*,CEikonEnv::Static()->AppUi())->iKeyLockController = this;
    }

CAknKeyLockNotifierSubject::CAknKeyLockNotifierSubject()
:iAllowNotifications(ETrue)
    {
    }


CAknKeyLockNotifierSubject::~CAknKeyLockNotifierSubject()
    {
    if ( iResourceFileOffset )
        CCoeEnv::Static()->DeleteResourceFile(iResourceFileOffset);
    delete iKeyLockControl;
    delete iObserverList;
    }

void CAknKeyLockNotifierSubject::Release()
    {
    delete this;
    }

CAknKeyLockNotifierSubject::TNotifierInfo CAknKeyLockNotifierSubject::RegisterL()
    {
    iInfo.iUid=KAknKeyLockNotifierUid;
    iInfo.iChannel=EAknNotifierChannelKeyLock;
    iInfo.iPriority=ENotifierPriorityHigh;
    return iInfo;
    }

CAknKeyLockNotifierSubject::TNotifierInfo CAknKeyLockNotifierSubject::Info() const
    {
    return iInfo;
    }

TPtrC8 CAknKeyLockNotifierSubject::StartL(const TDesC8& aBuffer)
    {
    SAknNotifierPackage<SAknKeyLockNotifierParams>* params
        = ( SAknNotifierPackage<SAknKeyLockNotifierParams>*)aBuffer.Ptr();

    if ( aBuffer.Length() < 0 || (TUint)aBuffer.Length() < sizeof(SAknNotifierPackage<SAknKeyLockNotifierParams>)
        || params->iSignature != KAKNNOTIFIERSIGNATURE )
        {
        User::Leave( KErrArgument );
        }

    switch (params->iParamData.iReason)
        {
        case ELockEnabled:
        case ELockDisabled:
        case EAllowNotifications:
        case EStopNotifications:
        case EOfferKeylock:
        case ECancelAllNotifications:
        case EEnableAutoLockEmulation:
        case EDisableWithoutNote:
        case EEnableWithoutNote:
            break;
        case EInquire:
            {
            iRetPckg().iEnabled = IsKeyLockEnabled();
            }
        default:
            break;
        }
    return iRetPckg;
    }

void CAknKeyLockNotifierSubject::StartL(const TDesC8& aBuffer, TInt /*aReplySlot*/, const RMessagePtr2& aMessage)
    {
    SAknNotifierPackage<SAknKeyLockNotifierParams>* params
        = ( SAknNotifierPackage<SAknKeyLockNotifierParams>*)aBuffer.Ptr();

    if ( aBuffer.Length() < 0 || (TUint)aBuffer.Length() < sizeof(SAknNotifierPackage<SAknKeyLockNotifierParams>)
        || params->iSignature != KAKNNOTIFIERSIGNATURE )
        {
        User::Leave( KErrArgument );
        }

    switch (params->iParamData.iReason)
        {
        case ELockEnabled:
            DoEnableKeyLock();
            break;
        case ELockDisabled:
            DoDisableKeyLock();
            break;
        case EAllowNotifications:
            DoAllowNotifications();
            break;
        case EStopNotifications:
            DoStopNotifications();
            break;
        case EOfferKeylock:
            DoOfferKeyLock();
            break;
        case ECancelAllNotifications:
            DoCancelAllNotificatons();
            break;
        case EEnableAutoLockEmulation:
            NotifyStatusChange(EShowSoftNotifications);
            LockKeys(ETrue);
            break;
        case EDisableWithoutNote:
            UnlockKeys();
            break;
        case EEnableWithoutNote:
            if (!IsKeyLockEnabled())
                {
                iKeyLockControl->EnableKeylock(EFalse);
                }
            break;
        case ECommandFSWToHideApplication:
            {
            TInt uid(0);
            TBool disable(EFalse);
            RDesReadStream readStream(aBuffer);
            readStream.ReadInt32L(); // signature
            readStream.ReadInt32L(); // op
            uid = readStream.ReadInt32L(); // uid
            disable = readStream.ReadInt32L(); // enable / disable
            STATIC_CAST(CEikServAppUi*,CEikonEnv::Static()->AppUi())->HideApplicationFromFswL(uid,disable);
            }
            break;
        default:
            break;
        };

    aMessage.Complete(KErrNone);
    }

void CAknKeyLockNotifierSubject::Cancel()
    {
    }

TPtrC8 CAknKeyLockNotifierSubject::UpdateL(const TDesC8& aBuffer)
    {
    return TPtrC8(aBuffer);
    }



TBool CAknKeyLockNotifierSubject::IsKeyLockEnabled()
    {
    return iKeyLockControl->iKeyLockEnabled;
    }

TBool CAknKeyLockNotifierSubject::AllowNotifications()
    {
    return iAllowNotifications;
    }



void CAknKeyLockNotifierSubject::UnlockKeys()
    {
    if (IsKeyLockEnabled())
        {
        iKeyLockControl->DisableKeylock();
        }
    }

void CAknKeyLockNotifierSubject::LockKeys(TBool aAutoLockOn)
    {

    // Well have to disable keylock if we are changing autolock status
    if ( iKeyLockControl->iKeyLockEnabled &&
        aAutoLockOn != iKeyLockControl->iAutolockEnabled )
        {
        iKeyLockControl->DisableKeylock();
        }

    if (!IsKeyLockEnabled())
        {
        iKeyLockControl->AutolockEnabled(aAutoLockOn);

        iKeyLockControl->EnableKeylock();
        }
    }


void CAknKeyLockNotifierSubject::AddObserverL(MAknKeyLockObserver* aObserver)
    {
#if defined(_DEBUG)
    TInt count = iObserverList->Count();
    for (TInt ii=0; ii<count; ii++)
        {
        if ( ((*iObserverList)[ii]) == aObserver)
            {
            Panic(EAknPanicKeyLockObserverAlreadyExists);
            }
        }
#endif
    iObserverList->AppendL(aObserver);

    // Make sure that the observer isn't obscuring the keylock CBA
    ShowKeylockCba();
    }


void CAknKeyLockNotifierSubject::RemoveObserver(MAknKeyLockObserver* aObserver)
    {
    TInt count = iObserverList->Count();
    for (TInt ii=0; ii<count; ii++)
        {
        if ( ((*iObserverList)[ii]) == aObserver)
            {
            iObserverList->Delete(ii);
            return;
            }
        }
#if defined(_DEBUG)
    Panic(EAknPanicKeyLockObserverNotFound);
#endif
    }


void CAknKeyLockNotifierSubject::ShowKeylockCba()
    {
    if (iKeyLockControl->iKeyLockEnabled)
        {
        iKeyLockControl->ShowKeylockCba();
        }
    }

void CAknKeyLockNotifierSubject::NotifyStatusChange(TKeyLockStatus aStatus)
    {
    TInt count = iObserverList->Count();
    for (TInt ii=count-1; ii>=0; ii--)
        {
        ((*iObserverList)[ii])->KeyLockStatusChange(aStatus);
        }
    }

void CAknKeyLockNotifierSubject::DoAllowNotifications()
    {
    TBool lastvalue = iAllowNotifications;
    iAllowNotifications = ETrue;
    NotifyStatusChange(EKeyLockAllowNotifications);
    if (!lastvalue)
        {
        CEikonEnv* env = CEikonEnv::Static();
        // To prevent this being called more than once
        env->SetAutoForwarding(ETrue);
        while (iActiveWindowCount)
            {
            env->BringForwards(ETrue);
            iActiveWindowCount--;
            }
        env->RootWin().SetOrdinalPosition(0, ECoeWinPriorityAlwaysAtFront);
        env->BringForwards(ETrue);
        env->BringForwards(EFalse);

        // Enable FSW
        STATIC_CAST(CEikServAppUi*,env->AppUi())->SuppressAppSwitching(EFalse);
        }
    }

void CAknKeyLockNotifierSubject::DoStopNotifications()
    {
    TBool lastvalue = iAllowNotifications;
    iAllowNotifications = EFalse;
    NotifyStatusChange(EKeyLockStopNotifications);
    if (lastvalue)
        {
        // To prevent this being called more than once
        // Count number of times BringForwards is needed to make EikSrvUi go to background
        iActiveWindowCount = 0;
        CEikonEnv* env = CEikonEnv::Static();
        TInt windowId = env->RootWin().Identifier();
        while (env->WsSession().GetWindowGroupOrdinalPriority(windowId) > 0)
            {
            iActiveWindowCount++;
            env->BringForwards(EFalse);
            }
        env->SetAutoForwarding(EFalse);
        STATIC_CAST(CEikServAppUi*,env->AppUi())->SuppressAppSwitching(ETrue);
        }
    }

void CAknKeyLockNotifierSubject::DoCancelAllNotificatons()
    {
    // Used when end key is pressed, to allow phone app to cancel all
    // notifications. Global notes / soft notifications that would
    // not normally be shown (out of priority) are not cancelled

    if ( IsKeyLockEnabled() )
        {
        return;
        }

    NotifyStatusChange(EKeyLockCancelNotification);

    // Send cancel key event to all other notifications, and hope they cancel

    TRAPD(err, AknDialogShutter::ShutDialogsL(*CEikonEnv::Static()));
    // Ignore error message - there's nothing more we can do
    }



void CAknKeyLockNotifierSubject::DoEnableKeyLock()
    {
    if (!IsKeyLockEnabled())
        {
        iKeyLockControl->EnableKeylock();
        }
    }

void CAknKeyLockNotifierSubject::DoDisableKeyLock()
    {
    if (IsKeyLockEnabled())
        {
        iKeyLockControl->DisableKeylock();
        // Attempt to display KeyActive note
        iKeyLockControl->DisplayKeyActiveNote();
        }
    else if (iKeyLockControl->iOfferLockEnabled)
        {
        // Remove the offer key lock CBA
        iKeyLockControl->OfferTimerExpired();
        }
    }


void CAknKeyLockNotifierSubject::DoOfferKeyLock()
    {
    if (!IsKeyLockEnabled())
        {
        NotifyStatusChange(EKeyLockOffered);
        iKeyLockControl->OfferKeylock();
        }
    }
