bluetoothengine/btnotif/btnotifsrv/src/btnotifconnection.cpp
changeset 29 48ae3789ce00
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothengine/btnotif/btnotifsrv/src/btnotifconnection.cpp	Mon May 03 14:36:07 2010 +0300
@@ -0,0 +1,964 @@
+/*
+* ============================================================================
+*  Name        : btnotifconnection.cpp
+*  Part of     : bluetoothengine / btnotif
+*  Description : Class for observing events of a single connection, and for 
+*                managing any user notifications related to the connection.
+*
+*  Copyright © 2009 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:
+*  Nokia Corporation
+* ============================================================================
+* Template version: 4.1
+*/
+
+#include "btnotifconnection.h"
+#include <btextnotifiers.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <btextnotifierspartner.h>
+#endif
+
+#include "btnotifconnectiontracker.h"
+#include "btnotifpairinghelper.h"
+#include "btnotificationmanager.h"
+#include "btnotifclientserver.h"
+#include "bluetoothtrace.h"
+
+/**  Id for the baseband connection watcher active object. */
+const TInt KConnectionWatcher = 40;
+/**  Id for the registry watcher active object. */
+const TInt KRegistryWatcher = 41;
+/**  Id for the active object for updating the registry. */
+const TInt KRegistryRetriever = 42;
+/**  Event mask for subscribing to baseband connection events  
+ * (need to check if these are appropriate). */
+const TInt KBbEventMask = ENotifyAnyRole | ENotifyAuthenticationComplete |
+    ENotifyPhysicalLinkUp | ENotifyPhysicalLinkDown | ENotifyPhysicalLinkError;
+
+
+// ======== LOCAL FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Decide the device name to display from the device information, and 
+// converts the name if necessary.
+// ---------------------------------------------------------------------------
+//
+void GetDeviceNameL( TBTDeviceName& aName, const CBTDevice& aDevice )
+    {
+    if( aDevice.IsValidFriendlyName() )
+        {
+        aName.Copy( aDevice.FriendlyName() );
+        }
+    else
+        {
+        aName.Zero();
+        if( aDevice.IsValidDeviceName() )
+            {
+            aName = BTDeviceNameConverter::ToUnicodeL( aDevice.DeviceName() );
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// Compare 2 device records device pairing has succeeded.
+// aDev2 is the updated device record, aDev1 is the previous record.
+// ---------------------------------------------------------------------------
+//
+TBool CheckRegistryPairedStatus( const CBTDevice* aOrig, const CBTDevice* aNew )
+    {
+    TBool result = EFalse;
+    // Use the device class to check that this has any valid information.
+    if( aOrig->AsNamelessDevice().IsValidDeviceClass() &&
+        !( aOrig->IsValidPaired() && aOrig->IsPaired() ) ||
+        aOrig->LinkKeyType() == ELinkKeyUnauthenticatedUpgradable )
+        {
+        // Only consider the result if the original device is not marked as paired.
+        if( aNew->IsValidPaired() && aNew->IsPaired() && aNew->IsValidLinkKey() && 
+            aNew->LinkKeyType() != ELinkKeyUnauthenticatedUpgradable )
+            {
+            // The new device record has valid pairing information, so
+            // this device is now paired.
+            result = ETrue;
+            }
+        }
+    return result;
+    }
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// C++ default constructor
+// ---------------------------------------------------------------------------
+//
+CBTNotifConnection::CBTNotifConnection(  const TBTDevAddr& aAddr,
+    CBTNotifConnectionTracker* aTracker )
+:   iAddr( aAddr ),
+    iTracker( aTracker )
+    {
+    }
+
+
+// ---------------------------------------------------------------------------
+// Symbian 2nd-phase constructor
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::ConstructL()
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    iDevice = CBTDevice::NewL( iAddr );
+    iPhyActive = CBtSimpleActive::NewL(*this, KConnectionWatcher );
+    iRegActive = CBtSimpleActive::NewL( *this, KRegistryRetriever );
+    // ToDo: need to check if this succeeds if a connection is 
+    // being created, in case of outgoing pairing.
+    User::LeaveIfError( iPhyLink.Open( iTracker->SocketServerSession(), iAddr ) );
+    // Subscribe to events.
+    iBasebandEvent.FillZ(); // To be sure that we are not reading false events.
+    iPhyLink.NotifyNextBasebandChangeEvent( iBasebandEvent,
+                iPhyActive->RequestStatus(), KBbEventMask );
+    iPhyActive->GoActive();
+    // Get the details from BT registry
+    TBTRegistrySearch pattern;
+    pattern.FindAddress( iAddr );
+    User::LeaveIfError( iRegistry.Open( iTracker->RegistryServerSession() ) );
+    iRegistry.CreateView( pattern, iRegActive->RequestStatus() );
+    iRegActive->GoActive();
+    iCurrentOp = EReadingRegistry;
+    iRegDevArray  = new CBTDeviceArray(1);  // only 1 entry ever used
+    // ToDo: more initialization needed?
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// NewLC.
+// ---------------------------------------------------------------------------
+//
+CBTNotifConnection* CBTNotifConnection::NewLC( const TBTDevAddr& aAddr,
+    CBTNotifConnectionTracker* aTracker )
+    {
+    CBTNotifConnection* self = new( ELeave ) CBTNotifConnection( aAddr, aTracker );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CBTNotifConnection::~CBTNotifConnection()
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    if( iNotification )
+        {
+        // Clear the notification callback, we cannot receive them anymore.
+        iNotification->RemoveObserver();
+        iNotification->Close(); // Also dequeues the notification from the queue.
+        iNotification = NULL;
+        }
+    delete iRegActive;
+    delete iRegistryResponse;
+    iRegistry.Close();
+    delete iDevMan;
+
+    delete iPhyActive;
+    iPhyLink.Close();
+    delete iDevice;
+    delete iPairingHelper;
+
+    while( iMsgHandleQ.Count() )
+        {
+        CompleteClientRequest( KErrDisconnected, KNullDesC8 );
+        }
+    iMsgHandleQ.Close();
+    iAcceptedConnections.Close();
+    iDeniedConnections.Close();
+    iRegDevArray->ResetAndDestroy(); 
+    delete iRegDevArray;
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Check what to do next.
+// This function should be called whenever we may be ready for the next
+// request/action, which is from any callback function i.e. 
+// MBAORequestCompletedL, MBRNotificationClosed, HandleNotifierRequestL and
+// CancelNotifierRequestL.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::CheckNextOperationL()
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    if( iCurrentOp == EIdle )
+        {
+        // Check the link state, to see if it has gone down already.
+        TUint32 linkState = 0;
+        TInt err = iPhyLink.PhysicalLinkState( linkState );
+        TBool linkDown = linkState & ENotifyPhysicalLinkDown;
+        if( ( !err && linkDown ) || err == KErrDisconnected )
+            {
+            // The link state tells us that the link is down,
+            // inform the connection tracker the we are done.
+            iTracker->HandleLinkCountChangeL();
+            // Note that we may be deleted now!
+            }
+        else if( iMsgHandleQ.Count() )
+            {
+            // Get the next request and handle it.
+            // ToDo: differentiate between notifier and pairing message!
+            const RMessage2* message = iTracker->Server()->FindMessageFromHandle( iMsgHandleQ[0] );
+            NOTIF_NOTHANDLED( message )
+            TInt opcode = message->Function();
+            if( opcode <= EBTNotifUpdateNotifier )
+                {
+                TBuf8<0x250> paramsBuf;    // Size needs to be long enough to read all possible parameter sizes.
+                message->ReadL( EBTNotifSrvParamSlot, paramsBuf );
+                HandleNotifierRequestL( paramsBuf, *message );
+                }
+            else
+                {
+                iMsgHandleQ.Remove( 0 );
+                StartBondingL( *message );
+                }
+            }
+        }
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Complete the first outstanding client request and removes it from the queue.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::CompleteClientRequest( TInt aReason, const TDesC8& aReply )
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    NOTIF_NOTHANDLED( iMsgHandleQ.Count() )
+    TInt err = iTracker->Server()->CompleteMessage( iMsgHandleQ[0], aReason, aReply );
+    NOTIF_NOTHANDLED( !err )
+    iMsgHandleQ.Remove( 0 );
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Distinguish a request and pass to corresponding handle.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::HandleNotifierRequestL( const TDesC8& aParams,
+    const RMessage2& aMessage )
+    {
+    BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aMessage.Int0() );
+    if( !iMsgHandleQ.Count() || iMsgHandleQ[0] != aMessage.Handle() )
+        {
+        // If we are processing a queued request, we of course don't queue 
+        // it again. In that case we are handling the first request from the queue.
+        iMsgHandleQ.AppendL( aMessage.Handle() );
+        }
+    if( iCurrentOp == EIdle || iCurrentOp == EBonding )
+        {
+        // ToDo: check non-pairing operation when bonding
+        TInt uid = aMessage.Int0();
+        if( uid == KBTManAuthNotifierUid.iUid )
+            {
+            HandleAuthorizationReqL( aParams );
+            }
+        else if( uid == KBTManPinNotifierUid.iUid ||
+                 uid == KBTPinCodeEntryNotifierUid.iUid ||
+                 uid == KBTNumericComparisonNotifierUid.iUid ||
+                 uid == KBTPasskeyDisplayNotifierUid.iUid )
+            {
+            if( !iPairingHelper )
+                {
+                BOstrace0( TRACE_NORMAL, DUMMY_DEVLIST, 
+                        "[BTNOTIF]\t CBTNotifConnection::HandleNotifierRequestL: creating CBTNotifPairingHelper");
+                iPairingHelper = CBTNotifPairingHelper::NewL( this, iTracker );
+                }
+            if( iCurrentOp != EBonding  )
+                {
+                iCurrentOp = EPairing;
+                }
+            iPairingHelper->StartPairingNotifierL( uid, aParams );
+            }
+        // We may be done with the current request, proceed to the next one
+        CheckNextOperationL();
+        }
+    BOstraceFunctionExit1( DUMMY_DEVLIST, this );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Update a notifier, update the outstanding dialog if the notifier request 
+// is currently being served.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::HandleNotifierUpdateL( const TDesC8& aParams,
+    const RMessage2& aMessage )
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    NOTIF_NOTHANDLED( iCurrentOp != EIdle )
+    (void) aParams;
+    TBuf8<0x250> paramsBuf;    // Size needs to be long enough to read all possible sizes.
+    aMessage.ReadL( EBTNotifSrvParamSlot, paramsBuf );
+    TInt uid = aMessage.Int0();
+    if( uid == KBTManAuthNotifierUid.iUid )
+        {
+        TBTNotifierUpdateParams params;
+        TPckgC<TBTNotifierUpdateParams> paramsPckg( params );
+        paramsPckg.Set( paramsBuf );
+        // The result means result of conversion to unicode
+        if( !paramsPckg().iResult )
+            {
+            // Only update locally, registry will update us with the same info later on.
+            iDevice->SetDeviceNameL( BTDeviceNameConverter::ToUTF8L( paramsPckg().iName ) );
+            if( iNotification )
+                {
+                // Update the dialog with the new name. It is up to the dialog to 
+                // determine the validity (in case another dialog is shown).
+                //iNotification->Update(  )
+                }
+            }
+        }
+    else if( iPairingHelper && ( uid == KBTPinCodeEntryNotifierUid.iUid ||
+             uid == KBTNumericComparisonNotifierUid.iUid ||
+             uid == KBTPasskeyDisplayNotifierUid.iUid ) )
+        {
+        // Just forward to pairing helper
+        iPairingHelper->UpdatePairingNotifierL( uid, paramsBuf );
+        }
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Cancel a request, dismiss the outstanding dialog if the notifier request 
+// is currently being served.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::CancelNotifierRequestL( const RMessage2& aMessage )
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    NOTIF_NOTHANDLED( iCurrentOp != EIdle )
+    TInt pos = iMsgHandleQ.Find( aMessage.Handle() );
+    if( pos > KErrNotFound )
+        {
+        // We have queued the message, remove it from the queue.
+        iMsgHandleQ.Remove( pos );
+        // We use the supplied handle to remove it, as it may not be
+        // the first in the queue.
+        TInt err = iTracker->Server()->CompleteMessage( aMessage.Handle(), KErrCancel, KNullDesC8 );
+        NOTIF_NOTHANDLED( !err )
+        if( pos == 0 )
+            {
+            // There could be the case that we are still post-processing
+            // the previous request (e.g. blocking query), then the next
+            // notification is not yet started but the first in the queue.
+            // We can see that from the current operation type.
+            if( iNotification && iCurrentOp < EAdditionalNotes )
+                {
+                // Cancel the user query
+                // This will also unregister us from the notification.
+                TInt err = iNotification->Close();
+                NOTIF_NOTHANDLED( !err )
+                iNotification = NULL;
+                iCurrentOp = EIdle;
+                }
+            if( iPairingHelper )
+                {
+                // The pairing helper calls back PairingCompleted and sets state.
+                iPairingHelper->CancelPairingNotifierL( aMessage.Int0() );
+                // The pairing helper may have now been deleted.
+                }
+            }
+        }
+    // We may be done with the current request, proceed to the next one
+    CheckNextOperationL();
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Start a bonding operation with the remote device.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::StartBondingL( const RMessage2& aMessage )
+    {
+    BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aMessage.Function() );
+    if( iCurrentOp == EIdle || iCurrentOp > EInternalOperations )
+        {
+        __ASSERT_ALWAYS( !iPairingHelper, PanicServer( EBTNotifPanicBadState ) );
+        iPairingHelper = CBTNotifPairingHelper::NewL( this, iTracker );
+        // The pairingg helper stored the handle, not in our queue here.
+        // This is because bonding will generate a pairing notifier request, which 
+        // will be completed first. The bookkeeping gets complicated if we have to
+        // re-order the queue here.
+        iPairingHelper->StartBondingL( aMessage.Handle() );
+        iCurrentOp = EBonding;
+        }
+    else if( iCurrentOp == EPairing || iCurrentOp == EBonding )
+        {
+        // We only do one pairing at the time.
+        User::Leave( KErrInUse );
+        }
+    else
+        {
+        // We only store it here if it is not handled immediately.
+        iMsgHandleQ.AppendL( aMessage.Handle() );
+        }
+    BOstraceFunctionExit1( DUMMY_DEVLIST, this );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Cancel an ongoing bonding operation with the remote device.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::CancelBondingL()
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    if( iPairingHelper )
+        {
+        iPairingHelper->CancelBondingL();
+        }
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// The pairing handler has completed a pairing operation.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::PairingCompleted()
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    __ASSERT_ALWAYS( iPairingHelper, PanicServer( EBTNotifPanicNullMember ) );
+    if( iPairingHelper->CurrentOperation() == CBTNotifPairingHelper::EIdle )
+        {
+        // We are still idle. Remove the pairing helper
+        delete iPairingHelper;
+        iPairingHelper = NULL;
+        }
+    if( iCurrentOp == EPairing || iCurrentOp == EBonding )
+        {
+        iCurrentOp = EIdle;
+        TRAP_IGNORE( CheckNextOperationL() );
+        }
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Process a new pairing result, and determine if we need to show 
+// anything to the user.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::PairingResult( TInt aError )
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    if( !iPairingHelper )
+        {
+        TRAP_IGNORE( iPairingHelper = CBTNotifPairingHelper::NewL( this, iTracker ) );
+        }
+    if( iPairingHelper )
+        {
+        iPairingHelper->HandleAuthenticationCompleteL( aError );
+        }
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Process the new service-level connection, and determine if we need to
+// show anything to the user.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::ServiceConnectedL( TBTProfile aProfile )
+    {
+    (void) aProfile;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Process the new service-level disconnection, and determine if we need to
+// show anything to the user.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::ServiceDisconnectedL( TBTProfile aProfile )
+    {
+    (void) aProfile;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Ask the user if he/she wants to block future connection requests. 
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::LaunchBlockingQueryL()
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    iCurrentOp = EBlocking;
+    TBTDialogResourceId resourceId = EBlockUnpairedDevice;
+    if( iDevice->IsValidPaired() && iDevice->IsPaired() &&
+        iDevice->LinkKeyType() != ELinkKeyUnauthenticatedUpgradable )
+        {
+        resourceId = EBlockPairedDevice;
+        }
+    PrepareNotificationL( TBluetoothDialogParams::EQuery, resourceId );
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Modify the record for the remote device in BTRegistry, with the changes 
+// already made in the local record.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::UpdateRegistryEntryL()
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    // We use CBTEngDevMan here. We could use the registry API directly, however,
+    // using this convenience API makes the registry processing much simpler.
+    if( !iDevMan )
+        {
+        iDevMan = CBTEngDevMan::NewL( this );
+        }
+    iDevMan->ModifyDevice( *iDevice );
+    if( iCurrentOp == EIdle ||
+        ( ( iCurrentOp == EPairing || iCurrentOp == EBonding ) &&
+          iPairingHelper->CurrentOperation() == CBTNotifPairingHelper::EIdle ) )
+        {
+        // To make sure that we don't get deleted while updating.
+        iCurrentOp = EUpdatingRegistry;
+        }
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+// ---------------------------------------------------------------------------
+// Modify the record for the remote device in BTRegistry, if aTrusted == true, then
+// update trusted status after reading device info from registry
+//
+// ---------------------------------------------------------------------------
+
+void CBTNotifConnection::UpdateRegistryEntryL( TBool aTrusted )
+    {
+    BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aTrusted );
+    if (!aTrusted) {
+        UpdateRegistryEntryL();
+        return;
+        }
+    // We use CBTEngDevMan here. We could use the registry API directly, however,
+    // using this convenience API makes the registry processing much simpler.
+    if( !iDevMan )
+        {
+        iDevMan = CBTEngDevMan::NewL( this );
+        }
+    // first read device info from registry, to make sure we have up-to-date local info
+    iCurrentOp = EReadingRegistry;
+    GetDeviceFromRegistry( iDevice->BDAddr() );
+    BOstraceFunctionExit1( DUMMY_DEVLIST, this );
+    }
+
+// ---------------------------------------------------------------------------
+// From class MBTNotificationResult.
+// Handle a result from a user query.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::MBRDataReceived( CHbSymbianVariantMap & aData )
+    {
+    (void) aData;
+    NOTIF_NOTIMPL
+    }
+
+
+// ---------------------------------------------------------------------------
+// From class MBTNotificationResult.
+// The notification is finished.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::MBRNotificationClosed( TInt aError, const TDesC8& aData )
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    // ToDo: call leaving function from here!
+    __ASSERT_ALWAYS( iCurrentOp != EIdle, PanicServer( EBTNotifPanicBadState ) );
+    // First unregister from the notification, so we can already get the next one.
+    iNotification->RemoveObserver();
+    iNotification = NULL;
+    TRAP_IGNORE( NotificationClosedL( aError, aData ) );
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// From class MBtSimpleActiveObserver.
+// Handle the active object completion.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::RequestCompletedL( CBtSimpleActive* aActive,
+    TInt aStatus )
+    {
+    BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, aActive->RequestId() );
+    switch( aActive->RequestId() )
+        {
+        case KRegistryRetriever:
+            {
+            BOstrace0( TRACE_NORMAL, DUMMY_DEVLIST,  
+                    "[BTNOTIF]\t CBTNotifConnection::MBAORequestCompletedL: KRegistryRetriever" );
+            if( !iRegistryResponse )
+                {
+                // We have just created the view, now get the results.
+                // There can only be one result, as the address is unique.
+                // (note: how about LE random addresses?)
+                // Or then we have tried to re-open an existing view, so we get KErrInuse.
+                // We anyway just get the results.
+                __ASSERT_ALWAYS( aStatus < 2, PanicServer( EBTNotifPanicCorrupt ) );
+                iRegistryResponse = CBTRegistryResponse::NewL( iRegistry );
+                iRegistryResponse->Start( iRegActive->RequestStatus() );
+                iRegActive->GoActive();
+                }
+            else
+                {
+                if( !aStatus )
+                    {
+                    // There can be only one result.
+                    __ASSERT_ALWAYS( iRegistryResponse->Results().Count() == 1, PanicServer( EBTNotifPanicCorrupt ) );
+                    CBTDevice* regDevice = iRegistryResponse->Results()[0];
+                    TBool paired = CheckRegistryPairedStatus( iDevice, regDevice );
+                    iDevice->UpdateL( *regDevice );
+                    if( paired )
+                        {
+                        __ASSERT_ALWAYS( iPairingHelper, PanicServer( EBTNotifPanicNullMember ) );
+                        iPairingHelper->HandleAuthenticationCompleteL( KErrNone );
+                        }
+                    }
+                // ToDo: error handling of registry response result?
+                delete iRegistryResponse;
+                iRegistryResponse = NULL;
+                }
+            if( iCurrentOp == EReadingRegistry && !iRegActive->IsActive() )
+                {
+                // If this is part of the sequence of operations, we are done.
+                // Otherwise we just update with the latest info from registry,
+                // and then we don't interrupt or change the state.
+                iCurrentOp = EIdle;
+                }
+            }
+            // ToDo: start registry watching (preferably using registry API when this is available)
+           break;
+       case KRegistryWatcher:
+           {
+           BOstrace0( TRACE_NORMAL, DUMMY_DEVLIST,  
+                   "[BTNOTIF]\t CBTNotifConnection::MBAORequestCompletedL: KRegistryWatcher" );
+           NOTIF_NOTHANDLED( !aStatus )
+           // Ignore updates while we are already retrieving.
+           if( !iRegActive->IsActive() )
+               {
+               // Refresh our information with the latest from registry
+               iRegActive->SetRequestId( KRegistryRetriever );
+               TBTRegistrySearch pattern;
+               pattern.FindAddress( iAddr );
+               iRegistry.CreateView( pattern, iRegActive->RequestStatus() );
+               iRegActive->GoActive();
+               }
+           }
+           break;
+        case KConnectionWatcher:
+            {
+            BOstrace0( TRACE_NORMAL, DUMMY_DEVLIST, 
+                    "[BTNOTIF]\t CBTNotifConnection::MBAORequestCompletedL: KConnectionWatcher" );
+            TUint32 event = iBasebandEvent().EventType();
+            // First subscribe to the next event notification.
+            // This will overwrite iBasebandEvent().EventType() with KBbEventMask
+            iPhyLink.NotifyNextBasebandChangeEvent( iBasebandEvent,
+                        iPhyActive->RequestStatus(), KBbEventMask );
+            iPhyActive->GoActive();
+            // Link down and link error are handled in CheckNextOperationL below.
+            // ToDo: handle events!
+            if( event & ( ENotifyPhysicalLinkDown | ENotifyPhysicalLinkError ) )
+                {
+                // We re-use the error code to store the indication that the 
+                // link has disconnected. This will only be overridden by next 
+                // event, which can only be a connection up event.
+                iBasebandEvent().SetErrorCode( KErrDisconnected );
+                }
+            if( iPairingHelper )
+                {
+                if( event & ( ENotifyPhysicalLinkDown | ENotifyPhysicalLinkError |
+                    ENotifyAuthenticationComplete ) )
+                    {
+                    // Results interesting for pairing result processing.
+                    iPairingHelper->HandleAuthenticationCompleteL( iBasebandEvent().SymbianErrorCode() );
+                    }
+                else if( event & ENotifyPhysicalLinkUp &&
+                        iPairingHelper->CurrentOperation() == CBTNotifPairingHelper::EDedicatedBonding )
+                    {
+                    iPairingHelper->StartBondingL( 0 );
+                    }
+                }
+            }
+            break;
+        default:
+            PanicServer( EBTNotifPanicBadState );
+            break;
+        }
+    // We may be done with the current request, proceed to the next one
+    CheckNextOperationL();
+    BOstraceFunctionExit1( DUMMY_DEVLIST, this );
+    }
+
+
+// ---------------------------------------------------------------------------
+// From class MBtSimpleActiveObserver.
+// Cancel and clean up all requests related to the active object.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::CancelRequest( TInt aRequestId )
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    if ( aRequestId == KConnectionWatcher )
+        {
+        iPhyLink.CancelNextBasebandChangeEventNotifier();
+        }
+    else if ( aRequestId == KRegistryWatcher && iRegistryResponse )
+        {
+        iRegistryResponse->Cancel();
+        }
+    else if ( aRequestId == KRegistryRetriever )
+        {
+        iRegistry.CancelRequest( iRegActive->RequestStatus());
+        }    
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+// ---------------------------------------------------------------------------
+// From class MBtSimpleActiveObserver.
+// 
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::HandleError( CBtSimpleActive* aActive, 
+        TInt aError )
+    {
+    (void) aActive;
+    (void) aError;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MBTEngDevmanObserver.
+// Registry modification has completed.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::HandleDevManComplete( TInt aErr )
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    (void) aErr;
+    NOTIF_NOTHANDLED( !aErr )
+    if( iCurrentOp == EUpdatingRegistry )
+        {
+        // To make sure that we don't get deleted while updating.
+        iCurrentOp = EIdle;
+        }
+    // Refresh is done separately, we will get notified through 
+    // the registry watcher of the change.
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// From class MBTEngDevmanObserver.
+// Callback for getting a device from the registry
+//
+// Currently only used in context of setting device to trusted
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::HandleGetDevicesComplete( 
+        TInt err, CBTDeviceArray* deviceArray ) 
+    {
+    BOstraceFunctionEntryExt( DUMMY_DEVLIST, this, err );
+    // err is not used here very much, -1 could be returned if there is no device in registry,
+    // but this case is covered by examing mRegDevArray.
+    if (!err && (iCurrentOp == EReadingRegistry) ) {
+        CBTDevice* dev (0);
+        if ( deviceArray->Count() ) {
+            dev = deviceArray->At( 0 );
+            }
+        if ( dev ) {
+            iDevice = dev->CopyL();
+            }
+        // Set device to trusted
+        // Copy the existing security settings.
+        TBTDeviceSecurity sec( iDevice->GlobalSecurity().SecurityValue(),
+                      iDevice->GlobalSecurity().PasskeyMinLength() );
+        sec.SetNoAuthorise( ETrue );  // new value:  set device as trusted
+        iDevice->SetGlobalSecurity( sec );
+        iDevMan->ModifyDevice( *iDevice );   // write trusted (& paired) status to registry
+        // To make sure that we don't get deleted while updating.
+        iCurrentOp = EUpdatingRegistry;
+        }
+    BOstraceFunctionExit1( DUMMY_DEVLIST, this );
+    }
+
+// ---------------------------------------------------------------------------
+// Retrieves device from registry based on BT address parameter
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::GetDeviceFromRegistry( const TBTDevAddr &addr )
+{
+    BOstraceFunctionEntry1( DUMMY_DEVLIST, this );
+    TBTRegistrySearch searchPattern;
+    searchPattern.FindAddress( addr );
+    // and get this device from registry
+    iRegDevArray->ResetAndDestroy();
+    iDevMan->GetDevices(searchPattern, iRegDevArray);
+    BOstraceFunctionExit1( DUMMY_DEVLIST, this );
+}
+
+// ---------------------------------------------------------------------------
+// Get and configure a notification.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::PrepareNotificationL( TBluetoothDialogParams::TBTDialogType aType,
+    TBTDialogResourceId aResourceId )
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    iNotification = iTracker->NotificationManager()->GetNotification();
+    User::LeaveIfNull( iNotification ); // For OOM exception, leaves with KErrNoMemory
+    iNotification->SetObserver( this );
+    iNotification->SetNotificationType( aType, aResourceId );
+    // Set the address of the remote device
+    TBuf<KBTDevAddrSize> addr;
+    addr.Copy( iAddr.Des() );
+    TInt err = iNotification->SetData( TBluetoothDialogParams::EAddress, addr );
+    NOTIF_NOTHANDLED( !err )
+    // Set the name of the remote device
+    TBTDeviceName name;
+    GetDeviceNameL( name, *iDevice );
+    // ToDo: handle leave in name conversion!
+    err = iNotification->SetData( (TInt) TBluetoothDeviceDialog::EDeviceName, name );
+    NOTIF_NOTHANDLED( !err )
+    // Queue the notification for displaying to the user
+    err = iTracker->NotificationManager()->QueueNotification( iNotification );
+    NOTIF_NOTHANDLED( !err )
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// The notification is finished, handle the result.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::NotificationClosedL( TInt aError, const TDesC8& aData )
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    switch( iCurrentOp )
+        {
+        case EAuthorizing:
+            CompleteAuthorizationReqL( aError, aData );
+            break;
+        case EBlocking:
+            CompleteBlockingReqL( aError, aData );
+            break;
+        default:
+            NOTIF_NOTIMPL
+            break;
+        }
+    // We may be done with the current request, proceed to the next one
+    CheckNextOperationL();
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Handle a request for authorization of this connection.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::HandleAuthorizationReqL( const TDesC8& aParams )
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    __ASSERT_ALWAYS( iCurrentOp == EIdle, PanicServer( EBTNotifPanicBadState ) );
+    __ASSERT_ALWAYS( !iNotification, PanicServer( EBTNotifPanicCorrupt ) );
+    TBTAuthorisationParams params;
+    TPckgC<TBTAuthorisationParams> paramsPckg( params );
+    paramsPckg.Set( aParams );
+    iCurrentOp = EAuthorizing;
+    // The name in the parameter package is the latest one, retrieved from 
+    // the remote device during this connection.
+    if( paramsPckg().iName.Length() )
+        {
+        // Update the local device record. No need to update the registry,
+        // that will be done by the stack, and we will receive the update 
+        // information when that has completed.
+        iDevice->SetDeviceNameL( BTDeviceNameConverter::ToUTF8L( paramsPckg().iName ) );
+        }
+    PrepareNotificationL( TBluetoothDialogParams::EQuery, EAuthorization );
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Process the user input and complete the outstanding authorization request. 
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::CompleteAuthorizationReqL( TInt aError, const TDesC8& aData )
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    // Set our state to idle for now. This may get changed if the user just chose 
+    // to block, or if we have a pending request.
+    iCurrentOp = EIdle;
+    if( !aError )
+        {
+        TPckgC<TBool> result( EFalse );
+        result.Set( aData );
+        TBool proceed = iTracker->UpdateBlockingHistoryL( iDevice, result() );
+        if( result() == EFalse && proceed )
+            {
+            // The user denied the connection, ask to block the device.
+            LaunchBlockingQueryL();
+            }
+        CompleteClientRequest( KErrNone, aData );
+        }
+    else
+        {
+        CompleteClientRequest( aError, KNullDesC8 );
+        }
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }
+
+
+// ---------------------------------------------------------------------------
+// Process the user input for blocking a device.
+// ---------------------------------------------------------------------------
+//
+void CBTNotifConnection::CompleteBlockingReqL( TInt aError, const TDesC8& aData )
+    {
+    BOstraceFunctionEntry0( DUMMY_DEVLIST );
+    TPckgC<TBool> result( EFalse );
+    result.Set( KNullDesC8 );    // to test!
+    result.Set( aData );
+    iCurrentOp = EIdle; // May get changed if we have a pending request.
+    if( !aError && result() )
+        {
+        // The user accepted to block this device.
+        TBTDeviceSecurity sec;  // use default values when setting as banned.
+        sec.SetBanned( ETrue );
+        iDevice->SetGlobalSecurity( sec );
+        if( iDevice->IsValidPaired() && iDevice->IsPaired() )
+            {
+            // Deleting the link key will also set the device as unpaired.
+            iDevice->DeleteLinkKey();
+            }
+        UpdateRegistryEntryL();
+        }
+    BOstraceFunctionExit0( DUMMY_DEVLIST );
+    }