I’ve just started learning android programming and I’m trying to design it such that when device B(without app) disconnects from device A(with the app), device B can reconnect to device A again. What I’ve tried is to run startBTConnection after the disconnection is detected, but the BluetoothDevice and socket always becomes null after the disconnect happens.
Connect.java
public class Connect extends AppCompatActivity {
private static final String TAG = "Connect";
public ArrayList<BluetoothDevice> myBTDevicesArrayList = new ArrayList<>();
public ArrayList<BluetoothDevice> myBTPairedDevicesArrayList = new ArrayList<>();
public DeviceListAdapter myDeviceListAdapter;
public DeviceListAdapter myPairedDeviceListAdapter;
BluetoothConnectionService myBluetoothConnection;
//Bounded Device
static BluetoothDevice myBTDevice;
BluetoothDevice myBTConnectionDevice;
BluetoothAdapter myBluetoothAdapter;
ListView lvNewDevices;
static ListView lvPairedDevices;
ImageButton btnSend;
EditText sendMessage;
Button btnSearch;
StringBuilder incomingMsg;
TextView incomingMsgTextView;
Button bluetoothConnect;
TextView deviceSearchStatus;
ProgressDialog myProgressDialog, connectionDialog;
TextView pairedDeviceText;
Intent connectIntent;
//UUID
public static final UUID myUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
public static BluetoothDevice getBluetoothDevice() {
return myBTDevice;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_connect);
bluetoothConnect = findViewById(R.id.connectBtn);
btnSearch = findViewById(R.id.searchBtn);
lvNewDevices = findViewById(R.id.listNewDevice);
lvPairedDevices = findViewById(R.id.pairedDeviceList);
btnSend = findViewById(R.id.btSend);
sendMessage = findViewById(R.id.messageText);
incomingMsgTextView = findViewById(R.id.incomingText);
deviceSearchStatus = findViewById(R.id.deviceSearchStatus);
pairedDeviceText = findViewById(R.id.pairedDeviceText);
incomingMsg = new StringBuilder();
myBTDevice = null;
//REGISTER BROADCAST RECEIVER FOR IMCOMING MSG
LocalBroadcastManager.getInstance(this).registerReceiver(btConnectionReceiver, new IntentFilter("btConnectionStatus"));
//REGISTER BROADCAST RECEIVER FOR IMCOMING MSG
LocalBroadcastManager.getInstance(this).registerReceiver(myReceiver, new IntentFilter("IncomingMsg"));
//REGISTER BROADCAST WHEN BOND STATE CHANGES (E.G PAIRING)
IntentFilter bondFilter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver(bondingBroadcastReceiver, bondFilter);
IntentFilter intentFilter = new IntentFilter(myBluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
registerReceiver(discoverabilityBroadcastReceiver, intentFilter);
IntentFilter BTIntent = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(enableBTBroadcastReceiver, BTIntent);
IntentFilter discoverDevicesIntent = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(discoveryBroadcastReceiver, discoverDevicesIntent);
IntentFilter discoverStartedIntent = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
registerReceiver(discoveryStartedBroadcastReceiver, discoverStartedIntent);
IntentFilter discoverEndedIntent = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(discoveryEndedBroadcastReceiver, discoverEndedIntent);
myBTDevicesArrayList = new ArrayList<>();
myBTPairedDevicesArrayList = new ArrayList<>();
myBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//ONCLICKLISTENER FOR SEARCH BUTTON
btnSearch.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Log.d(TAG, "onClick: search button");
enableBT();
myBTDevicesArrayList.clear();
}
});
//ONCLICKLISTENER FOR CONNECT BUTTON
bluetoothConnect.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if (myBTDevice == null) {
if (ActivityCompat.checkSelfPermission(Connect.this, Manifest.permission.BLUETOOTH_ADMIN) != PackageManager.PERMISSION_GRANTED) {
}
Toast.makeText(Connect.this, "No Paired Device! Please Search/Select a Device.",
Toast.LENGTH_LONG).show();
} else if (myBluetoothAdapter.getProfileConnectionState(BluetoothHeadset.HEADSET) == BluetoothAdapter.STATE_CONNECTED) {
Toast.makeText(Connect.this, "Bluetooth Already Connected",
Toast.LENGTH_LONG).show();
} else {
Log.d(TAG, "onClick: connect button");
//START CONNECTION WITH THE BOUNDED DEVICE
Intent intent1 = new Intent();
intent1.setAction("com.example.mdpandroidcontroller.btConnectionStatus");
intent1.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
sendBroadcast(intent1);
startBTConnection(myBTDevice, myUUID);
}
lvPairedDevices.setAdapter(myPairedDeviceListAdapter);
}
});
@Override
protected void onDestroy() {
Log.d(TAG, "ConnectActivity: onDestroyed: destroyed");
super.onDestroy();
unregisterReceiver(discoverabilityBroadcastReceiver);
unregisterReceiver(discoveryBroadcastReceiver);
unregisterReceiver(bondingBroadcastReceiver);
unregisterReceiver(discoveryStartedBroadcastReceiver);
unregisterReceiver(discoveryEndedBroadcastReceiver);
unregisterReceiver(enableBTBroadcastReceiver);
LocalBroadcastManager.getInstance(this).unregisterReceiver(btConnectionReceiver);
}
//BROADCAST RECEIVER FOR BLUETOOTH CONNECTION STATUS
BroadcastReceiver btConnectionReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Receiving btConnectionStatus Msg!!!");
String connectionStatus = intent.getStringExtra("ConnectionStatus");
myBTConnectionDevice = intent.getParcelableExtra("Device");
//DISCONNECTED FROM BLUETOOTH CHAT
if (connectionStatus.equals("disconnect")) {
Log.d("ConnectAcitvity:", "Device Disconnected");
//CHECK FOR NOT NULL
if (connectIntent != null) {
stopService(connectIntent);
}
//RECONNECT DIALOG MSG
AlertDialog alertDialog = new AlertDialog.Builder(Connect.this).create();
alertDialog.setTitle("BLUETOOTH DISCONNECTED");
alertDialog.setMessage("Connection with device has ended. Do you want to reconnect?");
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, "Yes",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
startBTConnection(myBTConnectionDevice, myUUID);
}
});
alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "No",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialog.show();
}
//SUCCESSFULLY CONNECTED TO BLUETOOTH DEVICE
else if (connectionStatus.equals("connect")) {
Log.d("ConnectAcitvity:", "Device Connected");
if(myBTConnectionDevice != null){
Toast.makeText(Connect.this, "Connection Established: " + myBTConnectionDevice.getName(),
Toast.LENGTH_LONG).show();
}
}
//BLUETOOTH CONNECTION FAILED
else if (connectionStatus.equals("connectionFail")) {
Toast.makeText(Connect.this, "Connection Failed: " + myBTConnectionDevice.getName(),
Toast.LENGTH_LONG).show();
}
}
};
/*
Create a BroadcastReceiver for ACTION_FOUND (Enable Discoverability).
*/
private final BroadcastReceiver discoverabilityBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED)) {
int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.ERROR);
switch (mode) {
case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
Log.d(TAG, "OnReceiver: DISCOVERABILITY ENABLED");
startSearch();
//START BLUETOOTH CONNECTION SERVICE WHICH WILL START THE ACCEPTTHREAD TO LISTEN FOR CONNECTION
connectIntent = new Intent(Connect.this, BluetoothConnectionService.class);
connectIntent.putExtra("serviceType", "listen");
startService(connectIntent);
Constants.setConnected(true);
checkPairedDevice();
myBluetoothConnection = new BluetoothConnectionService();
break;
//DEVICE IS NOT IN DISCOVERABLE MODE
case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
Log.d(TAG, "OnReceiver: DISCOVERABILITY DISABLED, ABLE TO RECEIVE CONNECTION");
break;
//BLUETOOTH TURNING ON STATE
case BluetoothAdapter.SCAN_MODE_NONE:
Log.d(TAG, "OnReceiver: DISCOVERABILITY DISABLED, NOT ABLE TO RECEIVE CONNECTION");
break;
//BLUETOOTH TURNED ON STATE
case BluetoothAdapter.STATE_CONNECTING:
Log.d(TAG, "OnReceiver: CONNECTING");
break;
//BLUETOOTH TURNED ON STATE
case BluetoothAdapter.STATE_CONNECTED:
Log.d(TAG, "OnReceiver: CONNECTED");
break;
}
}
}
};
/*
Create a BroadcastReceiver for ACTION_FOUND (Get Discovered Devices Info).
*/
private final BroadcastReceiver discoveryBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
Log.d(TAG, "SEARCH ME!");
if (action.equals(BluetoothDevice.ACTION_FOUND)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
myBTDevicesArrayList.add(device);
if (ActivityCompat.checkSelfPermission(Connect.this, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
}
Log.d(TAG, "OnReceive: " + device.getName() + ": " + device.getAddress());
myDeviceListAdapter = new DeviceListAdapter(context, R.layout.device_adapter_view, myBTDevicesArrayList);
lvNewDevices.setAdapter(myDeviceListAdapter);
}
}
};
/*
Create a BroadcastReceiver for ACTION_DISCOVERY_STARTED (Start Discovering Devices).
*/
private final BroadcastReceiver discoveryStartedBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED)) {
Log.d(TAG, "STARTED DISCOVERY!!!");
}
}
};
/*
Create a BroadcastReceiver for ACTION_DISCOVERY_FINISHED (End Discovering Devices).
*/
private final BroadcastReceiver discoveryEndedBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
Log.d(TAG, "ENDED DISCOVERY!!!");
}
}
};
/*
Create a BroadcastReceiver for ACTION_FOUND (Pairing Devices).
*/
private final BroadcastReceiver bondingBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
//BONDING DEVICE
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//BluetoothConnectionService.setMyDevice(device);
//BOUNDED ALREADY
if (ActivityCompat.checkSelfPermission(Connect.this, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
}
if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
Log.d(TAG, "BoundReceiver: Bond Bonded with: " + device.getName());
//BluetoothConnectionService.setMyDevice(device);
myProgressDialog.dismiss();
Toast.makeText(Connect.this, "Bound Successfully With: " + device.getName(),
Toast.LENGTH_LONG).show();
myBTDevice = device;
checkPairedDevice();
lvNewDevices.setAdapter(myDeviceListAdapter);
Constants.setConnected(true);
}
//BONDING WITH ANOTHER DEVICES
if (device.getBondState() == BluetoothDevice.BOND_BONDING) {
Log.d(TAG, "BoundReceiver: Bonding With Another Device");
myProgressDialog = ProgressDialog.show(Connect.this, "Bonding With Device", "Please Wait...", true);
Constants.setConnected(true);
}
//BREAKING A BOND
if (device.getBondState() == BluetoothDevice.BOND_NONE) {
Log.d(TAG, "BoundReceiver: Breaking Bond");
if (myProgressDialog != null && myProgressDialog.isShowing()) {
myProgressDialog.dismiss();
}
//DIALOG MSG POPUP
AlertDialog alertDialog = new AlertDialog.Builder(Connect.this).create();
alertDialog.setTitle("Bonding Status");
alertDialog.setMessage("Bond Disconnected!");
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialog.show();
Constants.setConnected(false);
myBTDevice = null;
}
}
}
};
/*
TURN DISCOVERABILITY ON
*/
private void discoverabilityON() {
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 900);
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_ADVERTISE) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
}
startActivity(discoverableIntent);
}
/* START DISCOVERING OTHER DEVICES */
private void startSearch() {
Log.d(TAG, "btnDiscover: Looking for unpaired devices.");
//DISCOVER OTHER DEVICES
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
}
if (myBluetoothAdapter.isDiscovering()) {
myBluetoothAdapter.cancelDiscovery();
Log.d(TAG, "BTDiscovery: canceling discovery");
//check BT permission in manifest
//checkBTPermission();
myBluetoothAdapter.startDiscovery();
Log.d(TAG, "BTDiscovery: enable discovery");
}
if (!myBluetoothAdapter.isDiscovering()) {
//check BT permission in manifest
//checkBTPermission();
myBluetoothAdapter.startDiscovery();
Log.d(TAG, "BTDiscovery: enable discovery");
}
}
/*
START BLUETOOTH CHAT SERVICE METHOD
*/
public void startBTConnection(BluetoothDevice device, UUID uuid) {
Log.d(TAG, "StartBTConnection: Initializing RFCOM Bluetooth Connection");
//myBluetoothConnection.startClient(device, uuid);
connectIntent = new Intent(Connect.this, BluetoothConnectionService.class);
connectIntent.putExtra("serviceType", "connect");
connectIntent.putExtra("device", device);
connectIntent.putExtra("id", uuid);
Log.d(TAG, "StartBTConnection: Starting Bluetooth Connection Service!");
startService(connectIntent);
Constants.setConnected(true);
}
public void checkPairedDevice() {
//CHECK IF THERE IS PAIRED DEVICES
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
}
Set<BluetoothDevice> pairedDevices = myBluetoothAdapter.getBondedDevices();
myBTPairedDevicesArrayList.clear();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
Log.d(TAG, "PAIRED DEVICES: " + device.getName() + "," + device.getAddress());
myBTPairedDevicesArrayList.add(device);
}
pairedDeviceText.setText("Paired Devices: ");
myPairedDeviceListAdapter = new DeviceListAdapter(this, R.layout.device_adapter_view, myBTPairedDevicesArrayList);
lvPairedDevices.setAdapter(myPairedDeviceListAdapter);
} else {
/*String[] noDevice = {"No Device"};
ListAdapter emptyListAdapter = new ArrayAdapter<String>(this, R.layout.device_adapter_view,R.id.deviceName, noDevice);
lvPairedDevices.setAdapter(emptyListAdapter);*/
pairedDeviceText.setText("No Paired Devices: ");
Log.d(TAG, "NO PAIRED DEVICE!!");
}
}
}
BluetoothConnectionService.java
public class BluetoothConnectionService extends IntentService {
private static final String TAG = "BTConnectionAService";
private static final String appName = "App";
//UUID
private static final UUID myUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private BluetoothAdapter myBluetoothAdapter;
private AcceptThread myAcceptThread;
private ConnectThread myConnectThread;
public BluetoothDevice myDevice;
private UUID deviceUUID;
private Handler mHandler;
Context myContext;
ProgressDialog myProgressDialog;
private static String BLUETOOTH_CONNECTION_TAG = "Bluetooth (Connection)";
private int mState;
public interface ConnectionConstants {
// Constants that indicate the current connection state
int STATE_DISCONNECTED = 0;
int STATE_CONNECTING = 1;
int STATE_CONNECTED = 2;
}
public BluetoothConnectionService() {
super("BluetoothConnectionService");
// mHandler = new Handler(Looper.getMainLooper());
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
myContext = getApplicationContext();
myBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (intent.getStringExtra("serviceType").equals("listen")) {
myDevice = (BluetoothDevice) intent.getExtras().getParcelable("device");
Log.d(TAG, "Service Handle: startAcceptThread");
startAcceptThread();
} else {
myDevice = (BluetoothDevice) intent.getExtras().getParcelable("device");
deviceUUID = (UUID) intent.getSerializableExtra("id");
Log.d(TAG, "Service Handle: startClientThread");
startClientThread(myDevice, deviceUUID);
}
}
private class ConnectThread extends Thread {
private BluetoothSocket mySocket;
public ConnectThread(BluetoothDevice device, UUID uuid) {
Log.d(TAG, "ConnectThread: started");
myDevice = device;
deviceUUID = uuid;
}
public void run() {
BluetoothSocket temp = null;
Intent connectionStatusIntent;
Log.d(TAG, "Run: myConnectThread");
/* Get a BluetoothSocket for a connection with given BluetoothDevice */
try {
Log.d(TAG, "ConnectThread: Trying to create InsecureRFcommSocket using UUID: " + myUUID);
if (ActivityCompat.checkSelfPermission(BluetoothConnectionService.this, android.Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
}
temp = myDevice.createRfcommSocketToServiceRecord(deviceUUID);
} catch (IOException e) {
Log.d(TAG, "ConnectThread: Could not create InsecureRFcommSocket " + e.getMessage());
}
mySocket = temp;
//Cancel discovery to prevent slow connection
myBluetoothAdapter.cancelDiscovery();
try {
Log.d(TAG, "Connecting to Device: " + myDevice);
//Blocking call and will only return on a successful connection / exception
mySocket.connect();
//BROADCAST CONNECTION MSG
connectionStatusIntent = new Intent("btConnectionStatus");
connectionStatusIntent.putExtra("ConnectionStatus", "connect");
connectionStatusIntent.putExtra("Device", myDevice);
LocalBroadcastManager.getInstance(myContext).sendBroadcast(connectionStatusIntent);
Log.d(TAG, "run: ConnectThread connected");
//START BLUETOOTH CHAT
BluetoothChat.connected(mySocket, myDevice, myContext);
//CANCEL ACCEPT THREAD FOR LISTENING
if (myAcceptThread != null) {
myAcceptThread.cancel();
myAcceptThread = null;
}
} catch (IOException e) {
//Close socket on error
try {
mySocket.close();
connectionStatusIntent = new Intent("btConnectionStatus");
connectionStatusIntent.putExtra("ConnectionStatus", "connectionFail");
connectionStatusIntent.putExtra("Device", myDevice);
LocalBroadcastManager.getInstance(myContext).sendBroadcast(connectionStatusIntent);
Log.d(TAG, "run: Socket Closed: Connection Failed!! " + e.getMessage());
} catch (IOException e1) {
Log.d(TAG, "myConnectThread, run: Unable to close socket connection: " + e1.getMessage());
}
}
try {
//Dismiss Progress Dialog when connection established
//myProgressDialog.dismiss();
//mHandler.post(new DisplayToast(getApplicationContext(),"Connection Established With: "+myDevice.getName()));
} catch (NullPointerException e) {
e.printStackTrace();
}
}
public void cancel() {
try {
Log.d(TAG, "Cancel: Closing Client Socket");
mySocket.close();
} catch (IOException e) {
Log.d(TAG, "Cancel: Closing mySocket in ConnectThread Failed " + e.getMessage());
}
}
}
public synchronized void startAcceptThread() {
Log.d(TAG, "start");
//Cancel any thread attempting to make a connection
if (myConnectThread != null) {
myConnectThread.cancel();
myConnectThread = null;
}
if (myAcceptThread == null) {
myAcceptThread = new AcceptThread();
myAcceptThread.start();
}
}
public void startClientThread(BluetoothDevice device, UUID uuid) {
Log.d(TAG, "startClient: Started");
myConnectThread = new ConnectThread(device, uuid);
myConnectThread.start();
}
}
error
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.bluetooth.BluetoothDevice.getName()' on a null object reference
at com.example.mdpandroidcontroller.Connect$6.onReceive(Connect.java:347)
at androidx.localbroadcastmanager.content.LocalBroadcastManager.executePendingBroadcasts(LocalBroadcastManager.java:313)
at androidx.localbroadcastmanager.content.LocalBroadcastManager$1.handleMessage(LocalBroadcastManager.java:121)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7918)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
Can you elaborate on how your code “doesn’t work”? What were you expecting, and what actually happened? If you got an exception/error, post the line it occurred on and the exception/error details which can be done with a minimal reproducible example. Please edit your question to add these details into it or we may not be able to help.
♦