管理VoIP配置
详细描述
S60第三版SDK不提供任何API来增加,编辑或删除VoIP的配置信息。
解决方案
没有VoIP配置管理方面的API,VoIP配置只能通过设置程序(Settings->Connection->Internet设置)来手动调整编辑。
同样,VoIP设置也可以通过OMA Client Provisioning修改,更多信息请参考下列Forum Nokia文档:
Client Provisioning Registration
http://www.forum.nokia.com/info/sw.n..._v1_7.zip.html
OMA DM: Management Object for Nokia VoIP Implementation
http://www.forum.nokia.com/info/sw.n..._1_en.pdf.html
以及http://www.forum.nokia.com/main/reso...voice_over_IP/
如何使用名片夹程序中的图标
详细描述
下列代码展示了如果重载使用名片夹程序中的图标(这个示例中,使用的名片分组中的图标)
#include <pbkiconinfo.h> // link against pbkview.lib #include <gulicon.h> // link against egul.lib CPbkIconInfoContainer* iconContainer = CPbkIconInfoContainer::NewL( iCoeEnv ); CGulIcon* icon = iconContainer->LoadBitmapL( EPbkqgn_prop_group_open_tab1 );
可参考pbkiconid.hrh以了解相关图标的id值
如何动态添加菜单项
详细描述
不需要对资源文件做任何改变即可动态添加菜单项了:)
首先,需要在程序资源文件中定义一个空的菜单。
#include <eikon.rh> #include <avkon.rh> #include <avkon.rsg> #include "MyApp.hrh" RESOURCE RSS_SIGNATURE { } RESOURCE TBUF r_default_document_name { buf=""; } RESOURCE EIK_APP_INFO { menubar = r_myapp_menubar; cba = R_AVKON_SOFTKEYS_OPTIONS_EXIT; } RESOURCE MENU_BAR r_myapp_menubar { titles = { MENU_TITLE { menu_pane = r_myapp_menu; } }; } RESOURCE MENU_PANE r_myapp_menu { items = { // Empty implementation of menu }; }
然后重载应用程序UI类中的MEikMenuObserver:ynInitMenuPaneL()方法
void CMyAppUi::DynInitMenuPaneL( TInt aResourceId, CEikMenuPane* aMenuPane ) { if( aResourceId == R_MYAPP_MENU ) { CEikMenuPaneItem::SData itemData; itemData.iText = _L("New menu item"); // Label text for the menu item itemData.iCommandId = ECmdYourMenu; // Command ID for the menu item itemData.iFlags = 0; itemData.iCascadeId = 0; aMenuPane->AddMenuItemL( itemData ); } }
注意,不需要直接去调用DynInitMenuPaneL()方法,因为当菜单键被按下后,系统会负责自动调用。
如何生成视频电话和VoIP电话
详细描述
现在可以通过使用AIW Service Handler API初始化视频和网络电话(VoIP),这组API属于S60第三版SDK的扩展插件。
视频电话
下列示例演示了如何初始化一个视频通话
MakeAiwCallL( _L("+3581234567"), _L("Firstname Lastname"), EAiwVideo); // EAiwForcedVideo doesn't show dialogs // MakeAiwCallL( _L("+3581234567"), _L("Firstname Lastname"), EAiwForcedVideo); void MakeAiwCallL( const TDesC& aNumber, const TDesC& aName, TAiwCallType aCallType ) { // Create AIW service handler CAiwServiceHandler* serviceHandler = CAiwServiceHandler::NewLC(); // Create AIW interest RCriteriaArray interest; CleanupClosePushL( interest ); CAiwCriteriaItem* criteria = CAiwCriteriaItem::NewLC( KAiwCmdCall, KAiwCmdCall, _L8( "*" ) ); const TUid KUidAiwBase = { KAiwClassBase }; criteria->SetServiceClass( KUidAiwBase ); User::LeaveIfError( interest.Append( criteria ) ); // Attach to AIW interest serviceHandler->AttachL( interest ); // Create AIW param package TAiwDialDataV1 data; TAiwDialDataV1Pckg dataPckg( data ); iNameBuffer = aName.Left( iNameBuffer.MaxLength() ); data.SetName( iNameBuffer ); iTelNumber = aNumber.Left( iTelNumber.MaxLength() ); data.SetTelephoneNumber( iTelNumber ); data.SetCallType( aCallType ); data.SetWindowGroup( CCoeEnv::Static()->RootWin().Identifier() ); CAiwGenericParamList& paramList = serviceHandler->InParamListL(); TPtrC8 ptr; ptr.Set( dataPckg ); TAiwVariant variant( ptr ); TAiwGenericParam param( EGenericParamCallDialDataV1, variant ); paramList.AppendL( param ); // Execute AIW command serviceHandler->ExecuteServiceCmdL( KAiwCmdCall, paramList, serviceHandler->OutParamListL() ); // destroy criteria, interest, and serviceHandler CleanupStack::PopAndDestroy( 3 ); }
VoIP电话
下面这个函数可以初始化VoIP电话:
MakeAiwCallL( _L("user@sip.server.com"), _L("Firstname Lastname"), EAiwVoIPCall );
* 相关链接
Extensions plug-in package for S60 3rd Edition SDK for Symbian OS, for C++, Maintenance Release
http://www.forum.nokia.com/info/sw.n...g-In_Pack.html
Extensions plug-in package for S60 3rd Edition SDK for Symbian OS, for C++, supporting Feature Pack 1
http://www.forum.nokia.com/info/sw.n...Pack1.zip.html
关于AMR文件编码模式的解决方案
详细描述
一个AMR文件的帧长度变化是根据AMR数据的编码模式(bit rate)来定的。当我们使用API如Audio Proxy Server(APS)来播放AMR文件时,就需要知道其帧长度,因为利用APS播放的数据序列必须每个缓冲准确包含一帧。
关于AMR编码模式的信息可以从每帧的第一个字节获取。下列代码示例演示了如何操作。
注意AMR文件总是以一个6字节信息("#!AMR\n")为开头的,下面跟着帧数据。
解决方案
#define KAMRHeaderLength 6 // Table containing AMR-NB frame lengths for each encoding mode const TInt KAMRFrameLenTable[8] = { 13, 14, 16, 18, 20, 21, 27, 32 }; /****************************************************************************** * void ResolveAMRFrameLengthL * Parameters: * aFs File server session * aAMRFile Path and file name of an AMR-NB file * aFrameLen On return, contains the frame length ******************************************************************************/ void ResolveAMRFrameLengthL( RFs& aFs, const TDesC& aAMRFile, TInt& aFrameLen ) { RFile file; User::LeaveIfError( file.Open(aFs, aAMRFile, EFileRead|EFileStream) ); // Skip the header part TBuf8<KAMRHeaderLength> header; TInt ret = file.Read( header, KAMRHeaderLength ); if( ret == KErrNone ) { file.Read( header, 1 ); // read 1st byte of the first frame if( header.Length() ) { // Resolve AMR mode (0..7) and frame length from the table TInt mode = (header[0] & 0x38) >> 3; // 0x38 == 00111000 aFrameLen = KAMRFrameLenTable[mode]; } } file.Close(); }
如何获取S60第三版中情景模式的相关信息
详细描述
我们可以通过Profiles Engine API来获取关于情景模式的细节信息,如定义的情景模式的顺序位置,以及他们的名称等。
这里的API可以通过下列获得
Extensions plug-in package for S60 3rd Edition SDK
http://www.forum.nokia.com/info/sw.n...Pack1.zip.html
解决方案
下列代码演示了如何找出每个情景模式的名称:
#include <mprofileengine.h> // link against ProfileEng.lib #include <MProfilesNamesArray.h> MProfileEngine* profileEngine = CreateProfileEngineL(); CleanupReleasePushL( *profileEngine ); MProfilesNamesArray* profileNames = profileEngine->ProfilesNamesArrayLC(); for( TInt i = 0; i < profileNames->MdcaCount(); ++i ) { // Name of each profile is returned by // profileNames->ProfileName(i)->Name(); } CleanupStack::PopAndDestroy(2); // profileNames, profileEngine
为何MAknsSkinInstance::GetCachedItemData()返回NULL?
详细描述
S60中的skin server提供了一种方法从缺省皮肤中创建一张位图(CFbsBitmap)。
位图通常从皮肤中获取,如下所示:
#include <aknsskininstance.h> MAknsSkinInstance* skin = AknsUtils::SkinInstance(); CAknsItemData* skinItem = skin->GetCachedItemData( someUID, EAknsITBitmap ); if( skinItem != NULL ) { CFbsBitmap* bitmap = static_cast<CAknsBitmapItemData*>(skinItem)->Bitmap(); }
上述方法对位图(EAknsITBitmaps)或遮罩位图(EAknsITMaskedBitmap)来说都工作得很好,但这并不意味着对所有皮肤成员都如此。例如,如果上面的someUID出现下列值:
KAknsIIDQsnBgAreaMainIdle, KAknsIIDQsnBgScreenIdle, KAknsIIDQsnBgScreen
那么GetCachedItemData()则会返回NULL,因为这些UID不是和位图挂钩的,他们只是EAknsITEffectQueue类型的一部分。
如果当前主题中的某个皮肤元素是EAknsITEffectQueue类型。这就意味这该元素是支持特效的。特效是scalable UI的主要特性之一。当一个皮肤元素支持特效,这就意味着该元素有多个帧。每帧都可能是一个图片或是图片/像素处理方案(能对前一帧产生影响)。特效可以通过改变时间来编程处理,甚至第一张图片(背景图)能被指明为另一个皮肤元素。
正因为如此,我们无法通过MAknsSkinInstance从EAknsITEffectQueue类型的皮肤元素中返回一个单独的CFbsBitmap实例,下列解决方案描述了如何处理这样的情况。
解决方案
使用AknsDrawUtils来处理:
1)如果程序需要在它的一个控件(从CCoeControl派生)中绘制一个当前背景皮肤,就可以使用AknsDrawUtils::Background()来处理:
下列代码演示了如何处理:
// Create a background context (in ConstructL(), as a class member) iSkinContext = CAknsBasicBackgroundControlContext::NewL( KAknsIIDQsnBgAreaMain, Rect(), EFalse ); Then, in the Draw() function: CWindowGc& gc = SystemGc(); TRect rect = Rect(); gc.Clear( rect ); AknsDrawUtils::Background( AknsUtils::SkinInstance(), iSkinContext, this, gc, rect );
2)如果程序需要一个位图实例,就可以利用AknsDrawUtils:rawBackground()在一个CFbsBitGc上绘制出当前皮肤内容:
// Create an off-screen bitmap and context (CFbsBitGc) // Also remember to take care of destruction / cleanup during leaves CFbsBitmap* offScreenBitmap = new (ELeave) CFbsBitmap(); User::LeaveIfError( offScreenBitmap->Create( aSize, aDisplayMode ) ); CFbsBitGc* bitGc = 0; CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL( offScreenBitmap ); User::LeaveIfError( bitmapDevice->CreateContext( bitGc ) ); // Draw the content on the off-screen bitmap AknsDrawUtils::DrawBackground( AknsUtils::SkinInstance(), iSkinContext, this, *bitGc, TPoint(0,0), rect, KAknsDrawParamDefault ); // offScreenBitmap now contains current skin content
多线程中的内存分配问题
详细描述
在共享一个堆栈空间的多线程程序中使用User::Alloc()以及User::Available()是无法做到线程安全的。
在一个多线程程序中,主线程可以为一个子线程指定堆栈空间。有两个选项:分配堆栈和共享堆栈。
如果两个或多个线程共同操作一个共享堆栈,则需要同步机制(如互斥等)。
解决方案
1)共享堆栈:
IMPORT_C TInt Create( const TDesC &aName, TThreadFunction aFunction, TInt aStackSize, RAllocator *aHeap, TAny *aPtr, TOwnerType aType = EOwnerProcess );
如果上面的aHeap参数设置为NULL,线程将会和主线程共享同一堆栈。
在下面这个情况中,内存分配将会在各自线程中同步处理:
RMutex sharedMutex; ... sharedMutex.Wait(); array[i] = User::Alloc( bytesToAlloc ); sharedMutex.Signal(); sharedMutex.Wait(); TInt heapSize = User::Available( largestBlock ); sharedMutex.Signal();
2)分配堆栈
当使用下列RThread::Create()的重载版本时,新的线程将使用它自己的堆栈。
IMPORT_C TInt Create( const TDesC &aName, TThreadFunction aFunction, TInt aStackSize, TInt aHeapMinSize, TInt aHeapMaxSize, TAny *aPtr, TOwnerType aType = EOwnerProcess );
这里不同的堆栈,内存的分配调用将无法再同步处理。
在SIS包中使用RUNREMOVE选项
详细描述
为了防止卸载过程中出现失败,我们要认真考虑那些将要被删除的二进制文件的执行顺序。特别当在文件中包含了使用RUNREMOVE(RR)选项的可执行文件,其执行还依赖于一个或数个DLL文件。
解决方案
二进制文件是根据其在pkg文件中的列表顺序进行删除的,下列解决方案描述了如何组织这样的pkg文件。这个示例中假设有一个可执行文件(EXE1)以及相关联的一个DLL文件(DLL1):
Case 1: DLL1 EXE1, FR, RR -> EXE fails to run during uninstallation since the DLL has already been deleted Case 2: EXE1, FR, RR DLL1 - DLL1 -> All OK Case 3: IF <statement> DLL1 ENDIF EXE1, FR, RR -> All OK.
条件语句将被最后执行,因此当EXE1正被操作时DLL1仍然存在。
如何改变程序所属窗口组
详细描述
可以在退出一个程序后选择一个任务运行在前台。缺省情况下,如果程序是从菜单启动的,那菜单程序将被置于前台。
但我们可以通过下列方法来改变程序所属窗口组:
void RWindowGroup::SetOwningWindowGroup( TInt aIdentifier );
解决方案
下列代码示例演示了如何将待机屏幕设置为其所属窗口组(在S60第三版中),这样当程序退出后,将回到待机界面。
#include <apgtask.h> // link against apgrfx.lib, ws32.lib const TUid KUidPhoneIdle = { 0x101fd64c }; TApaTaskList taskList( iCoeEnv->WsSession() ); TApaTask task = taskList->FindApp( KUidPhoneIdle ); if( task.Exists() ) { iCoeEnv->RootWin().SetOwningWindowGroup( task.WgId() ); }
当网络连接临时丢失后必须要重新注册SIP客户端
详细描述
如果PDP context丢失(如因为临时出了网络覆盖范畴),这时SIP堆栈将清空所有SIP注册和对话数据。
当链接已经重新建立,SIP客户端必须要重新向服务器注册。
相关文档
MSIPConnectionObserver::ConnectionStateChanged()
http://forum.nokia.com/document/Cpp_...31f0f2f984d58b
自定义窗口的消色参数无法正确工作的问题
详细描述
当使用下列方法时:
void RWsSession::SetDefaultFadingParameters( TUInt8 aBlackMap, TUint8 aWhiteMap ); void RWindowTreeNode::SetFaded( TBool aFaded, TFadeControl aIncludeChildren, TUInt8 aBlackMap, TUint8 aWhiteMap );
可以为窗口设置出消色(fading)效果,但其使用结果取决于手机设备和当前屏幕状态。
有一些设备中,这个消色参数会被忽略掉,而在另一些设备中(如N95),则在竖屏下才能生效,在横屏下是无法工作的。在横屏下将使用系统缺省的消色遮罩。无论程序开始于竖屏,而后来切换到横屏或者直接开始于横屏都会出现这样的状况。
此外,如果UI控件在竖屏模式下被消色处理(使用自定义的参数)时又被重绘了,那将使用系统缺省的消色遮罩替代先前自定义的消色遮罩了。
获得音量键回应
详细描述
Remote Control API(RemCon)可用来获得音量高低键事件的通知。RemCon API也提供了处理其他媒体播放键(播放/暂停,停止,前进,后退)的事件类型,不过这些按键事件无法被捕捉到,因为他们是为音乐播放器程序所保留的。
媒体键的应用
详细描述
媒体键的按键事件是无法通过常规手段监测到的,这点和其他按键事件不同。媒体键,如播放/暂停,停止,音量高/低,前进以及后退等键,属于一些S60第三版手机的新特性,不会生成一般的按键事件,以便被程序框架捕捉,如HandleKeyEventL()以及OfferKeyEventL()。
解决方案
媒体键的按键事件要通过Remote Control API来处理。
下列代码片段演示了如何处理:
CRemConInterfaceSelector CRemConCoreApiTarget MRemConCoreApiTargetObserver Remote Control API requires ReadUserData capability. //------------------------------------------------------------------------------ #include <remconcoreapitargetobserver.h> // link against RemConCoreApi.lib #include <remconcoreapitarget.h> // and #include <remconinterfaceselector.h> // RemConInterfaceBase.lib class CMediaKeysTestUi : public CAknAppUi, public MRemConCoreApiTargetObserver { ... // From MRemConCoreApiTargetObserver void MrccatoCommand(TRemConCoreApiOperationId aOperationId, TRemConCoreApiButtonAction aButtonAct); // following functions from MRemConCoreApiTargetObserver are not needed // in this case -> use empty implementations for these: // MrccatoPlay // MrccatoTuneFunction // MrccatoSelectDiskFunction // MrccatoSelectAvInputFunction // MrccatoSelectAudioInputFunction private: CRemConInterfaceSelector* iInterfaceSelector; CRemConCoreApiTarget* iCoreTarget; }; void CMediaKeysTestUi::ConstructL() { ... iInterfaceSelector = CRemConInterfaceSelector::NewL(); iCoreTarget = CRemConCoreApiTarget::NewL(*iInterfaceSelector, *this); iInterfaceSelector->OpenTargetL(); } // ---------------------------------------------------------------------------- // MrccatoCommand() // Receives events (press/click/release) from the following buttons: // 'Play/Pause', 'Volume Up', 'Volume Down', 'Stop', 'Rewind', 'Forward' // ---------------------------------------------------------------------------- void CMediaKeysTestUi::MrccatoCommand(TRemConCoreApiOperationId aOperationId, TRemConCoreApiButtonAction aButtonAct) { TRequestStatus status; switch( aOperationId ) { case ERemConCoreApiPausePlayFunction: { switch (aButtonAct) { case ERemConCoreApiButtonPress: // Play/Pause button pressed break; case ERemConCoreApiButtonRelease: // Play/Pause button released break; case ERemConCoreApiButtonClick: // Play/Pause button clicked break; default: // Play/Pause unknown action break; } //Send the response back to Remcon server iCoreTarget->PausePlayFunctionResponse(status, KErrNone); User::WaitForRequest(status); break; } case ERemConCoreApiStop: { switch (aButtonAct) { // see above (case ERemConCoreApiPausePlayFunction) // for possible actions } iCoreTarget->StopResponse(status, KErrNone); User::WaitForRequest(status); break; } case ERemConCoreApiRewind: { switch (aButtonAct) { // see above for possible actions } iCoreTarget->RewindResponse(status, KErrNone); User::WaitForRequest(status); break; } case ERemConCoreApiForward: { switch (aButtonAct) { // see above for possible actions } iCoreTarget->ForwardResponse(status, KErrNone); User::WaitForRequest(status); break; } case ERemConCoreApiVolumeUp: { switch (aButtonAct) { // see above for possible actions } iCoreTarget->VolumeUpResponse(status, KErrNone); User::WaitForRequest(status); break; } case ERemConCoreApiVolumeDown: { switch (aButtonAct) { // see above for possible actions } iCoreTarget->VolumeDownResponse(status, KErrNone); User::WaitForRequest(status); break; } case ERemConCoreApiFastForward: { switch (aButtonAct) { // see above for possible actions } iCoreTarget->FastForwardResponse(status, KErrNone); User::WaitForRequest(status); break; } case ERemConCoreApiBackward: { switch (aButtonAct) { // see above for possible actions } iCoreTarget->BackwardResponse(status, KErrNone); User::WaitForRequest(status); break; } default: break; } } //------------------------------------------------------------------------------
注意,当按下这些按键,媒体键无法自动重复这些命令,如果需要重复,那需要自己来完成一个(CPeriodic)时间器。
自动获得特定WLAN通知无法工作的问题
详细描述
SDK中定义了异步获取WLAN连接状态通知的API(参考Connection Monitor API)
但并非在所有SDK文档中描述的通知都能正常接收到,例如如下事件:
EConnMonBearerAvailabilityChange
EConnMonSignalStrengthChange
文档中记述了可以通过MConnectionMonitorObserver::EventL()异步获取。但因为一直工作的网络承载监测系统和信号强度总系统会消耗一些电量,所以在S60第三版手机中这些事件的通知无法自动获取。
EConnMonBearerAvailabilityChange事件可以用来监测WLAN变化状态(如果系统设置中允许了WLAN后台扫描)。根据设置中扫描间隔设定,这些事件可能无法立刻获得。
EConnMonSignalStrengthChange事件只在蜂窝承载系统(GPRS,WCDMA等)下才有效。
解决方案
如果需要这些功能,为了立即反映出系统变化,程序只能完成自己的逻辑定时查询,同时查询信号强度和/或承载信号。
EglInitialize在某些设备上无法创建控制环境
详细描述
eglInitialize函数在那些支持3D图形硬件加速的设备上无法自动创建控制环境(CCoeEnv),这只对那些在程序框架外使用OpenGL ES的程序起作用,例如Open C程序(它没有实现标准的S60 UI)
如何重现
当你试图在上述设备上运行opencopenlex示例时,程序就会返回-6006错误,这个示例包含在[http://www.forum.nokia.com/info/sw.n...K_Plug-In.html Open C SDK Plug-In] 中。
解决方案
如果需要的话,请手动创建(并注销)这个控制环境
CCoeEnv* coeEnv = CCoeEnv::Static(); if( !coeEnv ) { coeEnv = new ( ELeave ) CCoeEnv(); coeEnv->ConstructL( ETrue, 0 ); }
S60第三版SDK,FP1中使用WLAN Info API获得WLAN MAC地址
详细描述
WLAN Info API是S60第三版FP1 SDK中扩展插件包的一部分内容。包括为无线接口发布&订阅mac地址的功能。
wlaninternalpskeys.h包括需要的P&S类和关键信息:
const TUid KPSUidWlan = { 0x101f8ec5 }; const TUint KPSWlanMacAddress = 0x00000001; const RProperty::TType KPSWlanMacAddressType = RProperty::EByteArray;
不管如何,只有当WLAN打开时才能获得MAC地址,如果要在WLAN关闭时找出mac地址,则请参考Retrieving WLAN MAC address部分(可以在所有S60第三版手机运行)。
参考链接
Extensions plug-in package for S60 3rd Edition SDK for Symbian OS, for C++, supporting Feature Pack 1
http://www.forum.nokia.com/info/sw.n...g-In_Pack.html
如何访问SyncML远程和本地数据库
详细描述
可以通过如下示例代码来访问SyncML远程和本地数据库
SyncML Client API是
Extensions plug-in package for S60 3rd Edition SDK
http://www.forum.nokia.com/info/sw.n...Pack1.zip.html
的一部分。
RSyncMLSession syncSession; syncSession.OpenL(); //Open sync session RSyncMLDataSyncProfile profile; RArray<TSmlTaskId> taskArray; TSmlOpenMode openMode = TSmlOpenMode::ESmlReadWrite; profile.OpenL( syncSession, profid, openMode ); //Open Profile profile.ListTasksL( taskArray ); RSyncMLTask task; task.OpenL( profile, taskArray[0] ); HBufC* localDataStore = task.ClientDataSource().AllocL(); // local database HBufC* remDataStore = task.ServerDataSource().AllocL(); // remote database task.Close(); profile.Close(); syncSession.Close();
通过设备管理增加接入点
详细描述
可以通过使用一个设备管理服务器来增加管理对象,比如Funambol或SCTS DM服务器
当试图使用./AP/<x>命令来增加接入点时,如果某些强制节点丢失,那操作可能会报告404错误。
解决方案
如果要成功生成接入点,需要增加下列命令到操作的自定义列表中,并作为一个命令发送:
Add ./AP/<APIdxxx> Add ./AP/<APIdxxx>/NAPDef/<NAPIdxxx> Add ./AP/<APIdxxx>/NAPDef/<NAPIdxxx>/Name NewAPName Add ./AP/<APIdxxx>/NAPDef/<NAPIdxxx>/Bearer/<BIdxxx> Add ./AP/<APIdxxx>/NAPDef/<NAPIdxxx>/Bearer/<BIdxxx>/BearerL GSM-GPRS Add ./AP/<APIdxxx>/NAPDef/<NAPIdxxx>/Bearer/<BIdxxx>/Direction Outgoing
下列代码演示了如何使用第三版telephony API(CTelephony)来获得已接和未接来电号码。
下列代码需要使用活动对象实现完成,因此有一个派生自CActive的类。
// Class members CTelephony* iTelephony; CTelephony::TCallStatusV1 iLineStatus; CTelephony::TCallStatus iLastInformedLineStatus; Construction & initialization: iTelephony = CTelephony::NewL(); // Initialize with 'unknown' statuses iLineStatus.iStatus = CTelephony::EStatusUnknown; iLastInformedLineStatus = CTelephony::EStatusUnknown; CTelephony::TCallStatusV1Pckg lineStatusPckg( iLineStatus ); // Request notification about the changes in voice line status iTelephony->NotifyChange( iStatus, CTelephony::EVoiceLineStatusChange, lineStatusPckg ); SetActive(); Implementation of CActive::RunL() // Within CActive::RunL(): if( iLineStatus.iStatus == CTelephony::EStatusDialling ) { GetNumber(); } if(iLineStatus.iStatus == CTelephony::EStatusRinging) { if(iLastInformedLineStatus != CTelephony::EStatusDialling) { GetNumber(); } } iLastInformedLineStatus = iLineStatus.iStatus; Implementation of CActive::DoCancel(): iTelephony->CancelAsync( CTelephony::EVoiceLineStatusChangeCancel ); Implementation of GetNumber(): CTelephony::TCallInfoV1 callInfoV1; CTelephony::TCallInfoV1Pckg callInfoV1Pckg( callInfoV1 ); CTelephony::TCallSelectionV1 callSelectionV1; CTelephony::TCallSelectionV1Pckg callSelectionV1Pckg( callSelectionV1 ); CTelephony::TRemotePartyInfoV1 remotePartyInfoV1; CTelephony::TRemotePartyInfoV1Pckg remotePartyInfoV1Pckg( remotePartyInfoV1 ); callSelectionV1.iLine = CTelephony::EVoiceLine; callSelectionV1.iSelect = CTelephony::EInProgressCall; iTelephony->GetCallInfo( callSelectionV1Pckg, callInfoV1Pckg, remotePartyInfoV1Pckg ); if( remotePartyInfoV1.iRemoteIdStatus == CTelephony::ERemoteIdentityAvailable ) {
S60手机的蓝牙堆栈尚不支持SCO(Synchronous Connection Oriented,即同步面向连接)数据连接。
解决方案
暂无解决方案,第三版开发者可以先用ACL数据连接替代。(ACL即异步无连接Asynchronous Connection-Less,ACL)