bluetooth/btexample/testui/BTTextNotifiers/src/BTManDeviceScanner.cpp
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btexample/testui/BTTextNotifiers/src/BTManDeviceScanner.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,533 @@
+// Copyright (c) 2000-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 "BTTextNotifiers.h"
+#include <btdevice.h>
+#include <e32cons.h>
+#include <es_sock.h>
+#include <bt_sock.h>
+#include <btextnotifiers.h>
+#include <bluetooth/logger.h>
+#include <e32keys.h>
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, "TextNotifiers");
+#endif
+
+void CBTManDeviceScanner::NotifyErrorL(TRefByValue<const TDesC> aErrorNotification)
+	{
+	LOG_FUNC
+	CConsoleBase* console = BTTextNotifiersConsole::AutoSizeNewL(_L("Device Selector"), TSize(50,2));
+	CleanupStack::PushL(console);
+	console->Printf(aErrorNotification);
+	console->Printf(_L("\nPress any key to continue"));
+	console->Getch();
+	CleanupStack::PopAndDestroy();
+	}
+
+void CBTManDeviceScanner::ResetDeviceLists()
+	{
+	LOG_FUNC
+	iDevices.ResetAndDestroy();
+	iDevices.Close();
+	
+	iNoNameDevices.ResetAndDestroy();
+	iNoNameDevices.Close();
+	}
+
+
+void CBTManDeviceScanner::EnsureConsoleExistsL()
+	{
+	LOG_FUNC
+	if(!iConsole)
+		{
+		StopWaitMessage();
+		iConsole = BTTextNotifiersConsole::AutoSizeNewL(_L("Device Selector"), TSize(70, 6+KMaxDeviceRows));
+		iConsole->Printf(iWaitMessage);
+		}
+	}
+
+void CBTManDeviceScanner::StartWaitMessageL()
+	{
+	LOG_FUNC
+	delete iWaitConsole;
+	iWaitConsole = 0;
+	iWaitConsole = BTTextNotifiersConsole::AutoSizeNewL(_L("Device Selector"), TSize(20,1));
+	iWaitConsole->Printf(iWaitMessage);
+	}
+
+void CBTManDeviceScanner::StopWaitMessage()
+	{
+	LOG_FUNC
+	delete iWaitConsole;
+	iWaitConsole = 0;
+	}
+
+void CBTManDeviceScanner::AddDiscoveredDeviceL(RBTDevices& aDeviceArray, const TNameEntry& aNameEntry)
+	{
+	LOG_FUNC
+	TInquirySockAddr& sa = TInquirySockAddr::Cast(aNameEntry().iAddr);
+	const TBTDevAddr& bdaddr = sa.BTAddr();
+	CBTDevice* device = CBTDevice::NewL(bdaddr);
+	CleanupStack::PushL(device);
+	
+	HBufC8* temp = HBufC8::NewLC(aNameEntry().iName.Length());	 // to convert iName to narrow
+	TPtr8 ptr=temp->Des();
+	ptr.Copy(aNameEntry().iName);
+
+	device->SetDeviceNameL(*temp);
+	TBTDeviceClass devClass(sa.MajorServiceClass(), 
+							sa.MajorClassOfDevice(), 
+							sa.MinorClassOfDevice());
+	device->SetDeviceClass(devClass);
+	User::LeaveIfError(aDeviceArray.Append(device));
+
+	CleanupStack::PopAndDestroy(1, temp);
+	CleanupStack::Pop(device);
+	}
+
+void CBTManDeviceScanner::SetupDeviceParams(RHostResolver aHr, TBTNamelessDevice& aDevInfo)
+	{
+	LOG_FUNC
+	SetupDeviceParams(_L(""), aDevInfo);
+	//iDevPms.SetDeviceAddress(aDevInfo.Addr());
+	//iDevPms.SetDeviceClass(aDevInfo.Class());
+	TInquirySockAddr addr;
+	addr.SetIAC(KGIAC);
+	TRequestStatus stat;
+	addr.SetAction(KHostResName);
+	addr.SetBTAddr(aDevInfo.Address());
+	TNameEntry entry;
+	aHr.GetByAddress(addr, entry, stat);
+	User::WaitForRequest(stat);
+	if (stat == KErrNone)
+		{
+		iDevPms.SetDeviceName(entry().iName);
+		}
+	}
+
+void CBTManDeviceScanner::SetupDeviceParams(const THostName& aName, TBTNamelessDevice& aDevInfo)
+	{
+	LOG_FUNC
+	iDevPms.SetDeviceAddress(aDevInfo.Address());
+	iDevPms.SetDeviceClass(aDevInfo.DeviceClass());
+	iDevPms.SetDeviceName(aName);
+	}
+
+void CBTManDeviceScanner::RubOutWaitMessage()
+	{
+	LOG_FUNC
+	TBuf<1> character;
+	if(iConsole->WhereX()||iConsole->WhereY())
+		{
+		TInt len = iWaitMessage.Length();
+		for(TInt i=0;i<len;++i)
+			{
+			character.SetLength(0);
+			character.Append(0x08);
+			iConsole->Printf(_L("%S"),&character);
+			}
+		}
+	}
+
+void CBTManDeviceScanner::PrintDiscoveredDevice()
+	{
+	LOG_FUNC
+
+	RubOutWaitMessage();
+	
+	const TBTDevAddr& bdaddr = iDevPms.BDAddr();
+	iConsole->Printf(_L("%d.\t0x%02x%02x%02x%02x%02x%02x\t"),
+						++iPrintedCounter,bdaddr[0],bdaddr[1],bdaddr[2],bdaddr[3],
+						bdaddr[4],bdaddr[5]);
+	if(!(iDevPms.DeviceName().Length()))
+		iConsole->Printf(_L("(No name found)\t"));
+	else
+		{
+		// need to widen it for displaying! just display 40 chars worth
+		TBuf<40> dispBuf;
+		dispBuf.Copy(iDevPms.DeviceName().Left(40));
+		iConsole->Printf(_L("\"%S\"\t"), &dispBuf);
+		}
+	iConsole->Printf(_L("0x%04x-"),iDevPms.DeviceClass().MajorServiceClass());
+	iConsole->Printf(_L("%02x-"),iDevPms.DeviceClass().MajorDeviceClass());
+	iConsole->Printf(_L("%02x\n"),iDevPms.DeviceClass().MinorDeviceClass());
+	iConsole->Printf(iWaitMessage);
+	}
+
+TBool CBTManDeviceScanner::DeviceNumberFromUserL(TBool allowMore)
+	{
+	LOG_FUNC
+	TBuf<3> numBuf;
+	TBuf<63> errStr;
+	errStr.SetLength(0);
+	numBuf.Zero();
+	TKeyCode code;
+	TBuf<1> character;
+
+	RubOutWaitMessage();
+	
+	TBuf<0x100> prompt(_L("\nIf the device you require appears above,\n\
+		\rselect the device number you require and THEN press 'Return'.\n\
+		\rIf not,  "));
+	if(allowMore)
+		{
+		prompt.SetLength(prompt.Length()-2);
+		prompt.Append(_L("\npress 'Esc' to abort or 'Return' to seek more devices.\n"));
+		iConsole->Printf(prompt);
+		}
+	else
+		{
+		prompt.SetLength(prompt.Length()-2);
+		prompt.Append(_L(" - THERE ARE NO MORE DEVICES - so\n\
+			\rpress 'Esc' to abort or 'Return' to ***REDO*** device inquiry.\n"));
+		iConsole->Printf(prompt);
+		}
+	FOREVER
+		{
+		code = iConsole->Getch();
+		if(!(numBuf.Length())&&code==EKeyEnter)
+			{
+			// No device number entered so this must be a redo device inquiry
+			iScanState = EScanStateUnfinished;
+			break;
+			}
+		if(!(numBuf.Length())&&code==EKeyBackspace)
+			{
+			// No device number entered so nothing to delete, just continue looking for input
+			continue;
+			}
+		if(!(code>=0x30&&code<=0x39)&&code!=EKeyEscape&&code!=EKeyEnter&&code!=EKeyBackspace)
+			{
+			// Not a valid number and not escape, enter or backspace, just continue looking for input
+			continue;
+			}
+		if(code==EKeyEscape)
+			{
+			// Escape is always abort regardless if a number has been entered
+			iScanState = EScanStateCancelled;
+			break;
+			}
+		character.SetLength(0);
+		character.Append(code);
+	
+		if (code == EKeyEnter)
+			{
+			// We must have a number at this point otherwise the enter key would have forced a
+			// redo inquiry above
+			TLex lex(numBuf);
+			TInt err = lex.Val(iChosenDeviceIndex, EDecimal);
+			User::LeaveIfError(err);
+			if(iChosenDeviceIndex<=iPrintedCounter&&
+				iChosenDeviceIndex>=((iPrintedCounter-1)/KMaxDeviceRows)*KMaxDeviceRows+1)
+				{
+				iScanState = EScanStateSelected;
+				break;
+				}
+			else
+				{
+				while((numBuf.Length() != 0))
+					{
+					character.SetLength(0);
+					character.Append(EKeyBackspace);
+					iConsole->Printf(_L("%S"),&character);
+					numBuf.SetLength((numBuf.Length()-1));
+					}
+				while((errStr.Length() != 0))
+					{
+					character.SetLength(0);
+					character.Append(EKeyBackspace);
+					iConsole->Printf(_L("%S"),&character);
+					errStr.SetLength((errStr.Length()-1));
+					}
+				errStr.Format(_L("Device %d does not exist! Please re-enter...."), iChosenDeviceIndex);
+				iConsole->Printf(_L("%S"), &errStr);
+				}
+			}
+		else if (code == EKeyBackspace)
+			{
+			// We must have a number at this point otherwise we would have asked for another key press
+			// above
+			iConsole->Printf(_L("%S"),&character);
+			numBuf.SetLength((numBuf.Length()-1));
+			}
+		else
+			{
+			if (numBuf.Length() < numBuf.MaxLength())
+				{
+				// Store the number
+				iConsole->Printf(_L("%S"),&character);
+				numBuf.Append(code);
+				}
+			}
+		}
+
+	delete iConsole;
+	iConsole = 0;
+
+	//return FALSE if scan not terminated (by cancelation or selection)
+	if(iScanState == EScanStateUnfinished)
+		{
+		StartWaitMessageL();
+		return EFalse;
+		}
+	return ETrue;
+	}
+
+TBool CBTManDeviceScanner::GetByScanL(TBTDevAddr& aBDAddr, 
+									  TBTDeviceName& aName, 
+									  TBTDeviceClass& aClass)
+	{
+ 	LOG_FUNC
+	StartWaitMessageL();
+    RSocketServ ss;
+	TInt ret=ss.Connect();
+	if(ret)
+		{
+		NotifyErrorL(_L("Internal error: unable to connect to outside socket."));
+		return EFalse;
+		}
+
+	RHostResolver hr;
+
+ 	TProtocolDesc pInfo;
+	// List out all the protocols
+ 	ret=ss.FindProtocol(_L("BTLinkManager"),pInfo);
+	if(ret)
+		{
+		NotifyErrorL(_L("Internal error: unable to find Bluetooth."));
+		ss.Close();
+		return EFalse;
+		}
+
+	ret = hr.Open(ss,pInfo.iAddrFamily,pInfo.iProtocol);
+	//ret = hr.Open(ss,KBTAddrFamily,KBTLinkManager);
+	if(ret)
+		{
+		NotifyErrorL(_L("Internal error: unable to find Bluetooth."));
+		ss.Close();
+		return EFalse;
+		}
+
+	iScanState = EScanStateUnfinished;
+	while(iScanState==EScanStateUnfinished)
+		{
+		iResultCountNoName = 0;
+		iResultCountWithName = 0;
+		iChosenDeviceIndex = 0;
+		iPrintedCounter = 0;
+		ResetDeviceLists();	
+
+		TInquirySockAddr addr;
+		addr.SetIAC(KGIAC);
+		TRequestStatus stat;
+		addr.SetAction(KHostResInquiry + KHostResName);	// Default: Both
+		TNameEntry entry;
+	
+		hr.GetByAddress(addr, entry, stat);
+		User::WaitForRequest(stat);
+
+		//Collect surrounding devices in a device array
+		iPrintedCounter = 0;
+		while (stat == KErrNone)
+			{
+			if(entry().iName.Length())
+				{
+				EnsureConsoleExistsL();
+				AddDiscoveredDeviceL(iDevices, entry);
+				SetupDeviceParams(entry().iName, (*iDevices[iResultCountWithName]).AsNamelessDevice());
+				PrintDiscoveredDevice();
+				iResultCountWithName++;
+				if(!(iPrintedCounter%KMaxDeviceRows))
+					if(CBTManDeviceScanner::DeviceNumberFromUserL(ETrue))
+						break;
+				}
+			else
+				{
+				// Don't add to the Devices list yet, add to a separate list for those
+				// who's name needs to be host resolve-d.
+				TNameEntry* copied = new(ELeave) TNameEntry();
+				CleanupStack::PushL(copied);
+				
+				(*copied)().iName = entry().iName; // should be 0 length
+				(*copied)().iAddr = entry().iAddr;
+				(*copied)().iFlags = entry().iFlags;
+				
+				User::LeaveIfError(iNoNameDevices.Append(copied));
+				CleanupStack::Pop(copied);
+				iResultCountNoName++;
+				}
+			if(iResultCountNoName+iResultCountWithName==999)
+				{
+				EnsureConsoleExistsL();
+				if(CBTManDeviceScanner::DeviceNumberFromUserL(EFalse))
+					//=>User has requested to see more devices
+					{
+					iScanState = EScanStateCancelled;//ensure do not search on unnamed devices
+					DisplayNoDeviceMessageL(ETrue);
+					}
+				break;
+				}
+			hr.Next(entry, stat);
+			User::WaitForRequest(stat);
+			}
+
+		addr.SetAction( KHostResName );
+		while(iResultCountNoName && iScanState==EScanStateUnfinished && 
+			  iPrintedCounter<(iResultCountWithName+iResultCountNoName))
+			{
+			EnsureConsoleExistsL();
+			//Should never happen....
+			if(iPrintedCounter<iResultCountWithName)
+				break;
+			
+			TNameEntry* noNameEntry = iNoNameDevices[iPrintedCounter-iResultCountWithName];
+			AddDiscoveredDeviceL(iDevices, *noNameEntry);
+			SetupDeviceParams(hr, (*iDevices[iPrintedCounter]).AsNamelessDevice());
+			PrintDiscoveredDevice();
+			if(!(iPrintedCounter%KMaxDeviceRows))
+				if(CBTManDeviceScanner::DeviceNumberFromUserL(ETrue))
+					break;
+			}
+
+		if(iConsole)
+			CBTManDeviceScanner::DeviceNumberFromUserL(EFalse);
+				/*NB because of parameter EFalse above will never change 
+					 state to EScanStateUnfinished so will never start wait dialog.*/
+		if(!iPrintedCounter)
+			{
+			DisplayNoDeviceMessageL(EFalse);
+			iScanState = EScanStateCancelled;
+			}
+		CheckUnfinishedL();
+		}
+
+	//now extract the selected device number from the string...
+	TBTNamelessDevice devInfo;
+	if(iScanState == EScanStateSelected)
+		{
+		if(iChosenDeviceIndex<=iResultCountWithName)
+			devInfo = (*iDevices[iChosenDeviceIndex-1]).AsNamelessDevice();
+		else if(iChosenDeviceIndex<=(iResultCountWithName+iResultCountNoName))
+			devInfo = (*iDevices[iChosenDeviceIndex-iResultCountWithName-1]).AsNamelessDevice();
+		else
+			{
+			iScanState = EScanStateCancelled;
+			NotifyErrorL(_L("Error taking in device selection."));
+			}
+		}
+
+	if(iScanState == EScanStateSelected)
+		{
+		StartWaitMessageL();
+		SetupDeviceParams(hr, devInfo);
+		aBDAddr = iDevPms.BDAddr();
+		aName.Copy(iDevPms.DeviceName());
+		aClass = iDevPms.DeviceClass();
+		StopWaitMessage();
+		}
+
+	//Shouldn't ever be true
+	if(iScanState == EScanStateUnfinished)
+		{
+		DisplayNoDeviceMessageL(iPrintedCounter?ETrue:EFalse);
+		}
+
+	StopWaitMessage();
+	hr.Close();
+	ss.Close();
+
+	return (iScanState == EScanStateSelected)?ETrue:EFalse;
+	}
+
+
+void CBTManDeviceScanner::DisplayNoDeviceMessageL(TBool isMore)
+	{
+	LOG_FUNC
+	CConsoleBase* console = 0;
+	TRAPD(err, console = BTTextNotifiersConsole::AutoSizeNewL(_L("Device Selection"), TSize(45,4)));
+	if(err)
+		return;
+	CleanupStack::PushL(console);
+
+	TBuf<0x40> prompt(_L("Sorry! No"));
+	if(isMore)
+		prompt.Append(_L(" more"));
+	prompt.Append(_L(" devices could be found.\n\nPress any key."));
+	console->Printf(prompt);
+	console->Getch();
+	CleanupStack::PopAndDestroy();//console
+	}
+
+	
+void CBTManDeviceScanner::CheckUnfinishedL()
+	{
+	LOG_FUNC
+	if(iScanState!=EScanStateUnfinished||
+		(iResultCountWithName+iResultCountNoName)%KMaxDeviceRows)
+		return;
+
+	CConsoleBase* console = 0;
+	TRAPD(err, console = BTTextNotifiersConsole::AutoSizeNewL(_L("Device Selection"), TSize(70,3)));
+	if(err)
+		return;
+	CleanupStack::PushL(console);
+
+	TBuf<0x100> prompt(_L("Sorry!"));
+	prompt.Append(_L(" - THERE ARE NO MORE DEVICES - so\n\
+		\rpress 'Esc' to abort or 'Return' to ***REDO*** device inquiry.\n"));
+	console->Printf(prompt);
+	TKeyCode code = console->Getch();
+	while(code!=0x1b&&code!=0x0d)
+		code = console->Getch();
+	iScanState = code==0x0d?EScanStateUnfinished:EScanStateCancelled;
+	CleanupStack::PopAndDestroy();//console
+	}
+
+
+
+CBTManDeviceScanner* CBTManDeviceScanner::NewL()
+	{
+	LOG_STATIC_FUNC
+	CBTManDeviceScanner* self=new (ELeave) CBTManDeviceScanner();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+CBTManDeviceScanner::~CBTManDeviceScanner()
+	{
+	LOG_FUNC
+	delete iConsole;
+	ResetDeviceLists();
+	iDevices.Close();
+	iNoNameDevices.Close();
+	}
+
+CBTManDeviceScanner::CBTManDeviceScanner()
+	: iWaitMessage(_L("Please wait..."))
+	{
+	LOG_FUNC
+	}
+
+void CBTManDeviceScanner::ConstructL()
+	{
+	LOG_FUNC
+	}
+
+
+
+