localconnectivityservice/headset/src/headset.cpp
branchRCL_3
changeset 40 52a167391590
child 44 7a45d2ea2f56
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/localconnectivityservice/headset/src/headset.cpp	Wed Sep 01 12:20:40 2010 +0100
@@ -0,0 +1,1206 @@
+/*
+* Copyright (c) 2004-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:  Generic hid implementation
+ *
+*/
+
+
+#include <etel3rdparty.h>
+#include <e32std.h>
+#include <e32svr.h>
+#include <coedef.h>
+#include <eiksvdef.h>
+#include <apgcli.h>
+#include <apgtask.h>
+#include <e32property.h>
+#include <alarmuidomainpskeys.h>
+
+#include <mpxplaybackmessage.h>
+#include <mpxmessagegeneraldefs.h>
+#include <mpxplaybackmessagedefs.h>
+
+#include "hidremconbearerinternalpskeys.h"
+#include "hidremconbearerscancodes.h"
+#include "headset.h"
+#include "finder.h"
+
+#include "debug.h"
+
+const TInt KHidUndefinedKeyCode = 0;
+const TInt KHidNotSetKeyValue = 0;
+const TInt KDoubleClickTimeout = 900000; // 0,9 seconds
+const TInt KDoubleClickTimeoutRing = 500000; // 0,5 seconds
+const TInt KScanClickTimeout = 500000; // 0,5 seconds
+const TInt KLongClickTimeout = 3000000; // 3 seconds
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// CHidHeadsetDriver()
+// ---------------------------------------------------------------------------
+//
+CHidHeadsetDriver::CHidHeadsetDriver( MDriverAccess* aGenericHid ) :
+    iGenericHid( aGenericHid ), iFieldList(), iDriverState( EUninitialised ),
+            iConnectionId( 0 ), iSupportedFieldCount( 0 ), iForwardStatus(
+                    EScanNotPressed ), iBackwardStatus( EScanNotPressed )
+    {
+    TRACE_FUNC_ENTRY_THIS
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// NewLC
+// ---------------------------------------------------------------------------
+//
+CHidHeadsetDriver* CHidHeadsetDriver::NewLC( MDriverAccess* aGenericHid )
+    {
+    TRACE_INFO((_L("[HID]\tCHidHeadsetDriver::NewLC(0x%08x)"), aGenericHid));
+    CHidHeadsetDriver* self = new ( ELeave ) CHidHeadsetDriver( aGenericHid );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// NewL
+// ---------------------------------------------------------------------------
+//
+CHidHeadsetDriver* CHidHeadsetDriver::NewL( MDriverAccess* aGenericHid )
+    {
+    CHidHeadsetDriver* self = CHidHeadsetDriver::NewLC( aGenericHid );
+    CleanupStack::Pop();
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// ConstructL()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::ConstructL()
+    {
+    TRACE_FUNC_THIS
+    iTelephony = CTelephony::NewL();
+    User::LeaveIfError( iAlarmServerSession.Connect() );
+    iMusicPlayer = MMPXPlaybackUtility::UtilityL( KPbModeActivePlayer );
+    iMusicPlayer->AddObserverL( *this );
+    }
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CHidHeadsetDriver::~CHidHeadsetDriver()
+    {
+    TRACE_FUNC_THIS
+    iAlarmServerSession.Close();
+    delete iTelephony;
+    iFieldList.Reset();
+    iFieldList.Close();
+    delete iDoubleClicktimer;
+    if ( iMusicPlayer )
+        {
+        iMusicPlayer->Close();
+        }
+    delete iScanPreviousTimer;
+    delete iScanNextTimer;
+    delete iLongClicktimer;
+    }
+
+// ---------------------------------------------------------------------------
+// From class CHidDriver
+// StartL()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::StartL( TInt /*aConnectionId*/)
+    {
+    TRACE_FUNC
+    // Ready to process headset events:
+    iDriverState = EInitialised;
+    }
+
+// ---------------------------------------------------------------------------
+// From class CHidDriver
+// InitialiseL()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::InitialiseL( TInt aConnectionId )
+    {
+    TRACE_FUNC
+    TRACE_INFO((_L("[HID]\tCHidHeadsetDriver::InitialiseL(%d)"),
+                        aConnectionId));
+    // Store the connection ID:
+    iConnectionId = aConnectionId;
+    }
+
+// ---------------------------------------------------------------------------
+// From class CHidDriver
+// Stop()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::Stop()
+    {
+    TRACE_FUNC
+    iDriverState = EDisabled;
+    }
+
+// ---------------------------------------------------------------------------
+// From class CHidDriver
+// DataIn()
+// ---------------------------------------------------------------------------
+//
+TInt CHidHeadsetDriver::DataIn( CHidTransport::THidChannelType aChannel,
+        const TDesC8& aPayload )
+    {
+    TInt retVal = KErrNone;
+    switch ( aChannel )
+        {
+        case CHidTransport::EHidChannelInt:
+            if ( EInitialised == iDriverState )
+                {
+                retVal = InterruptData( aPayload );
+                }
+            break;
+
+        case CHidTransport::EHidChannelCtrl:
+            retVal = KErrNotSupported;
+            break;
+
+        default:
+            retVal = KErrNotSupported;
+            break;
+        }
+    return retVal;
+    }
+
+// ---------------------------------------------------------------------------
+// From class CHidDriver
+// CommandResult()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::CommandResult( TInt /*aCmdAck*/)
+    {
+    // No implementation as we don't issue any requests to be acknowledged
+    }
+
+// ---------------------------------------------------------------------------
+// From class CHidDriver
+// Disconnected()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::Disconnected( TInt aReason )
+    {
+    TRACE_INFO((_L("[HID]\tCHidHeadsetDriver::Disconnected(%d)"), aReason));
+    aReason = aReason;
+    Stop();
+    }
+
+// ---------------------------------------------------------------------------
+// From class CHidDriver
+// SetInputHandlingReg()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::SetInputHandlingReg(
+        CHidInputDataHandlingReg* aHandlingReg )
+    {
+    iInputHandlingReg = aHandlingReg;
+    }
+
+// ---------------------------------------------------------------------------
+// From class CHidDriver
+// InterruptData()
+// ---------------------------------------------------------------------------
+//
+TInt CHidHeadsetDriver::InterruptData( const TDesC8& aPayload )
+    {
+    // If the report has a report ID, it is in the first byte.
+    // If not, this value is ignored (see CField::IsInReport()).
+    //
+    TInt retVal = KErrNone;
+    TInt ret = KErrNotSupported;
+    TInt firstByte = aPayload[0];
+
+    TRACE_INFO((_L("[HID]\tCHidHeadsetDriver::InterruptData(), report \
+            0x%x (%d), length %d"),firstByte, firstByte, aPayload.Length()));
+
+    if ( iFieldList.Count() == 0 )
+        {
+        retVal = KErrNotSupported;
+        }
+    for ( TInt i = 0; i < iFieldList.Count(); i++ )
+        {
+        if ( iFieldList[i]->IsInReport( firstByte ) )
+            {
+            ret = HandleReport( aPayload, iFieldList[i] );
+            if ( ret == KErrNone )
+                {
+                retVal = KErrNone;
+                }
+            }
+        else
+            {
+            retVal = KErrNotSupported;
+            }
+        }
+    return retVal;
+    }
+
+// ---------------------------------------------------------------------------
+// HandleReport()
+// ---------------------------------------------------------------------------
+//
+TInt CHidHeadsetDriver::HandleReport( const TDesC8& aReport,
+        const CField* aField )
+    {
+    TRACE_FUNC_ENTRY
+    TReportTranslator report( aReport, aField );
+    TInt retVal = KErrNotSupported;
+
+    // release if key if it pressed and relased
+    ReleasePressedKeys( report );
+
+    if ( HandleTelephonyUsage( report ) == KErrNone )
+        {
+        retVal = KErrNone;
+        }
+
+    if ( HandleControlUsage( report ) == KErrNone )
+        {
+        retVal = KErrNone;
+        }
+
+    if ( HandleVolumeUsage( report ) == KErrNone )
+        {
+        retVal = KErrNone;
+        }
+    TRACE_FUNC_EXIT
+    return retVal;
+    }
+
+// ---------------------------------------------------------------------------
+// HandleTelephonyUsage()
+// ---------------------------------------------------------------------------
+//
+TInt CHidHeadsetDriver::HandleTelephonyUsage( TReportTranslator& aReport )
+    {
+    TRACE_FUNC_ENTRY
+    TInt retVal = KErrNotSupported;
+    TInt hookSwitch = 0;
+    TInt mute = 0;
+    TInt poc = 0;
+
+    // P&S key variables
+    TUint key = KHidUndefinedKeyCode;
+    TInt value = KHidNotSetKeyValue;
+
+    if ( aReport.GetValue( mute, ETelephonyUsagePhoneMute ) == KErrNone
+            && mute == 1 )
+        {
+        TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::HandleReport(): Send mute \
+                command"));
+        if ( iInputHandlingReg->AllowedToHandleEvent( EUsagePageTelephony,
+                ETelephonyUsagePhoneMute ) )
+            {
+            key = KHidMuteKeyEvent;
+            value = KPSMuteClicked;
+            iInputHandlingReg->AddHandledEvent( EUsagePageTelephony,
+                    ETelephonyUsagePhoneMute );
+            }
+        }
+    else if ( aReport.GetValue( hookSwitch, ETelephonyUsageHookSwitch )
+            == KErrNone && hookSwitch == 1 )
+        {
+        TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::HandleReport(): Send hook \
+                switch command (disabled)"));
+        if ( iInputHandlingReg->AllowedToHandleEvent( EUsagePageTelephony,
+                ETelephonyUsageHookSwitch ) )
+            {
+            HookKeyPres( ETrue );
+            iInputHandlingReg->AddHandledEvent( EUsagePageTelephony,
+                    ETelephonyUsageHookSwitch );
+            }
+        }
+    else if ( aReport.GetValue( poc, ETelephonyUsagePoC ) == KErrNone && poc
+            == 1 )
+        {
+        TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::HandleReport(): Send PoC \
+                command (disabled)"));
+        if ( iInputHandlingReg->AllowedToHandleEvent( EUsagePageTelephony,
+                ETelephonyUsagePoC ) )
+            {
+            key = KHidMuteKeyEvent;
+            value = KPSMuteClicked;
+            iInputHandlingReg->AddHandledEvent( EUsagePageTelephony,
+                    ETelephonyUsagePoC );
+            }
+        }
+    if ( key != KHidUndefinedKeyCode && value != KHidNotSetKeyValue )
+        {
+        TInt err = RProperty::Set( KPSUidHidEventNotifier, key, value );
+        retVal = KErrNone;
+        }
+
+    TRACE_FUNC_EXIT
+    return retVal;
+    }
+
+// ---------------------------------------------------------------------------
+// HandleTelephonyUsage()
+// ---------------------------------------------------------------------------
+//
+TInt CHidHeadsetDriver::HandleControlUsage( TReportTranslator& aReport )
+    {
+    TRACE_FUNC_ENTRY
+    TInt retVal = KErrNotSupported;
+    TInt playPause = 0;
+    TInt scanNext = 0;
+    TInt scanPrev = 0;
+    TInt stop = 0;
+
+    // P&S key variables
+    TUint key = KHidUndefinedKeyCode;
+    TInt value = KHidNotSetKeyValue;
+
+    if ( aReport.GetValue( playPause, EConsumerUsagePlayPause ) == KErrNone
+            && playPause )
+        {
+        if ( iInputHandlingReg->AllowedToHandleEvent( EUsagePageConsumer,
+                EConsumerUsagePlayPause ) )
+            {
+            TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::HandleReport(): Send \
+                    play/pause command (currently only play)"));
+            key = KHidControlKeyEvent;
+            value = EPlayClicked;
+            iInputHandlingReg->AddHandledEvent( EUsagePageConsumer,
+                    EConsumerUsagePlayPause );
+            }
+        }
+    else if ( aReport.GetValue( scanNext, EConsumerUsageScanNext )
+            == KErrNone && scanNext )
+        {
+        if ( iInputHandlingReg->AllowedToHandleEvent( EUsagePageConsumer,
+                EConsumerUsageScanNext ) )
+            {
+            TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::HandleReport(): Send \
+                    scan next command"));
+            TRAP_IGNORE( HandleScanNextPressL() );
+            iInputHandlingReg->AddHandledEvent( EUsagePageConsumer,
+                    EConsumerUsageScanNext );
+            }
+        }
+    else if ( aReport.GetValue( scanPrev, EConsumerUsageScanPrev )
+            == KErrNone && scanPrev )
+        {
+        if ( iInputHandlingReg->AllowedToHandleEvent( EUsagePageConsumer,
+                EConsumerUsageScanPrev ) )
+            {
+            TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::HandleReport(): Scan \
+                    prev command"));
+            TRAP_IGNORE( HandleScanPrevPressL());
+            iInputHandlingReg->AddHandledEvent( EUsagePageConsumer,
+                    EConsumerUsageScanPrev );
+            }
+        }
+    else if ( aReport.GetValue( stop, EConsumerUsageStop ) == KErrNone
+            && stop )
+        {
+        if ( iInputHandlingReg->AllowedToHandleEvent( EUsagePageConsumer,
+                EConsumerUsageStop ) )
+            {
+            TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::HandleReport(): Send \
+                    stop command"));
+            key = KHidControlKeyEvent;
+            value = EStopClicked;
+            iInputHandlingReg->AddHandledEvent( EUsagePageConsumer,
+                    EConsumerUsageScanPrev );
+            }
+        }
+    if ( key != KHidUndefinedKeyCode && value != KHidNotSetKeyValue )
+        {
+        TInt err = RProperty::Set( KPSUidHidEventNotifier, key, value );
+        retVal = KErrNone;
+        }
+
+    TRACE_FUNC_EXIT
+    return retVal;
+    }
+
+// ---------------------------------------------------------------------------
+// HandleVolumeUsage()
+// ---------------------------------------------------------------------------
+//
+TInt CHidHeadsetDriver::HandleVolumeUsage( TReportTranslator& aReport )
+    {
+    TRACE_FUNC_ENTRY
+    TInt retVal = KErrNotSupported;
+
+    TInt volUp = 0;
+    TInt volDown = 0;
+    TInt speakermute = 0;
+
+    // P&S key variables
+    TUint key = KHidUndefinedKeyCode;
+    TInt value = KHidNotSetKeyValue;
+
+    if ( aReport.GetValue( volUp, EConsumerUsageVolumeInc ) == KErrNone
+            && volUp )
+        {
+        if ( iInputHandlingReg->AllowedToHandleEvent( EUsagePageConsumer,
+                EConsumerUsageVolumeInc ) )
+            {
+            TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::HandleReport(): \
+                    Send volume up command"));
+            key = KHidAccessoryVolumeEvent;
+            iVolumeUpPressed = ETrue;
+            value = KPSVolumeUpPressed;
+            iInputHandlingReg->AddHandledEvent( EUsagePageConsumer,
+                    EConsumerUsageScanPrev );
+            }
+        }
+    else if ( aReport.GetValue( volDown, EConsumerUsageVolumeDec )
+            == KErrNone && volDown )
+        {
+        if ( iInputHandlingReg->AllowedToHandleEvent( EUsagePageConsumer,
+                EConsumerUsageVolumeDec ) )
+            {
+            TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::HandleReport(): Send \
+                    volume down command"));
+            key = KHidAccessoryVolumeEvent;
+            iVolumeDownPressed = ETrue;
+            value = KPSVolumeDownPressed;
+            iInputHandlingReg->AddHandledEvent( EUsagePageConsumer,
+                    EConsumerUsageVolumeDec );
+            }
+        }
+    else if ( ( aReport.GetValue( speakermute, EConsumerUsageMute )
+            == KErrNone && speakermute == 1 ) )
+        {
+        if ( iInputHandlingReg->AllowedToHandleEvent( EUsagePageConsumer,
+                EConsumerUsageMute ) )
+            {
+            TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::HandleReport(): Send \
+                    mute command"));
+            key = KHidMuteKeyEvent;
+            value = KPSMuteClicked;
+            iInputHandlingReg->AddHandledEvent( EUsagePageConsumer,
+                    EConsumerUsageMute );
+            }
+        }
+
+    if ( key != KHidUndefinedKeyCode && value != KHidNotSetKeyValue )
+        {
+        TInt err = RProperty::Set( KPSUidHidEventNotifier, key, value );
+        retVal = KErrNone;
+        }
+
+    TRACE_FUNC_EXIT
+    return retVal;
+    }
+
+// ---------------------------------------------------------------------------
+// HandleScanNextPressL()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::HandleScanNextPressL()
+    {
+    TRACE_FUNC_ENTRY
+    iForwardStatus = EScanPressed;
+
+    delete iScanNextTimer;
+    iScanNextTimer = NULL;
+
+    /**
+     * Scan key has two different behaviour if you are short click buttun or long 
+     * click button. In short press next track command is sent and whit long press
+     * is sending seek forward command. iScanNextTimer is used to detect if click
+     * is long click or short click.
+     */
+
+    iScanNextTimer = CKeyPressTimer::NewL( this, TTimeIntervalMicroSeconds32(
+            KScanClickTimeout ), EScanNextPressTimer );
+
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// HandleScanNextPressL()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::HandleScanPrevPressL()
+    {
+    TRACE_FUNC_ENTRY
+    iBackwardStatus = EScanPressed;
+
+    delete iScanPreviousTimer;
+    iScanPreviousTimer = NULL;
+
+    /**
+     * Scan key has two different behaviour if you are short click buttun or 
+     * long click button. In short press previous track command is sent and 
+     * whit long press is sending seek forward command. iScanPreviousTimer 
+     * is used to detect if click is long click or short click.
+     */
+    iScanPreviousTimer = CKeyPressTimer::NewL( this,
+            TTimeIntervalMicroSeconds32( KScanClickTimeout ),
+            EScanPrevPressTimer );
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// ReleasePressedVolumeKeys
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::ReleasePressedVolumeKeys(
+        TReportTranslator& aReportTranslator )
+    {
+    TInt volUp = 0;
+    TInt volDown = 0;
+    TUint key = KHidUndefinedKeyCode;
+    TInt value = KHidNotSetKeyValue;
+
+    if ( iVolumeUpPressed )
+        {
+        if ( aReportTranslator.GetValue( volUp, EConsumerUsageVolumeInc )
+                == KErrNone && volDown == 0 )
+            {
+            TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::ReleasepressedKeys(): \
+                    Volume up released"));
+            key = KHidAccessoryVolumeEvent;
+            iVolumeUpPressed = EFalse;
+            value = KPSVolumeUpReleased;
+            }
+        }
+    else if ( iVolumeDownPressed )
+        {
+        if ( aReportTranslator.GetValue( volDown, EConsumerUsageVolumeDec )
+                == KErrNone && volDown == 0 )
+            {
+            TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::ReleasepressedKeys(): \
+                    Volume downkey realeased"));
+            key = KHidAccessoryVolumeEvent;
+            iVolumeDownPressed = EFalse;
+            value = KPSVolumeDownReleased;
+            }
+        }
+    if ( key != KHidUndefinedKeyCode && value != KHidNotSetKeyValue )
+        {
+        TInt err = RProperty::Set( KPSUidHidEventNotifier, key, value );
+
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// ReleasePressedScanKeys()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::ReleasePressedScanKeys(
+        TReportTranslator& aReportTranslator )
+    {
+    TInt scanNext = 0;
+    TInt scanPrev = 0;
+    TUint key = KHidUndefinedKeyCode;
+    TInt value = KHidNotSetKeyValue;
+
+    if ( iForwardStatus != EScanNotPressed )
+        {
+        if ( aReportTranslator.GetValue( scanNext, EConsumerUsageScanNext )
+                == KErrNone && scanNext == 0 )
+            {
+            TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::HandleReport(): Scan \
+                    next command released"));
+            HandleScanNextRelease( key, value );
+            }
+        }
+    else if ( iBackwardStatus != EScanNotPressed )
+        {
+        if ( aReportTranslator.GetValue( scanPrev, EConsumerUsageScanPrev )
+                == KErrNone && scanPrev == 0 )
+            {
+            TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::HandleReport(): Scan \
+                    prev command released"));
+            HandleScanPreviousRelease( key, value );
+            }
+        }
+    if ( key != KHidUndefinedKeyCode && value != KHidNotSetKeyValue )
+        {
+        TInt err = RProperty::Set( KPSUidHidEventNotifier, key, value );
+        }
+    }
+// ---------------------------------------------------------------------------
+// ReleasePressedKeys()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::ReleasePressedKeys(
+        TReportTranslator& aReportTranslator )
+    {
+    TRACE_FUNC_ENTRY
+
+    TInt hookSwitch = 0;
+    /*
+     * Check hook key release here, because hook key long press
+     * is handled different way.
+     */
+    if ( iOnHookPressed || iOffHookPressed || iNoneHookPressed )
+        {
+        if ( aReportTranslator.GetValue( hookSwitch,
+                ETelephonyUsageHookSwitch ) == KErrNone && hookSwitch == 0 )
+            {
+            ReleaseHookKey();
+            }
+        }
+    ReleasePressedVolumeKeys( aReportTranslator );
+
+    ReleasePressedScanKeys( aReportTranslator );
+
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// HandleScanNextRelease()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::HandleScanNextRelease( TUint& aKeyCode, TInt& aValue )
+    {
+    TRACE_FUNC_ENTRY
+    aKeyCode = KHidControlKeyEvent;
+    if ( iForwardStatus == EScanPressed )
+        {
+        aValue = EForwardClicked;
+        }
+    else //long press
+        {
+        aValue = EFastForwardReleased;
+        }
+    iForwardStatus = EScanNotPressed;
+
+    delete iScanNextTimer;
+    iScanNextTimer = NULL;
+
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// HandleScanPreviousRelease()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::HandleScanPreviousRelease( TUint& aKeyCode,
+        TInt& aValue )
+    {
+    TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::HandleReport(): Scan prev \
+            command released"));
+    aKeyCode = KHidControlKeyEvent;
+    if ( iBackwardStatus == EScanPressed )
+        {
+        aValue = EBackwardClicked;
+        }
+    else //long press
+        {
+        aValue = ERewindReleased;
+        }
+    iBackwardStatus = EScanNotPressed;
+
+    delete iScanPreviousTimer;
+    iScanPreviousTimer = NULL;
+
+    TRACE_FUNC_EXIT
+    }
+// ---------------------------------------------------------------------------
+// HookKeyPres()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::HookKeyPres( TBool aStatus )
+    {
+    TRACE_FUNC_ENTRY
+
+    THookHandling hookStatus = HookStatus();
+    if ( !iAlarmStatus )
+        {
+        iAlarmStatus = AlarmStatus();
+        }
+
+    iPlayingStatus = MusicPlayingStatus();
+
+    if ( aStatus )
+        {
+        switch ( hookStatus )
+            {
+            case EOnHook:
+                if ( !iIncomingCallStatus )
+                    {
+                    // For the first click, trigger the timer 
+                    // single click is handled in ExpiredDoubleClickTimer
+                    if ( iDoubleClicktimer )
+                        {
+                        delete iDoubleClicktimer;
+                        iDoubleClicktimer = NULL;
+                        }
+                    TRAP_IGNORE( iDoubleClicktimer = CKeyPressTimer::NewL( this,
+                        TTimeIntervalMicroSeconds32( KDoubleClickTimeoutRing ),
+                        EDoubleClickTimer ) );
+                    if ( iDoubleClicktimer )
+                        {
+                        iIncomingCallStatus = ETrue;
+                        }
+                    else // If fail to create timer, handle as single click, 
+                    // for double click case, the next click will hang off
+                        {
+                        iIncomingCallStatus = EFalse;
+                        iOnHookPressed = ETrue;
+                        }
+                    break; // switch
+                    }
+                else
+                    {
+                    iIncomingCallStatus = EFalse;
+                    if ( iDoubleClicktimer )
+                        {
+                        delete iDoubleClicktimer;
+                        iDoubleClicktimer = NULL;
+                        }
+                    // This is the double click case, handle as EOffHook
+                    }
+                // No break here
+            case EOffHook:
+                TRACE_INFO(_L("[HID]\tCHidHeadsetDriver Hook Off Pressed"));
+                iOffHookPressed = ETrue;
+                break;
+            case ENoHook:
+                TRACE_INFO(_L("[HID]\tCHidHeadsetDriver Hook None Pressed")); 
+                TRAP_IGNORE( HandleNoneHookPressL() );                
+                break;
+            default:
+                TRACE_INFO(_L("CHidHeadsetDriver::HookKeyPres : Not \
+                        supported"));                
+            }
+        }
+    else
+        {
+        ReleaseHookKey();
+        }
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// ReleaseHookKey()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::ReleaseHookKey()
+    {
+    TRACE_FUNC_ENTRY
+
+    if ( iOnHookPressed )
+        {
+        TRACE_INFO(_L("[HID]\tCHidHeadsetDriver Hook On released"));
+        iOnHookPressed = EFalse;
+        // Incoming call
+        RProperty::Set( KPSUidHidEventNotifier, KHidHookKeyEvent,
+                KPSAnsweClicked );
+        }
+    if ( iOffHookPressed )
+        {
+        TRACE_INFO(_L("[HID]\tCHidHeadsetDriver Hook Off released"));
+        iOffHookPressed = EFalse;
+        // Disconnect connected call
+        RProperty::Set( KPSUidHidEventNotifier, KHidHookKeyEvent,
+                KPSHangUpClicked );
+        }
+    if ( iNoneHookPressed && !iAlarmStatus )
+        {
+        TRAP_IGNORE( HandleIdleHookReleaseL() );
+        }
+    if ( iNoneHookPressed && iAlarmStatus )
+        {
+        TRAP_IGNORE( HandleAlarmHookReleaseL() );
+        }
+    if ( iLongClicktimer )
+        {
+        iLongPress = EFalse;
+        }
+    delete iLongClicktimer;
+    iLongClicktimer = NULL;
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// HandleNoneHook()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::HandleNoneHookPressL()
+    {
+    TRACE_FUNC_ENTRY
+    /**  Start long press timer is alarm is ongoing, or phone
+     *   is not alarming and thre are no hook key press whitout
+     *   release
+     */
+    if ( iAlarmStatus || ( !iNoneHookPressed && !iAlarmStatus ) )
+        {
+        iNoneHookPressed = ETrue;
+        iLongPress = EFalse;
+
+        delete iLongClicktimer;
+        iLongClicktimer = NULL;
+
+        iLongClicktimer = CKeyPressTimer::NewL( this,
+                TTimeIntervalMicroSeconds32( KLongClickTimeout ),
+                ELongPressTimer );
+        }
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// HandleAlarmHookReleaseL()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::HandleAlarmHookReleaseL()
+    {
+    TRACE_FUNC_ENTRY
+    TRACE_INFO(_L("[HID]\tCHidHeadsetDriver Hook None released"));
+    /**
+     * Hook key is released when there is active alarm. Start double
+     * click timer for monitoring double click.
+     */
+    if ( !iDoubleClicktimer && !iLongPress )
+        {
+        iDoubleClicktimer = CKeyPressTimer::NewL( this,
+                TTimeIntervalMicroSeconds32( KDoubleClickTimeout ),
+                EDoubleClickTimer );
+        }
+    /**
+     * Stot alar when hook key is pressed long time during alarm.
+     */
+    else if ( iLongPress )
+        {
+        TRACE_INFO(_L("[HID]\tCHidHeadsetDriver Stop alarm"));
+        RProperty::Set( KPSUidAlarmExtCntl, KAlarmStopKey, 
+                EAlarmUIStopAlarm );
+        iAlarmStatus = EFalse;
+        iLongPress = EFalse;
+        }
+    /**
+     * Double click timer exsist and is it not long press, so 
+     * this is double click release. Then snooze alarm.
+     */
+    else if ( !iLongPress )
+        {
+        delete iDoubleClicktimer;
+        iDoubleClicktimer = NULL;
+        iAlarmStatus = EFalse;
+        TRACE_INFO(_L("[HID]\tCHidHeadsetDriver Snooze"));
+        RProperty::Set( KPSUidAlarmExtCntl, KAlarmSnoozeKey,
+                EAlarmUISnoozeAlarm );
+        }
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// HandleIdleHookReleaseL
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::HandleIdleHookReleaseL()
+    {
+    TRACE_FUNC_ENTRY
+    TRACE_INFO(_L("[HID]\tCHidHeadsetDriver Hook None released"));
+    iNoneHookPressed = EFalse;
+    /**
+     * Hook key is released when there is music playing ongoing. Start double
+     * click timer for monitoring double click.
+     */
+    if ( !iDoubleClicktimer && !iLongPress )
+        {
+        iDoubleClicktimer = CKeyPressTimer::NewL( this,
+                TTimeIntervalMicroSeconds32( KDoubleClickTimeout ),
+                EDoubleClickTimer );
+        }
+    /**
+     * Hook key is released when there is not music playing ongoing. 
+     * Because double click timer is active this is second release in
+     * short beriod and redial needs to be issued.
+     */
+    else if ( !iLongPress && !iPlayingStatus )
+        {
+        delete iDoubleClicktimer;
+        iDoubleClicktimer = NULL;
+        TRACE_INFO(_L("[HID]\tCHidHeadsetDriver Redial"));
+        RProperty::Set( KPSUidHidEventNotifier, KHidHookKeyEvent, 
+                KPSRedial );
+        }
+    /**
+     * Hook key is released when there is music playing ongoing. 
+     * Because double click timer is active, is send forward command sent
+     * and DoubleNextClick set to true for sending next command.
+     */
+    else if ( iPlayingStatus && !iLongPress )
+        {
+        delete iDoubleClicktimer;
+        iDoubleClicktimer = NULL;
+        TRACE_INFO(_L("[HID]\tCHidHeadsetDriver next after next"));
+        if ( !iLongPress )
+            {
+            iDoubleNextClick = ETrue; //set to true and when player change 
+                                      //track press next again 
+            }
+        RProperty::Set( KPSUidHidEventNotifier, KHidControlKeyEvent,
+                EForwardClicked ); //next after next
+        }
+    /**
+     * Long press release when there are no actie calls, alarms, and music
+     * playing is stopped, activates voice dialing.
+     */
+    else if ( iLongPress )
+        {
+        delete iDoubleClicktimer;
+        iDoubleClicktimer = NULL;
+        TRACE_INFO(_L("[HID]\tCHidHeadsetDriver VoiceDial"));
+        RProperty::Set( KPSUidHidEventNotifier, KHidHookKeyEvent,
+                KPSVoiceDial );
+        iLongPress = EFalse;
+        }
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// GetHookStatus()
+// ---------------------------------------------------------------------------
+//
+CHidHeadsetDriver::THookHandling CHidHeadsetDriver::HookStatus()
+    {
+    TRACE_FUNC_ENTRY
+    THookHandling retVal = EOffHook;
+    TInt ret = KErrNone;
+    CTelephony::TCallStatusV1 callStatusV1;
+    CTelephony::TCallStatusV1Pckg callStatusV1Pckg( callStatusV1 );
+    ret = iTelephony->GetLineStatus( CTelephony::EVoiceLine,
+                    callStatusV1Pckg );
+    if ( ret != KErrNone )
+        {
+        retVal = ENoHook;
+        }
+    CTelephony::TCallStatus voiceLineStatus = callStatusV1.iStatus;
+    TRACE_INFO((_L("[HID]\tCHidHeadsetDriver GetHookStatus voiceline \
+            status %d"), voiceLineStatus));
+
+    if ( voiceLineStatus == CTelephony::EStatusHold || voiceLineStatus
+            == CTelephony::EStatusRinging )
+        {
+            TRACE_INFO(_L("[HID]\tCHidHeadsetDriver GetHookStatus on hook"));
+        retVal = EOnHook;
+        }
+    else if ( voiceLineStatus == CTelephony::EStatusUnknown
+            || voiceLineStatus == CTelephony::EStatusIdle )
+        {
+            TRACE_INFO(_L("[HID]\tCHidHeadsetDriver GetHookStatus no hook"));
+        retVal = ENoHook;
+        }
+        TRACE_FUNC_EXIT
+    return retVal;
+    }
+
+// ---------------------------------------------------------------------------
+// From class CHidDriver
+// CanHandleReportL()
+// ---------------------------------------------------------------------------
+//
+TInt CHidHeadsetDriver::CanHandleReportL( CReportRoot* aReportRoot )
+    {
+    TRACE_INFO((_L("[HID]\tCHidHeadsetDriver::CanHandleReport(0x%08x)"),
+                        aReportRoot));
+
+    THidFieldSearch search;
+
+    THeadsetFinder headsetFinder;
+    search.SearchL( aReportRoot, &headsetFinder );
+
+    iSupportedFieldCount = headsetFinder.FieldCount();
+    for ( TInt i = 0; i < headsetFinder.FieldCount(); i++ )
+        {
+        User::LeaveIfError( iFieldList.Append( headsetFinder.GetFieldAtIndex(
+                i ) ) );
+        TRACE_INFO((_L("[HID]\tCHidHeadsetDriver::CanHandleReportL, field \
+                pointer: 0x%08x"), iFieldList[i]));
+        }
+
+    TInt valid = KErrHidUnrecognised;
+
+    if ( headsetFinder.Found() )
+        {
+        valid = KErrNone;
+        }
+    // empty finder's field list before going out of scope.
+    headsetFinder.EmptyList();
+
+    TRACE_INFO((_L("[HID]\tCHidHeadsetDriver::CanHandleReport() returning \
+            %d"), valid));
+    return valid;
+    }
+
+// ---------------------------------------------------------------------------
+// From class CHidDriver
+// SupportedFieldCount
+// ---------------------------------------------------------------------------
+//
+TInt CHidHeadsetDriver::SupportedFieldCount()
+    {
+    return iSupportedFieldCount;
+    }
+// ---------------------------------------------------------------------------
+// From class MTimerNotifier
+// TimerExpired()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::TimerExpired( TTimerType aTimerType )
+    {
+    TRACE_FUNC_ENTRY
+    switch ( aTimerType )
+        {
+        case EDoubleClickTimer:
+            ExpiredDoubleClickTimer();
+            break;
+        case ELongPressTimer:
+            ExpiredLongClickTimer();
+            break;
+        case EScanNextPressTimer:
+            iForwardStatus = EScanLongPress;
+            RProperty::Set( KPSUidHidEventNotifier, KHidControlKeyEvent,
+                    EFastForwardPressed );
+            break;
+        case EScanPrevPressTimer:
+            iBackwardStatus = EScanLongPress;
+            RProperty::Set( KPSUidHidEventNotifier, KHidControlKeyEvent,
+                    ERewindPressed );
+            break;
+        default:
+            TRACE_INFO(_L("CHidHeadsetDriver::TimerExpired : Not supported"))
+            ;
+        }
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// ExpiredDoubleClickTimer()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::ExpiredDoubleClickTimer()
+    {
+    TRACE_FUNC_ENTRY
+    if ( iDoubleClicktimer )
+        {
+        delete iDoubleClicktimer;
+        iDoubleClicktimer = NULL;
+        
+        if ( iIncomingCallStatus )
+            {
+            iIncomingCallStatus = EFalse;
+            iOnHookPressed = ETrue;
+            ReleaseHookKey();
+            }
+        if ( iAlarmStatus )
+            {
+            RProperty::Set( KPSUidAlarmExtCntl, KAlarmStopKey,
+                    EAlarmUIStopAlarm );
+            iAlarmStatus = EFalse;
+            }
+        if ( iPlayingStatus )
+            {
+            RProperty::Set( KPSUidHidEventNotifier, KHidControlKeyEvent,
+                    EForwardClicked );
+            iPlayingStatus = EFalse;
+            }
+        }
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// ExpiredLongClickTimer()
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::ExpiredLongClickTimer()
+    {
+    TRACE_FUNC_ENTRY
+    if ( iLongClicktimer )
+        {
+        TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::TimerExpired long click"));
+        delete iLongClicktimer;
+        iLongClicktimer = NULL;
+        iLongPress = ETrue;
+        ReleaseHookKey();
+        }
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// AlarmStatus()
+// ---------------------------------------------------------------------------
+//
+TBool CHidHeadsetDriver::AlarmStatus()
+    {
+    TRACE_FUNC_ENTRY
+    TInt activealarmcount = 0;
+    TBool retVal = EFalse;
+    activealarmcount = iAlarmServerSession.AlarmCountByState(
+            EAlarmStateNotifying );
+    if ( activealarmcount > 0 )
+        {
+        TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::AlarmStatus active alarms"));
+        retVal = ETrue;
+        }
+    else
+        {
+        TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::AlarmStatus no active \
+                alarms"));
+        retVal = EFalse;
+        }
+    TRACE_FUNC_EXIT
+    return retVal;
+    }
+
+// ---------------------------------------------------------------------------
+// AlarmStatus()
+// ---------------------------------------------------------------------------
+//
+TBool CHidHeadsetDriver::MusicPlayingStatus()
+    {
+    TRACE_FUNC_ENTRY
+    TBool retVal = EFalse;
+    TMPXPlaybackState state = EPbStateNotInitialised;
+    TRAPD( err, state = iMusicPlayer->StateL() );
+    if ( state == EPbStatePlaying && err == KErrNone )
+        {
+        TRACE_INFO(_L("[HID]\tCHidHeadsetDriver::MusicPlayingStatus play \
+                active"));
+        retVal = ETrue;
+        }
+    TRACE_FUNC_EXIT
+    return retVal;
+    }
+
+// ---------------------------------------------------------------------------
+// HandlePlaybackMessage
+// ---------------------------------------------------------------------------
+//
+void CHidHeadsetDriver::HandlePlaybackMessage( CMPXMessage* aMsg, TInt /*aErr*/)
+    {
+    TRACE_FUNC_ENTRY
+
+    TMPXMessageId id( aMsg->ValueTObjectL<TMPXMessageId> (
+            KMPXMessageGeneralId ) );
+    // send nect track whit double hook click when track is changed
+    if ( id == KMPXMessagePbMediaChanged && iDoubleNextClick )
+        {
+        TRACE_INFO(_L("[HID]\tHandlePlaybackMessage: PbMediaChangeg"));
+        RProperty::Set( KPSUidHidEventNotifier, KHidControlKeyEvent,
+                EForwardClicked );
+        iDoubleNextClick = EFalse;
+        }
+    TRACE_FUNC_EXIT
+    }
+