bluetoothengine/bteng/src/btengpairman.cpp
changeset 15 00f9ee97d895
parent 0 f63038272f30
--- a/bluetoothengine/bteng/src/btengpairman.cpp	Tue Feb 02 00:20:42 2010 +0200
+++ b/bluetoothengine/bteng/src/btengpairman.cpp	Fri Apr 16 15:08:36 2010 +0300
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* 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"
@@ -33,6 +33,7 @@
     ERegistryPairedDevicesNewView,
     ERegistryInitiatePairedDevicesList,
     ERegistryGetPairedDevices,
+    ERegistryGetLocalAddress,
     };
 
 /**  The message argument which holds the Bluetooth address. */
@@ -81,16 +82,20 @@
         User::LeaveIfError( iAuthenResult.Open( *iPairingServ ) );
         iSSPResultActive = CBTEngActive::NewL( *this, ESimplePairingResult, CActive::EPriorityStandard );
         iAuthenResultActive = CBTEngActive::NewL( *this, EAuthenticationResult, CActive::EPriorityStandard );        
-        SubscribeSspPairingResult();
-        SubscribeAuthenticateResult();
         }
 
+    // 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 );
-    // Start to get the list of all paired devices.
-    CreatePairedDevicesView( ERegistryInitiatePairedDevicesView );
-    iPairedDevices = new (ELeave) RArray<TBTNamelessDevice>;
+    iPairedDevices = new (ELeave) RArray<TBTNamelessDevice>; 
+
+    // Initialise paired devices list
+    iLocalAddrActive = CBTEngActive::NewL( *this, ERegistryGetLocalAddress, CActive::EPriorityStandard );
+    InitPairedDevicesList();
+ 
     TRACE_FUNC_EXIT
     }
 
@@ -134,6 +139,89 @@
         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
     }
 
@@ -156,14 +244,24 @@
             }
         case EBTEngPairDevice:
             {
+            if ( !iMessage.IsNull() )
+                {
+                User::Leave( KErrServerBusy );
+                }
             TBTDevAddrPckgBuf addrPkg;
             aMessage.ReadL( KBTEngAddrSlot, addrPkg );
             PairDeviceL( addrPkg(), aMessage.Int1() );
+            iMessage = RMessage2( aMessage );
             break;
             }
         case EBTEngCancelPairDevice:
             {
-            CancelCommand( opcode );
+            // Only the client who requested pairing can cancel it:
+            if ( !iMessage.IsNull() && aMessage.Session() == iMessage.Session() )
+                {
+                iPairer->CancelOutgoingPair();
+                iMessage.Complete( KErrCancel );
+                }
             break;
             }
         default:
@@ -177,27 +275,6 @@
     }
 
 // ---------------------------------------------------------------------------
-// Cancels outgoing pairing requests
-// ---------------------------------------------------------------------------
-//
-void CBTEngPairMan::CancelCommand( TInt aOpCode )
-    {
-    switch( aOpCode )
-        {
-        case EBTEngPairDevice:
-            {
-            TRACE_FUNC_ENTRY
-            if ( iPairer )
-                {
-                iPairer->CancelOutgoingPair();
-                }
-            TRACE_FUNC_EXIT
-            break;
-            }
-        }
-    }
-
-// ---------------------------------------------------------------------------
 // Handle a change in BTRegistry remote devices table.
 // ---------------------------------------------------------------------------
 //
@@ -228,7 +305,7 @@
 //
 RSocketServ& CBTEngPairMan::SocketServ()
     {
-    return iServer.SocketServ();
+    return iServer.SocketServer();
     }
 
 // ---------------------------------------------------------------------------
@@ -237,7 +314,7 @@
 //
 RBTRegServ& CBTEngPairMan::BTRegServ()
     {
-    return iServer.BTRegServ();
+    return iServer.RegistrServer();
     }
 
 // ---------------------------------------------------------------------------
@@ -265,13 +342,23 @@
         aErr = KErrNone;
         }
     // we must complete client's pairing request:
-    iServer.iSessionIter.SetToLast();
-    CBTEngSrvSession* session = (CBTEngSrvSession*) iServer.iSessionIter--;
-    TInt ret( KErrNotFound );
-    while( session && ret )
+    if ( !iMessage.IsNull()  )
         {
-        ret = session->CompletePairRequest( aErr );
-        session = (CBTEngSrvSession*) iServer.iSessionIter--;
+        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
     }
@@ -291,30 +378,41 @@
     if ( index > KErrNotFound )
         {
         dev = (*iPairedDevices)[index];
-        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 ) )
+        
+        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 )
             {
-            // 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 ) );
+            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 );
             }
-        // 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. 
@@ -329,6 +427,7 @@
         err = UpdateRegDevice( dev );
         TRACE_INFO( ( _L( "[BTENG] CBTEngOtgPair write Ui cookie ret %d"), err ) );
         }
+    TRACE_FUNC_EXIT
     return err;
     }
 
@@ -393,11 +492,26 @@
             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!!") ) )
@@ -431,6 +545,7 @@
     {
     TRACE_FUNC_ARG( ( _L( "%d" ), aActivate ) )
     TRACE_BDADDR( aAddr )
+    iPairingOperationAttempted = ETrue;
     TInt err( KErrNone );
     if ( !aActivate )
         {
@@ -463,6 +578,7 @@
 //
 void CBTEngPairMan::PairDeviceL( const TBTDevAddr& aAddr, TUint32 aCod )
     {
+    iPairingOperationAttempted = ETrue;
     if ( !iPairer)
         {
         // no existing pair handling, create one:
@@ -496,27 +612,35 @@
     }
 
 // ---------------------------------------------------------------------------
-// Subscribes to simple pairing result from Pairing Server
+// Subscribes to simple pairing result from Pairing Server (if not already 
+// subscribed).
 // ---------------------------------------------------------------------------
 //
 void CBTEngPairMan::SubscribeSspPairingResult()
     {
     TRACE_FUNC_ENTRY
-    iPairingResult.SimplePairingResult( iSimplePairingRemote, iSSPResultActive->RequestStatus() );
-    iSSPResultActive->GoActive();
+    if ( !iSSPResultActive->IsActive() )
+        {
+        iPairingResult.SimplePairingResult( iSimplePairingRemote, iSSPResultActive->RequestStatus() );
+        iSSPResultActive->GoActive();
+        }
     TRACE_FUNC_EXIT
     }
 
 // ---------------------------------------------------------------------------
-// Subscribes to authentication result from Pairing Server
+// Subscribes to authentication result from Pairing Server (if not already
+// subscribed).
 // ---------------------------------------------------------------------------
 //
 void CBTEngPairMan::SubscribeAuthenticateResult()
     {
     TRACE_FUNC_ENTRY
-    // Subscribe authentication result (which requires pairing for unpaired devices)
-    iAuthenResult.AuthenticationResult( iAuthenticateRemote, iAuthenResultActive->RequestStatus() );
-    iAuthenResultActive->GoActive();
+    if ( !iAuthenResultActive->IsActive() )
+        {
+        // Subscribe authentication result (which requires pairing for unpaired devices)
+        iAuthenResult.AuthenticationResult( iAuthenticateRemote, iAuthenResultActive->RequestStatus() );
+        iAuthenResultActive->GoActive();
+        }
     TRACE_FUNC_EXIT
     }
 
@@ -567,7 +691,14 @@
 void CBTEngPairMan::CreatePairedDevicesView( TInt aReqId )
     {
     TRACE_FUNC_ENTRY
-    iNotHandledRegEventCounter = 0;
+    if ( aReqId == ERegistryInitiatePairedDevicesView )
+        {
+        iNotHandledInitEventCounter = 0;
+        }
+    else
+        {
+        iNotHandledRegEventCounter = 0;
+        }
     TBTRegistrySearch searchPattern;
     searchPattern.FindBonded();
     iRegistryActive->SetRequestId( aReqId );
@@ -605,8 +736,14 @@
     TRACE_FUNC_ENTRY
 
     if ( aReqId == ERegistryInitiatePairedDevicesView )
-        {// Initialization phase, list paired devices if there are.
-        if ( aStatus > KErrNone )
+        {// 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 );
             }
@@ -617,7 +754,25 @@
         }
     else
         {
-        if (iNotHandledRegEventCounter)
+        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 );
@@ -647,19 +802,46 @@
     (void) iBTRegistry.CloseView();
     if ( aReqId == ERegistryInitiatePairedDevicesList )
         {
-        // We completed the initialization of paired device list, 
-        // move all paired devices to the array:
-        UpdatePairedDeviceListL();
+        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();
+            }
         }
-    
-    if (iNotHandledRegEventCounter)
-        { // more registry change detected, create paired device view again:
-        CreatePairedDevicesView( ERegistryPairedDevicesNewView );
-        }
-    else if ( aReqId == ERegistryGetPairedDevices)
+    else
         {
-        // no more registry change detected, find new pairings:
-        CheckPairEventL();
+        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
@@ -718,9 +900,10 @@
         TRACE_BDADDR( dev.Address() );
         if ( newPaired && !iPairer)
             {
+            iPairingOperationAttempted = ETrue;
             iPairer = CBTEngIncPair::NewL( *this, dev.Address() );
             }
-        if ( iPairer )
+        if ( newPaired && iPairer )
             {
             // Ask pair handler to decide what to do:
             iPairer->HandleRegistryNewPairedEvent( dev );