bluetooth/btexample/testui/BTTextNotifiers/src/btpantextnotifier.cpp
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btexample/testui/BTTextNotifiers/src/btpantextnotifier.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,527 @@
+// 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 "BTTextNotifiers.h"
+#include <btdevice.h>
+#include <e32cons.h>
+#include <bluetooth/logger.h>
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, "TextNotifiers");
+#endif
+
+_LIT(KBTPanDeviceSelectionNotifier, "PanDevSlctNotif"); // for panics
+_LIT(KBTPanNotifierConsoleName, "PAN device selector");
+
+//
+// Notifier
+//
+
+CBTPanDeviceSelectionNotifier* CBTPanDeviceSelectionNotifier::NewLC()
+	{
+	LOG_STATIC_FUNC
+	CBTPanDeviceSelectionNotifier* self = new(ELeave) CBTPanDeviceSelectionNotifier();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+CBTPanDeviceSelectionNotifier::CBTPanDeviceSelectionNotifier()
+	{
+	LOG_FUNC
+	}
+
+void CBTPanDeviceSelectionNotifier::ConstructL()
+	{
+	LOG_FUNC
+	iEngine = CBTPanDeviceSelectionNotifierEngine::NewL(*this);
+	}
+
+CBTPanDeviceSelectionNotifier::~CBTPanDeviceSelectionNotifier()
+	{
+	LOG_FUNC
+	delete iEngine;
+	}
+
+void CBTPanDeviceSelectionNotifier::Release()
+	{
+	LOG_FUNC
+	Cancel();
+	delete this;
+	}
+	
+CBTPanDeviceSelectionNotifier::TNotifierInfo CBTPanDeviceSelectionNotifier::RegisterL()
+	{
+	LOG_FUNC
+	iInfo.iUid=KBTPanDeviceSelectionNotifierUid;
+	iInfo.iChannel=KScreenOutputChannel;
+	iInfo.iPriority=ENotifierPriorityVLow;
+	return iInfo;
+	}
+
+CBTPanDeviceSelectionNotifier::TNotifierInfo CBTPanDeviceSelectionNotifier::Info() const
+	{
+	LOG_FUNC
+	return iInfo;
+	}
+
+TPtrC8 CBTPanDeviceSelectionNotifier::StartL(const TDesC8& /*aBuffer*/)
+	{
+	LOG_FUNC
+	LOG(_L("The synchronous StartL overload is not used."))
+	User::Panic(KBTPanDeviceSelectionNotifier, KErrNotSupported);
+	return KNullDesC8(); // should never be reached
+	}
+	
+void CBTPanDeviceSelectionNotifier::StartL(const TDesC8& aBuffer, TInt aReplySlot, const RMessagePtr2& aMessage)
+	{
+	LOG_FUNC
+	iReplySlot = aReplySlot;
+	iMessage = RMessage2(aMessage);
+	iMessageOutstanding = ETrue;
+
+	TRAPD(err, iEngine->PromptForDevicesL(aBuffer));
+	FTRACE(FPrint(_L("RNot\tPAN device selection notifier completed with result %d"), err));
+	if (err)
+		{
+		aMessage.Complete(err);
+		iMessageOutstanding = EFalse;
+		User::Leave(err);
+		}
+	}
+	
+void CBTPanDeviceSelectionNotifier::Cancel()
+	{
+	LOG_FUNC
+	iEngine->Stop();
+
+	if (iMessageOutstanding)
+		{
+		iMessage.Complete(KErrCancel);
+		iMessageOutstanding = EFalse;
+		}
+	}
+
+TPtrC8 CBTPanDeviceSelectionNotifier::UpdateL(const TDesC8& /*aBuffer*/)
+/**
+
+*/
+	{
+	LOG_FUNC
+	return KNullDesC8();
+	}
+
+void CBTPanDeviceSelectionNotifier::DeviceSelectionComplete(TBTDeviceList& aDevices)
+/**
+The user has selected the devices they want to connect to
+*/
+	{
+	LOG_FUNC
+	TInt err = iMessage.Write(iReplySlot, aDevices);
+	iMessage.Complete(err);
+	iMessageOutstanding = EFalse;
+	}
+	
+void CBTPanDeviceSelectionNotifier::DeviceSelectionError(TInt aError)
+/**
+There was an error during device selection
+*/
+	{
+	LOG_FUNC
+	LOG1(_L("\taError = %d"), aError);
+	if(iMessageOutstanding)
+		{
+		iMessage.Complete(aError);
+		iMessageOutstanding = KErrNone;
+		}
+	}
+	
+//
+// Notifier engine
+//
+
+_LIT(KNewline, "\n");
+_LIT(KBTPanDSNSelectedDevice, "-> ");
+_LIT(KBTPanDSNNotSelectedDevice, "   ");
+_LIT(KBTPanDSNSelected, " * ");
+_LIT(KBTPanDSNNotSelected, "   ");
+_LIT(KBTPanDSNDevAddrOpen, "[");
+_LIT(KBTPanDSNDevAddrClose, "]");
+_LIT(KBTPanDeviceSelectionNotifierInstructions, "Use [up] and [down] arrow keys to move around; press [space] to select a device, press [return] to finish, [esc] to cancel:\nUp to 8 devices can be selected.\n");
+_LIT(KBTPanDSNNoMoreDevices, " --- Device discovery complete ---");
+const TUint KBTPanDSNDevNameMaxChars = 20;
+const TUint KBTPanDSNMaxReadableBufLength = 12;
+const TUint KBTPanDSNDeviceDisplayBufLength = (sizeof(KBTPanDSNSelected)/2)+KBTPanDSNDevNameMaxChars+(sizeof(KBTPanDSNDevAddrOpen)/2)+KBTPanDSNMaxReadableBufLength+(sizeof(KBTPanDSNDevAddrClose)/2);
+const TUint KBTPanDSNInitialDeviceCount = KMaxDeviceRows; // start out by assuming we're going to discover this many devices - will realloc later if necessary
+const TUint KBTPanDSNInitialBufSize = ((sizeof(KBTPanDeviceSelectionNotifierInstructions)/2)+(KBTPanDSNInitialDeviceCount*KBTPanDSNDeviceDisplayBufLength));
+
+CBTPanDeviceSelectionNotifierEngine* CBTPanDeviceSelectionNotifierEngine::NewL(MBTPanDeviceSelectionNotify& aNotify)
+/**
+
+*/
+	{
+	LOG_STATIC_FUNC
+	CBTPanDeviceSelectionNotifierEngine* self = new(ELeave) CBTPanDeviceSelectionNotifierEngine(aNotify);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CBTPanDeviceSelectionNotifierEngine::CBTPanDeviceSelectionNotifierEngine(MBTPanDeviceSelectionNotify& aNotify) :
+	CActive(EPriorityStandard), iDevices(KMaxDeviceRows), iDisplayPtr(NULL, 0), iNotify(aNotify)
+/**
+
+*/
+	{
+	LOG_FUNC
+	CActiveScheduler::Add(this);
+	}
+
+void CBTPanDeviceSelectionNotifierEngine::ConstructL()
+/**
+
+*/
+	{
+	LOG_FUNC
+	iDisplayBuf = HBufC::NewL(KBTPanDSNInitialBufSize);
+	iDisplayPtr.Set(iDisplayBuf->Des());
+	}
+
+CBTPanDeviceSelectionNotifierEngine::~CBTPanDeviceSelectionNotifierEngine()
+/**
+
+*/
+	{
+	LOG_FUNC
+	delete iDeviceDiscoverer;
+	iDeviceDiscoverer = NULL;
+	
+	delete iConsole;
+	iConsole = NULL;
+	
+	delete iDisplayBuf;
+	iDisplayBuf = NULL;
+	
+	iDevices.Close();
+	}
+
+void CBTPanDeviceSelectionNotifierEngine::PromptForDevicesL(const TDesC8& /*aBuffer*/)
+/**
+Start a device discovery
+TODO: Reset state each time this is called
+*/
+	{
+	LOG_FUNC
+	iDeviceDiscoverer = CBTPanDeviceSelectionNotifierDeviceDiscoverer::NewL(*this);
+	iConsole = Console::NewL(KBTPanNotifierConsoleName, TSize(KConsFullScreen,KConsFullScreen));
+	Redraw();
+	iDeviceDiscoverer->StartDeviceDiscovery();
+	iConsole->Read(iStatus);
+	SetActive();
+	}
+
+void CBTPanDeviceSelectionNotifierEngine::Stop()
+/**
+The notifier wants us to abort - stop everything
+*/
+	{
+	LOG_FUNC
+	AbortEverything();
+	}
+
+void CBTPanDeviceSelectionNotifierEngine::RunL()
+/**
+Got input from the user
+*/
+	{
+	LOG_FUNC
+	TChar key = iConsole->KeyCode();
+	switch(key)
+		{
+		case EKeyUpArrow:
+			{
+			if(iCurrentlySelectedDevice>0)
+				{
+				--iCurrentlySelectedDevice;
+				}
+			if(iCurrentlySelectedDevice<iPositionOfTopDeviceInList)
+				{
+				--iPositionOfTopDeviceInList;
+				}
+			break;
+			}
+		case EKeyDownArrow:
+			{
+			if(iCurrentlySelectedDevice < (iDevices.Count()-1))
+				{
+				++iCurrentlySelectedDevice;
+				}
+			if(iCurrentlySelectedDevice>=(iPositionOfTopDeviceInList+KMaxDeviceRows))
+				{
+				++iPositionOfTopDeviceInList;
+				}
+			break;
+			}
+		case EKeySpace:
+			{
+			if(iDevices.Count()) // make sure there's something in the array
+				{
+				if(iDevices[iCurrentlySelectedDevice]->iSelected)
+					{
+					iDevices[iCurrentlySelectedDevice]->iSelected = EFalse;
+					}
+				else
+					{
+					if(NumberOfDevicesSelected()<KMaxPanDevicesForSimultaneousSelection)
+						{
+						iDevices[iCurrentlySelectedDevice]->iSelected = ETrue;
+						}
+					}
+				}
+			break;
+			}
+		case EKeyEnter:
+			{
+			PackageSelectedDevicesAndCompleteNotifier();
+			return;
+			}
+		default:
+			// fall through
+		case EKeyEscape:
+			{
+			CompleteNotifierWithError(KErrCancel);
+			return;
+			}
+		}
+		
+	Redraw();
+	iConsole->Read(iStatus);	// post another read
+	SetActive();
+	}
+
+void CBTPanDeviceSelectionNotifierEngine::DoCancel()
+/**
+
+*/
+	{
+	LOG_FUNC
+	iConsole->ReadCancel();
+	}
+
+void CBTPanDeviceSelectionNotifierEngine::NewDeviceFoundL(TNameRecord& aNewDevice)
+/**
+Add the new device to the end of the list
+*/
+	{
+	LOG_FUNC
+	LOG1(_L("\tDevice Name = %S"), &(aNewDevice.iName));
+	TBTDeviceSelectionInfo* devInfo = new(ELeave) TBTDeviceSelectionInfo();
+	devInfo->iNameRecord = aNewDevice;
+	devInfo->iSelected = EFalse;
+	User::LeaveIfError(iDevices.Append(devInfo));
+
+	// check if we need to allocate bigger buffer
+	TUint instructions = sizeof(KBTPanDeviceSelectionNotifierInstructions)/2;
+	TUint devices = iDevices.Count();
+	TUint devDisplay = KBTPanDSNDeviceDisplayBufLength;
+	TUint minRequiredBufSize = instructions+(devices*devDisplay);
+	if(iDisplayPtr.MaxLength() < minRequiredBufSize)
+		{
+		delete iDisplayBuf;
+		iDisplayBuf = NULL;
+		TUint size = (sizeof(KBTPanDeviceSelectionNotifierInstructions)/2)+2*iDevices.Count()*KBTPanDSNDeviceDisplayBufLength;
+		iDisplayBuf = HBufC::NewL( size );
+		iDisplayPtr.Set(iDisplayBuf->Des());
+		}		
+	Redraw();
+	}
+
+void CBTPanDeviceSelectionNotifierEngine::DeviceSearchComplete(TInt aError)
+/**
+No more devices can be found
+*/
+	{
+	LOG_FUNC
+	LOG1(_L("\taError = %d"), aError);
+	if(aError!=KErrEof)	// there's a problem, so complete with an error
+		{
+		CompleteNotifierWithError(aError);
+		return;
+		}
+	else
+		{
+		iDeviceSearchComplete = ETrue;		
+		Redraw();
+		}
+	}
+
+TInt CBTPanDeviceSelectionNotifierEngine::DisplayDevice(TUint aDeviceNumber, TPtr& aDisplayBuf)
+/**
+
+*/
+	{
+	LOG_FUNC
+	//ASSERT(aDisplayBuf.Length()==KBTPanDSNDeviceDisplayBufLength);
+	if(aDeviceNumber>=iDevices.Count())
+		{
+		return KErrNotFound;
+		}
+	else
+		{
+		if(iDevices[aDeviceNumber]->iSelected)
+			{
+			aDisplayBuf.Append(KBTPanDSNSelected);
+			}
+		else
+			{
+			aDisplayBuf.Append(KBTPanDSNNotSelected);
+			}
+			
+		aDisplayBuf.Append(iDevices[aDeviceNumber]->iNameRecord.iName.Left(KBTPanDSNDevNameMaxChars));	// append device name
+		aDisplayBuf.Append(KBTPanDSNDevAddrOpen);
+		TBuf<KBTPanDSNMaxReadableBufLength> readableDevAddrBuf;
+		static_cast<TInquirySockAddr>(iDevices[aDeviceNumber]->iNameRecord.iAddr).BTAddr().GetReadable(readableDevAddrBuf);	// append device address
+		aDisplayBuf.Append(readableDevAddrBuf);
+		aDisplayBuf.Append(KBTPanDSNDevAddrClose);
+		return KErrNone;
+		}
+	}
+	
+void CBTPanDeviceSelectionNotifierEngine::DisplayInstructions(TPtr& aDisplayBuf)
+/**
+~130 chars
+*/
+	{
+	LOG_FUNC
+	aDisplayBuf.Append(KBTPanDeviceSelectionNotifierInstructions);
+	}
+
+void CBTPanDeviceSelectionNotifierEngine::Redraw()
+/**
+Redraw the console
+*/
+	{
+	LOG_FUNC
+	iDisplayPtr.Zero();
+	iConsole->ClearScreen();
+	
+	TInt err;
+	DisplayInstructions(iDisplayPtr);
+	for(TInt i = 0; i < KMaxDeviceRows; ++i)
+		{
+		if(iPositionOfTopDeviceInList+i==iCurrentlySelectedDevice)
+			{
+			iDisplayPtr.Append(KBTPanDSNSelectedDevice);
+			}
+		else
+			{
+			iDisplayPtr.Append(KBTPanDSNNotSelectedDevice);
+			}
+			
+		err = DisplayDevice(iPositionOfTopDeviceInList+i, iDisplayPtr);
+		if(err==KErrNotFound)	// no more devices left
+			{
+			break;
+			}
+		iDisplayPtr.Append(KNewline);
+		}
+		
+	if(iDeviceSearchComplete)
+		{
+		iDisplayPtr.Append(KBTPanDSNNoMoreDevices);
+		}
+		
+	iConsole->Write(*iDisplayBuf);
+	}
+	
+void CBTPanDeviceSelectionNotifierEngine::PackageSelectedDevicesAndCompleteNotifier()
+/**
+Package the selected device addresses into the device list and pass back to the notifier
+*/
+	{
+	LOG_FUNC
+	AbortEverything();	// stop inquiry and remove console
+	
+	TBTDeviceList deviceList;
+	for(TInt i = 0; i < iDevices.Count(); ++i)
+		{
+		if(iDevices[i]->iSelected)
+			{
+			TBTDevAddr devAddr = static_cast<TInquirySockAddr>(iDevices[i]->iNameRecord.iAddr).BTAddr();
+			deviceList.AddDevice(devAddr);
+			}
+		}
+	
+	iNotify.DeviceSelectionComplete(deviceList);
+	}
+
+void CBTPanDeviceSelectionNotifierEngine::CompleteNotifierWithError(TInt aError)
+/**
+An error occurred during device selection - cancel everything and complete the notifier with an error
+*/
+	{
+	LOG_FUNC
+	if(iAborting)
+		{
+		// do nothing, we're already aborting everything
+		}
+	else
+		{
+		iAborting = ETrue; // make a note that we're aborting
+		AbortEverything();
+		iNotify.DeviceSelectionError(aError);
+		iAborting = EFalse; // reset flag
+		}
+	}
+
+void CBTPanDeviceSelectionNotifierEngine::AbortEverything()
+/**
+Common method to abort everything - called from both the notifier error path and our own
+*/
+	{
+	LOG_FUNC
+	if(iDeviceDiscoverer)
+		{
+		iDeviceDiscoverer->Cancel();	// cancel the device discovery, and delete the device discoverer
+		delete iDeviceDiscoverer;
+		iDeviceDiscoverer = NULL;
+		}
+		
+	Cancel();						// cancel the input from the console
+	if(iConsole)
+		{
+		delete iConsole;				// remove the console from screen
+		iConsole = NULL;
+		}
+	}	
+	
+TInt CBTPanDeviceSelectionNotifierEngine::NumberOfDevicesSelected()
+/**
+Return the number of devices marked as selected in the array
+*/
+	{
+	LOG_FUNC
+	TInt count = 0;
+	for(TInt i=0; i < iDevices.Count(); ++i)
+		{
+		if(iDevices[i]->iSelected)
+			{
+			++count;
+			}
+		}
+	return count;
+	}
+