Intention to receive BLE connection event notification on Android peripherals

I am developing a peripheral mode BLE application that runs on Android. There are several excellent functional examples that describe how to develop peripheral applications here and.

There is one slight difference between the sample applications and the system that I have to develop. In sample applications, the GATT server runs on a peripheral device. The peripheral device advertises, performs a central scan and locates the device and sends a request to the GATT server.

On my system, the GATT server will be in central mode. The peripheral device will receive a connection request, you need to find the address of the requesting device and initiate a connection to the GATT server on the central mode device.

Nomenclature and detailed operation

MyApp (BLE Peripheral, Advertiser, GATT Client)

TgtDev (central BLE center, scanner, GATT server)

  • TgtDev constantly scans and searches for ads with a specific UUID.
  • MyApp is launched and begins to advertise its presence.
  • TgtDev detects MyApp and sends a connection request.
  • Upon receipt of a connection request, MyApp will ask the user to accept or decline the connection request. At this point, he will need to read the address of the device requesting the connection.
  • If the user accepts, MyApp will request a connection to the GATT server on TgtDev.
  • , MyApp .

. MyApp . , registerReceiver(). , , BroadcastReceiver , .

GattCallback() , . , .

, ?

EDIT: 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;
    }
    }
+4

All Articles