我正在开发一个在Android上运行的外设模式BLE应用程序 . 有几个很好的功能示例描述了如何开发外设模式应用herehere .

样本应用程序与我需要开发的系统之间存在一个细微差别 . 在示例应用程序中,GATT服务器在外围模式设备上运行 . 外围设备通告,集中扫描并定位设备并向GATT服务器发送请求 .

在我的系统中,GATT服务器将位于中央模式设备上 . 外围设备将收到连接请求,需要找到请求设备的地址并启动与中央模式设备上的GATT服务器的连接 .

Nomenclature and Detailed Operation

MyApp(BLE外设;广告商,GATT客户端)

TgtDev(BLE中心;扫描仪,运行GATT服务器)

  • TgtDev不断扫描并查找具有特定UUID的广告 .

  • MyApp已启动并开始宣传其存在 .

  • TgtDev检测到MyApp并发送连接请求 .

  • 接收连接请求时,MyApp将请求用户接受或拒绝连接请求 . 此时,它将需要读取请求连接的设备的地址 .

  • 如果用户接受,MyApp将请求连接TgtDev上的GATT服务器 .

  • 如果用户拒绝请求,MyApp将停止广告 .

我的申请代码如下所示 . 我希望在收到连接请求时收到MyApp的意图 . 看起来这应该可以使用registerReceiver()的适当的intent过滤器 . 但是,我没有看到在发出连接请求时调用BroadcastReceiver .

提供了GattCallback()函数的实现,但未使用 . 要注册回调,我需要连接设备的地址 .

关于我在这里缺少什么的任何建议?

编辑:添加有关系统和Android日志消息的信息 . 外围设备Nexus 6运行5.1 . MyApp targetSdkVersion 21.跟踪TgtDev上的代码路径我可以看到MyApp接受了连接事件 . 我能用BLE嗅探器证实这一点 .

记录消息 .

I/ActivityManager(  802): START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.user.advertiser/.PeripheralActivity (has extras)} from uid 10034 on display 0
V/WindowManager(  802): addAppToken: AppWindowToken{2ff62ab token=Token{225f8cfa ActivityRecord{f3dc325 u0 com.example.user.advertiser/.PeripheralActivity t89}}} to stack=1 task=89 at 0
V/WindowManager(  802): Adding window Window{2d18b520 u0 Starting com.example.user.advertiser} at 3 of 9 (after Window{14f690b7 u0 com.google.android.googlequicksearchbox/com.google.android.launcher.GEL})
D/BluetoothManagerService(  802): checkIfCallerIsForegroundUser: valid=true callingUser=0 parentUser=-10000 foregroundUser=0
D/BluetoothManagerService(  802): checkIfCallerIsForegroundUser: valid=true callingUser=0 parentUser=-10000 foregroundUser=0
D/BluetoothLeAdvertiser( 4018): onClientRegistered() - status=0 clientIf=5
V/WindowManager(  802): Adding window Window{16d3a650 u0 com.example.user.advertiser/com.example.user.advertiser.PeripheralActivity} at 3 of 10 (before Window{2d18b520 u0 Starting com.example.user.advertiser})
I/ActivityManager(  802): Displayed com.example.user.advertiser/.PeripheralActivity: +129ms
E/bt-att  ( 3236): MTU request PDU with MTU size 517
W/bt-att  ( 3236): Call back not found for application conn_id=3
W/bt-att  ( 3236): Call back not found for application conn_id=4
W/bt-att  ( 3236): Call back not found for application conn_id=5
W/bt-btif ( 3236): info:x0
E/BluetoothRemoteDevices( 3236): aclStateChangeCallback: Device is NULL
W/bt-btif ( 3236): bta_gattc_conn_cback() - cif=3 connected=0 conn_id=3 reason=0x0016
W/bt-btif ( 3236): bta_gattc_conn_cback() - cif=4 connected=0 conn_id=4 reason=0x0016
W/bt-btif ( 3236): bta_gattc_conn_cback() - cif=5 connected=0 conn_id=5 reason=0x0016
E/bt-btm  ( 3236): btm_sec_disconnected - Clearing Pending flag
E/BluetoothRemoteDevices( 3236): aclStateChangeCallback: Device is NULL
W/PackageManager( 1045): Failure retrieving resources for com.example.user.advertiser: Resource ID #0x0

应用代码

public class PeripheralActivity extends Activity {
    private static final String TAG = "PeripheralActivity";

    private BluetoothManager mBluetoothManager;
    private BluetoothAdapter mBluetoothAdapter;
    private BluetoothLeAdvertiser mBluetoothLeAdvertiser;

    private ArrayList<BluetoothDevice> mConnectedDevices;
    private ArrayAdapter<BluetoothDevice> mConnectedDevicesAdapter;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ListView list = new ListView(this);
        setContentView(list);

    mConnectedDevices = new ArrayList<BluetoothDevice>();
    mConnectedDevicesAdapter = new ArrayAdapter<BluetoothDevice>(this,
            android.R.layout.simple_list_item_1, mConnectedDevices);
    list.setAdapter(mConnectedDevicesAdapter);

    /*
     * Bluetooth in Android 4.3+ is accessed via the BluetoothManager, rather than
     * the old static BluetoothAdapter.getInstance()
     */
    mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
    mBluetoothAdapter = mBluetoothManager.getAdapter();
    }

    @Override
    protected void onResume() {
    super.onResume();

    // extraneous code; check if bluetooth is on, advertising is supported etc.

    registerReceiver(intentReceiver, makeGattUpdateIntentFilter());
    mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
    startAdvertising();
    }

    @Override
    protected void onPause() {
    super.onPause();
    stopAdvertising();
    if (intentReceiver != null)
    {
        unregisterReceiver(intentReceiver);
    }
    }

     /*
     * Callback handles all incoming requests from GATT clients.
     * From connections to read/write requests.
     */
    private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        super.onConnectionStateChange(gatt, status, newState);
        Log.i(TAG, "onConnectionStateChange "
                +DeviceProfile.getStatusDescription(status)+" "
                +DeviceProfile.getStateDescription(newState));

        if (newState == BluetoothProfile.STATE_CONNECTED) {
            Log.i(TAG, "connected");

        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
            Log.i(TAG, "disconnected");

        } else if (newState == BluetoothProfile.STATE_CONNECTING) {
            Log.i(TAG, "attempting to connect");

        }
    }      

    private BroadcastReceiver intentReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent receivedIntent) {
        Log.v(TAG, "Entered intent receiver");
        if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(receivedIntent.getAction()))
        {
            Log.v(TAG, "Received Pairing request");
        }
        if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(receivedIntent.getAction()))
        {
            Log.v(TAG, "connected");
        }
        if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(receivedIntent.getAction()))
        {
            Log.v(TAG, "disconnected");
        }
        if (BluetoothDevice.ACTION_FOUND.equals(receivedIntent.getAction()))
        {
            Log.v(TAG, "action found");
            BluetoothDevice foundDevice = receivedIntent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            Log.v(TAG, foundDevice.getName()+" "+foundDevice.getAddress()+" was found");
            BluetoothDevice foundDeviceClass = receivedIntent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
            Log.v(TAG, "BT class: "+foundDeviceClass.toString());
        }
        if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(receivedIntent.getAction()))
        {
            Log.v(TAG, "bond state changed");
        }
    }
    };

    /*
     * Initialize the advertiser
     */
     private void startAdvertising() {
    if (mBluetoothLeAdvertiser == null) return;

    AdvertiseSettings settings = new AdvertiseSettings.Builder()
            .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
            .setConnectable(true)
            .setTimeout(0)
            .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
            .build();

    AdvertiseData data = new AdvertiseData.Builder()
            .setIncludeDeviceName(true)
            .addServiceUuid(new ParcelUuid(DeviceProfile.SERVICE_UUID))
            .build();

    mBluetoothLeAdvertiser.startAdvertising(settings, data, mAdvertiseCallback);
    }

    /*
     * Terminate the advertiser
     */
     private void stopAdvertising() {
     if (mBluetoothLeAdvertiser == null) return;

     mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
    }

    /*
     * Callback handles events from the framework describing
     * if we were successful in starting the advertisement requests.
     */
    private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {
    @Override
    public void onStartSuccess(AdvertiseSettings settingsInEffect) {
        Log.i(TAG, "Peripheral Advertise Started.");        
    }

    @Override
    public void onStartFailure(int errorCode) {
        Log.w(TAG, "Peripheral Advertise Failed: ");
    }
    };      


    private static IntentFilter makeGattUpdateIntentFilter() {

    final IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
    intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
    intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
    intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
    intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);

    return intentFilter;
    }
    }