這篇文章將所有的android藍(lán)牙的東西都集合在這里,主要分一下幾個部分,所有分析都基于Bluedroid:
(1) Android Bluedroid藍(lán)牙基本框架
(2) 主要目錄及文件結(jié)構(gòu)
(3) 藍(lán)牙主要的支持的profile
(4) 藍(lán)牙基本流程分析:藍(lán)牙啟動, 藍(lán)牙搜索, 藍(lán)牙連接, 藍(lán)牙傳輸文件,藍(lán)牙通話和播放音樂
(1) Android Bluedroid藍(lán)牙基本框架

根據(jù)上圖,代碼調(diào)用過程一般基于下面的流程
APP->Framework---->(通過Binder)BluetoothService-->(通過JNI)調(diào)用Native Bluetooth->bluedroid->hci
(2) 模塊的主要目錄以及文件結(jié)構(gòu):
APP:
Settings
packages/apps/Settings/src/com/android/settings/bluetooth
主要文件說明:
BluetoothEnabler.java 界面上藍(lán)牙開啟、關(guān)閉的開關(guān)就是它了,
BluetoothSettings.java 主界面,用于管理配對和連接設(shè)備
LocalBluetoothManager.java 提供了藍(lán)牙API上的簡單調(diào)用接口,這里只是開始。
CachedBluetoothDevice.java 描述藍(lán)牙設(shè)備的類,對BluetoothDevice的再封裝
BluetoothPairingDialog.java 那個配對提示的對話框
Phone
packages/apps/services/Telecom/src/com/android/server/telecom/BluetoothManager.java
這里是通話調(diào)用藍(lán)牙Audio,
connectBluetoothAudio
disconnectBluetoothAudio
Framework:
/frameworks/base/core/java/android/bluetooth/
BluetoothA2dp.java A2DP的功能實(shí)現(xiàn)
BluetoothAdapter.java 藍(lán)牙action的定義,虛擬設(shè)備屬性以及操作方法
BluetoothAudioGateway.java 藍(lán)牙語音網(wǎng)關(guān)
BluetoothClass.java 藍(lán)牙設(shè)備類型的定義
BluetoothDevice.java 藍(lán)牙設(shè)備屬性
BluetoothDevicePicker.java 定義遠(yuǎn)程藍(lán)牙設(shè)備的特性,比如需要認(rèn)證,設(shè)備類型
BluetoothHeadset.java 定義藍(lán)牙headset功能的屬性以及接口
BluetoothInputStream.java 藍(lán)牙流接口的實(shí)現(xiàn)(輸入流)
BluetoothOutputStream.java 藍(lán)牙流接口的實(shí)現(xiàn)(輸出流)
BluetoothServerSocket.java 藍(lán)牙socket服務(wù)端具備的方法
BluetoothSocket.java 藍(lán)牙socket的封裝
BluetoothUuid.java 藍(lán)牙uuid的定義以及uuid的解析
(3) 藍(lán)牙主要的支持的profile
HFP/HSP
A2DP
AVRCP
PBAP
DUN
OPP
PAN
(4) 藍(lán)牙基本流程分析:
a. 藍(lán)牙開啟:
首先是BluetoothManagerService的啟動, 這個服務(wù)也是在SystemServer中啟動的, 在開機(jī)后,SystemServer進(jìn)程由zygote進(jìn)程fork出來后,會啟動一系列的service,這里面就有BluetoothManagerService:
frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices() {
BluetoothManagerService bluetooth = null;
//初始化一個BluetoothManagerService;
bluetooth = new BluetoothManagerService(context);
ServiceManager.addService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, bluetooth);
}
看一下BluetoothManagerService的構(gòu)造函數(shù)
BluetoothManagerService(Context context) {
loadStoredNameAndAddress(); //讀取藍(lán)牙打開默認(rèn)名稱和地址
if (isBluetoothPersistedStateOn()) { //判斷藍(lán)牙是否打開
mEnableExternal = true; //如果藍(lán)牙打開,這個設(shè)為true,等boot完后,開啟enable 藍(lán)牙的過程
}
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
synchronized(mReceiver) {
if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
//Enable
if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
sendEnableMsg(mQuietEnableExternal);
}
}
}
廣播中接收Boot是否完成, 完成后調(diào)用sendEnable來開啟藍(lán)牙,mEnableExternal這個值就在這里用到了。
b. 點(diǎn)擊藍(lán)牙開關(guān)開啟藍(lán)牙流程
Settings菜單點(diǎn)擊菜單開啟藍(lán)牙:
APP層路徑packages/apps/Settings/src/com/android/settings/bluetooth
BluetoothSettings.java
public void onActivityCreated(Bundle savedInstanceState) {
mSwitchBar = activity.getSwitchBar(); //界面上的swtichbar控件
mBluetoothEnabler = new BluetoothEnabler(activity, mSwitchBar); //傳送給BluetoothEnabler, 通過BluetoothEnable控制
mBluetoothEnabler.setupSwitchBar();
}
BluetoothEnabler.java
private final LocalBluetoothAdapter mLocalAdapter; //localBluetoothAdapter
public BlutoothEnable(){ //構(gòu)造函數(shù),定義了localBluetoothManager和LocalBluetoothAdapter
LocalBluetoothManager manager = LocalBluetoothManager.getInstance(context);
mLocalAdapter = manager.getBluetoothAdapter();
}
public void resume(Context context) {
// Bluetooth state is not sticky, so set it manually
handleStateChanged(mLocalAdapter.getBluetoothState()); //設(shè)置初始狀態(tài)
mSwitchBar.addOnSwitchChangeListener(this); //設(shè)置switch監(jiān)聽
}
public void onSwitchChanged(Switch switchView, boolean isChecked) {
if (mLocalAdapter != null) {
mLocalAdapter.setBluetoothEnabled(isChecked); //
}
}
LocalBluetoothAdapter.java
public void setBluetoothEnabled(boolean enabled) {
private final BluetoothAdapter mAdapter;
boolean success = enabled? mAdapter.enable(): mAdapter.disable(); 調(diào)用BluetoothAdapter的enable/disable
}
通過調(diào)用BluetoothAdapter的函數(shù),就調(diào)用到了framework的接口:
LocalBluetoothAdapter.java
private final IBluetoothManager mManagerService;
public static synchronized BluetoothAdapter getDefaultAdapter() {
IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b); //這邊會返回一個managerService的代理
}
public boolean enable() {
return mManagerService.enable(ActivityThread.currentPackageName()); //通過代理調(diào)用BluetoothManagerService的enable.
}
BluetoothManagerService
class BluetoothManagerService extends IBluetoothManager.Stub{
private final BluetoothHandler mHandler;
private IBluetooth mBluetooth;
public boolean enable(String callingPackage) {
//這里會獲取藍(lán)牙的權(quán)限
synchronized(mReceiver) {
//通過發(fā)送消息的方式enable
sendEnableMsg(false);
}
}
private void sendEnableMsg(boolean quietMode) {
//這邊回去發(fā)送消息, quietMode決定打開后是否需要AutoConnect,這邊是false
mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
quietMode ? 1 : 0, 0));
}
//Handler是BluetoothManagerService的內(nèi)部類,這邊處理接收的命令
private class BluetoothHandler extends Handler {
public void handleMessage(Message msg) {
case MESSAGE_ENABLE:
//調(diào)用handleEnable函數(shù)處理
handleEnable(msg.arg1 == 1);
break;
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
mBluetooth = IBluetooth.Stub.asInterface(service);
break;
}
}
private void handleEnable(boolean quietMode) {
synchronized(mConnection) {
try {
//傳進(jìn)來是false,所以走enable,即開啟會重新連接
if (!mQuietEnable) {
//調(diào)用mBluetooth的enable,mBluetooth上面有定義,是IBluetooth的代理, server端在package/apps/Bluetooth里面
if(!mBluetooth.enable()) {
}
}
else {
if(!mBluetooth.enableNoAutoConnect()) {
}
}
} catch (RemoteException e) {
Log.e(TAG,"Unable to call enable()",e);
}
}
}
}
之前調(diào)用IBluetooth的service端的部分:
AdapterService.java
static { //這里添加了so庫,并定義了一些 native函數(shù)
System.load("/system/lib/libbluetooth_jni.so");
classInitNative();
}
private static class AdapterServiceBinder extends IBluetooth.Stub {
public boolean enable() {
return service.enable(); //這邊又要看這個service,這個service即是 AdapterService
}
}
boolean enable() {
return enable (false);
}
public synchronized boolean enable(boolean quietMode) {
//這邊會發(fā)送一個消息到狀態(tài)機(jī)AdapaterState
Message m =
mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON);
mAdapterStateMachine.sendMessage(m);
}
void processStart() {
//啟動藍(lán)牙的部分, 如果是第一次開啟的話, 走下面的路徑, 繼續(xù)想state狀態(tài)機(jī)發(fā)送AdapterState.STARTED狀態(tài)
if (!mProfilesStarted && supportedProfileServices.length >0) {
//Startup all profile services
setProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_ON);
}else {
debugLog("processStart() - Profile Services alreay started");
mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STARTED));
}
}
AdapterState.java 狀態(tài)機(jī)文件,負(fù)責(zé)跟AdapterService的溝通
private class OffState extends State {
public boolean processMessage(Message msg) {
switch(msg.what) {
case USER_TURN_ON:
adapterService.processStart(); //adpaterService調(diào)用processStart函數(shù)
break;
}
}
最后,看一下狀態(tài)機(jī)里面的函數(shù)
private class PendingCommandState extends State {
public boolean processMessage(Message msg) {
boolean ret = adapterService.enableNative(); //這邊就調(diào)用到j(luò)ni的地方了
}
看一下簡單的流程圖, 大體一致,但也稍微有不同的地方

這邊只到了JNI,下面JNI如何調(diào)用CPP的呢~
這邊調(diào)用packages/apps/Bluetooth/jni下面的jni文件:
com_android_bluetooth_btservice_AdapterService.cpp
static jboolean enableNative(JNIENv* env, jobject obj){
int ret = sBluetoothInterface->enable();
}
在然后好像真的沒有了, 后面進(jìn)入到hal,調(diào)用Bluedroid協(xié)議棧了
hardware/libhardware/include/hardware/bluetooth.h
typedef struct{
int(*enable)(void);
}bt_interface_t;
Bluedroid協(xié)議棧位于external/bluetooth/bluedroid
bluetooth.c
static int enable(void){
return btif_enable_bluetooth();
}
btif_core.c
bt_status_t btif_enable_bluetooth(void)
{
bte_main_enable();
}
bte_main.c
void bte_main_enable(){
BTE_Init();
GKI_create_task(); //創(chuàng)建GKI task
bte_hci_enable();
GKI_run();
}
c. 藍(lán)牙搜索:
APP測:
BluetoothSettings.java
//藍(lán)牙狀態(tài)改變監(jiān)聽
public void onBluetoothStateChanged(int bluetoothState) {
super.onBluetoothStateChanged(bluetoothState);
updateContent(bluetoothState);
}
private void updateContent(int bluetoothState) {
case BluetoothAdapter.STATE_ON: //藍(lán)牙開啟完成后,開始掃描
if (!mInitialScanStarted) {
startScanning();
}
break;
case BluetoothAdapter.STATE_TURNING_ON: //藍(lán)牙開啟中,將scanStart設(shè)置為false
mInitialScanStarted = false;
break;
}
這邊的BluetoothAdapter.STATE有4個狀態(tài):
STATE_OF = 10;
STATE_TURNING_ON = 11;
STATE_ON = 12;
STATE_TURNING_OFF = 13;
private void startScanning() {
mLocalAdapter.startScanning(true);//調(diào)用localAdapter的startScanning函數(shù)
}
LocalBluetoothAdapter.java
void startScanning(boolean force) {
// If we are playing music, don't scan unless forced.
//這里回去判斷a2dp profile,如果正在a2dp存在,則不能掃描
A2dpProfile a2dp = mProfileManager.getA2dpProfile();
if (a2dp != null && a2dp.isA2dpPlaying()) {
return;
}
A2dpSinkProfile a2dpSink = mProfileManager.getA2dpSinkProfile();
if ((a2dpSink != null) && (a2dpSink.isA2dpPlaying())){
return;
}
if (mAdapter.startDiscovery()) { //調(diào)用framwork的接口
mLastScan = System.currentTimeMillis();
}
}
Framework:
BluetoothAdapter.java
private IBluetooth mService; //這么快就用到IBluetooth了。。。
BluetoothAdapter(IBluetoothManager managerService) {
try {
//構(gòu)造函數(shù)里直接就獲取mService,這個mService跟managerService是一樣一樣的,是IBluetooth的客戶端代理,跟Service(AdapterService)通訊
mService = managerService.registerAdapter(mManagerCallback);
} catch (RemoteException e) {Log.e(TAG, "", e);}
}
public boolean startDiscovery() {
if (mService != null) return mService.startDiscovery(); //開始掃描
}
還是來看一下mService是如何獲取的
BluetoothManagerService.java
public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
synchronized(mConnection) {
return mBluetooth; //就是返回BluetoothManagerService的mBluetooth
}
}
Service (Service的目錄在packages/apps/bluetooth里面)
AdapterService.java
private static class AdapterServiceBinder extends IBluetooth.Stub {
public boolean startDiscovery() {
AdapterService service = getService();
return service.startDiscovery();
}
}
這里有個內(nèi)部類AdapterServiceBinder,是遠(yuǎn)程通訊的服務(wù)端:
直接調(diào)用了AdapterService的startDiscovery函數(shù)
boolean startDiscovery() {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
//do not allow new connections with active multicast
A2dpService a2dpService = A2dpService.getA2dpService();
if (a2dpService != null &&
a2dpService.isMulticastOngoing(null)) {
Log.i(TAG,"A2dp Multicast is Ongoing, ignore discovery");
return false;
}
return startDiscoveryNative();
}
這邊也是簡單粗暴的,直接返回startDiscoveryNative(),調(diào)用JNI函數(shù)
JNI
JNI的文件需要到packages/apps/bluetooth/jni下面,adapterservice對應(yīng)的jni文件為
com_android_bluetooth_btservice_AdapterService.cpp
static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {
int ret = sBluetoothInterface->start_discovery();
}
HAL
hal主要看hanrdware/libhardware/include/hardware/bluetooth.h
int (*start_discovery)(void);
//Bluedroid協(xié)議棧部分
bluetooth.c
static int statrt_discovery(void){
retun btif_dm_start_discovery();
}
btif_dm.c
這個函數(shù)start device discovery/inquiry
bt_status_t btif_dm_start_discovery(void){
/*find nearby devices*/
BTA_DmSearch(...);
}
d. 藍(lán)牙掃描結(jié)果返回
掃描結(jié)果反饋到上層則是從協(xié)議棧->hal->bluetoothService->APP
external/bluetooth/bluedroid/btif/src/
btif_dm.c
static void btif_dm_search_devices_evt (UINT16 event, char *p_param)
{
case BTA_DM_INQ_RES_EVT:
/* Callback to notify upper layer of device */
//調(diào)用注冊的callback, device_found_cb
HAL_CBACK(bt_hal_cbacks, device_found_cb,num_properties, properties);
break;
}
HAL
bluetooth.h
//
typedef void (*device_found_callback)(int num_properties,
bt_property_t *properties);
JNI
com_android_bluetooth_btservice_AdapterService.cpp
static void device_found_callback(int num_properties, bt_property_t *properties) {
if (sJniCallbacksObj) {
callbackEnv->CallVoidMethod(sJniCallbacksObj, method_deviceFoundCallback, addr);
}
}
Service
//deviceFoundCallback
RemoteDevices.java
void deviceFoundCallback(byte[] address) {
Intent intent = new Intent(BluetoothDevice.ACTION_FOUND); //send broadcast
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothDevice.EXTRA_CLASS,
new BluetoothClass(Integer.valueOf(deviceProp.mBluetoothClass)));
intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi);
intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName);
mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);
}
這里調(diào)用發(fā)送廣播,Action_Found給到上層
APP(Settings)
BluetoothEventManager.java
BluetoothEventManager(LocalBluetoothAdapter adapter,
CachedBluetoothDeviceManager deviceManager, Context context) {
mLocalAdapter = adapter;
mDeviceManager = deviceManager;
mAdapterIntentFilter = new IntentFilter();
mProfileIntentFilter = new IntentFilter();
mHandlerMap = new HashMap<String, Handler>();
mContext = context;
// Bluetooth on/off broadcasts
addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler());
// Discovery broadcasts
addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));
addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));
addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler());
addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());
// Pairing broadcasts
addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());
addHandler(BluetoothDevice.ACTION_PAIRING_CANCEL, new PairingCancelHandler());
// Fine-grained state broadcasts
addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());
addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());
// Dock event broadcasts
addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());
mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter);
setDefaultBtName();
}
這邊注冊廣播接收器
addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
private class DeviceFoundHandler implements Handler {
public void onReceive(Context context, Intent intent,
BluetoothDevice device) {
if (cachedDevice == null) {
cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "
+ cachedDevice);
// callback to UI to create Preference for new device
dispatchDeviceAdded(cachedDevice);
}
}
}
DeviceFoundHandler接收廣播,并調(diào)用dispatchDeviceAdded(cachedDevice);刷新上層顯示
private void dispatchDeviceAdded(CachedBluetoothDevice cachedDevice) {
synchronized (mCallbacks) {
for (BluetoothCallback callback : mCallbacks) {
callback.onDeviceAdded(cachedDevice);
}
}
}
調(diào)用callback.onDeviceAdded(cachedDevice); 回調(diào)返給上層
ListFragment DeviceListPreferenceFragment.java
public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
、、、
}
DeviceListPreferenceFragment繼承BluetoothCallback接口,重寫onDeviceAdded.
藍(lán)牙連接:
藍(lán)牙OPP文件傳輸:
起點(diǎn)自函數(shù)packages/apps/Bluetooth/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java
if (action.equals(Intent.ACTION_SEND) || action.equals(Intent.ACTION_SEND_MULTIPLE)) {
if (!isBluetoothAllowed()) {
Intent in = new Intent(this, BluetoothOppBtErrorActivity.class);
in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
in.putExtra("title", this.getString(R.string.airplane_error_title));
in.putExtra("content", this.getString(R.string.airplane_error_msg));
startActivity(in);
finish();
return;
}
if (action.equals(Intent.ACTION_SEND)) {
Thread t = new Thread(new Runnable() {
public void run() {
BluetoothOppManager.getInstance(BluetoothOppLauncherActivity.this)
.saveSendingFileInfo(type,stream.toString(), false);
//Done getting file info..Launch device picker and finish this activity
launchDevicePicker();
finish();
}
});
t.start();
return;
}
}
isBluetoothAllowed()判斷Bluetooth是否允許,如果不允許,彈出Error.
如果返回true,則開啟個線程,
launchDevicePicker 加載藍(lán)牙列表
private final void launchDevicePicker() {
if (!BluetoothOppManager.getInstance(this).isEnabled()) {
if (V) Log.v(TAG, "Prepare Enable BT!! ");
Intent in = new Intent(this, BluetoothOppBtEnableActivity.class);
in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(in);
} else {
if (V) Log.v(TAG, "BT already enabled!! ");
Intent in1 = new Intent(BluetoothDevicePicker.ACTION_LAUNCH);
in1.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
in1.putExtra(BluetoothDevicePicker.EXTRA_NEED_AUTH, false);
in1.putExtra(BluetoothDevicePicker.EXTRA_FILTER_TYPE,
BluetoothDevicePicker.FILTER_TYPE_TRANSFER);
in1.putExtra(BluetoothDevicePicker.EXTRA_LAUNCH_PACKAGE,
Constants.THIS_PACKAGE_NAME);
in1.putExtra(BluetoothDevicePicker.EXTRA_LAUNCH_CLASS,
BluetoothOppReceiver.class.getName());
if (V) {Log.d(TAG,"Launching " +BluetoothDevicePicker.ACTION_LAUNCH );}
startActivity(in1);
}
}
BluetoothOppManager.getInstance(this).isEnabled()判斷藍(lán)牙是否打開,如果打開,則跳轉(zhuǎn)到列表
DevicePickerFragment.java
@Override
void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
mLocalAdapter.stopScanning();
LocalBluetoothPreferences.persistSelectedDeviceInPicker(
getActivity(), mSelectedDevice.getAddress());
if ((btPreference.getCachedDevice().getBondState() ==
BluetoothDevice.BOND_BONDED) || !mNeedAuth) {
sendDevicePickedIntent(mSelectedDevice);
finish();
} else {
super.onDevicePreferenceClick(btPreference);
}
}
private void sendDevicePickedIntent(BluetoothDevice device) {
mDeviceSelected = true;
Intent intent = new Intent(BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
if (mLaunchPackage != null && mLaunchClass != null) {
intent.setClassName(mLaunchPackage, mLaunchClass);
}
getActivity().sendBroadcast(intent);
}
這邊發(fā)送一個selectd的廣播,搜關(guān)鍵字查詢廣播接收。
BluetoothOppReceiver.java
public void onReceive(Context context, Intent intent) {
else if (action.equals(BluetoothDevicePicker.ACTION_DEVICE_SELECTED)) {
// Insert transfer session record to database
mOppManager.startTransfer(remoteDevice);
}
}
public void startTransfer(BluetoothDevice device) {
if (V) Log.v(TAG, "Active InsertShareThread number is : " + mInsertShareThreadNum);
InsertShareInfoThread insertThread;
insertThread = new InsertShareInfoThread(device, mMultipleFlag, mMimeTypeOfSendingFile,
mUriOfSendingFile, mNameOfSendingFile, mMimeTypeOfSendingFiles, mUrisOfSendingFiles,
mIsHandoverInitiated);
}
insertThread.start();
}
private class InsertShareInfoThread extends Thread {
public void run() {
insertSingleShare();
}
}
上面步驟即是接收廣播后的操作~最終調(diào)用insertSingleShare來操作,后面的步驟略掉。
藍(lán)牙接電話與聽音樂: