diff -r 000000000000 -r 9cfd9a3ee49c datasourcemodules/bluetoothgpspositioningmodule/btgpsconfig/src/lbsbtgpsconfigimpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/datasourcemodules/bluetoothgpspositioningmodule/btgpsconfig/src/lbsbtgpsconfigimpl.cpp Tue Feb 02 01:50:39 2010 +0200 @@ -0,0 +1,948 @@ +// Copyright (c) 2008-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: +// LBS Bluetooth GPS Configuration API implementation +// + +#include "lbsbtgpsconfigimpl.h" +#include + +/** LBS Bluetooth GPS Configuration central repository UID +@internalComponent +*/ +const TUint32 KLbsBtGpsConfigRepositoryUid = 0x102869C1; + +//------------------------------------------------------- +// CENREP FORMAT +// +// key format: 0xAAAABBBB +// where: +// AAAA = Device index +// BBBB = Setting index + +const TUint32 KDeviceIndexMask = 0xFFFF0000; +const TUint32 KDeviceIndexShift = 16; + +// Maximum number of devices allowed in the list +const TUint32 KMaxDevices = 20; + +// Index of first device in the list +const TUint32 KFirstDeviceIndex = 0x0001; + +// GENERAL SETTINGS (stored under device index 0000) + +// Centrep data version +//const TUint32 KSettingVersion = 0x00000000; + +// Stores the last allocated unique device key +const TUint32 KSettingLastKey = 0x00000001; + +// Stores the number of devices in the list +const TUint32 KSettingNumDevices = 0x00000002; + +// PER-DEVICE SETTINGS (BBBB) + +// Unique key identifying the device +const TUint32 KDeviceSettingKey = 0x0000; + +// Device type +const TUint32 KDeviceSettingType = 0x0001; + +// Device bluetooth socket address +const TUint32 KDeviceSettingSockAddr = 0x0002; +//------------------------------------------------------- + +// Partial key and mask for centrep notifications - notify on all changes +const TUint32 KNotifyPartialKey = 0x00000000; +const TUint32 KNotifyMask = 0x00000000; + + +// Number of times to retry if the repository is locked +const TInt KLockedRetries = 10000; + +// Time to wait before retrying if the repository is locked +const TInt KLockedRetryDelay = 100; + + +/** Static constructor (with observer) +Creates an instance of the LBS Bluetooth GPS Configuration API implementation, +specifying a callback to recieve update notifications. + +@param aObserver [IN] Observer which will recieve update notifications. + +@return A newly constructed CLbsBtGpsConfigImpl object. + +@capability LocalServices + +@internalComponent +*/ +CLbsBtGpsConfigImpl* CLbsBtGpsConfigImpl::NewL(MLbsBtGpsConfigObserver* aObserver) + { + // Check capabilities first + RProcess process; + if (!process.HasCapability(ECapabilityLocalServices)) + { + User::Leave(KErrPermissionDenied); + } + + CLbsBtGpsConfigImpl* self = new (ELeave) CLbsBtGpsConfigImpl(aObserver); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + + +/** Destructor +@internalComponent +*/ +CLbsBtGpsConfigImpl::~CLbsBtGpsConfigImpl() + { + Cancel(); + delete iRepos; + } + + +/** Returns the number of devices present in the list + +@return Number of devices. + +@leave KErrPermissionDenied if the client does not have the required capabilities. + +@capability LocalServices + +@internalComponent +*/ +TInt CLbsBtGpsConfigImpl::GetDeviceCount(TInt& aCount) + { + // Check capabilities first + RProcess process; + if (!process.HasCapability(ECapabilityLocalServices)) + { + return KErrPermissionDenied; + } + + TInt err = iRepos->Get(KSettingNumDevices, aCount); + if (err == KErrNotFound) + { + // If the entry is not found, the number of devices is zero. + // Don't treat this as an error. + aCount = 0; + err = KErrNone; + } + + return err; + } + + +/** Adds a new device at the specified position index within the list + +@param aAddress [In] Address of the new device. +@param aPosition [In] Position in the list at which to add the device, note that any existing entries below this position will be shifted down. +@param aKey [Out] Recieves the unique key assigned to identify the new device. + +Specifying aPosition >= DeviceCount() will result in the device being added to the end of the list. + +@return KErrNone if the operation succeeded. + KErrAlreadyExists if an entry with the same address is already present in the list. + KErrOverflow if there is no space left to add another entry. + KErrPermissionDenied if the client does not have the required capabilities. + +@capability LocalServices +@capability WriteDeviceData + +@internalComponent +*/ +TInt CLbsBtGpsConfigImpl::AddDevice(const TBTDevAddr& aAddress, TInt aPosition, TLbsBtGpsEntryKey& aKey) + { + // Check capabilities first + RProcess process; + if (!process.HasCapability(ECapabilityLocalServices)) + { + return KErrPermissionDenied; + } + if (!process.HasCapability(ECapabilityWriteDeviceData)) + { + return KErrPermissionDenied; + } + + TRAPD(err, AddDeviceL(aAddress, aPosition, aKey)); + return err; + } + + +/** Removes a device from the list + +@param aKey [In] The key identifying the device. + +@return KErrNone if the operation succeeded. + KErrNotFound if the specified device is not present in the list. + KErrPermissionDenied if the client does not have the required capabilities. + +@capability LocalServices +@capability WriteDeviceData + +@internalComponent +*/ +TInt CLbsBtGpsConfigImpl::RemoveDevice(TLbsBtGpsEntryKey aKey) + { + // Check capabilities first + RProcess process; + if (!process.HasCapability(ECapabilityLocalServices)) + { + return KErrPermissionDenied; + } + if (!process.HasCapability(ECapabilityWriteDeviceData)) + { + return KErrPermissionDenied; + } + + TRAPD(err, RemoveDeviceL(aKey)); + return err; + } + + +/** Empties the device list, removing all device entries + +@return KErrNone if the operation succeeded. + KErrPermissionDenied if the client does not have the required capabilities. + +@capability LocalServices +@capability WriteDeviceData + +@internalComponent +*/ +TInt CLbsBtGpsConfigImpl::EmptyDeviceList() + { + // Check capabilities first + RProcess process; + if (!process.HasCapability(ECapabilityLocalServices)) + { + return KErrPermissionDenied; + } + if (!process.HasCapability(ECapabilityWriteDeviceData)) + { + return KErrPermissionDenied; + } + + TRAPD(err, EmptyDeviceListL()); + return err; + } + + +/** Reorders a device in the list by specifying a new position index + +@param aKey [In] The key identifying the device. +@param aNewPosition [In] New position index for the device in the list (where 0 indicates the start of the list). + +The device identified by the key will assume the specified position in the list, shifting exsiting devices as +required in order to achieve this. + +Specifying aNewPosition = 0 will result in the device being moved to the start of the list. +Specifying aNewPosition >= DeviceCount() will result in the device being moved to the end of the list. + +When a device is moved towards the start of the list, other devices located between the old and new positions +will be shifted towards the end of the list by one place. For example, starting with a list {A,B,C,D,E}, moving +device D to position 1 would result in {A,D,B,C,E}. + +Similarly, when a device is moved towards the end of the list, other devices located between the old and new +positions will be shifted towards the start of the list by one place. For example, starting with a list {A,B,C,D,E}, +moving device B to position 3 would result in {A,C,D,B,E} + +@return KErrNone if the operation succeeded. + ErrNotFound if the specified device is not present in the list. + KErrPermissionDenied if the client does not have the required capabilities. + +@capability LocalServices +@capability WriteDeviceData + +@internalComponent +*/ +TInt CLbsBtGpsConfigImpl::ReorderDevice(TLbsBtGpsEntryKey aKey, TInt aNewPosition) + { + // Check capabilities first + RProcess process; + if (!process.HasCapability(ECapabilityLocalServices)) + { + return KErrPermissionDenied; + } + if (!process.HasCapability(ECapabilityWriteDeviceData)) + { + return KErrPermissionDenied; + } + + TRAPD(err, ReorderDeviceL(aKey, aNewPosition)); + return err; + } + + +/** Retrieves the list of devices + +@param aList [Out] Reference to an empty RPointerArray to populate with device entries from the list. + +@leave KErrPermissionDenied if the client does not have the required capabilities. + +@capability LocalServices + +@internalComponent +*/ +void CLbsBtGpsConfigImpl::GetDeviceListL(RPointerArray& aList) + { + // Check capabilities first + RProcess process; + if (!process.HasCapability(ECapabilityLocalServices)) + { + User::Leave(KErrPermissionDenied); + } + + // Attempt to start a transaction + User::LeaveIfError(StartTransactionL(CRepository::EReadTransaction)); + + TInt deviceCount; + User::LeaveIfError(GetDeviceCount(deviceCount)); + + for (TInt index=0; indexSetKey(devRecord.Key()); + devInfo->SetAddress(devRecord.SocketAddress().BTAddr()); + devInfo->SetType(devRecord.Type()); + aList.Append(devInfo); + CleanupStack::Pop(devInfo); + } + + } + + // End central repository transaction + User::LeaveIfError(EndTransaction()); + } + + +/** This methods is reserved for future expansion and should not be used + +@param aFunctionNumber Reserved for future expansion +@param aPtr1 Reserved for future expansion +@param aPtr2 Reserved for future expansion + +@capability LocalServices + +@internalComponent +*/ +TAny* CLbsBtGpsConfigImpl::ExtendedInterface(TInt /*aFunctionNumber*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/) + { + return NULL; + } + + +// ------------------ Internal API methods ------------------ + + +/** Updates the device information for a device in the list + +@param aDeviceInfo [In] The updated device info for the specified device. The key should identify an existing device in the list. + +@return KErrNone if the operation succeeded. + KErrNotFound if the specified device is not present in the list. + KErrPermissionDenied if the client does not have the required capabilities. + +@capability LocalServices +@capability WriteDeviceData + +@internalComponent +*/ +TInt CLbsBtGpsConfigImpl::UpdateDevice(const TLbsBtGpsDeviceRecord& aDeviceRecord) + { + // Check capabilities first + RProcess process; + if (!process.HasCapability(ECapabilityLocalServices)) + { + return KErrPermissionDenied; + } + if (!process.HasCapability(ECapabilityWriteDeviceData)) + { + return KErrPermissionDenied; + } + + TRAPD(err, UpdateDeviceL(aDeviceRecord)); + return err; + } + + +/** Retrieves the list of device records + +@param aList [Out] Reference to an empty RPointerArray to populate with device records from the list. + +@leave KErrPermissionDenied if the client does not have the required capabilities. + +@capability LocalServices + +@internalComponent +*/ +void CLbsBtGpsConfigImpl::GetDeviceRecordListL(RPointerArray& aRecordList) + { + // Check capabilities first + RProcess process; + if (!process.HasCapability(ECapabilityLocalServices)) + { + User::Leave(KErrPermissionDenied); + } + + // Attempt to start a transaction + User::LeaveIfError(StartTransactionL(CRepository::EReadTransaction)); + + // Get the number of devices in the list + TInt deviceCount; + User::LeaveIfError(GetDeviceCount(deviceCount)); + + for (TInt index=0; indexNotifyCancel(KNotifyPartialKey, KNotifyMask); + } + + +/** Active object RunL method +@internalComponent +*/ +void CLbsBtGpsConfigImpl::RunL() + { + if (iObserver) + { + iObserver->OnDeviceListUpdate(); + iRepos->NotifyRequest(KNotifyPartialKey, KNotifyMask, iStatus); + SetActive(); + } + } + + +/** Adds a new device at the specified position index within the list - leaving version + +@see AddDevice + +@internalComponent +*/ +void CLbsBtGpsConfigImpl::AddDeviceL(const TBTDevAddr& aAddress, TInt aPosition, TLbsBtGpsEntryKey& aKey) + { + TInt err; + TInt index; + + aKey = KLbsBtGpsEntryKeyNull; + + // Attempt to start a transaction + User::LeaveIfError(StartTransactionL(CRepository::EReadWriteTransaction)); + + // Retrieve the current number of devices in the list + TInt deviceCount; + User::LeaveIfError(GetDeviceCount(deviceCount)); + + // Check that the desired position is in range, adjust if required + if (aPosition < 0 || aPosition > deviceCount) + { + aPosition = deviceCount; + } + + // Leave if we've reached the maximum number of devices allowed in the list + if (deviceCount >= KMaxDevices) + { + User::Leave(KErrOverflow); + } + + // Device record container + TLbsBtGpsDeviceRecord devRecord; + + // Leave if a device with this address is already present in the list + for (index=0; indexGet(KSettingLastKey, key); + if (err == KErrNotFound) + { + // Value not present in centrep, initialise sequence to NULL key + key = KLbsBtGpsEntryKeyNull; + } + else + { + User::LeaveIfError(err); + } + + // Increment to get next available key to assign to the new device + ++key; + + // Write current key + User::LeaveIfError(iRepos->Set(KSettingLastKey, key)); + + // Move all entries following the desired position down one place, starting from the end + for (index=deviceCount-1; index>=aPosition; --index) + { + User::LeaveIfError(MoveDeviceRecord(index, index+1)); + } + + // Build a device record to add to the list + devRecord.SetKey(key); + + TBTSockAddr sockAddr; + sockAddr.SetBTAddr(aAddress); + devRecord.SetSocketAddress(sockAddr); + + // Set unknown type for new devices + devRecord.SetType(TLbsBtGpsDeviceInfo::ELbsBtGpsDeviceUnknown); + + // Write the new device record at the desired position + User::LeaveIfError(WriteDeviceRecord(aPosition, devRecord)); + + // Increment device counter and write to cenrep + ++deviceCount; + User::LeaveIfError(iRepos->Set(KSettingNumDevices, deviceCount)); + + // End central repository transaction + User::LeaveIfError(EndTransaction()); + + // Set key to return to client now the transaction has succeeded + aKey = key; + } + + +/** Removes a device from the list - leaving version + +@see RemoveDevice + +@internalComponent +*/ +void CLbsBtGpsConfigImpl::RemoveDeviceL(TLbsBtGpsEntryKey aKey) + { + // Attempt to start a transaction + User::LeaveIfError(StartTransactionL(CRepository::EReadWriteTransaction)); + + // Get the number of devices in the list + TInt deviceCount; + User::LeaveIfError(GetDeviceCount(deviceCount)); + + // Flag to indicate if we have found the device record yet + TBool foundDevice = EFalse; + + // Device record container + TLbsBtGpsDeviceRecord devRecord; + + // Look for the device record + for (TInt index=0; indexDelete(keyBase, KDeviceIndexMask, errKey)); + } + } + + if (!foundDevice) + { + User::Leave(KErrNotFound); + } + + // Decrement device counter and write to cenrep + --deviceCount; + User::LeaveIfError(iRepos->Set(KSettingNumDevices, deviceCount)); + + // End central repository transaction + User::LeaveIfError(EndTransaction()); + } + + +/** Empties the device list, removing all device entries - leaving version + +@see EmptyDeviceList + +@internalComponent +*/ +void CLbsBtGpsConfigImpl::EmptyDeviceListL() + { + // Read last allocated device key as we want to save this + TInt key; + TInt err = iRepos->Get(KSettingLastKey, key); + if (err == KErrNotFound) + { + // Value not present in centrep, initialise sequence to NULL key + key = KLbsBtGpsEntryKeyNull; + } + else if (err != KErrNone) + { + User::Leave(err); + } + + // Reset the repository + User::LeaveIfError(iRepos->Reset()); + + // Write back last key value + User::LeaveIfError(iRepos->Set(KSettingLastKey, key)); + } + + +/** Reorders a device in the list by specifying a new position index - leaving version + +@see ReorderDevice + +@internalComponent +*/ +void CLbsBtGpsConfigImpl::ReorderDeviceL(TLbsBtGpsEntryKey aKey, TInt aNewPosition) + { + // Attempt to start a transaction + User::LeaveIfError(StartTransactionL(CRepository::EReadWriteTransaction)); + + // Get the number of devices in the list + TInt deviceCount; + User::LeaveIfError(GetDeviceCount(deviceCount)); + + // Check that the desired position is in range, adjust if required + if (aNewPosition < 0 || aNewPosition >= deviceCount) + { + aNewPosition = deviceCount-1; + } + + // This will store the current position of the device, if found + TInt oldPosition = KErrNotFound; + + // This will store the device record while we move it + TLbsBtGpsDeviceRecord devRecord; + + // Look for the device entry to move + TInt index; + for (index=0; indexDelete(keyBase, KDeviceIndexMask, errKey)); + + if (oldPosition < aNewPosition) + { + // Moving towards the end of the list - shift intermediate entries up one place + for (index = oldPosition + 1; index <= aNewPosition; ++index) + { + User::LeaveIfError(MoveDeviceRecord(index,index-1)); + } + } + else if (oldPosition > aNewPosition) + { + // Moving towards the start of the list - shift intermediate entries down one place + for (index = oldPosition - 1; index >= aNewPosition; --index) + { + User::LeaveIfError(MoveDeviceRecord(index,index+1)); + } + } + + // Write the record at the new position + User::LeaveIfError(WriteDeviceRecord(aNewPosition, devRecord)); + } + + // End central repository transaction + User::LeaveIfError(EndTransaction()); + } + + +/** Updates the device information for a device in the list - leaving version + +@see UpdateDevice + +@internalComponent +*/ +void CLbsBtGpsConfigImpl::UpdateDeviceL(const TLbsBtGpsDeviceRecord& aDeviceRecord) + { + // Attempt to start a transaction + User::LeaveIfError(StartTransactionL(CRepository::EReadWriteTransaction)); + + // Get the number of devices in the list + TInt deviceCount; + User::LeaveIfError(GetDeviceCount(deviceCount)); + + // Flag to indicate if we have found the device record yet + TBool foundDevice = EFalse; + + // Device record container + TLbsBtGpsDeviceRecord devRecord; + + // Look for the device record + for (TInt index=0; indexStartTransaction(aMode); + + if (err == KErrNone) + { + // Transaction started succesfully + break; + } + else if (err == KErrLocked && (retries++ < KLockedRetries)) + { + // Repository is locked by another client, wait before retrying + User::After(TTimeIntervalMicroSeconds32(KLockedRetryDelay)); + } + else + { + // Another error occurred, or maximum number of retries reached + return err; + } + } + + // Make sure the transaction is cancelled if something goes wrong + iRepos->CleanupCancelTransactionPushL(); + + return KErrNone; + } + + +/** End (commit) a central repository transaction + +@return KErrNone if the operation succeeded. + +@internalComponent +*/ +TInt CLbsBtGpsConfigImpl::EndTransaction() + { + CleanupStack::Pop(); // CleanupCancelTransaction + + TUint32 errKey; + return iRepos->CommitTransaction(errKey); + } + + +/** Read a device record from cenrep by index + +@param aIndex [In] The index of the device entry to read +@param aDeviceInfo [Out] Device info to fill from cenrep + +StartTransaction should have been called. + +@internalComponent +*/ +TInt CLbsBtGpsConfigImpl::ReadDeviceRecord(TInt aIndex, TLbsBtGpsDeviceRecord& aDeviceRecord) + { + TInt err; + TUint32 keyBase = (KFirstDeviceIndex + aIndex) << KDeviceIndexShift; + + TInt deviceKey; + err = iRepos->Get(keyBase | KDeviceSettingKey, deviceKey); + if (err != KErrNone) + { + return err; + } + aDeviceRecord.SetKey(deviceKey); + + TInt deviceType; + err = iRepos->Get(keyBase | KDeviceSettingType, deviceType); + if (err != KErrNone) + { + return err; + } + aDeviceRecord.SetType(deviceType); + + TBuf addressBuffer; + err = iRepos->Get(keyBase | KDeviceSettingSockAddr, addressBuffer); + if (err != KErrNone) + { + return err; + } + TBTSockAddr address; + address.Copy(addressBuffer); + aDeviceRecord.SetSocketAddress(address); + + return KErrNone; + } + + +/** Write a device record to cenrep by index + +@param aIndex [In] The index of the device entry to write +@param aDeviceInfo [Out] Device info to write to cenrep + +StartTransaction should have been called. + +@internalComponent +*/ +TInt CLbsBtGpsConfigImpl::WriteDeviceRecord(TInt aIndex, const TLbsBtGpsDeviceRecord& aDeviceRecord) + { + TInt err; + TUint32 keyBase = (KFirstDeviceIndex + aIndex) << KDeviceIndexShift; + + TInt deviceKey = aDeviceRecord.Key(); + err = iRepos->Set(keyBase | KDeviceSettingKey, deviceKey); + if (err != KErrNone) + { + return err; + } + + TInt deviceType = aDeviceRecord.Type(); + err = iRepos->Set(keyBase | KDeviceSettingType, deviceType); + if (err != KErrNone) + { + return err; + } + + TBuf addressBuffer; + addressBuffer.Copy(aDeviceRecord.SocketAddress()); + err = iRepos->Set(keyBase | KDeviceSettingSockAddr, addressBuffer); + if (err != KErrNone) + { + return err; + } + + return KErrNone; + } + + +/** Move a device record from old to new position + +@param aOldIndex [In] The current index of the device record in the list +@param aOldIndex [In] The new index of the device record in the list + +StartTransaction should have been called. + +@internalComponent +*/ +TInt CLbsBtGpsConfigImpl::MoveDeviceRecord(TInt aOldIndex, TInt aNewIndex) + { + TUint32 oldKeyBase = (KFirstDeviceIndex + aOldIndex) << KDeviceIndexShift; + TUint32 newKeyBase = (KFirstDeviceIndex + aNewIndex) << KDeviceIndexShift; + TUint32 errKey; + + return iRepos->Move(oldKeyBase, newKeyBase, KDeviceIndexMask, errKey); + } + + +/** Class constructor + +@param aObserver [IN] Optional observer, which will recieve update notifications. + +@internalComponent +*/ +CLbsBtGpsConfigImpl::CLbsBtGpsConfigImpl(MLbsBtGpsConfigObserver* aObserver) +: CActive(CActive::EPriorityStandard), + iObserver(aObserver) + { + CActiveScheduler::Add(this); + } + + +/** Second phase constructor +@internalComponent +*/ +void CLbsBtGpsConfigImpl::ConstructL() + { + iRepos = CRepository::NewL(TUid::Uid(KLbsBtGpsConfigRepositoryUid)); + iRepos->NotifyRequest(KNotifyPartialKey, KNotifyMask, iStatus); + SetActive(); + }