restart BTLE after backgrounding
Internal/NewNode has a startNearby() method that calls Bluetooth.bluetoothOn() -> Bluetooth.startServer() -> Bluetooth.tryStartServer() -> BluetoothManager.openGattServer().
https://github.com/clostra/newnode/blob/44f48fe824592987d2025a019b2c1e3dcd4a5693/android/src/main/java/com/clostra/newnode/internal/Bluetooth.java#L265
The startNearby() method is called in onActivityResumed() which causes a new BluetoothGattServer to be created each time a new activity is opened.
https://github.com/clostra/newnode/blob/44f48fe824592987d2025a019b2c1e3dcd4a5693/android/src/main/java/com/clostra/newnode/internal/NewNode.java#L623
It works fine a few times (usually 1 or 3 times), and then openGattServer() starts returning null, which results in the exception described above. Before returning null, the openGattServer() method runs for a long time and does it on the main thread, which causes the interface to freeze.
Bluetooth com.newnode.messenger E startServer
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.bluetooth.BluetoothGattServer.addService(android.bluetooth.BluetoothGattService)' on a null object reference
at com.clostra.newnode.internal.Bluetooth.tryStartServer(Bluetooth.java:280)
at com.clostra.newnode.internal.Bluetooth.startServer(Bluetooth.java:288)
at com.clostra.newnode.internal.Bluetooth.bluetoothOn(Bluetooth.java:142)
at com.clostra.newnode.internal.NewNode.startNearby(NewNode.java:590)
at com.clostra.newnode.internal.NewNode.onActivityResumed(NewNode.java:622)
at android.app.Application.dispatchActivityResumed(Application.java:450)
at android.app.Activity.dispatchActivityResumed(Activity.java:1482)
at android.app.Activity.onResume(Activity.java:2043)
at androidx.fragment.app.FragmentActivity.onResume(FragmentActivity.java:455)
at com.clostra.nnm.BaseActivity.onResume(BaseActivity.java:46)
at com.clostra.nnm.PassphraseRequiredActivity.onResume(PassphraseRequiredActivity.java:78)
at com.clostra.nnm.conversation.ConversationActivity.onResume(ConversationActivity.java:508)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1531)
at android.app.Activity.performResume(Activity.java:8734)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:5351)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:5444)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:54)
at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2574)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8757)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
@ghazel, It looks like GattServer should be run from the main thread. Therefore, the only thing that can be done is to check before starting that server is not running. Something like this:
if (gattServer != null) {
return;
}
// run openGattServer
More research is needed here. L2cap channels are also exhausted by recreating advertise/scan objects every time. In particular listenUsingInsecureL2capChannel().
The question is what, if anything, needs to be restarted or recreated after the app has been backgrounded for long enough that BTLE advertise/scan has stopped.