diff -r 000000000000 -r 29b1cd4cb562 bluetoothcommsprofiles/btpan/panagt/panagtremdevselector.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetoothcommsprofiles/btpan/panagt/panagtremdevselector.cpp Fri Jan 15 08:13:17 2010 +0200 @@ -0,0 +1,292 @@ +// Copyright (c) 2004-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: +// +// Description: +// + +#include +#include +#include +#include "panagtlog.h" +#include "panagtremdevselector.h" +using namespace PanAgent; + +#ifdef __FLOG_ACTIVE +_LIT8(KLogComponent, LOG_COMPONENT_PAN_AGENT); +#endif + +CPanRemoteDeviceSelector::CPanRemoteDeviceSelector( + MOutgoingConnectionCreator& aOutgoingConnectionCreator, CCommsDbAccess& aDatabase) : + CActive(KPanAgtAoRemoteDevicePromptPriority), + iOutgoingConnectionCreator(aOutgoingConnectionCreator), + iDatabase(aDatabase) +/** +Store all the pointers and chuck ourselves on the active scheduler +*/ + { + CActiveScheduler::Add(this); + } + +CPanRemoteDeviceSelector::~CPanRemoteDeviceSelector() + { + iDevAddresses.Close(); + } + +void CPanRemoteDeviceSelector::PerformRemoteDeviceSelectionL() +/** +Find out whether there are any remote devices in commdb, or whether we should be prompting +(or whether we should just do nothing) +*/ + { + LOG(_L("RemDevSelector: Deciding which device to connect to.")); + TInt err; + + TBool prompt; + iDatabase.GetBoolL(TPtrC(PAN_SERVICE_EXTENSIONS), TPtrC(PAN_PROMPT_FOR_REMOTE_DEVICES), prompt); + + LOG1(_L("RemDevSelector: prompt mode is %d..."), prompt); + + if (prompt) + { + LOG(_L("RemDevSelector: ...starting notifier...")); + + // Check if we're already prompting for devices. + if (IsPrompting()) + { + User::Leave(KErrInUse); + } + + User::LeaveIfError(err = iNotifier.Connect()); + iNotifier.StartNotifierAndGetResponse(iStatus, KBTPanDeviceSelectionNotifierUid, KNullDesC8, iDeviceList); + iState = EWaitingForNotifier; + SetActive(); + return; + } + + // If we've got here, we aren't allowed to prompt until we've tried to connect to a fixed set of devices. + LOG(_L("RemDevSelector: ...reading address(es) from commdb...")); + + TRAP(err, iDatabase.GetBoolL(TPtrC(PAN_SERVICE_EXTENSIONS), TPtrC(PAN_PROMPT_IF_MAC_LIST_FAILS), iPromptIfMACFails)); + if (err) + { + iPromptIfMACFails = EFalse; + } + LOG1(_L("RemDevSelector: prompt fallback set to %d"), iPromptIfMACFails); + + TBuf remoteDeviceAddressList; + TRAP(err, iDatabase.GetDesL(TPtrC(PAN_SERVICE_EXTENSIONS), TPtrC(PAN_PEER_MAC_ADDRESSES), remoteDeviceAddressList)); + + // Parse buffer from commdb + if((remoteDeviceAddressList.Length()) && !err) // firstly make sure there's something in the buffer + { + LOG1(_L("RemDevSelector: ...commdb buffer is %d bytes long..."), remoteDeviceAddressList.Length()); + + ConvertListToArray(remoteDeviceAddressList); + //Connect only to one of the devices at a time. + } + + if (HasMoreDevices()) + { + CreateNextConnectionL(); + } + else + { + if(err) + { + LOG1(_L("RemDevSelector: ...reading device addressses from commdb failed with %d, and prompt mode disabled. Giving up - this must be a listen only connection, or someone's screwed up the commdb settings."), err); + } + else + { + LOG(_L("RemDevSelector: ...no device addresses in commdb, and prompt mode disabled. Giving up - this must be a listen only connection, or someone's screwed up the commdb settings.")); + } + } + } + + +/** +Called by the PanAgent upon disconnection (before PAN connection is up) to see if +there is more devices it can try to connect +*/ +TBool CPanRemoteDeviceSelector::HasMoreDevices() + { + return iPromptIfMACFails || (iDevAddresses.Count() > 0); + } + +/** +Called by the PanAgent upon device active to prevent PanAgent from trying the next +device upon disconnection of a successful PAN connection. +*/ +void CPanRemoteDeviceSelector::Reset() + { + iDevAddresses.Reset(); + } + +void CPanRemoteDeviceSelector::RunL() +/** +Prompt has completed. We assume the user want to connect to all of them if multiple +devices are selected. +*/ + { + switch(iState) + { + case EWaitingForNotifier: + { + LOG1(_L("RemDevSelector: ...notifier completed with %d"), iStatus.Int()); + TInt err = iNotifier.CancelNotifier(KBTPanDeviceSelectionNotifierUid); + LOG1(_L("RemDevSelector: ...CancelNotifier completed with %d"), err); + + if(iStatus==KErrNone) + { + TBTDevAddr devAddr; + err = iDeviceList.GetDevice(devAddr); + while(err==KErrNone) + { + TRAP(err, iOutgoingConnectionCreator.CreateNewConnectionForOutgoingL(devAddr)); + if(err) // might be that device is connected already, or a more general error + { + err = iOutgoingConnectionCreator.DeviceSelectionError(err); // replace one err with anoth-err + if(err==KErrDisconnected) // we've decided to disconnect + { + return; + } + } + err = iDeviceList.GetDevice(devAddr); + } + iDeviceList.Reset(); + } + else + { + if (iStatus==KErrCancel) + { + // The user has rejected the remote device(s) by cancelling the selector, + // but in order that CNifSession::DecideWhetherToRetry() will respond to + // this action by going to the next IAP in its connection preference list, + // we need to change the reported error... + iStatus = KErrCouldNotConnect; + } + + iOutgoingConnectionCreator.DeviceSelectionError(iStatus.Int()); + return; + } + break; + } + case ENotWaiting: + // fall through + default: + { + PanAgentPanic(EAsyncOperationOnOutgoingConnectionStarterWhenItsNotPerformingAnAsyncRequest); + } + } + } + +TBool CPanRemoteDeviceSelector::IsPrompting() +/** +Is there currently a prompt on screen? +*/ + { + return((iState==EWaitingForNotifier)&&IsActive()); + } + +void CPanRemoteDeviceSelector::DoCancel() +/** + +*/ + { + switch(iState) + { + case EWaitingForNotifier: + { + iNotifier.CancelNotifier(KBTPanDeviceSelectionNotifierUid); + break; + } + case ENotWaiting: + // fall through + default: + { + PanAgentPanic(EAsyncOperationOnOutgoingConnectionStarterWhenItsNotPerformingAnAsyncRequest); + break; + } + } + } + +void CPanRemoteDeviceSelector::ConvertListToArray(TDesC& aDeviceAddrList) +/** +Put the comma-separated list of readable BT device addresses into an array +*/ + { + TBTDevAddr devAddr; + TLex lex(aDeviceAddrList); + + TChar charComma(','); // this weird construct is needed to prevent us needing static data + while(lex.Peek()!=charComma && !lex.Eos()) + { + lex.Mark(); + while((lex.Get()!=charComma) && !lex.Eos()) + { + + } + devAddr.SetReadable(lex.MarkedToken()); + // RArrays default to a granularity of 8 and we only connect to one device + // at a time so it's reasonable to ignore this error, as a) in common use + // bluetooth piconet size can't go beyond 8 anyway and b) if we use up + // all the 8/16/... addresses in this array the user will be prompted for + // more (although they probably won't have enough memory to make the + // connection anyway). + (void)iDevAddresses.Append(devAddr); + } + } + +/** +Connect to the first device in the address list and remove it from the list +*/ +void CPanRemoteDeviceSelector::CreateNextConnectionL() + { + //Assertion here is just for flusing out internal problems e.g. The notifier completes the + //Request with KErrNone while no devices are selected + __ASSERT_DEBUG(HasMoreDevices(), PanAgentPanic(EPanAgtRemDevSelectorNoDevicesToConnect)); + + // If we've run out of addresses in our list, CommsDat may be configured to allow us to ask + // the user for another device. + // In fact, if we're here and we have no devices, then we *MUST* be allowed to ask, as this + // will have already been checked. So we can assume the prompt flag without having to check. + if (!iDevAddresses.Count()) + { + iPromptIfMACFails = EFalse; // To maintain symmetry with the consumption of the remote list, clear this flag. + + LOG(_L("RemDevSelector: ...starting notifier (empty devices list or no more remaining)...")); + + // Check if we're already prompting for devices. + if (IsPrompting()) + { + User::Leave(KErrInUse); + } + + User::LeaveIfError(iNotifier.Connect()); + iNotifier.StartNotifierAndGetResponse(iStatus, KBTPanDeviceSelectionNotifierUid, KNullDesC8, iDeviceList); + iState = EWaitingForNotifier; + SetActive(); + return; + } + + + TBTDevAddr remDevAddr = iDevAddresses[0]; + +#ifdef __FLOG_ACTIVE + TBuf tempDevAddrBuf; + remDevAddr.GetReadable(tempDevAddrBuf, KNullDesC, KBtAddrSeparator, KNullDesC); + LOG1(_L("RemDevSelector: Creating connection to new device, address: %S"), &tempDevAddrBuf); +#endif + + + iDevAddresses.Remove(0); + iOutgoingConnectionCreator.CreateNewConnectionForOutgoingL(remDevAddr); + }