bluetoothengine/bteng/src/btengpairman.cpp
branchRCL_3
changeset 56 9386f31cc85b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothengine/bteng/src/btengpairman.cpp	Wed Sep 01 12:20:04 2010 +0100
@@ -0,0 +1,916 @@
+/*
+* Copyright (c) 2009-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:  Pairing result receiver in Bluetooth engine subsystem
+*
+*/
+
+#include "btengpairman.h"
+#include "btengserver.h"
+#include "btengsrvsession.h"
+#include "btengotgpair.h"
+#include "btengincpair.h"
+#include "btengclientserver.h"
+#include "debug.h"
+#include <e32property.h>
+
+/**  Identification for active object */
+enum TPairManActiveRequestId
+    {
+    ESimplePairingResult,
+    EAuthenticationResult,
+    ERegistryInitiatePairedDevicesView,
+    ERegistryPairedDevicesNewView,
+    ERegistryInitiatePairedDevicesList,
+    ERegistryGetPairedDevices,
+    ERegistryGetLocalAddress,
+    };
+
+/**  The message argument which holds the Bluetooth address. */
+const TInt KBTEngAddrSlot = 0;
+
+// ---------------------------------------------------------------------------
+// Tells if two TBTNamelessDevice instances are for the same remote device
+// ---------------------------------------------------------------------------
+//
+TBool CompareDeviceByAddress( const TBTNamelessDevice& aDevA, const TBTNamelessDevice& aDevB )
+    {
+    return aDevA.Address() == aDevB.Address();
+    }
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// C++ default constructor
+// ---------------------------------------------------------------------------
+//
+CBTEngPairMan::CBTEngPairMan( CBTEngServer& aServer )
+    : iServer( aServer )
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// Symbian 2nd-phase constructor
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::ConstructL()
+    {
+    TRACE_FUNC_ENTRY
+        // Connect to pairing server for authentication & simple pairing 
+        // results directly from the BT stack.
+        // Pairing server doesn't exist if we run BT 2.0 stack:
+    iPairingServ = new (ELeave) RBluetoothPairingServer;
+    TInt err = iPairingServ->Connect();
+    if ( err)
+        {
+        delete iPairingServ;
+        iPairingServ = NULL;
+        }
+    else
+        {
+        User::LeaveIfError( iPairingResult.Open( *iPairingServ ) );
+        User::LeaveIfError( iAuthenResult.Open( *iPairingServ ) );
+        iSSPResultActive = CBTEngActive::NewL( *this, ESimplePairingResult, CActive::EPriorityStandard );
+        iAuthenResultActive = CBTEngActive::NewL( *this, EAuthenticationResult, CActive::EPriorityStandard );        
+        }
+
+    // RProperty for accessing the local device address
+    User::LeaveIfError( iPropertyLocalAddr.Attach(KPropertyUidBluetoothCategory, KPropertyKeyBluetoothGetLocalDeviceAddress) );
+
+    // connect to registry
+    User::LeaveIfError( iBTRegistry.Open( BTRegServ() ) );    
+    iRegistryActive = CBTEngActive::NewL( *this, ERegistryInitiatePairedDevicesView, CActive::EPriorityStandard );
+    iPairedDevices = new (ELeave) RArray<TBTNamelessDevice>; 
+
+    // Initialise paired devices list
+    iLocalAddrActive = CBTEngActive::NewL( *this, ERegistryGetLocalAddress, CActive::EPriorityStandard );
+    InitPairedDevicesList();
+ 
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// NewL
+// ---------------------------------------------------------------------------
+//
+CBTEngPairMan* CBTEngPairMan::NewL( CBTEngServer& aServer )
+    {
+    CBTEngPairMan* self = NULL;
+    self = new  CBTEngPairMan( aServer );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CBTEngPairMan::~CBTEngPairMan()
+    {
+    TRACE_FUNC_ENTRY
+    CancelSubscribe();
+    delete iSSPResultActive;
+    delete iAuthenResultActive;
+    delete iRegistryActive;
+    delete iPairedDevicesResp;
+    delete iPairer;
+    if ( iPairedDevices )
+        {
+        iPairedDevices->Close();
+        delete iPairedDevices;
+        }
+    iBTRegistry.Close();
+    iPairingResult.Close();
+    iAuthenResult.Close();
+    if ( iPairingServ )
+        {
+        iPairingServ->Close();
+        delete iPairingServ;
+        }
+    if ( !iMessage.IsNull() )
+        {
+        iMessage.Complete( KErrCancel );
+        }
+    iPropertyLocalAddr.Cancel();
+    iPropertyLocalAddr.Close();
+    delete iLocalAddrActive;
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// Initialises the paired devices list.
+// If the local address is not available from the P&S key 
+// KPropertyKeyBluetoothGetLocalDeviceAddress, then the list may need to be 
+// updated once the H/W is switched on. This is so that any registry update 
+// from a restore operation can be included in the list, without mistaking the 
+// new devices for new pairings.
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::InitPairedDevicesList()
+    {
+    TRACE_FUNC_ENTRY
+
+    // Check that we have the Bluetooth local address. If we don't then initialise anyway, but subscribe for an update.
+    // This allows us to refresh our paired devices list to include updates made to the remote devices table of the 
+    // Bluetooth registry from a restore operation. We need to include these devices without mistaking them for new 
+    // pairings. We look solely at the P&S key for the address to avoid the condition whereby the address has been
+    // entered into the reigstry but the Bluetooth Manager server has not begun the restore process yet. The signalling
+    // of the P&S key will cause Bluetooth Manager to update the registry with any restored devices before fulfilling
+    // any further requests.
+
+    // Subscribe to local address property in case we need an update.
+    iPropertyLocalAddr.Subscribe( iLocalAddrActive->iStatus );
+    iLocalAddrActive->SetRequestId( ERegistryGetLocalAddress );
+    iLocalAddrActive->GoActive();
+
+    // Attempt to read address from P&S key.
+    TBuf8<KBTDevAddrSize> btAddrDes;
+    TInt err = iPropertyLocalAddr.Get( btAddrDes );
+
+    // Is the P&S key defined yet? (if not, stack not up yet)
+    if ( err == KErrNone )
+        {
+        // P&S key defined, is local address set? (if not, H/W not initialised yet)
+        if ( btAddrDes.Length() == KBTDevAddrSize )
+            {
+            TBTDevAddr btAddr = btAddrDes;
+
+            if ( btAddr != TBTDevAddr() )
+                {
+                // Non-zero local address is available.
+                iPropertyLocalAddr.Cancel();
+                iLocalAddrActive->CancelRequest();
+                }
+            }
+        }
+
+    // Perform initialisation of the paired devices list.
+    DoInitPairedDevicesList();
+
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// Initialises the paired devices list (second stage)
+// This method performs the actual initialisation, now that the local BT H/W
+// address had been made available.
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::DoInitPairedDevicesList()
+    {
+    TRACE_FUNC_ENTRY
+
+    if ( !iRegistryActive->IsActive() )
+        {
+        // Start to get the list of all paired devices.
+        CreatePairedDevicesView( ERegistryInitiatePairedDevicesView );
+        }
+    else
+        {
+        iNotHandledInitEventCounter++;
+        }
+
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// Handles pairing related commands from BTEng clients.
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::ProcessCommandL( const RMessage2& aMessage )
+    {
+    TRACE_FUNC_ENTRY
+    TInt opcode = aMessage.Function();
+    TBTDevAddrPckgBuf addrPkg;
+    switch( opcode )
+        {
+        case EBTEngSetPairingObserver:
+            {
+            aMessage.ReadL( KBTEngAddrSlot, addrPkg );
+            SetPairObserver( addrPkg(), aMessage.Int1() );
+            break;
+            }
+        case EBTEngPairDevice:
+            {
+            if ( !iMessage.IsNull() )
+                {
+                User::Leave( KErrServerBusy );
+                }
+            TBTDevAddrPckgBuf addrPkg;
+            aMessage.ReadL( KBTEngAddrSlot, addrPkg );
+            PairDeviceL( addrPkg(), aMessage.Int1() );
+            iMessage = RMessage2( aMessage );
+            break;
+            }
+        case EBTEngCancelPairDevice:
+            {
+            // Only the client who requested pairing can cancel it:
+            if ( !iMessage.IsNull() && aMessage.Session() == iMessage.Session() )
+                {
+                iPairer->CancelOutgoingPair();
+                iMessage.Complete( KErrCancel );
+                }
+            break;
+            }
+        default:
+            {
+            TRACE_INFO( ( _L( "CBTEngPairMan ProcessCommandL: bad request (%d)" ), 
+                           aMessage.Function() ) )
+            User::Leave( KErrArgument );
+            }
+        }
+    TRACE_FUNC_EXIT    
+    }
+
+// ---------------------------------------------------------------------------
+// Handle a change in BTRegistry remote devices table.
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::RemoteRegistryChangeDetected()
+    {
+    if ( !iRegistryActive->IsActive() )
+        {
+        CreatePairedDevicesView( ERegistryPairedDevicesNewView );
+        }
+    else
+        {
+        iNotHandledRegEventCounter++;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Returns the RBluetoothPairingServer instance.
+// ---------------------------------------------------------------------------
+//
+RBluetoothPairingServer* CBTEngPairMan::PairingServer()
+    {
+    return iPairingServ;
+    }
+
+// ---------------------------------------------------------------------------
+// Access the reference of RSockServ
+// ---------------------------------------------------------------------------
+//
+RSocketServ& CBTEngPairMan::SocketServ()
+    {
+    return iServer.SocketServer();
+    }
+
+// ---------------------------------------------------------------------------
+// Access the reference of RBTRegSrv
+// ---------------------------------------------------------------------------
+//
+RBTRegServ& CBTEngPairMan::BTRegServ()
+    {
+    return iServer.RegistrServer();
+    }
+
+// ---------------------------------------------------------------------------
+// Deletes the current pairing handler and transfer the responsibility
+// to the specified.
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::RenewPairer( CBTEngPairBase* aPairer )
+    {
+    delete iPairer;
+    iPairer = aPairer;
+    }
+
+// ---------------------------------------------------------------------------
+// Find the session who requested this and completes its request.
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::OutgoingPairCompleted( TInt aErr )
+    {
+    TRACE_FUNC_ENTRY
+    // the meaning of KHCIErrorBase equals KErrNone. Hide this specific BT stack
+	// detail from clients:
+    if ( aErr == KHCIErrorBase )
+        {
+        aErr = KErrNone;
+        }
+    // we must complete client's pairing request:
+    if ( !iMessage.IsNull()  )
+        {
+        iMessage.Complete( aErr );
+        }
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// A session will be ended, completes the pending request for this session.
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::SessionClosed( CSession2* aSession )
+    {
+    TRACE_FUNC_ARG( ( _L( " session %x"), aSession ) )
+    if ( !iMessage.IsNull() && iMessage.Session() == aSession )
+        {
+        iMessage.Complete( KErrCancel );
+        }
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// Unpair the device from registry
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::UnpairDevice( const TBTDevAddr& aAddr )
+    {
+    TRACE_FUNC_ENTRY
+    TIdentityRelation<TBTNamelessDevice> addrComp( CompareDeviceByAddress );
+    TBTNamelessDevice dev;
+    dev.SetAddress( aAddr );
+    // only do unpairing if the we have a link key with it.
+    TInt index = iPairedDevices->Find( dev, addrComp );
+    if ( index > KErrNotFound )
+        {
+        dev = (*iPairedDevices)[index];
+        
+        TRequestStatus status( KRequestPending );
+        // Unpair the device in registry (synchronously)
+        iBTRegistry.UnpairDevice( dev.Address(), status );
+        User::WaitForRequest( status );
+        TRACE_INFO( ( _L( "Delete link key, res %d"), status.Int() ) )
+        
+        if ( status == KErrNone )
+            {
+            TBTDeviceSecurity security = dev.GlobalSecurity();
+            // Clear trust setting so that correct icon will be shown in ui applications.
+            security.SetNoAuthenticate(EFalse );
+            security.SetNoAuthorise(EFalse );
+            dev.SetGlobalSecurity(security);
+            dev.DeleteLinkKey();
+            if ( dev.IsValidUiCookie() && 
+                 ( dev.UiCookie() & EBTUiCookieJustWorksPaired ) )
+                {
+                // Remove the UI cookie bit for Just Works pairing.
+                TInt32 cookie = dev.UiCookie() & ~EBTUiCookieJustWorksPaired;
+                dev.SetUiCookie( cookie );
+                TRACE_INFO( ( _L( "UI cookie %x cleared"), EBTUiCookieJustWorksPaired ) );
+                }
+            // modify the device in registry synchronously
+            // status.Int() could be -1 if the device is not in registry 
+            // which is totally fine for us.
+            (void) UpdateRegDevice( dev );
+            }
+        }
+    TRACE_FUNC_EXIT
+    }
+
+TInt CBTEngPairMan::AddUiCookieJustWorksPaired( const TBTNamelessDevice& aDev )
+    {
+	TRACE_FUNC_ENTRY
+    TInt err( KErrNone );
+    // There might be UI cookies used by other applications,
+    // we should not overwrite them. 
+    TInt32 cookie = aDev.IsValidUiCookie() ? aDev.UiCookie() : EBTUiCookieUndefined;
+    if ( !( cookie & EBTUiCookieJustWorksPaired ) )
+        {
+        // Only update the cookie if the wanted one is not in registry yet
+        // to keep minimal operations with registry.
+        TBTNamelessDevice dev = aDev;		
+        cookie |= EBTUiCookieJustWorksPaired;
+        dev.SetUiCookie( cookie );
+        err = UpdateRegDevice( dev );
+        TRACE_INFO( ( _L( "[BTENG] CBTEngOtgPair write Ui cookie ret %d"), err ) );
+        }
+    TRACE_FUNC_EXIT
+    return err;
+    }
+
+// ---------------------------------------------------------------------------
+// update a nameless device in registry
+// ---------------------------------------------------------------------------
+//
+TInt CBTEngPairMan::UpdateRegDevice( const TBTNamelessDevice& aDev )
+    {
+    TRequestStatus status( KRequestPending );
+    // update the device in registry synchronously
+    iBTRegistry.ModifyDevice( aDev, status );
+    User::WaitForRequest( status );
+    TRACE_INFO( ( _L( "UpdateRegDevice, ret %d"), status.Int() ) )
+    return status.Int();
+    }
+
+// ---------------------------------------------------------------------------
+// Ask server class the connection status of the specified device
+// ---------------------------------------------------------------------------
+//
+TBTEngConnectionStatus CBTEngPairMan::IsDeviceConnected( const TBTDevAddr& aAddr )
+    {
+    return iServer.IsDeviceConnected( aAddr );
+    }
+
+// ---------------------------------------------------------------------------
+// From class MBTEngActiveObserver.
+// Checks if there is an authentication result.
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::RequestCompletedL( CBTEngActive* /*aActive*/, TInt aId, TInt aStatus )
+    {
+    TRACE_FUNC_ARG( ( _L( "aId: %d, aStatus: %d"), aId, aStatus ) )
+        // Check which request completed.
+    switch( aId )
+        {
+        case ESimplePairingResult:
+            {
+            TBTDevAddr tmpAddr = iSimplePairingRemote;
+            if (aStatus != KErrServerTerminated)
+                {
+                SubscribeSspPairingResult();
+                }
+            HandlePairingResultL( tmpAddr, aStatus );
+            break;
+            }
+        case EAuthenticationResult:
+            {
+            TBTDevAddr tmpAddr = iAuthenticateRemote;
+            if (aStatus != KErrServerTerminated)
+                {
+                SubscribeAuthenticateResult();
+                }
+            HandlePairingResultL( tmpAddr, aStatus );
+            break;
+            }
+        case ERegistryInitiatePairedDevicesView:
+        case ERegistryPairedDevicesNewView:
+            {
+            HandleCreatePairedDevicesViewCompletedL( aStatus, aId );
+            break;
+            }
+        case ERegistryInitiatePairedDevicesList:
+            {			
+			if (iSSPResultActive && iAuthenResultActive)
+				{
+				SubscribeSspPairingResult();
+				SubscribeAuthenticateResult();
+				}
+            HandleGetPairedDevicesCompletedL( aStatus, aId );
+            break;
+            }
+        case ERegistryGetPairedDevices:    
+            {
+            HandleGetPairedDevicesCompletedL( aStatus, aId );
+            break;
+            }
+        case ERegistryGetLocalAddress:
+            {
+            // Refresh paired devices list to include any restored devices.
+            DoInitPairedDevicesList();
+            break;
+            }
+        default:
+                // Should not be possible, but no need for handling.
+            TRACE_INFO( (_L("[BTEng]: CBTEngPairMan::RequestCompletedL unhandled event!!") ) )
+            break;
+        }
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// From class MBTEngActiveObserver.
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::HandleError( CBTEngActive* aActive, TInt aId, TInt aError )
+    {
+    TRACE_FUNC_ARG( ( _L( "request id: %d, error: %d" ), aId, aError ) )
+    (void) aActive;
+    (void) aError;
+    if ( aId == ERegistryInitiatePairedDevicesList || 
+         aId == ERegistryGetPairedDevices )
+        {// leave happened in registry operation, delete registry response:
+        delete iPairedDevicesResp;
+        iPairedDevicesResp = NULL;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Activate or deactivate a pairing handler
+// ---------------------------------------------------------------------------
+//
+TInt CBTEngPairMan::SetPairObserver(const TBTDevAddr& aAddr, TBool aActivate)
+    {
+    TRACE_FUNC_ARG( ( _L( "%d" ), aActivate ) )
+    TRACE_BDADDR( aAddr )
+    iPairingOperationAttempted = ETrue;
+    TInt err( KErrNone );
+    if ( !aActivate )
+        {
+        if ( iPairer )
+            {
+            iPairer->StopPairHandling( aAddr );
+            }
+        return err;
+        }
+    
+    if ( !iPairer)
+        {
+        // This is an incoming pair, unpair it from registry and 
+        // create the handler:
+        UnpairDevice( aAddr );
+        TRAP( err, iPairer = CBTEngIncPair::NewL( *this, aAddr ));     
+        }
+    if ( iPairer)
+        {
+        // let the handler decide what to do:
+        err = iPairer->ObserveIncomingPair( aAddr );        
+        }    
+    TRACE_FUNC_EXIT
+    return err;
+    }
+
+// ---------------------------------------------------------------------------
+// Delegates the request to current pair handler
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::PairDeviceL( const TBTDevAddr& aAddr, TUint32 aCod )
+    {
+    iPairingOperationAttempted = ETrue;
+    if ( !iPairer)
+        {
+        // no existing pair handling, create one:
+        iPairer = CBTEngOtgPair::NewL( *this, aAddr );
+        }
+    // let pair handler decide what to do:
+    iPairer->HandleOutgoingPairL( aAddr, aCod );
+    }
+
+// ---------------------------------------------------------------------------
+// cancel Subscribings to simple pairing result and authentication result from
+// Pairing Server
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::CancelSubscribe()
+    {
+    TRACE_FUNC_ENTRY
+    if( iSSPResultActive && iSSPResultActive->IsActive() )
+        {
+            // Cancel listening Simple pairing result
+        iPairingResult.CancelSimplePairingResult();
+        iSSPResultActive->Cancel();
+        }
+    if( iAuthenResultActive && iAuthenResultActive->IsActive() )
+        {
+            // Cancel listening authentication result
+        iAuthenResult.CancelAuthenticationResult();
+        iAuthenResultActive->Cancel();
+        }
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// Subscribes to simple pairing result from Pairing Server (if not already 
+// subscribed).
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::SubscribeSspPairingResult()
+    {
+    TRACE_FUNC_ENTRY
+    if ( !iSSPResultActive->IsActive() )
+        {
+        iPairingResult.SimplePairingResult( iSimplePairingRemote, iSSPResultActive->RequestStatus() );
+        iSSPResultActive->GoActive();
+        }
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// Subscribes to authentication result from Pairing Server (if not already
+// subscribed).
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::SubscribeAuthenticateResult()
+    {
+    TRACE_FUNC_ENTRY
+    if ( !iAuthenResultActive->IsActive() )
+        {
+        // Subscribe authentication result (which requires pairing for unpaired devices)
+        iAuthenResult.AuthenticationResult( iAuthenticateRemote, iAuthenResultActive->RequestStatus() );
+        iAuthenResultActive->GoActive();
+        }
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// Handle a pairing result from the pairing server.
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::HandlePairingResultL( const TBTDevAddr& aAddr, TInt aResult )
+    {
+    TRACE_FUNC_ARG( (_L("result %d"), aResult ) )
+    TRACE_BDADDR( aAddr );
+    if ( !iPairer && ( aResult == KErrNone || aResult == KHCIErrorBase ) )
+        {
+        // we only create new handler if incoming pairing succeeds.
+        // Pairing failure could be caused by user local cancellation, as the  
+        // result, the handler was destroyed by notifier. We shall not
+        // instantiate the handler again.
+        // If a pairing failed due to other reasons than user local cancelling,
+        // it will be catched by the already started handler 
+        // (except Just Works pairing - no handler for it at all until we receive
+        // registry change event. Thus if incoming JWs pairing failed, no user
+        // notification will be shown.)
+        TBTNamelessDevice dev;
+        dev.SetAddress( aAddr );
+        TIdentityRelation<TBTNamelessDevice> addrComp( CompareDeviceByAddress );
+        TInt index = iPairedDevices->Find( dev, addrComp );
+        
+        // If the device is not found in the old paired device list, it is a new
+        // paired device:
+        if ( index == KErrNotFound)
+            {
+            // No handler yet, create incoming pairing handler:
+            iPairer = CBTEngIncPair::NewL( *this, aAddr );
+            }
+        }
+    if ( iPairer )
+        {
+        iPairer->HandlePairServerResult( aAddr, aResult );
+        }  
+
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// issue creating a bonded devices view
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::CreatePairedDevicesView( TInt aReqId )
+    {
+    TRACE_FUNC_ENTRY
+    if ( aReqId == ERegistryInitiatePairedDevicesView )
+        {
+        iNotHandledInitEventCounter = 0;
+        }
+    else
+        {
+        iNotHandledRegEventCounter = 0;
+        }
+    TBTRegistrySearch searchPattern;
+    searchPattern.FindBonded();
+    iRegistryActive->SetRequestId( aReqId );
+    iBTRegistry.CreateView( searchPattern, iRegistryActive->iStatus );
+    iRegistryActive->GoActive();
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// gets the paired devices from the view created by CreatePairedDevicesView
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::GetPairedDevices( TInt aReqId )
+    {
+    TRACE_FUNC_ENTRY
+    delete iPairedDevicesResp;
+    iPairedDevicesResp = NULL;
+    TRAP_IGNORE( iPairedDevicesResp = CBTRegistryResponse::NewL( iBTRegistry ) );
+    if ( iPairedDevicesResp )
+        {
+        iRegistryActive->SetRequestId( aReqId );
+        iPairedDevicesResp->Start( iRegistryActive->iStatus );
+        iRegistryActive->GoActive();
+        }
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// re-create a paired device view if registry was changed during the previous
+// operation. otherwise if the view is not empty, get the paired devices.
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::HandleCreatePairedDevicesViewCompletedL( TInt aStatus, TInt aReqId )
+    {
+    TRACE_FUNC_ENTRY
+
+    if ( aReqId == ERegistryInitiatePairedDevicesView )
+        {// Initialization phase, list paired devices if there are any.
+        if ( iNotHandledInitEventCounter )
+            {
+            // Reinitialisaton detected, create paired device view again:
+            (void) iBTRegistry.CloseView();
+            CreatePairedDevicesView( ERegistryInitiatePairedDevicesView );
+            }
+        else if ( aStatus > KErrNone )
+            {
+            GetPairedDevices( ERegistryInitiatePairedDevicesList );
+            }
+        else
+            {//no paired device, close the view.
+            (void) iBTRegistry.CloseView();
+            }
+        }
+    else
+        {
+        if ( iNotHandledInitEventCounter )
+            {
+            // We need to reinitialise but we may be pairing.
+            // This situation is not expected to arise, as reinitialisation means
+            // that the H/W was only just switched on.
+            // If we have ever started to take part in a pairing, then prioritise that
+            // pairing.
+            (void) iBTRegistry.CloseView();
+            if ( iPairingOperationAttempted )
+                {
+                iNotHandledInitEventCounter = 0;
+                CreatePairedDevicesView( ERegistryPairedDevicesNewView );
+                }
+            else
+                {
+                CreatePairedDevicesView( ERegistryInitiatePairedDevicesView );
+                }
+            }
+        else if (iNotHandledRegEventCounter)
+            { // more registry change detected, create paired device view again:
+            (void) iBTRegistry.CloseView();
+            CreatePairedDevicesView( ERegistryPairedDevicesNewView );
+            }          
+        else if ( aStatus > KErrNone )
+            { // paired device available, get them:
+            GetPairedDevices( ERegistryGetPairedDevices );
+            }
+        else
+            {
+            // No paired devices in registry, empty local db:
+            (void) iBTRegistry.CloseView();
+            iPairedDevices->Reset();
+            }
+        }
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// update paired device list. if registry was changed, create a new view.
+// otherwise check for new pairing event.
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::HandleGetPairedDevicesCompletedL( TInt /*aStatus*/, TInt aReqId )
+    {
+    TRACE_FUNC_ENTRY
+    (void) iBTRegistry.CloseView();
+    if ( aReqId == ERegistryInitiatePairedDevicesList )
+        {
+        if ( iNotHandledInitEventCounter )
+            {
+            // Reinitialisation required, create paired device view again:
+            CreatePairedDevicesView( ERegistryInitiatePairedDevicesView );
+            }
+        else
+            {
+            // We completed the initialisation of paired device list, 
+            // move all paired devices to the array:
+            UpdatePairedDeviceListL();
+            }
+        }
+    else
+        {
+        if (iNotHandledInitEventCounter)
+            {
+            // We need to reinitialise but we may be pairing.
+            // This situation is not expected to arise, as reinitialisation means
+            // that the H/W was only just switched on.
+            // If we have ever started to take part in a pairing, then prioritise that
+            // pairing.
+            if ( iPairingOperationAttempted )
+                {
+                iNotHandledInitEventCounter = 0;
+                CreatePairedDevicesView( ERegistryPairedDevicesNewView );
+                }
+            else
+                {
+                CreatePairedDevicesView( ERegistryInitiatePairedDevicesView );
+                }		
+            }     
+        else if (iNotHandledRegEventCounter)
+            { // more registry change detected, create paired device view again:
+            CreatePairedDevicesView( ERegistryPairedDevicesNewView );
+            }
+        else if ( aReqId == ERegistryGetPairedDevices)
+           {
+            // no more registry change detected, find new pairings:
+            CheckPairEventL();
+           }
+        }
+
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// copy the nameless devices to local array
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::UpdatePairedDeviceListL()
+    {
+    TRACE_FUNC_ENTRY
+    iPairedDevices->Reset();
+    for ( TInt i = 0; i < iPairedDevicesResp->Results().Count(); i++ )
+        {
+        TRACE_BDADDR( iPairedDevicesResp->Results()[i]->BDAddr() );
+        TRACE_INFO((_L("[BTENG]\t linkkeytype %d"), 
+                iPairedDevicesResp->Results()[i]->LinkKeyType()))
+        iPairedDevices->AppendL( iPairedDevicesResp->Results()[i]->AsNamelessDevice() );
+        }
+    delete iPairedDevicesResp;
+    iPairedDevicesResp = NULL;
+    TRACE_FUNC_EXIT
+    }
+
+// ---------------------------------------------------------------------------
+// find new paired devices. for each, delegate the information to
+// current pair handler.
+// ---------------------------------------------------------------------------
+//
+void CBTEngPairMan::CheckPairEventL()
+    {
+    TRACE_FUNC_ENTRY
+    RArray<TBTNamelessDevice>* pairedDevicesOld;
+    pairedDevicesOld = iPairedDevices;
+    CleanupStack::PushL( pairedDevicesOld );
+    CleanupClosePushL( *pairedDevicesOld );
+    iPairedDevices = NULL;
+    iPairedDevices = new (ELeave) RArray<TBTNamelessDevice>;
+    UpdatePairedDeviceListL();
+    
+    TIdentityRelation<TBTNamelessDevice> addrComp( CompareDeviceByAddress );
+    for ( TInt i = 0; i < iPairedDevices->Count(); i++ )
+        {
+        TBTNamelessDevice& dev = (*iPairedDevices)[i];        
+        TInt index = pairedDevicesOld->Find( dev, addrComp );
+ 
+        // If the device is not found in the old paired device list or
+        // the link key type has been changed from 
+        // ELinkKeyUnauthenticatedUpgradable, the device is a new 
+        // paired device:
+        TBool newPaired = dev.LinkKeyType() != ELinkKeyUnauthenticatedUpgradable && 
+             ( index == KErrNotFound  || 
+                 ( index > KErrNotFound &&
+                 dev.LinkKeyType() != (*pairedDevicesOld)[index].LinkKeyType() ) );
+        TRACE_BDADDR( dev.Address() );
+        if ( newPaired && !iPairer)
+            {
+            iPairingOperationAttempted = ETrue;
+            iPairer = CBTEngIncPair::NewL( *this, dev.Address() );
+            }
+        if ( newPaired && iPairer )
+            {
+            // Ask pair handler to decide what to do:
+            iPairer->HandleRegistryNewPairedEvent( dev );
+            }
+        }
+    // Free old paired device list resource:
+    CleanupStack::PopAndDestroy( 2 );
+    TRACE_FUNC_EXIT
+    }
+