1. Android实现了对Headset和Handsfree两种profile的支持。其实现核心是BluetoothHeadsetService,在PhoneApp创建的时候会启动它。
  2. if(getSystemService(Context.BLUETOOTH_SERVICE)!=null){
  3. mBtHandsfree=newBluetoothHandsfree(this,phone);
  4. startService(newIntent(this,BluetoothHeadsetService.class));
  5. }else{
  6. //Deviceisnotbluetoothcapable
  7. mBtHandsfree=null;
  8. }
  9. BluetoothHeadsetService通过接收ENABLED_ACTION、BONDING_CREATED_ACTION、DISABLED_ACTION和REMOTE_DEVICE_DISCONNECT_REQUESTEDACTION来改变状态,它也会监听Phone的状态变化。
  10. IntentFilterfilter=newIntentFilter(BluetoothIntent.BONDING_CREATED_ACTION);
  11. filter.addAction(BluetoothIntent.REMOTE_DEVICE_DISCONNECT_REQUESTED_ACTION);
  12. filter.addAction(BluetoothIntent.ENABLED_ACTION);
  13. filter.addAction(BluetoothIntent.DISABLED_ACTION);
  14. registerReceiver(mBluetoothIntentReceiver,filter);
  15. mPhone.registerForPhoneStateChanged(mStateChangeHandler,PHONE_STATE_CHANGED,null);
  16. BluetoothHeadsetService收到ENABLED_ACTION时,会先向BlueZ注册Headset和Handsfree两种profile(通过执行sdptool来实现的,均作为AudioGateway),然后让BluetoothAudioGateway接收RFCOMM连接,让BluetoothHandsfree接收SCO连接(这些操作都是为了让蓝牙耳机能主动连上Android)。
  17. if(action.equals(BluetoothIntent.ENABLED_ACTION)){
  18. //SDPservermaynotbeready,sowait3secondsbefore
  19. //registeringrecords.
  20. //TODO:UseadifferentmechanismtoregisterSDPrecords,
  21. //thatactuallyACK’sonsuccess,sothatwecanretryrather
  22. //thanhardcodinga3secondguess.
  23. mHandler.sendMessageDelayed(mHandler.obtainMessage(REGISTER_SDP_RECORDS),3000);
  24. mAg.start(mIncomingConnectionHandler);
  25. mBtHandsfree.onBluetoothEnabled();
  26. }
  27. BluetoothHeadsetService收到DISABLED_ACTION时,会停止BluetoothAudioGateway和BluetoothHandsfree。
  28. if(action.equals(BluetoothIntent.DISABLED_ACTION)){
  29. mBtHandsfree.onBluetoothDisabled();
  30. mAg.stop();
  31. }
  32. Android跟蓝牙耳机建立连接有两种方式。
  33. 1.Android主动跟蓝牙耳机连BluetoothSettings中和蓝牙耳机配对上之后,BluetoothHeadsetService会收到BONDING_CREATED_ACTION,这个时候BluetoothHeadsetService会主动去和蓝牙耳机建立RFCOMM连接。
  34. if(action.equals(BluetoothIntent.BONDING_CREATED_ACTION)){
  35. if(mState==BluetoothHeadset.STATE_DISCONNECTED){
  36. //LetstryandinitiateanRFCOMMconnection
  37. try{
  38. mBinder.connectHeadset(address,null);
  39. }catch(RemoteExceptione){}
  40. }
  41. }
  42. RFCOMM连接的真正实现是在ConnectionThread中,它分两步,第一步先通过SDPClient查询蓝牙设备时候支持Headset和Handsfreeprofile。
  43. //1)SDPquery
  44. SDPClientclient=SDPClient.getSDPClient(address);
  45. if(DBG)log(”ConnectingtoSDPserver(”+address+“)…”);
  46. if(!client.connectSDPAsync()){
  47. Log.e(TAG,“FailedtostartSDPconnectionto”+address);
  48. mConnectingStatusHandler.obtainMessage(SDP_ERROR).sendToTarget();
  49. client.disconnectSDP();
  50. return;
  51. }
  52. if(isInterrupted()){
  53. client.disconnectSDP();
  54. return;
  55. }
  56. if(!client.waitForSDPAsyncConnect(20000)){//20secs
  57. if(DBG)log(”FailedtomakeSDPconnectionto”+address);
  58. mConnectingStatusHandler.obtainMessage(SDP_ERROR).sendToTarget();
  59. client.disconnectSDP();
  60. return;
  61. }
  62. if(DBG)log(”SDPserverconnected(”+address+“)”);
  63. intheadsetChannel=client.isHeadset();
  64. if(DBG)log(”headsetchannel=”+headsetChannel);
  65. inthandsfreeChannel=client.isHandsfree();
  66. if(DBG)log(”handsfreechannel=”+handsfreeChannel);
  67. client.disconnectSDP();
  68. 2步才是去真正建立RFCOMM连接。
  69. //2)RFCOMMconnect
  70. mHeadset=newHeadsetBase(mBluetooth,address,channel);
  71. if(isInterrupted()){
  72. return;
  73. }
  74. intresult=mHeadset.waitForAsyncConnect(20000,//20secs
  75. mConnectedStatusHandler);
  76. if(DBG)log(”HeadsetRFCOMMconnectionattempttook”+(System.currentTimeMillis()–timestamp)+”ms”);
  77. if(isInterrupted()){
  78. return;
  79. }
  80. if(result<0){
  81. Log.e(TAG,“mHeadset.waitForAsyncConnect()error:”+result);
  82. mConnectingStatusHandler.obtainMessage(RFCOMM_ERROR).sendToTarget();
  83. return;
  84. }elseif(result==0){
  85. Log.e(TAG,“mHeadset.waitForAsyncConnect()error:”+result+”(timeout)”);
  86. mConnectingStatusHandler.obtainMessage(RFCOMM_ERROR).sendToTarget();
  87. return;
  88. }else{
  89. if(DBG)log(”mHeadset.waitForAsyncConnect()success”);
  90. mConnectingStatusHandler.obtainMessage(RFCOMM_CONNECTED).sendToTarget();
  91. }
  92. 当RFCOMM连接成功建立后,BluetoothHeadsetDevice会收到RFCOMM_CONNECTED消息,它会调用BluetoothHandsfree来建立SCO连接,广播通知Headset状态变化的Intent(PhoneApp和BluetoothSettings会接收这个Intent)。
  93. caseRFCOMM_CONNECTED:
  94. //success
  95. if(DBG)log(”Rfcommconnected”);
  96. if(mConnectThread!=null){
  97. try{
  98. mConnectThread.join();
  99. }catch(InterruptedExceptione){
  100. Log.w(TAG,“Connectattemptcancelled,ignoring
  101. RFCOMM_CONNECTED”,e);
  102. return;
  103. }
  104. mConnectThread=null;
  105. }
  106. setState(BluetoothHeadset.STATE_CONNECTED,BluetoothHeadset.RESULT_SUCCESS);
  107. mBtHandsfree.connectHeadset(mHeadset,mHeadsetType);
  108. break;
  109. BluetoothHandsfree会先做一些初始化工作,比如根据是Headset还是Handsfree初始化不同的ATParser,并且启动一个接收线程从已建立的RFCOMM上接收蓝牙耳机过来的控制命令(也就是AT命令),接着判断如果是在打电话过程中,才去建立SCO连接来打通数据通道。
  110. /*package*/
  111. voidconnectHeadset(HeadsetBaseheadset,intheadsetType){
  112. mHeadset=headset;
  113. mHeadsetType=headsetType;
  114. if(mHeadsetType==TYPE_HEADSET){
  115. initializeHeadsetAtParser();
  116. }else{
  117. initializeHandsfreeAtParser();
  118. }
  119. headset.startEventThread();
  120. configAudioParameters();
  121. if(inDebug()){
  122. startDebug();
  123. }
  124. if(isIncallAudio()){
  125. audioOn();
  126. }
  127. }
  128. 建立SCO连接是通过SCOSocket实现的
  129. /**RequesttoestablishSCO(audio)connectiontobluetooth
  130. *headset/handsfree,ifoneisconnected.Doesnotblock.
  131. *Returnsfalseiftheuserhasrequestedaudiooff,orifthere
  132. *issomeotherimmediateproblemthatwillpreventBTaudio.
  133. */
  134. /*package*/
  135. synchronizedbooleanaudioOn(){
  136. mOutgoingSco=createScoSocket();
  137. if(!mOutgoingSco.connect(mHeadset.getAddress())){
  138. mOutgoingSco=null;
  139. }
  140. returntrue;
  141. }
  142. 当SCO连接成功建立后,BluetoothHandsfree会收到SCO_CONNECTED消息,它就会去调用AudioManager的setBluetoothScoOn函数,从而通知音频系统有个蓝牙耳机可用了。
  143. 到此,Android完成了和蓝牙耳机的全部连接。
  144. caseSCO_CONNECTED:
  145. if(msg.arg1==ScoSocket.STATE_CONNECTED&&isHeadsetConnected()&&mConnectedSco==null){
  146. if(DBG)log(”RoutingaudioforoutgoingSCOconection”);
  147. mConnectedSco=(ScoSocket)msg.obj;
  148. mAudioManager.setBluetoothScoOn(true);
  149. }elseif(msg.arg1==ScoSocket.STATE_CONNECTED){
  150. if(DBG)log(”RejectingnewconnectedoutgoingSCOsocket”);
  151. ((ScoSocket)msg.obj).close();
  152. mOutgoingSco.close();
  153. }
  154. mOutgoingSco=null;
  155. break;
  156. 2.蓝牙耳机主动跟Android连首先BluetoothAudioGateway会在一个线程中收到来自蓝牙耳机的RFCOMM连接,然后发送消息给BluetoothHeadsetService。
  157. mConnectingHeadsetRfcommChannel=-1;
  158. mConnectingHandsfreeRfcommChannel=-1;
  159. if(waitForHandsfreeConnectNative(SELECT_WAIT_TIMEOUT)==false){
  160. if(mTimeoutRemainingMs>0){
  161. try{
  162. Log.i(tag,“selectthreadtimedout,but”+
  163. mTimeoutRemainingMs+“msof
  164. waitingremain.”);
  165. Thread.sleep(mTimeoutRemainingMs);
  166. }catch(InterruptedExceptione){
  167. Log.i(tag,“selectthreadwasinterrupted(2),
  168. exiting”);
  169. mInterrupted=true;
  170. }
  171. }
  172. }
  173. BluetoothHeadsetService会根据当前的状态来处理消息,分3种情况,第一是当前状态是非连接状态,会发送RFCOMM_CONNECTED消息,后续处理请参见前面的分析。
  174. caseBluetoothHeadset.STATE_DISCONNECTED:
  175. //headsetconnectingus,letsjoin
  176. setState(BluetoothHeadset.STATE_CONNECTING);
  177. mHeadsetAddress=info.mAddress;
  178. mHeadset=newHeadsetBase(mBluetooth,mHeadsetAddress,info.mSocketFd,info.mRfcommChan,mConnectedStatusHandler);
  179. mHeadsetType=type;
  180. mConnectingStatusHandler.obtainMessage(RFCOMM_CONNECTED).sendToTarget();
  181. break;
  182. 如果当前是正在连接状态,则先停掉已经存在的ConnectThread,并直接调用BluetoothHandsfree去建立SCO连接。
  183. caseBluetoothHeadset.STATE_CONNECTING:
  184. //Ifwearehere,weareindangerofaracecondition
  185. //incomingrfcommconnection,butwearealsoattemptingan
  186. //outgoingconnection.Letstryandinterrupttheoutgoing
  187. //connection.
  188. mConnectThread.interrupt();
  189. //Nowcontinuewithnewconnection,includingcallingcallback
  190. mHeadset=newHeadsetBase(mBluetooth,mHeadsetAddress,info.mSocketFd,info.mRfcommChan,mConnectedStatusHandler);
  191. mHeadsetType=type;
  192. setState(BluetoothHeadset.STATE_CONNECTED,BluetoothHeadset.RESULT_SUCCESS);
  193. mBtHandsfree.connectHeadset(mHeadset,mHeadsetType);
  194. //Makesurethatoldoutgoingconnectthreadisdead.
  195. break;
  196. 如果当前是已连接的状态,这种情况是一种错误case,所以直接断掉所有连接。
  197. caseBluetoothHeadset.STATE_CONNECTED:
  198. if(DBG)log(”Alreadyconnectedto”+mHeadsetAddress+“,disconnecting”+info.mAddress);
  199. mBluetooth.disconnectRemoteDeviceAcl(info.mAddress);
  200. break;
  201. 蓝牙耳机也可能会主动发起SCO连接,BluetoothHandsfree会接收到一个SCO_ACCEPTED消息,它会去调用AudioManager的setBluetoothScoOn函数,从而通知音频系统有个蓝牙耳机可用了。到此,蓝牙耳机完成了和Android的全部连接。
  202. caseSCO_ACCEPTED:
  203. if(msg.arg1==ScoSocket.STATE_CONNECTED){
  204. if(isHeadsetConnected()&&mAudioPossible&&mConnectedSco==null){
  205. Log.i(TAG,“RoutingaudioforincomingSCOconnection”);
  206. mConnectedSco=(ScoSocket)msg.obj;
  207. mAudioManager.setBluetoothScoOn(true);
  208. }else{
  209. Log.i(TAG,“RejectingincomingSCOconnection”);
  210. ((ScoSocket)msg.obj).close();
  211. }
  212. }//elseerrortryingtoaccept,tryagain
  213. mIncomingSco=createScoSocket();
  214. mIncomingSco.accept();
  215. break;



更多相关文章

  1. android SIM卡状态
  2. android时序图 以及UML中时序图、流程图、状态图、协作图之间的
  3. Android(安卓)电源管理
  4. android开源框架源码分析:Okhttp
  5. Android(安卓)Process 优先级
  6. android sim卡 TelephonyManager类:Android手机及Sim卡状态的获取
  7. android检查网络连接状态的变化,无网络时跳转到设置界面
  8. 聊聊Android切图
  9. Android(安卓)shape使用

随机推荐

  1. mysql的MVCC多版本并发控制的实现
  2. mysql查询的控制语句图文详解
  3. 详解MySQL InnoDB存储引擎的内存管理
  4. MySQL Innodb关键特性之插入缓冲(insert
  5. 如何使用Maxwell实时同步mysql数据
  6. MySQL创建索引需要了解的
  7. mysql数据库基本语法及操作大全
  8. MySQL外键设置的方法实例
  9. MySQL 使用SQL语句修改表名的实现
  10. mysql批量新增和存储的方法实例