/*
* ============================================================================
* 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 );
}