diff -r 613943a21004 -r 9386f31cc85b bluetoothengine/bteng/src/btengpairman.cpp --- /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 + +/** 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; + + // 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 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 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 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* pairedDevicesOld; + pairedDevicesOld = iPairedDevices; + CleanupStack::PushL( pairedDevicesOld ); + CleanupClosePushL( *pairedDevicesOld ); + iPairedDevices = NULL; + iPairedDevices = new (ELeave) RArray; + UpdatePairedDeviceListL(); + + TIdentityRelation 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 + } +