Longterm Android BLE Connections

Article

TJ Dahunsi

Sep 08 2014 · 3 mins

Categories:
technology

Before going through this, you should have gone over this post. Assuming you've done that the following terms should be familiar to you:

  1. A started Android service

  2. A bound Android service

To review, a bound service is one that returns an "ibinder" for an Android component to attach to. This component can be an Activity, a Fragment, or even another service. The BluetoothLeService used in the demo provided on the developer's website is this sort of service, therefore, the connection is only active as long as there is a component bound to it, in this case, it's the "DeviceControlActivity" class. Now, once yo press home on your Android device or turn off the screen, the onStop method is called on the DeviceControlActivity class, indicating that the activity may be destroyed at the Android system's discretion. Once this activity is destroyed, the BluetoothLeService becomes unbound, which in turn can be destroyed anytime at the system's discretion. The system's "discretion" is discussed in greater detail here.

Therefore, the key to keeping the BLE service running in the background, is to start a service that is independent of whether or not system components are bound to it, and subsequently bind activities or other services to it if you please. This is done by calling startService(intent) where the intent points to the class of the service you're trying to call. Mine is aptly called "ServiceBinder".

In my DeviceControl activity, I have a switch that enables and disables notifications. When notifications are enabled, I want to automatically start the service that will bind to the BluetoothLeService and keep it running. The code for that though is for another post. Below is the code for my enable notifications switch. Note that I also set the service to the foreground and create a pending intent for another activity called "LongTerm" to latch on to so I can see real time data whenever I want.

public void enableNotifications(View view) { Switch enableNotifications = (Switch) findViewById(R.id.enable\_notifications); enableNotifications.setVisibility(View.VISIBLE); // Turn off notifications. if(enableNotifications.isChecked() == false) { Intent intent = new Intent(this, ServiceBinder.class); stopService(intent); RelativeLayoutbuttons = (RelativeLayout) findViewById(R.id.buttons); buttons.setVisibility(View.VISIBLE); mBluetoothLeService.removeCharacteristicNotification(mNotifyCharacteristic, false); mBluetoothLeService.stopForeground(true); } // Turn on notifications. else { Intent intent = new Intent(this, ServiceBinder.class); intent.putExtra(EXTRA_DEVICE_ADDRESS_BINDER, mDeviceAddress); intent.putExtra(EXTRA_DEVICE_NAME_BINDER, mDeviceName); startService(intent); Notification notification = new Notification(R.drawable.mime\_notification\_icon, getText(R.string.sampling\_data),System.currentTimeMillis()); Intent notificationIntent = new Intent(this, LongTerm.class); notificationIntent.putExtra(EXTRA_DEVICE_ADDRESS_BINDER, mDeviceAddress); notificationIntent.putExtra(EXTRA_DEVICE_NAME_BINDER, mDeviceName); PendingIntentpendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG\_CANCEL\_CURRENT); notification.setLatestEventInfo(this,"Mime is sampling data","Service connected", pendingIntent); mBluetoothLeService.startForeground(ONGOING\_NOTIFICATION\_ID, notification); com.androidplot.xy.XYPlot data = (com.androidplot.xy.XYPlot) findViewById(R.id.bioimpedancePlot); data.setVisibility(View.VISIBLE); RelativeLayoutbuttons = (RelativeLayout) findViewById(R.id.buttons); buttons.setVisibility(View.VISIBLE); mBluetoothLeService.setCharacteristicNotification(mNotifyCharacteristic, true); } }

If you use this code exactly, your IDE will most likely tell you the method used for the Notifications is deprecated. This is deliberate. Android 4.4.3 - 4.4.4 on the Nexus 5 and the Moto X (my device), the Notification builder has a bug that ruins the pendingIntent when the notification is clicked, it doesn't work. Reverting to the deprecated method fixes the issue for me, so till that bug is fixed, I'm sticking with the deprecated method. Details on the bug can be found here. Also, com.androidplot.xy.XYPlot is not a native Android library, so "CMD + O" on a Mac (CTRL + O on Windows) won't import it. You can find the library and documentation on how to use it here.

,