bluetoothengine/btserviceutil/src/btdevrepositoryimpl.cpp
author hgs
Mon, 03 May 2010 14:36:07 +0300
changeset 29 48ae3789ce00
child 31 a0ea99b6fa53
permissions -rw-r--r--
201017_2

/*
* Copyright (c) 2010 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: respository of remote Bluetooth devices.
*
*/

#include "btdevrepositoryimpl.h"
#include <e32property.h>
#include <bt_subscribe.h>
#include <btservices/btdevrepository.h>
#include "btserviceutilconsts.h"

// ---------------------------------------------------------------------------
// Tells if two CBTDevice instances are for the same remote device
// ---------------------------------------------------------------------------
//
TBool CompareDeviceByAddress( const CBTDevice& aDevA, const CBTDevice& aDevB )
    {
    return aDevA.BDAddr() == aDevB.BDAddr();
    }

// ---------------------------------------------------------------------------
// Tells if these two instances are for the same remote device
// ---------------------------------------------------------------------------
//
TBool MatchDeviceAddress(const TBTDevAddr* aAddr, const CBTDevice& aDev)
    {
    return *aAddr == aDev.BDAddr();
    }

// ---------------------------------------------------------------------------
// Tells if these two instances are for the same remote device
// ---------------------------------------------------------------------------
//
TBool MatchDeviceAddress(const TBTDevAddr* aAddr, const CBtDevExtension& aDev)
    {
    return *aAddr == aDev.Device().BDAddr();
    }

// ======== MEMBER FUNCTIONS ========

// ---------------------------------------------------------------------------
// C++ default constructor
// ---------------------------------------------------------------------------
//
CBtDevRepositoryImpl::CBtDevRepositoryImpl()
    {
    }

// ---------------------------------------------------------------------------
// Symbian 2nd-phase constructor
// ---------------------------------------------------------------------------
//
void CBtDevRepositoryImpl::ConstructL()
    {
    // connect to registry
    User::LeaveIfError( iBTRegServ.Connect() );
    User::LeaveIfError( iBTRegistry.Open( iBTRegServ ) );
    iRegistryActive = CBtSimpleActive::NewL(
           *this, BtServiceUtil::ECreateRemoteDeviceViewRequest );
    // Start to get the list of devices from registry.
    CreateRemoteDeviceView();
    
    User::LeaveIfError( iBtRegistryKey.Attach(
            KPropertyUidBluetoothCategory, 
            KPropertyKeyBluetoothGetRegistryTableChange ) );

    iRegistryKeyActive = CBtSimpleActive::NewL( *this, BtServiceUtil::ERegistryPubSubWatcher );
    iBtRegistryKey.Subscribe( iRegistryKeyActive->RequestStatus() );
    iRegistryKeyActive->GoActive();
    iBtengConn = CBTEngConnMan::NewL( this );
    }

// ---------------------------------------------------------------------------
// NewL
// ---------------------------------------------------------------------------
//
CBtDevRepositoryImpl* CBtDevRepositoryImpl::NewL()
    {
    CBtDevRepositoryImpl* self = NULL;
    self = new (ELeave) CBtDevRepositoryImpl();
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CBtDevRepositoryImpl::~CBtDevRepositoryImpl()
    {
    iObservers.Close();
    delete iBtengConn;
    delete iRegistryActive;
    delete iRegRespRemoteDevices;
    iDevices.ResetAndDestroy();
    iDevices.Close();
    iBTRegistry.Close();
    iBTRegServ.Close();
    delete iRegistryKeyActive;
    iBtRegistryKey.Close();
    }

// ---------------------------------------------------------------------------
// AddObserverL
// ---------------------------------------------------------------------------
//
void CBtDevRepositoryImpl::AddObserverL( MBtDevRepositoryObserver* aObserver )
    {
    // Do not allow null pointer.
    if ( aObserver )
        {
        iObservers.AppendL( aObserver );
        }
    }

// ---------------------------------------------------------------------------
// RemoveObserver
// ---------------------------------------------------------------------------
//
void CBtDevRepositoryImpl::RemoveObserver( MBtDevRepositoryObserver* aObserver )
    {
    TInt i = iObservers.Find( aObserver );
    if ( i >= 0 )
        {
        iObservers.Remove( i );
        }
    }

// ---------------------------------------------------------------------------
// IsInitialized
// ---------------------------------------------------------------------------
//
TBool CBtDevRepositoryImpl::IsInitialized() const
    {
    return iInitialized;
    }

// ---------------------------------------------------------------------------
// AllDevices
// ---------------------------------------------------------------------------
//
const RDevExtensionArray& CBtDevRepositoryImpl::AllDevices() const
    {
    return iDevices;
    }

// ---------------------------------------------------------------------------
// Device
// ---------------------------------------------------------------------------
//
const CBtDevExtension* CBtDevRepositoryImpl::Device( 
        const TBTDevAddr& aAddr ) const
    {
    TInt pos = iDevices.Find( aAddr, MatchDeviceAddress);
    if ( pos > -1 )
        {
        return iDevices[pos];
        }
    return NULL;
    }

// ---------------------------------------------------------------------------
// From class MBtSimpleActiveObserver.
// Checks if there is an authentication result.
// ---------------------------------------------------------------------------
//
void CBtDevRepositoryImpl::RequestCompletedL( CBtSimpleActive* aActive, TInt aStatus )
    {
    if ( aActive->RequestId() == BtServiceUtil::ECreateRemoteDeviceViewRequest )
        {
        HandleCreateRemoteDeviceViewCompletedL( aStatus );
        }
    else if ( aActive->RequestId() == BtServiceUtil::EGetRemoteDevicesRequest )
        {
        HandleGetRemoteDevicesCompletedL( aStatus );
        }
    else if ( aActive->RequestId() == BtServiceUtil::ERegistryPubSubWatcher )
        {
        TInt myChangedTable;
        iBtRegistryKey.Subscribe( aActive->RequestStatus() );
        aActive->GoActive();
        TInt err = iBtRegistryKey.Get( myChangedTable );
        if( !err && myChangedTable == KRegistryChangeRemoteTable )
            {
            if ( !iRegistryActive->IsActive() )
                {
                CreateRemoteDeviceView();
                }
            else
                {
                iNotHandledRegEventCounter++;
                }
            }
        }
    }

// ---------------------------------------------------------------------------
// From class MBtSimpleActiveObserver.
// Checks if there is an authentication result.
// ---------------------------------------------------------------------------
//
void CBtDevRepositoryImpl::CancelRequest( TInt aRequestId )
    {
    if ( aRequestId == BtServiceUtil::ECreateRemoteDeviceViewRequest )
        {
        iBTRegistry.CancelRequest(iRegistryActive->RequestStatus());
        }
    else if ( aRequestId == BtServiceUtil::EGetRemoteDevicesRequest )
        {
        iRegRespRemoteDevices->Cancel();
        }
    else if ( aRequestId == BtServiceUtil::ERegistryPubSubWatcher )
        {
        iBtRegistryKey.Cancel();
        }
    }

// ---------------------------------------------------------------------------
// From class MBtSimpleActiveObserver.
// ---------------------------------------------------------------------------
//
void CBtDevRepositoryImpl::HandleError( CBtSimpleActive* aActive, TInt aError )
    {
    (void) aError;
    if ( aActive->RequestId() == BtServiceUtil::ECreateRemoteDeviceViewRequest || 
            aActive->RequestId() == BtServiceUtil::EGetRemoteDevicesRequest )
        {// leave happened in registry operation, delete registry response:
        delete iRegRespRemoteDevices;
        iRegRespRemoteDevices = NULL;
        }
    }

// ---------------------------------------------------------------------------
// From class MBTEngConnObserver.
// ---------------------------------------------------------------------------
//
void CBtDevRepositoryImpl::ConnectComplete( TBTDevAddr& aAddr, TInt aErr, 
                               RBTDevAddrArray* aConflicts)
    {
    // connection is single profile based, to make sure getting the correct status, 
    // we always retrieve it from btengconnman:
    (void)aConflicts;
    (void) aErr;
    TInt pos = iDevices.Find( aAddr, MatchDeviceAddress );
    if ( pos > -1 )
        {
        TBTEngConnectionStatus  status = EBTEngNotConnected;
        // error returned from the call is treated as not connected.
        (void) iBtengConn->IsConnected( aAddr,  status );
        iDevices[pos]->SetServiceConnectionStatus( status );
        }
    }

// ---------------------------------------------------------------------------
// From class MBTEngConnObserver.
// ---------------------------------------------------------------------------
//
void CBtDevRepositoryImpl::DisconnectComplete( TBTDevAddr& aAddr, TInt aErr )
    {
    // unified handling for connections status events:
    ConnectComplete( aAddr, aErr, NULL);
    }

// ---------------------------------------------------------------------------
// issue creating a remote device view from the registry
// ---------------------------------------------------------------------------
//
void CBtDevRepositoryImpl::CreateRemoteDeviceView()
    {
    iNotHandledRegEventCounter = 0;
    (void) iBTRegistry.CloseView();
    TBTRegistrySearch searchPattern;
    searchPattern.FindAll();
    iRegistryActive->SetRequestId( BtServiceUtil::ECreateRemoteDeviceViewRequest );
    iBTRegistry.CreateView( searchPattern, iRegistryActive->iStatus );
    iRegistryActive->GoActive();
    }

// ---------------------------------------------------------------------------
// gets the paired devices from the view created by CreatePairedDevicesView
// ---------------------------------------------------------------------------
//
void CBtDevRepositoryImpl::GetRemoteDevicesL()
    {
    delete iRegRespRemoteDevices;
    iRegRespRemoteDevices = NULL;
    iRegRespRemoteDevices = CBTRegistryResponse::NewL( iBTRegistry );
    iRegistryActive->SetRequestId( BtServiceUtil::EGetRemoteDevicesRequest );
    iRegRespRemoteDevices->Start( iRegistryActive->iStatus );
    iRegistryActive->GoActive();
    }

// ---------------------------------------------------------------------------
// re-create a paired device view if registry was changed during the previous
// operation. otherwise if the view is not empty, get the remote devices.
// ---------------------------------------------------------------------------
//
void CBtDevRepositoryImpl::HandleCreateRemoteDeviceViewCompletedL( TInt aStatus )
    {
    // aStatus may indicate the number of devices from registry.
    // However, our algorithm does not rely on this return error 
    // for implementation simplicity.
    (void) aStatus;
    if (iNotHandledRegEventCounter)
        { // more registry change detected, create paired device view again:
        CreateRemoteDeviceView( );
        }
    else
        {
        GetRemoteDevicesL( );
        }
    }

// ---------------------------------------------------------------------------
// update remote device list. if registry was changed, create a new view.
// otherwise inform client for any changes.
// ---------------------------------------------------------------------------
//
void CBtDevRepositoryImpl::HandleGetRemoteDevicesCompletedL( TInt aStatus )
    {
    // aStatus may indicate the number of devices from registry.
    // However, our algorithm does not rely on this return error.
    (void) aStatus;
    if (iNotHandledRegEventCounter)
        { // more registry change detected, create paired device view again:
        CreateRemoteDeviceView( );
        return;
        }

    UpdateRemoteDeviceRepositoryL();
    if ( !iInitialized )
        {
        iInitialized = ETrue;
        // The first time we have got the device lists from registry,
        // Get the connections statuses of these devices from bteng.
        for ( TInt i = iDevices.Count() - 1; i > -1; --i )
            {
            TBTEngConnectionStatus  status = EBTEngNotConnected;
            // error returned from the call is treated as not connected.
            (void) iBtengConn->IsConnected( iDevices[i]->Addr(),  status );
            iDevices[i]->SetServiceConnectionStatus( status );
            }
        for ( TInt i = 0; i < iObservers.Count(); ++i )
            {
            iObservers[i]->RepositoryInitialiazed();
            }
        }
    }

// ---------------------------------------------------------------------------
// update remote devices in local array with the latest data
// ---------------------------------------------------------------------------
//
void CBtDevRepositoryImpl::UpdateRemoteDeviceRepositoryL()
    {
    TIdentityRelation<CBTDevice> addrComp( CompareDeviceByAddress );
    RBTDeviceArray& devsFromReg = iRegRespRemoteDevices->Results();
    for ( TInt i = iDevices.Count() - 1; i > -1; --i )
        {
        TInt pos = devsFromReg.Find( &(iDevices[i]->Device()), addrComp );
        if ( pos > KErrNotFound )
            {
            // Device is found in registry, check if its properties have been changed
            TUint similarity = devsFromReg[pos]->CompareTo( iDevices[i]->Device() );
            TBool changed = EFalse;
            if ( similarity != 
                    ( CBTDevice::EAllNameProperties | 
                      TBTNamelessDevice::EAllNamelessProperties) )
                {
                // This device was updated in registry.
                // move its ownership to local store
                iDevices[i]->SetDeviceL( devsFromReg[pos] );
                changed = ETrue;
                }
            else
                {
                // This device has no update:
                delete devsFromReg[pos];
                }
            // either the instance at pos has been moved or deleted.
            devsFromReg.Remove( pos );
            if ( iInitialized && changed )
                {
                for ( TInt i = 0; i < iObservers.Count(); ++i )
                    {
                    iObservers[i]->BtDeviceChangedInRegistry( *iDevices[i], similarity );
                    }
                }
            }
        else
            {
            // This device was deleted from registry.
            // Free it from the local store before informing client.
            TBTDevAddr addr = iDevices[i]->Addr();
            delete iDevices[i];
            iDevices.Remove( i );
            if ( iInitialized )
                {
                for ( TInt i = 0; i < iObservers.Count(); ++i )
                    {
                    iObservers[i]->BtDeviceDeleted( addr );
                    }
                }
            }
        }
    
    // Remaining devices in iRegRespRemoteDevices are new devices:
    for ( TInt i = 0; i < devsFromReg.Count() ; i++ )
        {
        CBtDevExtension* devExt = CBtDevExtension::NewLC( devsFromReg[i] );
        iDevices.AppendL( devExt );
        CleanupStack::Pop( devExt );
        devsFromReg.Remove( i );
        if ( iInitialized )
            {
            for ( TInt i = 0; i < iObservers.Count(); ++i )
                {
                iObservers[i]->BtDeviceAdded( *iDevices[ iDevices.Count() - 1 ] );
                }
            }
        }
    // the devices in devsFromReg was either deleted, or moved.
    delete iRegRespRemoteDevices;
    iRegRespRemoteDevices = NULL;
    }