--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothengine/bteng/src/btengserver.cpp Mon Jan 18 20:28:57 2010 +0200
@@ -0,0 +1,1414 @@
+/*
+* Copyright (c) 2006-2008 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: Server-side implementation of BTEng
+*
+*/
+
+
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <bthci.h>
+#include <bt_subscribe_partner.h>
+#endif
+
+#include <e32base.h>
+#include <btmanclient.h>
+#include <es_sock.h>
+#include <btnotif.h>
+#include <utf.h>
+#include <ecom/ecom.h>
+#include <centralrepository.h>
+#include <featmgr.h>
+#include <AknSmallIndicator.h>
+#include <avkon.hrh>
+#include <bt_subscribe.h>
+#include "btengserver.h"
+#include "btengsrvstate.h"
+#include "btengsrvsession.h"
+#include "btengsrvpluginmgr.h"
+#include "btengsrvbbconnectionmgr.h"
+#include "btengsrvkeywatcher.h"
+#include "btengsdpdbhandler.h"
+#include "btengclientserver.h"
+#include "btengsecpolicy.h"
+#include "btengprivatecrkeys.h"
+#include "btengprivatepskeys.h"
+#include "btengplugin.h"
+#include "btengpairman.h"
+#include "debug.h"
+
+/** Bluetooth Engine server thread name */
+_LIT( KBTEngThreadName, "BTEngine" );
+
+/** Constant for converting minutes to microseconds */
+const TInt64 KMinutesInMicroSecs = MAKE_TINT64( 0, 60000000 );
+
+/** Idle timeout for shutting down the server (when power is off,
+ * and no clients are connected). The value is 3 seconds.
+ */
+const TInt KBTEngSrvIdleTimeout = 3000000;
+
+/** Timeout for disabling Simple Pairing debug mode. The value is 30 minutes. */
+const TInt KBTEngSspDebugModeTimeout = 1800000000;
+
+/** Timeout for determining that BT is not turned off automatically.
+ * The value is 10.5 seconds.
+ */
+const TInt KBTEngBtAutoOffTimeout = 10500000;
+
+/** Enumeration of bitmask for keeping track of different timers. */
+enum TTimerQueued
+ {
+ ENone = 0x00,
+ EScanModeTimer = 0x01,
+ EIdleTimer = 0x02,
+ EAutoPowerOffTimer = 0x04,
+ ESspDebugModeTimer = 0x08
+ };
+
+/** PubSub key read and write policies */
+_LIT_SECURITY_POLICY_C2( KBTEngPSKeyReadPolicy,
+ ECapabilityLocalServices, ECapabilityReadDeviceData );
+_LIT_SECURITY_POLICY_C2( KBTEngPSKeyWritePolicy,
+ ECapabilityLocalServices, ECapabilityWriteDeviceData );
+
+// Default values for Major and Minor Device Class
+const TUint16 KCoDDefaultServiceClass = EMajorServiceTelephony | EMajorServiceObjectTransfer | EMajorServiceNetworking;
+const TUint8 KCoDDefaultMajorDeviceClass = EMajorDevicePhone;
+const TUint8 KCoDDefaultMinorDeviceClass = EMinorDevicePhoneSmartPhone;
+
+// ======== LOCAL FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Constructs and returns an application object.
+// ---------------------------------------------------------------------------
+//
+void RunServerL()
+ {
+ TRACE_FUNC_ENTRY
+ User::RenameThread( KBTEngThreadName );
+ // Create and install the active scheduler for this thread.
+ CActiveScheduler* scheduler = new( ELeave ) CActiveScheduler();
+ CleanupStack::PushL( scheduler );
+ CActiveScheduler::Install( scheduler );
+ // create the server (leave it on the cleanup stack)
+ CBTEngServer* btServer = CBTEngServer::NewLC();
+ // Initialisation complete, now signal the client
+ RProcess::Rendezvous( KErrNone );
+ // The server is not up and running.
+ TRACE_INFO( ( _L( "[BTENG]\t BTEng server now up and running" ) ) )
+ // The active scheduler runs during the lifetime of this thread.
+ CActiveScheduler::Start();
+ // Cleanup the server and scheduler.
+ CleanupStack::PopAndDestroy( btServer );
+ CleanupStack::PopAndDestroy( scheduler );
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// Completes the message and panics the client.
+// ---------------------------------------------------------------------------
+//
+void PanicClient( const RMessage2& aMessage, TInt aPanic )
+ {
+ TRACE_INFO( ( _L( "[BTENG]\t PanicClient: Reason %d" ), aPanic ) )
+ aMessage.Panic( KBTEngPanic, aPanic );
+ }
+
+
+// ---------------------------------------------------------------------------
+// Panic the server.
+// ---------------------------------------------------------------------------
+//
+void PanicServer( TInt aPanic )
+ {
+ TRACE_INFO( ( _L( "[BTENG]\t PanicClient: Reason %d" ), aPanic ) )
+ User::Panic( KBTEngPanic, aPanic );
+ }
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// C++ default constructor
+// (Priority is not as high as in prev. architecture, but should be enough)
+// ---------------------------------------------------------------------------
+//
+CBTEngServer::CBTEngServer()
+: CPolicyServer( EPriorityHigh, KBTEngServerPolicy )
+ {
+ iEnableDutMode = EFalse;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Symbian 2nd-phase constructor
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::ConstructL()
+ {
+ TRACE_FUNC_ENTRY
+ // No need to check _BT flag here, as the server can
+ // only be started by BTEng components.
+
+ // Add the server to the active scheduler (from CServer2):
+ StartL( KBTEngServerName );
+ User::LeaveIfError( RProperty::Define( KPSUidBluetoothTestingMode, KBTDutEnabled,
+ RProperty::EInt, KBTEngPSKeyReadPolicy,
+ KBTEngPSKeyWritePolicy ) );
+ User::LeaveIfError( RProperty::Define( KPSUidBluetoothTestingMode, KBTSspDebugmode,
+ RProperty::EInt, KBTEngPSKeyReadPolicy,
+ KBTEngPSKeyWritePolicy ) );
+ User::LeaveIfError( RProperty::Define( KPSUidBluetoothEnginePrivateCategory,
+ KBTBlockDevAddr, RProperty::EText,
+ KBTEngPSKeyReadPolicy,
+ KBTEngPSKeyWritePolicy ) );
+ User::LeaveIfError( RProperty::Define( KPSUidBluetoothEnginePrivateCategory,
+ KBTOutgoingPairing,
+ RProperty::EByteArray,
+ KBTEngPSKeyReadPolicy,
+ KBTEngPSKeyWritePolicy) );
+ User::LeaveIfError( RProperty::Define( KPSUidBluetoothEnginePrivateCategory,
+ KBTConnectionTimeStamp,
+ RProperty::EByteArray,
+ KBTEngPSKeyReadPolicy,
+ KBTEngPSKeyWritePolicy) );
+ User::LeaveIfError( RProperty::Define( KPSUidBluetoothEnginePrivateCategory,
+ KBTTurnBTOffQueryOn,
+ RProperty::EInt,
+ KBTEngPSKeyReadPolicy,
+ KBTEngPSKeyWritePolicy) );
+
+ User::LeaveIfError( RProperty::Define( KPSUidBluetoothEnginePrivateCategory,
+ KBTNotifierLocks,
+ RProperty::EByteArray,
+ KBTEngPSKeyReadPolicy,
+ KBTEngPSKeyWritePolicy) );
+
+ User::LeaveIfError( iSocketServ.Connect() );
+ LoadBTPowerManagerL();
+ // The server is only started by its client, so leave the state
+ // machine in Init state. A request to turn power on will follow
+ // usually immediately.
+ iServerState = CBTEngSrvState::NewL( this );
+ iWatcher = CBTEngSrvKeyWatcher::NewL( this );
+ iPluginMgr = CBTEngSrvPluginMgr::NewL( this );
+ iBBConnMgr = CBTEngSrvBBConnMgr::NewL( iSocketServ );
+
+ User::LeaveIfError( iBTRegServ.Connect() );
+ iPairMan = CBTEngPairMan::NewL( *this );
+
+ TCallBack idleCb( IdleTimerCallBack, this );
+ iIdleCallBack.Set( idleCb );
+ TCallBack sspCb( DebugModeTimerCallBack, this );
+ iDebugModeCallBack.Set( sspCb );
+ TCallBack scanModeCb( ScanModeTimerCallBack, this );
+ iScanModeCallBack.Set( scanModeCb );
+ TCallBack powerOffCb( AutoPowerOffCallBack, this );
+ iPowerOffCallBack.Set( powerOffCb );
+ iTimer = CDeltaTimer::NewL(CActive::EPriorityLow);
+
+ iEnterpriseEnablementMode = BluetoothFeatures::EnterpriseEnablementL();
+ TRACE_INFO( ( _L( "iEnterpriseEnablementMode = %d" ), iEnterpriseEnablementMode) )
+ if ( iEnterpriseEnablementMode == BluetoothFeatures::EDisabled )
+ {
+ SetVisibilityModeL( EBTVisibilityModeNoScans, 0 );
+ }
+
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// NewL
+// ---------------------------------------------------------------------------
+//
+CBTEngServer* CBTEngServer::NewLC()
+ {
+ CBTEngServer* self = new( ELeave ) CBTEngServer();
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ return self;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CBTEngServer::~CBTEngServer()
+ {
+ TRACE_FUNC_ENTRY
+ if( iTimer )
+ {
+ iTimerQueued = ENone;
+ iTimer->Remove( iScanModeCallBack );
+ iTimer->Remove( iPowerOffCallBack );
+ iTimer->Remove( iIdleCallBack);
+ iTimer->Remove( iDebugModeCallBack );
+ }
+ RProperty::Delete( KPSUidBluetoothTestingMode, KBTDutEnabled );
+ RProperty::Delete( KPSUidBluetoothTestingMode, KBTSspDebugmode );
+ RProperty::Delete( KPSUidBluetoothEnginePrivateCategory, KBTBlockDevAddr );
+ RProperty::Delete( KPSUidBluetoothEnginePrivateCategory, KBTOutgoingPairing );
+ RProperty::Delete( KPSUidBluetoothEnginePrivateCategory, KBTConnectionTimeStamp );
+ RProperty::Delete( KPSUidBluetoothEnginePrivateCategory, KBTTurnBTOffQueryOn );
+ RProperty::Delete( KPSUidBluetoothEnginePrivateCategory, KBTNotifierLocks );
+ delete iTimer;
+ delete iSdpDbHandler;
+ delete iWatcher;
+ delete iPluginMgr;
+ delete iBBConnMgr;
+ delete iServerState;
+ delete iPairMan;
+ iPowerMgr.Close();
+ iSocketServ.Close();
+ iBTRegServ.Close();
+ }
+
+
+// ---------------------------------------------------------------------------
+// Turn BT on or off.
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::SetPowerStateL( TBTPowerStateValue aState, TBool aTemporary )
+ {
+ TRACE_FUNC_ARG( ( _L( "setting power state %d" ), (TInt) aState ) )
+ if ( aState == EBTPowerOn && iEnterpriseEnablementMode == BluetoothFeatures::EDisabled )
+ {
+ TRACE_INFO( ( _L( "\tno we're not... Bluetooth is enterprise-IT-disabled" ) ) )
+ User::Leave(KErrNotSupported);
+ }
+
+ TBTPowerStateValue currentState = EBTPowerOff;
+ CheckTemporaryPowerStateL( currentState, aState, aTemporary );
+
+ if( ( currentState == aState || ( aTemporary && aState == EBTPowerOff ) ) && iServerState->CurrentOperation() == CBTEngSrvState::ESrvOpIdle )
+ {
+ // The requested power state is already active, ignore silently.
+ // We don't return an error here, as there is no error situation.
+ TRACE_INFO( ( _L( "SetPowerStateL: nothing to do" ) ) )
+ if(currentState == aState)
+ {
+ // Make sure that the CenRep key is in sync.
+ // During boot-up, the pwoer is set from the CenRep key, so we could
+ // end up out-of-sync.
+ TRACE_INFO( ( _L( "SetPowerStateL: currentState == aState" ) ) )
+ UpdateCenRepPowerKeyL( aState );
+ }
+ return;
+ }
+ if( aState )
+ {
+ // Hardware power on is the first step.
+ User::LeaveIfError( SetPowerState( aState ) );
+ }
+ else
+ {
+ //Prevent BT visibility in the situation when we turn OFF BT Engine
+ //but FM Radio is still alive
+ SetVisibilityModeL( EBTVisibilityModeNoScans, 0 );
+ // Hardware power off is the last step.
+ // First disconnect all plug-ins.
+ iPluginMgr->DisconnectAllPlugins();
+ }
+ // We only signal that BT is on after everything has completed (through
+ // the CenRep power state key), so that all services are initialized.
+ // We signal that BT is off immediately though, so that our clients will
+ // not try to use BT during power down.
+ iServerState->StartStateMachineL( (TBool) aState );
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::SetVisibilityModeL( TBTVisibilityMode aMode, TInt aTime )
+ {
+ TRACE_FUNC_ENTRY
+
+ if ( aMode != EBTVisibilityModeNoScans && iEnterpriseEnablementMode == BluetoothFeatures::EDisabled )
+ {
+ TRACE_INFO( ( _L( "\tnot changing anything... Bluetooth is enterprise-IT-disabled" ) ) )
+ User::Leave(KErrNotSupported);
+ }
+
+ TInt err = KErrNone;
+ iTimerQueued &= ~EScanModeTimer;
+ iTimer->Remove( iScanModeCallBack );
+ if( aMode != EBTVisibilityModeNoScans )
+ {
+ CRepository* cenRep = CRepository::NewL( KCRUidBTEngPrivateSettings );
+ err = cenRep->Set( KBTDiscoverable, aMode );
+ delete cenRep;
+ }
+ if( !err && aMode == EBTVisibilityModeTemporary )
+ {
+ // We need TInt64 here, as the max. time in microseconds for the
+ // max. value (1 hour) is larger than KMaxTInt32.
+ TInt64 timeMicroSec = MAKE_TINT64( 0, aTime );
+ timeMicroSec = timeMicroSec * KMinutesInMicroSecs;
+ TTimeIntervalMicroSeconds interval( timeMicroSec );
+ // Queue callback to set the visibility back to hidden.
+ err = iTimer->QueueLong( interval, iScanModeCallBack );
+ iTimerQueued |= EScanModeTimer;
+ aMode = EBTVisibilityModeGeneral;
+ }
+ else if( !err && iRestoreVisibility )
+ {
+ // The user overrides, do not restore visibility mode anymore.
+ iRestoreVisibility = EFalse;
+ }
+ if( !err )
+ {
+ err = RProperty::Set( KUidSystemCategory,
+ KPropertyKeyBluetoothSetScanningStatus, aMode );
+ }
+ TBool hiddenMode = ( aMode == EBTVisibilityModeHidden );
+ if( !err && aMode != EBTVisibilityModeNoScans )
+ {
+ // In hidden mode, we only accept connections from paired devices.
+ err = RProperty::Set( KUidSystemCategory,
+ KPropertyKeyBluetoothSetAcceptPairedOnlyMode,
+ hiddenMode );
+ }
+
+ User::LeaveIfError( err ); // To communicate the result to the client.
+ TRACE_FUNC_EXIT
+ }
+
+// ---------------------------------------------------------------------------
+// The method is called when BT stack scanning mode P&S key is changed
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::UpdateVisibilityModeL( TInt aStackScanMode )
+ {
+ TRACE_FUNC_ENTRY
+ TRACE_INFO( ( _L( "[BTEng]\t aStackScanMode: %d" ), aStackScanMode ) )
+ TBTVisibilityMode currentMode;
+
+ CRepository* cenRep = CRepository::NewLC( KCRUidBTEngPrivateSettings );
+ User::LeaveIfError( cenRep->Get( KBTDiscoverable, (TInt&) currentMode ) );
+
+ // In case we are in temp visibility mode, we cannot always know whether the BT stack
+ // scan mode key was set by some external party or by us in SetVisibilityModeL above.
+ // Therefore we cannot stop the timer in case aMode is EBTVisibilityModeGeneral and
+ // currentmode is EBTVisibilityModeTemporary
+ if( !( currentMode == EBTVisibilityModeTemporary && aStackScanMode == EBTVisibilityModeGeneral ) )
+ {
+ // Cancel the timer and queue it again if needed.
+ iTimerQueued &= ~EScanModeTimer;
+ iTimer->Remove( iScanModeCallBack );
+ if( currentMode != aStackScanMode )
+ {
+ if( aStackScanMode == EPageScanOnly || aStackScanMode == EInquiryAndPageScan )
+ {
+ User::LeaveIfError( cenRep->Set( KBTDiscoverable, aStackScanMode ) );
+ }
+ else if( aStackScanMode == EInquiryScanOnly )
+ {
+ // We don't support ENoScansEnabled nor EInquiryScanOnly mode
+ // -> Consider these as same as Hidden
+ User::LeaveIfError( cenRep->Set( KBTDiscoverable, EBTVisibilityModeHidden ) );
+ }
+ else if( aStackScanMode == ENoScansEnabled )
+ {
+ //We don't change KBTDiscoverable here, because ENoScansEnabled
+ //indicates BT/SYSTEM shutdown is happening
+ }
+ }
+ }
+ SetUiIndicatorsL();
+ CleanupStack::PopAndDestroy( cenRep );
+ TRACE_FUNC_EXIT
+ }
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::DisconnectAllL()
+ {
+ TRACE_FUNC_ENTRY
+ iPluginMgr->DisconnectAllPlugins();
+ TCallBack cb( DisconnectAllCallBack, this );
+ iBBConnMgr->DisconnectAllLinksL( cb );
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::SetDutMode( TInt aDutMode )
+ {
+ TRACE_FUNC_ARG( ( _L( "DUT mode %d" ), aDutMode ) )
+
+ if (aDutMode == EBTDutOff)
+ {
+ return;
+ }
+
+ TInt powerState = EBTPowerOff;
+ CRepository* cenrep = NULL;
+
+ TRAPD(err, cenrep = CRepository::NewL(KCRUidBluetoothPowerState));
+
+ if (!err && cenrep)
+ {
+ cenrep->Get(KBTPowerState, powerState);
+ delete cenrep;
+ cenrep = NULL;
+ }
+ else
+ {
+ return;
+ }
+
+ if (powerState == EBTPowerOn)
+ {
+
+#ifndef __WINS__
+
+ TInt err = iDutMode.Open();
+ TRACE_FUNC_ARG( ( _L( "Open DUT mode handle err %d" ), err) )
+ if(!err)
+ {
+ iDutMode.ActivateDutMode();
+ iDutMode.Close();
+ }
+#endif //__WINS__
+ }
+ iEnableDutMode = EFalse;
+ }
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::ScanModeTimerCompletedL()
+ {
+ TRACE_FUNC_ENTRY
+ // The timer has completed, so remove our reference as well.
+ iTimerQueued &= ~EScanModeTimer;
+ iTimer->Remove( iScanModeCallBack );
+ SetVisibilityModeL( EBTVisibilityModeHidden, 0 );
+ TBTPowerStateValue power = EBTPowerOff;
+ TInt err = GetHwPowerState( (TBTPowerStateValue&) power );
+ if( !err && power )
+ {
+ // Show a notification to the user
+ TBTGenericInfoNotiferParamsPckg pckg;
+ pckg().iMessageType = EBTVisibilityTimeout;
+
+ RNotifier notifier;
+ TInt err = notifier.Connect();
+ if( !err )
+ {
+ err = notifier.StartNotifier( KBTGenericInfoNotifierUid, pckg );
+ notifier.Close();
+ }
+ }
+ TRACE_FUNC_RES( ( _L( "result: %d" ), err ) )
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::DisconnectAllCompleted()
+ {
+ // Check if we are powering off. Otherwise we have just been
+ // requested to disconnect all, e.g. for system shutdown.
+ if( iServerState->CurrentOperation() == CBTEngSrvState::EPowerOff )
+ {
+ (void) SetPowerState( EFalse );
+ // Put the state machine into idle state.
+ iServerState->ChangeState();
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::DispatchPluginMessageL( const RMessage2& aMessage )
+ {
+ iPluginMgr->ProcessCommandL( aMessage );
+ }
+
+
+// ---------------------------------------------------------------------------
+// A new session has been added, update the session count.
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::AddSession()
+ {
+ iSessionCount++;
+ // Remove the idle timer.
+ iTimerQueued &= ~EIdleTimer;
+ iTimer->Remove( iIdleCallBack );
+ }
+
+
+// ---------------------------------------------------------------------------
+// A session has been ended, update the session count.
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::RemoveSession( TBool aAutoOff )
+ {
+ TRACE_FUNC_ENTRY
+ TRACE_INFO( ( _L( "[CBTEngServer]\t aAutoOff %d"), aAutoOff ))
+ TRACE_INFO( ( _L( "[CBTEngServer]\t iSessionCount %d"), iSessionCount ))
+ iSessionCount--;
+ if( aAutoOff )
+ {
+ TRAP_IGNORE( SetPowerStateL( EBTPowerOff, ETrue ) );
+ }
+ else
+ {
+ CheckIdle();
+ }
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// From class CPolicyServer.
+// Checks version compatibility and constructs a new session object.
+// ---------------------------------------------------------------------------
+//
+CSession2* CBTEngServer::NewSessionL( const TVersion& aVersion,
+ const RMessage2& aMessage ) const
+ {
+ TRACE_FUNC_ENTRY
+ (void) aMessage;
+ // Compare our version with client-side version, CServer2 requires that
+ // we leave if they are not compatible.
+ // Compatible is interpreted here as equal or greater than our version.
+ TVersion srvVersion( KBTEngServerVersionMajor, KBTEngServerVersionMinor,
+ KBTEngServerVersionBuild );
+
+ if( !User::QueryVersionSupported( aVersion, srvVersion ) )
+ {
+ // EFalse is returned if our version is not less than or
+ // equal to the client version.
+ User::Leave( KErrNotSupported );
+ }
+ return CBTEngSrvSession::NewL();
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::CheckIdle()
+ {
+ TRACE_FUNC_ENTRY
+ __ASSERT_DEBUG( iTimer, PanicServer( EBTEngPanicMemberVarIsNull ) );
+ iTimerQueued &= ~EIdleTimer;
+ iTimer->Remove( iIdleCallBack );
+ if( iSessionCount <= 0 )
+ {
+ // No more sessions, check the power state.
+ TBTPowerStateValue pwr = EBTPowerOff;
+ TInt err = GetHwPowerState( pwr );
+ TRACE_INFO( ( _L( "[BTEng]\t No sessions; power state: %d" ), pwr ) )
+ if( !err &&!pwr
+ && iServerState->CurrentOperation() == CBTEngSrvState::ESrvOpIdle )
+ {
+ TRACE_INFO( ( _L( "[BTEng]\t Power off; starting shutdown timer" ) ) )
+ // power is off, start the shutdown timer.
+ TTimeIntervalMicroSeconds32 interval = KBTEngSrvIdleTimeout;
+ iTimer->Queue( interval, iIdleCallBack );
+ iTimerQueued |= EIdleTimer;
+ }
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+TInt CBTEngServer::SetPowerState( TBool aState )
+ {
+ TRACE_FUNC_ENTRY
+ TInt err = KErrNone;
+ // HCIv2 power state type is inverted from BTPM-defined type...
+ TBTPowerState powerState = (TBTPowerState) !aState;
+ TRequestStatus status;
+
+#ifndef __WINS__
+ iPowerMgr.SetPower( powerState, NULL, status );
+ User::WaitForRequest( status );
+ err = status.Int();
+#else //__WINS__
+ iPowerState = powerState;
+ err = KErrNone;
+#endif //__WINS__
+
+ if( !err && aState )
+ {
+ TInt dutMode;
+ err = RProperty::Get( KPSUidBluetoothTestingMode, KBTDutEnabled, dutMode );
+ if( !err && dutMode == EBTDutOn )
+ {
+ // Set the DUT mode key to OFF since DUT mode is disabled at this point
+ err = RProperty::Set( KPSUidBluetoothTestingMode, KBTDutEnabled, EBTDutOff );
+ }
+ // Set the local name straight away, so that an error
+ // in the loading of the BT stack will be detected here.
+ // Note that the HCIv2 power manager already loads the BT stack,
+ // so we do not need to do that here.
+ TRAP(err,SetLocalNameL());
+ }
+ if( err )
+ {
+ // Power off if an error occurred during power on sequence.
+#ifndef __WINS__
+ // This cannot happen in emulator environment.
+ iPowerMgr.SetPower( EBTOff, NULL, status );
+ User::WaitForRequest( status );
+#endif //__WINS__
+ }
+ TRACE_FUNC_RES( ( _L( "result: %d" ), err ) )
+ return err;
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+TInt CBTEngServer::SetLocalNameL()
+ {
+ TRACE_FUNC_ENTRY
+ RHostResolver hostResolver;
+ TBuf<KMaxBluetoothNameLen> name;
+ name.Zero();
+ TBuf<KMaxBluetoothNameLen> tmpName;
+
+ TInt err = RProperty::Get(KPropertyUidBluetoothCategory,
+ KPropertyKeyBluetoothGetDeviceName, name);
+ if(err == KErrNone)
+ {
+ err = RProperty::Get(KPropertyUidBluetoothCategory,
+ KPropertyKeyBluetoothSetDeviceName, tmpName);
+ if (tmpName.Compare(name))
+ {
+ // The name has not yet been updated. Use the new one.
+ name.Copy(tmpName);
+ }
+ }
+ // if name hasn't been set, check whats in the registry
+ if (err || !name.Length())
+ {
+ GetLocalNameFromRegistryL(name);
+ }
+
+ TRACE_INFO( ( _L( "[CBTEngServer]\t localDev.DeviceName(): '%S'" ), &name))
+
+ CleanupClosePushL(hostResolver);
+ User::LeaveIfError(hostResolver.Open(iSocketServ, KBTAddrFamily, KBTLinkManager));
+ User::LeaveIfError(hostResolver.SetHostName(name));
+ CleanupStack::PopAndDestroy(&hostResolver);
+
+ return KErrNone;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Checks whats written in the registry in order to set host name
+// ---------------------------------------------------------------------------
+//
+TInt CBTEngServer::GetLocalNameFromRegistryL(TDes& aName)
+ {
+ TRACE_FUNC_ENTRY
+ RBTRegServ btRegServ;
+ RBTLocalDevice btReg;
+ TBTLocalDevice localDev;
+
+ CleanupClosePushL(btRegServ);
+ CleanupClosePushL(btReg);
+
+ // In case of error, read local name from registry
+ aName.Zero();
+ User::LeaveIfError(btRegServ.Connect());
+ User::LeaveIfError(btReg.Open(btRegServ));
+
+ // Read the BT local name from BT Registry.
+ User::LeaveIfError(btReg.Get(localDev));
+
+ CleanupStack::PopAndDestroy(2,&btRegServ);
+
+ // BT registry keeps the device name in UTF-8 format, convert to unicode.
+ // The error can be > 0 if there are unconverted characters.
+ TInt err = CnvUtfConverter::ConvertToUnicodeFromUtf8(aName, localDev.DeviceName());
+ if (err != KErrNone)
+ User::Leave(err);
+ return KErrNone;
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::SetClassOfDeviceL()
+ {
+ TRACE_FUNC_ENTRY
+ TUint16 serviceClass = KCoDDefaultServiceClass;
+ // Check from feature manager if stereo audio is enabled.
+ FeatureManager::InitializeLibL();
+ TBool supported = FeatureManager::FeatureSupported( KFeatureIdBtStereoAudio );
+ FeatureManager::UnInitializeLib();
+ if( supported )
+ {
+ // A2DP spec says we should set this bit as we are a SRC
+ serviceClass |= EMajorServiceCapturing;
+ }
+ // These values may nayway be overridden by HCI
+ TBTDeviceClass cod( serviceClass, KCoDDefaultMajorDeviceClass,
+ KCoDDefaultMinorDeviceClass );
+ // Ignore error, it is non-critical
+ (void) RProperty::Set( KPropertyUidBluetoothControlCategory,
+ KPropertyKeyBluetoothSetDeviceClass, cod.DeviceClass() );
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::InitBTStackL()
+ {
+ TRACE_FUNC_ENTRY
+ iBBConnMgr->Subscribe();
+ TBTVisibilityMode visibility = EBTVisibilityModeHidden;
+ CRepository* cenRep = CRepository::NewL( KCRUidBTEngPrivateSettings );
+ TInt err = cenRep->Get( KBTDiscoverable, (TInt&) visibility );
+ delete cenRep;
+ if (iRestoreVisibility == EFalse)
+ {
+ if( err || visibility == EBTVisibilityModeTemporary && !( iTimerQueued & EScanModeTimer ) )
+ {
+ visibility = EBTVisibilityModeHidden;
+ }
+ SetVisibilityModeL( visibility, 0 );
+ }
+ SetClassOfDeviceL();
+ TBool sspDebugMode = EFalse;
+ (void) RProperty::Get( KPropertyUidBluetoothCategory,
+ KPropertyKeyBluetoothGetSimplePairingDebugMode,
+ (TInt&) sspDebugMode );
+ // Only set debug mode to off if it is on, to prevent a loop notifications.
+ if( sspDebugMode )
+ {
+ sspDebugMode = EFalse;
+ // Add LeaveIfError if unsuccessful
+ (void) RProperty::Set(KPropertyUidBluetoothCategory,
+ KPropertyKeyBluetoothSetSimplePairingDebugMode,
+ (TInt) sspDebugMode );
+ }
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::StopBTStackL()
+ {
+ TRACE_FUNC_ENTRY
+ TBTVisibilityMode visibility = EBTVisibilityModeHidden;
+ CRepository* cenRep = CRepository::NewL( KCRUidBTEngPrivateSettings );
+ // Ignore error here; if we can't read it, likely we can't set it either.
+ (void) cenRep->Get( KBTDiscoverable, (TInt&) visibility );
+ delete cenRep;
+ if( visibility == EBTVisibilityModeTemporary )
+ {
+ visibility = EBTVisibilityModeHidden;
+ SetVisibilityModeL( visibility, 0 ); // Also cancels scan mode timer.
+ }
+
+ // Stop listening to events
+ iBBConnMgr->Unsubscribe();
+ // Disconnect all links
+ TCallBack cb( DisconnectAllCallBack, this );
+ iBBConnMgr->DisconnectAllLinksL( cb );
+ // Results in a callback (which is called directly when there are no links).
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// Update the power state CenRep key.
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::UpdateCenRepPowerKeyL( TBTPowerStateValue aState )
+ {
+ TRACE_FUNC_ENTRY
+ CRepository* cenrep = CRepository::NewLC( KCRUidBluetoothPowerState );
+ User::LeaveIfError( cenrep->Set( KBTPowerState, (TInt) aState ) );
+ CleanupStack::PopAndDestroy( cenrep );
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// Loads the BT Power Manager; leaves if it cannot be loaded.
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::LoadBTPowerManagerL()
+ {
+ TRACE_FUNC_ENTRY
+ TRACE_INFO( ( _L( "[CBTEngServer]\t Using HCI API v2 power manager" ) ) )
+ User::LeaveIfError( iPowerMgr.Open() );
+#ifndef __WINS__
+ TRequestStatus status( KRequestPending );
+ iPowerMgr.SetPower( EBTOff, NULL, status );
+ User::WaitForRequest( status );
+ status = ( status.Int() == KErrAlreadyExists ? KErrNone : status.Int() );
+ User::LeaveIfError( status.Int() );
+#else //__WINS__
+ iPowerState = EBTOff;
+#endif //__WINS__
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::ManageDIServiceL( TBool aState )
+ {
+ TRACE_FUNC_ENTRY
+ // The session with the SDP database is kept open during the
+ // lifetime of BTEng server. This ensures that the database server
+ // will not destroy itself (and the SDP record) when there are no
+ // sessions anymore (which it would do). This also ensures that other
+ // sessions (of BT Engine Discovery API) can be closed without the SDP
+ // database being destroyed, and so saving memory.
+ TInt err = KErrNone;
+ if( !iSdpDbHandler )
+ {
+ iSdpDbHandler = CBTEngSdpDbHandler::NewL();
+ }
+ if( aState && !iDiSdpRecHandle )
+ {
+ // Use TRAP here, because the function will leave if
+ // the required CenRep keys are not available.
+ TInt vendorId = 0;
+ TInt productId = 0;
+ TRAP( err, GetProductIdsL( vendorId, productId ) );
+#ifdef __WINS__
+ err = KErrNone; // Ignore error and load with S60 RnD default values.
+#endif //__WINS__
+ if( !err )
+ {
+ TUUID uuid( EBTProfileDI );
+ iSdpDbHandler->RegisterSdpRecordL( uuid, vendorId, productId,
+ iDiSdpRecHandle );
+ }
+ }
+ if( ( !aState || err ) && iDiSdpRecHandle )
+ {
+ // Either we are shutting down, or we did not manage
+ // to fill the record with required data -> delete it.
+ iSdpDbHandler->DeleteSdpRecordL( iDiSdpRecHandle );
+ iDiSdpRecHandle = 0;
+ delete iSdpDbHandler;
+ iSdpDbHandler = NULL;
+ }
+ User::LeaveIfError( err ); // To pass back the result of the operation.
+ TRACE_FUNC_EXIT
+ }
+
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::GetProductIdsL( TInt& aVendorId, TInt& aProductId )
+ {
+ TRACE_FUNC_ENTRY
+ CRepository* cenRep = CRepository::NewLC( KCRUidBluetoothEngine );
+ User::LeaveIfError( cenRep->Get( KBTVendorID, aVendorId ) );
+ User::LeaveIfError( cenRep->Get( KBTProductID, aProductId ) );
+ CleanupStack::PopAndDestroy( cenRep ); //cenRep
+ }
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::SetUiIndicatorsL()
+ {
+ TRACE_FUNC_ENTRY
+ TInt powerState = EBTPowerOff;
+ TBTVisibilityMode visibilityMode = EBTVisibilityModeHidden;
+ CRepository* cenrep = NULL;
+ TInt phys = 0;
+ TInt connecting = 0;
+
+ cenrep = CRepository::NewLC( KCRUidBluetoothPowerState );
+ User::LeaveIfError( cenrep->Get( KBTPowerState, powerState ) );
+ CleanupStack::PopAndDestroy( cenrep );
+
+ if( powerState == EBTPowerOff )
+ {
+ SetIndicatorStateL( EAknIndicatorBluetoothModuleOn, EAknIndicatorStateOff );
+ SetIndicatorStateL( EAknIndicatorBluetooth, EAknIndicatorStateOff );
+ SetIndicatorStateL( EAknIndicatorBluetoothModuleOnVisible, EAknIndicatorStateOff );
+ SetIndicatorStateL( EAknIndicatorBluetoothVisible, EAknIndicatorStateOff );
+ }
+ else if( powerState == EBTPowerOn )
+ {
+ RProperty::Get( KPropertyUidBluetoothCategory, KPropertyKeyBluetoothPHYCount, phys );
+ RProperty::Get( KPropertyUidBluetoothCategory, KPropertyKeyBluetoothConnecting, connecting );
+
+ cenrep = CRepository::NewLC( KCRUidBTEngPrivateSettings );
+ User::LeaveIfError( cenrep->Get( KBTDiscoverable, (TInt&) visibilityMode ) );
+ CleanupStack::PopAndDestroy( cenrep );
+
+ if( visibilityMode == EBTVisibilityModeHidden )
+ {
+ if ( connecting ) // BT connecting and hidden
+ {
+ SetIndicatorStateL( EAknIndicatorBluetoothModuleOn, EAknIndicatorStateOff );
+ SetIndicatorStateL( EAknIndicatorBluetooth, EAknIndicatorStateAnimate );
+ }
+ else if ( phys > 0 ) // BT connection active and hidden
+ {
+ SetIndicatorStateL( EAknIndicatorBluetoothModuleOn, EAknIndicatorStateOff );
+ SetIndicatorStateL( EAknIndicatorBluetooth, EAknIndicatorStateOn );
+ }
+ else // BT connection not active and hidden
+ {
+ SetIndicatorStateL( EAknIndicatorBluetoothModuleOn, EAknIndicatorStateOn );
+ SetIndicatorStateL( EAknIndicatorBluetooth, EAknIndicatorStateOff );
+ }
+ SetIndicatorStateL( EAknIndicatorBluetoothModuleOnVisible, EAknIndicatorStateOff );
+ SetIndicatorStateL( EAknIndicatorBluetoothVisible, EAknIndicatorStateOff );
+ }
+ else if( visibilityMode == EBTVisibilityModeGeneral || visibilityMode == EBTVisibilityModeTemporary )
+ {
+ if ( connecting ) // BT connecting and visible
+ {
+ SetIndicatorStateL( EAknIndicatorBluetoothModuleOnVisible, EAknIndicatorStateOff );
+ SetIndicatorStateL( EAknIndicatorBluetoothVisible, EAknIndicatorStateAnimate );
+ }
+ else if ( phys > 0 ) // BT connection active and visible
+ {
+ SetIndicatorStateL( EAknIndicatorBluetoothModuleOnVisible, EAknIndicatorStateOff );
+ SetIndicatorStateL( EAknIndicatorBluetoothVisible, EAknIndicatorStateOn );
+ }
+ else // BT connection not active and visible
+ {
+ SetIndicatorStateL( EAknIndicatorBluetoothModuleOnVisible, EAknIndicatorStateOn );
+ SetIndicatorStateL( EAknIndicatorBluetoothVisible, EAknIndicatorStateOff );
+ }
+ SetIndicatorStateL( EAknIndicatorBluetoothModuleOn, EAknIndicatorStateOff );
+ SetIndicatorStateL( EAknIndicatorBluetooth, EAknIndicatorStateOff );
+ }
+ }
+ TRACE_FUNC_EXIT
+ }
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::SetIndicatorStateL( const TInt aIndicator, const TInt aState )
+ {
+ CAknSmallIndicator* indicator = CAknSmallIndicator::NewLC( TUid::Uid( aIndicator ) );
+ indicator->SetIndicatorStateL( aState );
+ CleanupStack::PopAndDestroy( indicator ); //indicator
+ }
+
+// ---------------------------------------------------------------------------
+// Gets the current HW power state.
+// For now this is a separate method to isolate the different variations.
+// ---------------------------------------------------------------------------
+//
+TInt CBTEngServer::GetHwPowerState( TBTPowerStateValue& aState )
+ {
+ TRACE_FUNC_ENTRY
+ TInt err = KErrNone;
+
+#ifndef __WINS__
+ err = iPowerMgr.GetPower( (TBTPowerState&) aState, NULL );
+#else //__WINS__
+ aState = (TBTPowerStateValue) iPowerState;
+#endif //__WINS__
+
+ // HCIv2 power state type is inverted from BTPM-defined type...
+ aState = (TBTPowerStateValue) !aState;
+ TRACE_FUNC_ARG( ( _L( "Power state is %d, result %d" ), (TInt) aState, err ) )
+ return err;
+ }
+
+// ---------------------------------------------------------------------------
+// Check the power state and if BT gets turned off automatically.
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::CheckTemporaryPowerStateL( TBTPowerStateValue& aCurrentState,
+ TBTPowerStateValue aNewState, TBool aTemporary )
+ {
+ TRACE_FUNC_ENTRY
+ User::LeaveIfError( GetHwPowerState( aCurrentState ) );
+ if( !aTemporary )
+ {
+ // Force the new power state, so clear all auto switch off flags.
+ // If power is off, this will anyway be ignored.
+ iAutoOffClients = 0;
+ iAutoSwitchOff = EFalse;
+ TCallBack cb;
+ iBBConnMgr->SetAutoSwitchOff( EFalse, cb );
+ if( iRestoreVisibility && aCurrentState == EBTPowerOn )
+ {
+ // Set visibility mode back to the value selected by the user.
+ SetVisibilityModeL( EBTVisibilityModeGeneral, 0 );
+ iRestoreVisibility = EFalse;
+ }
+ }
+ else
+ {
+ if( aCurrentState == aNewState )
+ {
+ if( iAutoSwitchOff && aNewState == EBTPowerOn )
+ {
+ iAutoOffClients++;
+ if( iTimerQueued & EAutoPowerOffTimer )
+ {
+ iTimer->Remove( iPowerOffCallBack );
+ iTimerQueued &= ~EAutoPowerOffTimer;
+ }
+ }
+ }
+ else if( iAutoSwitchOff || aNewState == EBTPowerOn )
+ {
+ aNewState == EBTPowerOff ? iAutoOffClients-- : iAutoOffClients++;
+ iAutoSwitchOff = ETrue;
+ if( aNewState == EBTPowerOff && iAutoOffClients <= 0 )
+ {
+ TCallBack powerOffCb( AutoPowerOffCallBack, this );
+ iBBConnMgr->SetAutoSwitchOff( ETrue, powerOffCb );
+ iTimer->Queue( KBTEngBtAutoOffTimeout, iPowerOffCallBack );
+ iTimerQueued |= EAutoPowerOffTimer;
+ }
+ else if( aNewState == EBTPowerOn )
+ {
+ CRepository* cenRep = CRepository::NewLC( KCRUidBTEngPrivateSettings );
+ TBTVisibilityMode visibility = EBTVisibilityModeGeneral;
+ TInt err = cenRep->Get( KBTDiscoverable, (TInt&) visibility );
+ CleanupStack::PopAndDestroy( cenRep );
+ if( !err && visibility == EBTVisibilityModeGeneral )
+ {
+ SetVisibilityModeL( EBTVisibilityModeHidden, 0 );
+ iRestoreVisibility = ETrue;
+ }
+ if( iTimerQueued & EAutoPowerOffTimer )
+ {
+ iTimer->Remove( iPowerOffCallBack );
+ iTimerQueued &= ~EAutoPowerOffTimer;
+ }
+ }
+ }
+ }
+ if( iAutoOffClients < 0 )
+ {
+ iAutoOffClients = 0;
+ }
+ TRACE_FUNC_EXIT
+ }
+
+// ---------------------------------------------------------------------------
+// Check the power state and if BT gets turned off automatically.
+// This method is invoked either when the timer has expired, or
+// if there are no more connections while the timer was running.
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::CheckAutoPowerOffL()
+ {
+ TRACE_FUNC_ENTRY
+ if ( iAutoOffClients > 0 )
+ {
+ TRACE_INFO( ( _L( "[CBTEngServer]\t iAutoOffClients %d"), iAutoOffClients ))
+ return;
+ }
+ TInt linkCount = 0;
+ TInt err = RProperty::Get( KPropertyUidBluetoothCategory,
+ KPropertyKeyBluetoothGetPHYCount, linkCount );
+ if( !err && !linkCount )
+ {
+ TRACE_INFO( ( _L( "[CBTEngServer]\t SetPowerStateL( EBTPowerOff, EFalse );")))
+ SetPowerStateL( EBTPowerOff, EFalse );
+ }
+ else
+ {
+ if( iRestoreVisibility )
+ {
+ // Set visibility mode back to the value selected by the user.
+ SetVisibilityModeL( EBTVisibilityModeGeneral, 0 );
+ iRestoreVisibility = EFalse;
+ }
+ // show note if non-audio connection exists
+ if ( !iPluginMgr->CheckAudioConnectionsL() )
+ {
+ RNotifier notifier;
+ TInt err = notifier.Connect();
+ if( !err )
+ {
+ TRequestStatus status;
+ TBTGenericInfoNotiferParamsPckg pckg;
+ pckg().iMessageType = EBTStayPowerOn;
+ TBuf8<sizeof(TInt)> result;
+ //notifier.StartNotifier( KBTGenericInfoNotifierUid, pckg, result );
+ notifier.StartNotifierAndGetResponse( status,
+ KBTGenericInfoNotifierUid,
+ pckg, result ); // Reply buffer not used.
+ User::WaitForRequest( status );
+ notifier.Close();
+ }
+ }
+ iAutoOffClients = 0;
+ iAutoSwitchOff = EFalse;
+ TCallBack cb;
+ iBBConnMgr->SetAutoSwitchOff( EFalse, cb );
+ }
+ TRACE_FUNC_EXIT
+ }
+
+// ---------------------------------------------------------------------------
+// ?implementation_description
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::CheckSspDebugModeL( TBool aDebugMode )
+ {
+ TRACE_FUNC_ARG( ( _L( "SSP debug mode state %d" ), (TInt) aDebugMode ) )
+ TBTPowerState pwr = EBTOff;
+ TBool currentMode = EFalse;
+ TInt err = RProperty::Get( KPropertyUidBluetoothCategory,
+ KPropertyKeyBluetoothGetSimplePairingDebugMode,
+ (TInt&) currentMode );
+#ifndef __WINS__
+ err = iPowerMgr.GetPower( pwr, NULL ); // Treat error as power off.
+#else //__WINS__
+ pwr = iPowerState;
+#endif //__WINS__
+ if( err || pwr == EBTOff )
+ {
+ iTimerQueued &= ~ESspDebugModeTimer;
+ iTimer->Remove( iDebugModeCallBack );
+ // Only set debug mode to off if it is on, to prevent a loop notifications.
+ if( currentMode )
+ {
+ (void) RProperty::Set( KPropertyUidBluetoothCategory,
+ KPropertyKeyBluetoothSetSimplePairingDebugMode,
+ (TInt) aDebugMode );
+ }
+ // In case of an error in getting the power state, turn BT off.
+ // If BT is already off, this call will be ignored.
+ SetPowerStateL( EBTPowerOff, EFalse );
+ }
+ else if( aDebugMode )
+ {
+ // Ignore if there already is a timer queued.
+ if( !( iTimerQueued & ESspDebugModeTimer ) )
+ {
+ iTimer->Queue( TTimeIntervalMicroSeconds32( KBTEngSspDebugModeTimeout ),
+ iDebugModeCallBack );
+ iTimerQueued &= ESspDebugModeTimer;
+ err = RProperty::Set(KPropertyUidBluetoothCategory,
+ KPropertyKeyBluetoothSetSimplePairingDebugMode,
+ (TInt) aDebugMode );
+ }
+ }
+ else
+ {
+ // Power is on, and debug mode is set to off.
+ TInt linkCount = 0;
+ err = RProperty::Get( KPropertyUidBluetoothCategory,
+ KPropertyKeyBluetoothGetPHYCount, linkCount );
+ if( err || !linkCount )
+ {
+ (void) RProperty::Set(KPropertyUidBluetoothCategory,
+ KPropertyKeyBluetoothSetSimplePairingDebugMode,
+ (TInt) aDebugMode );
+ SetPowerStateL( EBTPowerOff, EFalse );
+ }
+ else
+ {
+ // There are still existing connections, queue the
+ // timer again for half the period.
+ iTimer->Queue( TTimeIntervalMicroSeconds32( KBTEngSspDebugModeTimeout / 2 ),
+ iDebugModeCallBack );
+ iTimerQueued &= ESspDebugModeTimer;
+ }
+ }
+ TRACE_FUNC_EXIT
+ }
+
+// ---------------------------------------------------------------------------
+// returns the reference of pairing manager
+// ---------------------------------------------------------------------------
+//
+CBTEngPairMan& CBTEngServer::PairManager()
+ {
+ return *iPairMan;
+ }
+
+// ---------------------------------------------------------------------------
+// Delegate the information to pairing manager
+// ---------------------------------------------------------------------------
+//
+void CBTEngServer::RemoteRegistryChangeDetected()
+ {
+ iPairMan->RemoteRegistryChangeDetected();
+ }
+
+// ---------------------------------------------------------------------------
+// Access the reference of RSockServ
+// ---------------------------------------------------------------------------
+//
+RSocketServ& CBTEngServer::SocketServ()
+ {
+ return iSocketServ;
+ }
+
+// ---------------------------------------------------------------------------
+// Access the reference of RBTRegSrv
+// ---------------------------------------------------------------------------
+//
+RBTRegServ& CBTEngServer::BTRegServ()
+ {
+ return iBTRegServ;
+ }
+
+// ---------------------------------------------------------------------------
+// Ask plugin manager the connection status of the specified device
+// ---------------------------------------------------------------------------
+//
+TBTEngConnectionStatus CBTEngServer::IsDeviceConnected( const TBTDevAddr& aAddr )
+ {
+ TBTEngConnectionStatus status = EBTEngNotConnected;
+ if ( iPluginMgr )
+ {
+ status = iPluginMgr->IsDeviceConnected( aAddr );
+ }
+ return status;
+ }
+
+// ---------------------------------------------------------------------------
+// Static callback for temporary visibility mode.
+// ---------------------------------------------------------------------------
+//
+TInt CBTEngServer::ScanModeTimerCallBack( TAny* aPtr )
+ {
+ __ASSERT_ALWAYS(aPtr, PanicServer(EBTEngPanicArgumentIsNull) );
+ TRAPD( err, ( (CBTEngServer*) aPtr )->ScanModeTimerCompletedL() );
+ return err;
+ }
+
+// ---------------------------------------------------------------------------
+// Static callback for disconnecting all Baseband connections.
+// ---------------------------------------------------------------------------
+//
+TInt CBTEngServer::DisconnectAllCallBack( TAny* aPtr )
+ {
+ __ASSERT_ALWAYS(aPtr, PanicServer(EBTEngPanicArgumentIsNull) );
+ ( (CBTEngServer*) aPtr )->DisconnectAllCompleted();
+ return KErrNone;
+ }
+
+
+// ---------------------------------------------------------------------------
+// Static callback for idle timer timeout. We are shutting down ourselves.
+// ---------------------------------------------------------------------------
+//
+TInt CBTEngServer::IdleTimerCallBack( TAny* aPtr )
+ {
+ (void) aPtr;
+ CActiveScheduler::Stop(); // Will destroy CBTEngServer
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// Static callback for idle timer timeout. Turn off BT to get it out of
+// debug mode. If there are existing connections, queue the timer again.
+// ---------------------------------------------------------------------------
+//
+TInt CBTEngServer::DebugModeTimerCallBack( TAny* aPtr )
+ {
+ // Set our internal debug mode key to off. Ignore error, not critical here.
+ (void) RProperty::Set( KPSUidBluetoothTestingMode, KBTSspDebugmode, EFalse );
+
+ __ASSERT_ALWAYS(aPtr, PanicServer(EBTEngPanicArgumentIsNull) );
+
+ TRAP_IGNORE( ( (CBTEngServer*) aPtr )->CheckSspDebugModeL( EFalse ) );
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// Static callback for auto power off.
+// ---------------------------------------------------------------------------
+//
+TInt CBTEngServer::AutoPowerOffCallBack( TAny* aPtr )
+ {
+ TRACE_FUNC_ENTRY
+
+ __ASSERT_ALWAYS(aPtr, PanicServer(EBTEngPanicArgumentIsNull) );
+
+ CBTEngServer* server = (CBTEngServer*) aPtr;
+ server->iTimerQueued &= ~EAutoPowerOffTimer;
+ TRAPD( err, server->CheckAutoPowerOffL() );
+ return err;
+ }
+
+BluetoothFeatures::TEnterpriseEnablementMode CBTEngServer::EnterpriseEnablementMode() const
+ {
+ return iEnterpriseEnablementMode;
+ }
+
+// ======== GLOBAL FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Main function of the executable.
+// ---------------------------------------------------------------------------
+//
+GLDEF_C TInt E32Main()
+ {
+ __UHEAP_MARK;
+ TRACE_FUNC_ENTRY
+ CTrapCleanup* cleanup = CTrapCleanup::New();
+ TInt err = KErrNoMemory;
+ if ( cleanup )
+ {
+ TRAP( err, RunServerL() );
+ delete cleanup;
+ }
+ __UHEAP_MARKEND;
+ return err;
+ }