蓝牙开启位于setting中,即 package:com.android.settings.bluetooth
BluetoothSettings.java 中。
菜单选项MENU_ID_SCAN:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_ID_SCAN:
if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON) {
MetricsLogger.action(getActivity(), MetricsLogger.ACTION_BLUETOOTH_SCAN);
startScanning();
}
return true;
case MENU_ID_RENAME_DEVICE:
MetricsLogger.action(getActivity(), MetricsLogger.ACTION_BLUETOOTH_RENAME);
new BluetoothNameDialogFragment().show(
getFragmentManager(), "rename device");
return true;
case MENU_ID_SHOW_RECEIVED:
MetricsLogger.action(getActivity(), MetricsLogger.ACTION_BLUETOOTH_FILES);
Intent intent = new Intent(BTOPP_ACTION_OPEN_RECEIVED_FILES);
getActivity().sendBroadcast(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
调用startScanning,添加可用设备列表,并将缓存的设备中没有配对的设备清除。调用LocalBluetoothAdapter.startScanning方法开始扫描。
LocalBluetoothAdapter.startScanning
public void startScanning(boolean force) {
// Only start if we're not already scanning
if (!mAdapter.isDiscovering()) {
//如果不是强制扫描,在SCAN_EXPIRATION_MS间隔内,之扫描一次
if (!force) {
// Don't scan more than frequently than SCAN_EXPIRATION_MS,
// unless forced
if (mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) {
return;
}
// If we are playing music, don't scan unless forced.
//播放音乐时,不扫描
A2dpProfile a2dp = mProfileManager.getA2dpProfile();
if (a2dp != null && a2dp.isA2dpPlaying()) {
return;
}
}
//开始扫描
if (mAdapter.startDiscovery()) {
mLastScan = System.currentTimeMillis();
}
}
}
- 真在扫描则跳过
- 如果不是强制开始扫描,在SCAN_EXPIRATION_MS间隔时间内,只扫描一次;如果在播放音乐时,也不执行扫描
- 调用BluetoothAdapter.startDiscovery方法,启动扫描任务
BluetoothAdapter.startDiscovery方法调用远程服务AdapterServiceBinder.startDiscovery方法,开启扫描。
AdapterServiceBinder是AdapterService内IBluetooth.Stub接口类,主要用来处理蓝牙相关的服务调用;AdapterServiceBinder将传入的服务调用转交AdapterService处理。
AdapterServiceBinder.startDiscovery
public boolean startDiscovery() {
if (!Utils.checkCaller()) {
Log.w(TAG, "startDiscovery() - Not allowed for non-active user");
return false;
}
AdapterService service = getService();
if (service == null) return false;
return service.startDiscovery();
}
AdapterService.startDiscovery
boolean startDiscovery() {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
return startDiscoveryNative();
}
进入JNI层
startDiscoveryNative
在com_android_bluetooth_btservice_AdapterService.cpp文件中,调用startDiscoveryNative方法,
//蓝牙扫描
static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {
ALOGV("%s:",__FUNCTION__);
jboolean result = JNI_FALSE;
if (!sBluetoothInterface) return result;
int ret = sBluetoothInterface->start_discovery();
result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
return result;
}
start_discovery
startDiscoveryNative方法调用bluetooth.c中start_discovery方法
//蓝牙扫描
static int start_discovery(void)
{
/* sanity check */ //完整性检查
if (interface_ready() == FALSE)
return BT_STATUS_NOT_READY;
return btif_dm_start_discovery();
}
start_discovery方法调用btif_dm.c的btif_dm_start_discovery方法
btif_dm_start_discovery
btif_dm.c 设备管理(DM)相关的功能
btif_dm_start_discovery方法中最终调用 BTA_DmSearch(&inq_params, services, bte_search_devices_evt);
void BTA_DmSearch(tBTA_DM_INQ *p_dm_inq, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK *p_cback)
{
tBTA_DM_API_SEARCH *p_msg;
if ((p_msg = (tBTA_DM_API_SEARCH *) GKI_getbuf(sizeof(tBTA_DM_API_SEARCH))) != NULL)
{
memset(p_msg, 0, sizeof(tBTA_DM_API_SEARCH));
p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
p_msg->services = services;
p_msg->p_cback = p_cback;
p_msg->rs_res = BTA_DM_RS_NONE;
bta_sys_sendmsg(p_msg);
}
}
调用bta_sys_sendmsg向BTA发送扫描任务消息。
bte_search_devices_evt方法作为扫描任务的回调函数,
当扫描到设备时,回调bte_search_devices_evt方法,将上下文从BTE切换到BTIF
static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data)
{
UINT16 param_len = 0;
if (p_data)
param_len += sizeof(tBTA_DM_SEARCH);
/* Allocate buffer to hold the pointers (deep copy). The pointers will point to the end of the tBTA_DM_SEARCH */
switch (event)
{
case BTA_DM_INQ_RES_EVT:
{
if (p_data->inq_res.p_eir)
param_len += HCI_EXT_INQ_RESPONSE_LEN;
}
break;
case BTA_DM_DISC_RES_EVT:
{
if (p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data)
param_len += p_data->disc_res.raw_data_size;
}
break;
}
BTIF_TRACE_DEBUG("%s event=%s param_len=%d", __FUNCTION__, dump_dm_search_event(event), param_len);
/* if remote name is available in EIR, set teh flag so that stack doesnt trigger RNR */
if (event == BTA_DM_INQ_RES_EVT)
p_data->inq_res.remt_name_not_required = check_eir_remote_name(p_data, NULL, NULL);
btif_transfer_context (btif_dm_search_devices_evt , (UINT16) event, (void *)p_data, param_len,
(param_len > sizeof(tBTA_DM_SEARCH)) ? search_devices_copy_cb : NULL);
}
btif_dm_search_devices_evt
再调用btif_dm_search_devices_evt,btif_dm_search_devices_evt并将扫描到的设备通过HAL_CBACK方式返回。
static void btif_dm_search_devices_evt (UINT16 event, char *p_param)
{
tBTA_DM_SEARCH *p_search_data;
BTIF_TRACE_EVENT("%s event=%s", __FUNCTION__, dump_dm_search_event(event));
switch (event)
{
case BTA_DM_DISC_RES_EVT:
{
p_search_data = (tBTA_DM_SEARCH *)p_param;
/* Remote name update */
if (strlen((const char *) p_search_data->disc_res.bd_name))
{
bt_property_t properties[1];
bt_bdaddr_t bdaddr;
bt_status_t status;
properties[0].type = BT_PROPERTY_BDNAME;
properties[0].val = p_search_data->disc_res.bd_name;
properties[0].len = strlen((char *)p_search_data->disc_res.bd_name);
bdcpy(bdaddr.address, p_search_data->disc_res.bd_addr);
status = btif_storage_set_remote_device_property(&bdaddr, &properties[0]);
ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device property", status);
HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
status, &bdaddr, 1, properties);
}
/* TODO: Services? */
}
..........................省略............................
}
}
扫描到设备时,调用的是HAL_CBACK(bt_hal_cbacks, device_found_cb,
num_properties, properties);
device_found_cb即是device_found_callback方法,在com_android_bluetooth_btservice_AdapterService.cpp中实现
static void device_found_callback(int num_properties, bt_property_t *properties) {
jbyteArray addr = NULL;
int addr_index;
for (int i = 0; i < num_properties; i++) {
if (properties[i].type == BT_PROPERTY_BDADDR) {
addr = callbackEnv->NewByteArray(properties[i].len);
if (addr) {
callbackEnv->SetByteArrayRegion(addr, 0, properties[i].len,
(jbyte*)properties[i].val);
addr_index = i;
} else {
ALOGE("Address is NULL (unable to allocate) in %s", __FUNCTION__);
return;
}
}
}
if (addr == NULL) {
ALOGE("Address is NULL in %s", __FUNCTION__);
return;
}
ALOGV("%s: Properties: %d, Address: %s", __FUNCTION__, num_properties,
(const char *)properties[addr_index].val);
remote_device_properties_callback(BT_STATUS_SUCCESS, (bt_bdaddr_t *)properties[addr_index].val,
num_properties, properties);
callbackEnv->CallVoidMethod(sJniCallbacksObj, method_deviceFoundCallback, addr);
checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
callbackEnv->DeleteLocalRef(addr);
}
该方法对应JNI方法为method_deviceFoundCallback,即
jclass jniCallbackClass =
env->FindClass("com/android/bluetooth/btservice/JniCallbacks");
..................
method_deviceFoundCallback = env->GetMethodID(jniCallbackClass, "deviceFoundCallback", "([B)V");
对应JniCallbacks.java的deviceFoundCallback方法。
deviceFoundCallback
void deviceFoundCallback(byte[] address) {
mRemoteDevices.deviceFoundCallback(address);
}
deviceFoundCallback将扫描到的设备通过广播发送出去
void deviceFoundCallback(byte[] address) {
// The device properties are already registered - we can send the intent
// now
BluetoothDevice device = getDevice(address);
debugLog("deviceFoundCallback: Remote Address is:" + device);
DeviceProperties deviceProp = getDeviceProperties(device);
if (deviceProp == null) {
errorLog("Device Properties is null for Device:" + device);
return;
}
Intent intent = new Intent(BluetoothDevice.ACTION_FOUND);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothDevice.EXTRA_CLASS,
new BluetoothClass(deviceProp.mBluetoothClass));
intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi);
intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName);
mAdapterService.sendBroadcastMultiplePermissions(intent,
new String[] {AdapterService.BLUETOOTH_PERM,
android.Manifest.permission.ACCESS_COARSE_LOCATION});
}
注册android.bluetooth.device.action.FOUND的广播接收器都可以收到该广播。