bluetoothengine/btui/btuidelegate/btdelegateconnect.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 15:25:10 +0300
branchRCL_3
changeset 22 613943a21004
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* 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: 
*
*/

#include "btdelegateconnect.h"
#include "btuiutil.h"
#include "btqtconstants.h"
#include <QModelIndex>
#include <hblabel.h>
#include <btsettingmodel.h>
#include <btdevicemodel.h>
#include <hbnotificationdialog.h>
#include <hbmessagebox.h>
#include "btuiiconutil.h"
#include "btdelegatefactory.h"
#include <bluetoothuitrace.h>
#include <e32property.h>
#include <ctsydomainpskeys.h>  

BtDelegateConnect::BtDelegateConnect(
        BtSettingModel* settingModel, 
        BtDeviceModel* deviceModel, QObject *parent) :
    BtAbstractDelegate(settingModel, deviceModel, parent), mBtengConnMan(0),
    mAbstractDelegate(0), mActiveHandling(false)
{
    
}

BtDelegateConnect::~BtDelegateConnect()
{
    delete mBtengConnMan;
}

/*!
 * execute connect operation
 *    first check if power is on
 */
void BtDelegateConnect::exec( const QVariant &params )
{
    if ( mActiveHandling ) {
        emit commandCompleted( KErrAlreadyExists );
        return;
    }
    mIndex = params.value<QModelIndex>();
    mActiveHandling = true;
    // save needed values from model
    mDeviceName = (mIndex.data(BtDeviceModel::NameAliasRole)).toString();
    QString addrStr = (mIndex.data(BtDeviceModel::ReadableBdaddrRole)).toString(); 
    addrReadbleStringToSymbian( addrStr, mAddr );  
    
    mCod = (mIndex.data(BtDeviceModel::CoDRole)).toInt();
    mMajorProperty = (mIndex.data(BtDeviceModel::MajorPropertyRole)).toInt();
    
    // first turn on power if needed
    if (!isBtPowerOn()) {
        if (!mAbstractDelegate) //if there is no other delegate running
        { 
            mAbstractDelegate = BtDelegateFactory::newDelegate(BtDelegate::ManagePower, 
                    getSettingModel(), getDeviceModel() ); 
            connect( mAbstractDelegate, SIGNAL(commandCompleted(int)), this, SLOT(powerDelegateCompleted(int)) );
            mAbstractDelegate->exec(QVariant(BtPowerOn));
        }
    } 
    else {
        // power is already on
        exec_connect();
    }
}

/*!
 * power delegate has completed, continue processing
 */
void BtDelegateConnect::powerDelegateCompleted(int status)
{
    if (mAbstractDelegate)
    {
        disconnect(mAbstractDelegate);
        delete mAbstractDelegate;
        mAbstractDelegate = 0;
    }
    if ( status == KErrNone ) {
        // continue connecting
        exec_connect();
    } 
    else {
        // error
        emitCommandComplete(status);
    }
}

/*!
 * execute connect operation
 */
void BtDelegateConnect::exec_connect()
{
    int error = KErrNone;
    
    if ( ! mBtengConnMan ){
        TRAP( error, mBtengConnMan = CBTEngConnMan::NewL(this) );
    }

    if ( !error ) {
        TBTDeviceClass btEngDeviceClass(mCod);
        error = mBtengConnMan->Connect(mAddr, btEngDeviceClass);
    }
    
    if( error ) {
        emitCommandComplete(error);
    }
}

/*!
 * connect callback from CBTengConnMan
 */
void BtDelegateConnect::ConnectComplete( TBTDevAddr& aAddr, TInt aErr, 
                                   RBTDevAddrArray* aConflicts )
{
    // It is possible that another audio device has just connected to phone when we are
    // connecting to this audio device. Or a device is connected while this command
    // is idle. No handling for these cases.
    if ( mAddr != aAddr || !mActiveHandling ) {  
        return;
    }
    
    // conflict could occur as well if another audio device is already connected
    // since currently we don't support multiple audio device connections.
    if ( aErr && aConflicts && aConflicts->Count() ) {
        // get the display name of the device that is 
        // causing the conflict 
        QString conflictDevAddr;
        addrSymbianToReadbleString(conflictDevAddr, (*aConflicts)[0] );
        QModelIndex start = getDeviceModel()->index(0,0);
        QModelIndexList indexList = getDeviceModel()->match(start, BtDeviceModel::ReadableBdaddrRole, conflictDevAddr);
        BTUI_ASSERT_X(indexList.count(), "BtDelegateConnect::ConnectComplete()", "device missing from model!");
        mConflictDevIndex = indexList.at(0);
      
        // check if conflict device is being used in a call
        // Note:  actually only checking if *any* audio device is involved in a call, not necessarily the
        // one we are concerned with here.  Btaudioman does not currently support finding out the actual 
        // device involved in a call. 
        if (callOngoing()) {
            HbMessageBox::warning(hbTrId("txt_bt_info_not_possible_during_a_call"));
            emitCommandComplete(KErrCancel);
        }
        else {
            // no call, check if user wants to disconnect conflict device 
            QString conflictDevName = (mConflictDevIndex.data(BtDeviceModel::NameAliasRole)).toString();    
    
            QString questionText(hbTrId("txt_bt_info_to_connect_1_2_needs_to_be_disconnec")
                    .arg(mDeviceName).arg(conflictDevName));
            
            HbMessageBox::question( questionText, this, SLOT(handleUserAnswer(int)), 
                    HbMessageBox::Continue | HbMessageBox::Cancel );       
        }
    }
    else {
        // command is finished
        emitCommandComplete(aErr);
    }
}

/*!
 * handle user response to query about disconnecting conflict device
 */
void BtDelegateConnect::handleUserAnswer( int answer )
{
    if( answer == HbMessageBox::Continue ) { 
        // Continue, ie. disconnect conflict device and then try reconnecting again
        if (!mAbstractDelegate) //if there is no other delegate running
        { 
            QList<QVariant>list;
            QVariant paramFirst;
            paramFirst.setValue(mConflictDevIndex);    
            QVariant paramSecond(ServiceLevel);
            list.append(paramFirst);
            list.append(paramSecond);
            QVariant paramsList(list);
            mAbstractDelegate = BtDelegateFactory::newDelegate(BtDelegate::Disconnect, 
                    getSettingModel(), getDeviceModel() ); 
            connect( mAbstractDelegate, SIGNAL(commandCompleted(int)), this, SLOT(disconnectDelegateCompleted(int)) );
            mAbstractDelegate->exec(paramsList);
        }
    }
    else {
        // Cancel connect operation
        emitCommandComplete(KErrCancel);
    }
}

/*!
 * returns true if phone call is ongoing
 */
bool BtDelegateConnect::callOngoing()
{
    // ToDo:  check if there exists Qt PS key for ongoing call
    int callState;
    int err = RProperty::Get(KPSUidCtsyCallInformation, KCTsyCallState, callState);
    if (!err && (callState == EPSCTsyCallStateNone || callState == EPSCTsyCallStateUninitialized)) {
        return false;
    }
    else {
        return true;
    }
}

/*!
 * disconnecting conflict device has completed, continue connecting
 */
void BtDelegateConnect::disconnectDelegateCompleted(int status)
{
    if (mAbstractDelegate)
    {
        disconnect(mAbstractDelegate);
        delete mAbstractDelegate;
        mAbstractDelegate = 0;
    }
    // finished disconnecting conflict device, now reconnect to original device
    if ( status == KErrNone ) {
        exec_connect();
    }
    else {
        // disconnect failed, abort
        emitCommandComplete( status );
    }
}

/*!
 * not used here
 */
void BtDelegateConnect::DisconnectComplete( TBTDevAddr& aAddr, TInt aErr )
{
    Q_UNUSED(aAddr);
    Q_UNUSED(aErr);    
}

/*!
 * cancel connect operation
 *   ConnectComplete() callback will be called upon completion of cancel with KErrCancel
 */
void BtDelegateConnect::cancel()
{
    if ( mBtengConnMan ) {
        mBtengConnMan->CancelConnect(mAddr);
    }
}

/*!
 * shows user notes with connection success/failure information
 *    cancel operation is handled without a user note
 */
void BtDelegateConnect::emitCommandComplete(int error)
{
    if ( error == KErrNone ) {
        // success, show indicator with connection status
        
        HbIcon icon = getBadgedDeviceTypeIcon( mCod, mMajorProperty, BtuiNoCorners); 
        QString str(hbTrId("txt_bt_dpopinfo_connected_to_1"));
        HbNotificationDialog::launchDialog( icon, hbTrId("txt_bt_dpophead_connected"), 
            str.arg(mDeviceName) );  
    }
    else if ( error == KErrCancel ) {
        // no user note, return success since cancel operation completed successfully
        error = KErrNone;
    }
    else {
        // failure to connect, show user note
        QString err(hbTrId("txt_bt_info_unable_to_connect_with_bluetooth"));
        HbMessageBox::warning(err.arg(mDeviceName));
    }
    mActiveHandling = false;
    
    emit commandCompleted(error);
}