bluetooth/btstack/linkmgr/pairingscache.cpp
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/linkmgr/pairingscache.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,214 @@
+// Copyright (c) 2007-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 "pairingscache.h"
+#include "linkutil.h"
+
+/*static*/ CBTPairingsCache* CBTPairingsCache::NewL(MBTPairingsCacheObserver& aObserver, RBTRegServ& aRegServ)
+	{
+	CBTPairingsCache* self = new(ELeave) CBTPairingsCache(aObserver);
+	CleanupStack::PushL(self);
+	self->ConstructL(aRegServ);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CBTPairingsCache::CBTPairingsCache(MBTPairingsCacheObserver& aObserver)
+	: iObserver(aObserver)
+	{
+	}
+
+void CBTPairingsCache::ConstructL(RBTRegServ& aRegServ)
+	{
+	iBTPairedBDAddrGetter = CBTPairedBDAddrGetter::NewL(*this, aRegServ);
+	DoUpdateCache();
+	}
+
+CBTPairingsCache::~CBTPairingsCache()
+	{
+	delete iBTPairedBDAddrGetter;
+	iPairedBDAddrs.Close();
+	}
+
+void CBTPairingsCache::UpdateCache()
+	{
+	// First we must cancel any outstanding request, as this will be called
+	// when the registry has been modified an an external (API) user, and
+	// so an in progress 'get' may have a stale view.
+	iBTPairedBDAddrGetter->Cancel();
+	DoUpdateCache();
+	}
+
+void CBTPairingsCache::DoUpdateCache()
+	{
+    RemoveAllPairedDevices(); // Clear out the cache as it may be stale.
+	iCacheState = EUpdateOutstanding;
+	iBTPairedBDAddrGetter->Retrieve();
+	}
+
+CBTPairingsCache::TPairingState CBTPairingsCache::IsPaired(const TBTDevAddr& aBDAddr)
+	{
+	// We initially assume that there is no pairing to the remote device.
+    CBTPairingsCache::TPairingState ret = ENotPaired;
+    
+    // We determine whether they are in our pairing cache or not.
+    TBool inPairingCache = InPairingCache(aBDAddr);
+
+	// Now we do some additional work based on the state of the cache.
+	switch(iCacheState)
+		{
+	case EUpdateOutstanding:
+		// If an update has been requested then we make them
+		// wait for the answer.
+		ret = EDeferred;
+		break;
+	case EUpdateFailed:
+		// If we failed last time we should try again, and tell
+		// them to wait for the answer.
+		DoUpdateCache();
+		ret = EDeferred;
+		break;
+	case EValid:
+		// If the cache is valid then either we are paired or
+		// we aren't, the answer to which is based on whether they
+		// are in the cache or not.
+		break;
+	default:
+		Panic(EBTPairingsCacheBadState);
+		break;
+		}
+
+	// If we were already in the cache then that means there must be a pairing.
+	if(inPairingCache)
+		{
+		ret = EPaired;
+		}
+
+	// If we are deferring the decision about whether paired or not, then we 
+	// need to remember that we should inform the observer when we have 
+	// completed our attempt at getting an answer.
+	if(ret == EDeferred)
+		{
+		iDeferredDecision = ETrue;
+		}
+
+	return ret;
+	}
+
+TBool CBTPairingsCache::InPairingCache(const TBTDevAddr& aBDAddr)
+	{
+	return (PairedDeviceIndex(aBDAddr) >= 0) ? ETrue : EFalse;
+	}
+
+/**
+Wrapper for TBTDevAddr's == operation.
+This is needed by the TIdentityRelation parameter in RArray's Find method.
+*/
+/*static*/ TBool CBTPairingsCache::AreBDAddrsEqual(const TBTDevAddr& aA, const TBTDevAddr& aB)
+	{
+	return aA == aB;
+	}
+
+/**
+Returns either the index of the remote device address in the
+paired device address list if the specified address is
+included therein or KErrNotFound if not
+*/
+TInt CBTPairingsCache::PairedDeviceIndex(const TBTDevAddr& aBDAddr)
+	{
+	TIdentityRelation<TBTDevAddr> rel(AreBDAddrsEqual);
+	return iPairedBDAddrs.Find(aBDAddr, rel);
+	}
+
+TInt CBTPairingsCache::AddPairedDevice(const TBTDevAddr& aAddr)
+	{
+    __ASSERT_DEBUG(aAddr!=0, Panic(EBTConnectionBadDeviceAddress));
+	
+	TInt err = KErrNone;
+	if(!InPairingCache(aAddr))
+		{
+		err = iPairedBDAddrs.Append(aAddr);
+		}
+	return err;
+	}
+
+void CBTPairingsCache::RemoveAllPairedDevices()
+	{
+	for(TInt i=iPairedBDAddrs.Count()-1; i>=0; i--)
+		{
+		iPairedBDAddrs.Remove(i);
+		}
+	}
+
+void CBTPairingsCache::InformObserver(TInt aError)
+	{
+    // Ensure that we inform the observer only if they have been deferred.
+	if(iDeferredDecision)
+		{
+		iDeferredDecision = EFalse;
+		iObserver.MbpcoDeferredDecisionResolved(aError);
+		}
+	}
+
+/*virtual*/ void CBTPairingsCache::MbpdnAddPairedDevices(const RBTDeviceArray& aAddrs)
+	{
+	__ASSERT_DEBUG(iCacheState == EUpdateOutstanding, Panic(EBTPairingsCacheBadState));
+	
+	// check that the cache is still empty
+	__ASSERT_DEBUG(iPairedBDAddrs.Count() == 0, Panic(EBTPairingsCacheNotEmpty));
+	
+	TInt err = KErrNone;
+
+	TInt count = aAddrs.Count();
+	for (TInt i=0; i<count; i++)
+		{
+		err = AddPairedDevice(aAddrs[i]->BDAddr());
+		if(err != KErrNone)
+			{
+			break;
+			}
+		}
+
+	// We handle add failures ourselves.
+	iCacheState = (err == KErrNone) ? EValid : EUpdateFailed;
+
+	// We inform the observer, even if there was an error because it is
+	// possible that we managed to get the address they were after.
+	InformObserver(err);
+	}
+
+/*virtual*/ void CBTPairingsCache::MbpdnErrorInGettingPairedDevices(TInt aError)
+	{
+	__ASSERT_DEBUG(iCacheState == EUpdateOutstanding, Panic(EBTPairingsCacheBadState));
+	// Current cache should be ok - we should have cleared it before a getter is
+	// started.  This simply sets the flag to indicate that the current (empty) cache 
+	// is either complete if aErr is KErrNotFound (or KErrNone) or incomplete
+	// if aErr is anything else. In the latter case if the cache is needed in future 
+	// another getter should be kicked off.
+	TInt err = (aError != KErrNone && aError != KErrNotFound) ? aError : KErrNone;
+	if(err != KErrNone)
+		{
+		iCacheState = EUpdateFailed;
+		}
+	else
+		{
+		iCacheState = EValid;
+		}
+	
+	// Ensure that if we have been queried about the pairings and deferred the
+	// client, they must be informed.
+	InformObserver(err);
+	}
+