Why am I losing bluetooth client/server connection? - java

I am trying to connect from a desktop application (written in Java) to a Android application through Bluetooth.
For the desktop application I am using BlueCove API.
When I start the server (desktop application) and I start the Android application, the connection works fine. (i.e. The client sends a "Hello World" and the server prints it in the console). But when I leave the application (by pressing Back or Home button) and return back to it, the socket connection seems to be lost.
How can you check if a Bluetooth socket is already connected?
I would like to check the connection of the socket to not having connecting again.
What should I write (if it is the case) in the onPause, onResume methods?
I suppose that in the onDestroy method I should close the socket.
Here is the source code of the client server:
Server
Client
I also tried using IntentFilter to check for the state of the connection, but it didn't work.
#Override
public void onCreate(Bundle savedInstanceState) {
// .....
IntentFilter filter1 = new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED);
IntentFilter filter2 = new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
IntentFilter filter3 = new IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED);
this.registerReceiver(mReceiver, filter1);
this.registerReceiver(mReceiver, filter2);
this.registerReceiver(mReceiver, filter3);
}
//The BroadcastReceiver that listens for bluetooth broadcasts
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
//Device found
Toast.makeText(BluetoothClient.this, "Device not found", 2).show();
}
else if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
//Device is now connected
Toast.makeText(BluetoothClient.this, "Device connected", 2).show();
}
else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
//Done searching
Toast.makeText(BluetoothClient.this, "Done searching", 2).show();
}
else if (BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED.equals(action)) {
//Device is about to disconnect
Toast.makeText(BluetoothClient.this, "Device about to connect", 2).show();
}
else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
//Device has disconnected
Toast.makeText(BluetoothClient.this, "Device disconnected", 2).show();
}
}
};

Server
Client
I have modified the 2 source code files.
Now it should work fine. There are some small bugs regarding if the BT is not opened before entering the mobile app (it get stuck too much in a while) and for those who want to use this client/server you should take a look at onPause(), onResume(), onDestroy() functions.
The problem was that I did not use the socket correctly.
I hope that it will be useful for those who want to implement such an application with BT.

Related

Network Service Discovery not woking when app returns from AirPlane mode to Wifi during the running app

I am having a problem related to Network Service Discovery.
When I start the app with wifi connected, NSD Works Totally fine discovering the service and smoothly resolving them.
But the problem arises when we connect wifi, after disabling wifi or switching the wifi from airplane mode.
It just gets stuck on DiscoveryStarted and never proceeds from there, although it establishes the connection to the wifi router after turning off airplane mode.
In code I have also ensured that the discovery will only start when the wifi connection is ensured but, no luck.
Right now I have to kill the app in order for NSD to work properly.
I am using NSD Helper from Google Gist:
https://android.googlesource.com/platform/development/+/master/samples/training/NsdChat/src/com/example/android/nsdchat/NsdHelper.java
NsdHelper helper;
BroadcastReceiver wifiReciever = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
if (intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false)) {
//do stuff
helper.stopDiscovery();
helper = new NsdHelper(context);
helper.discoverServices();
} else {
// wifi connection was lost
helper.stopDiscovery();
}
}
}
};
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
//startDiscovery();
// helper = new NsdHelper(this);
// helper.discoverServices();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
registerReceiver(wifiReciever, intentFilter);
Toast.makeText(this,"Service Started",Toast.LENGTH_SHORT).show();
}
#Override
public void onDestroy() {
// if(service!= null)
// {
// service.stop();
// helper.stopDiscovery();
// }
unregisterReceiver(wifiReciever);
//
Toast.makeText(this,"Service destroyed",Toast.LENGTH_SHORT).show();
super.onDestroy();
}

Simple guide to use bluetooth

I have an app that requires the use of Bluetooth to send data like 4-5 numbers and 2-3 texts between devices but i am new to java and the guide from google developers page is a little difficult for me to understand.
In order to make it easier for anyone whiling to help me i will write down in steps what i have done so far.
1. I have asked for permissions in manifest:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
2. I got the default adapter in my activity:
final BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
3. I created a button that when clicked the device scans for other devices:
bt_scan.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//first checks if bluettoth is enabled
if (!mBluetoothAdapter.isEnabled()) {
//if not it enables it
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
// Register for broadcasts when a device is discovered.
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);
}
});
4. When a device is found, get the device information:
// Create a BroadcastReceiver for ACTION_FOUND.
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Discovery has found a device. Get the BluetoothDevice
// object and its info from the Intent.
BluetoothDevice device =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String deviceName = device.getName();
String deviceHardwareAddress = device.getAddress(); // MAC address
}
}
};
5. On destroy unregister the ACTION_FOUND receiver:
#Override
protected void onDestroy() {
super.onDestroy();
// Don't forget to unregister the *ACTION_FOUND* receiver.
unregisterReceiver(mReceiver);
}
6. I have created a second button that when clicked it enables discoverability (which must be clicked first from device A in order for scan button in device B, finds the device A):
bt_enable.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent discoverableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra( BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300);
startActivity(discoverableIntent);
}
});
Questions :
A. In step 3 what REQUEST_ENABLE_BT is for?
B. Is this all i need to establish a connection without any problems between two devices?
C. If i want to connect more than two devices, is there anything else i must add?
Q. What is REQUEST_ENABLE_BT for?
Let me try to comment the code
// If bluetooth is not switched on
if ( ! mBluetoothAdapter.isEnabled() ) {
// Create a system request to enable bluetooth
Intent enableBtIntent = new Intent( BluetoothAdapter.ACTION_REQUEST_ENABLE );
// Queue the request to pops the bluetooth dialogue
startActivityForResult( enableBtIntent, REQUEST_ENABLE_BT );
}
// Standby for device found, Bluetooth may still be disabled at this point
IntentFilter filter = new IntentFilter( BluetoothDevice.ACTION_FOUND );
registerReceiver( mReceiver, filter );
// Now that we are done, bluetooth dialogue will popup
// When it's done Android calls our onActivityResult
// (because we queued it with startActivityForResult).
Q. Is this all I need to establish a connection?
I think there are two more more steps you need to do:
A. Find the device, between step 3 and 4.
Just enabling Bluetooth does not mean it'll automatically scan nearby devices, because scanning cost battery and degrades existing connections.
But with BLUETOOTH_ADMIN permission your app can start and stop the scan.
You can also get previously paired device without scan.
Start Scan: BluetoothAdapter.startDiscovery() This will call ACTION_FOUND for each device found, which fit your code.
List of paired devices: BluetoothAdapter.getBondedDevices() Previously paired Bluetooths can be found in this Set without scanning or BLUETOOTH_ADMIN, and can be connected directly. Whether the device is actually online is unknown until successful or failure, though.
B. Establish the data connection, between 4 and 5.
A device connection is like connecting a network cable.
The computers are physically connected with IP, but your programs still need to open sockets for actual data transfer.
Connection: BluetoothDevice.createRfcommSocketToServiceRecord(uuid) Creates a socket from which data can be go through InputStream and OutputStream.
Don't forget to stop the scan: BluetoothAdapter.cancelDiscovery()
You seems to want to make an M2M messaging app, so I've skipped Bluetooth Low Energy (BLE).
Q. If I want to connect more than two devices, is that all?
As far as "multiple connection" part is concerned, no, you don't need to do anything special to connect to multiple devices at the same time.
The "management" is arguably the hard part, though.
For example you'd normally want to keep a list of the devices, and have a UI that let user selectively disconnect a device, all of which must respond to unexpected disconnections or switching off bluetooth (by user, by another app, or by the system such as low-power mode).
Depends on what you actually want to do with the bluetooth devices, you may need code to remember each one's state too.
Again with error handling.
So, do expect the final code will be a bit more developed.
I would like to answer Question A
A. In step 3 what REQUEST_ENABLE_BT is for?
private static final int REQUEST_ENABLE_BT = 1;
REQUEST_ENABLE_BT is simply an integer value which identifies your request. When you receive the result Intent, the callback onActivityResult(int requestCode, int resultCode, Intent data) provides the same request code to you. In this way you can handle results from other activites
Suppose you have Activity A from where you have requested to enable bluetooth
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
When device's bluetooth gets enable, a method onActivityResult(int requestCode, int resultCode, Intent data) will get invoked on Activity A. This method onActivityResult() is a callback method. This method will pass back the request code to the calling activity (Activity A) as soon as bluetooth gets enable. You have to override this method in your Activity A to handle results.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if(requestCode == REQUEST_ENABLE_BT)
Log.d("BLUETOOTH", "Successfully enabled");
}

My app freezes after fullscreen application on front

I am struggling with persistent problem with Android app that has MQTT ServiceConnection running on background. When ever I switch to an other application that has fullscreen surface (game, youtube on fullscreen, etc) the application completely freezes when trying to bring it on front again. It even refuses to relaunch if closed from drawer. The app won't reopen unless completely killed. The weird thing is that if I run the application via debugger it works perfectly. It makes the problem difficult to get handle on. I have put on prints on beginning of each life cycle method, even before call to super class method. None of them get printed when the app hangs, which hints that it hangs some where on the system level.
Now if I call stopService at onStop method, it works fine but defeats the purpose of having persistent service on the background. I have called unbindService also on onStop, but it does not help. With all the other application everything works fine, even you tube as long as it is not used in fullscreen.
The dependency to the MQTT library is
compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.0.2'
and this is my onStop() method
#Override
protected void onStop() {
FirebaseUserActions.getInstance().end(getIndexApiAction0());
if(mBoundToService) {
try {
unbindService(serviceConnection);
mBoundToService = false;
}
catch (Exception e)
{
e.printStackTrace();
}
}
super.onStop();
}
And the onStart() method would be this:
#Override
protected void onStart() {
Log.d(TAG, "onStart has been called");
super.onStart();
if(!mBoundToService) {
bindService(mqttIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
FirebaseUserActions.getInstance().start(getIndexApiAction());
}
But this never gets called. From the logs I can see that MQTT service is receiving messages and produces no errors. Messages continue to be received even as the application is hanged so the background service is alive and running.
The inlined Service connection class is like this:
private ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder binder)
{
mqttService = ((MQTTService.MyBinder) binder).getService();
mBoundToService = true;
Log.d(TAG,"MQTT service has been bound");
Handler handler = getHandler();
//NOTIFY THE LOGIN ACTIVITY THAT THE DATA HAS BEEN ACQUIRED
Message msg = handler.obtainMessage(Utils.HANDLE_MQTT_SERVICE_CONNECTED);
Bundle bundle = new Bundle();
bundle.putString(Utils.KEY_MQTT_SERVICE_BOUND,"Everything is complete");
msg.setData(bundle);
handler.sendMessage(msg);
}
#Override
public void onServiceDisconnected(ComponentName name) {
mBoundToService = false;
Log.d(TAG, "MQTT service has been UNbound");
}
};
The MQTT service is started like this from onCreate():
mqttIntent = new Intent(getApplicationContext(), MQTTService.class);
if(!mBoundToService){
Log.d(TAG,"Starting MQTT Intent");
startService(mqttIntent);
Log.d(TAG,"Binding MQTT Service");
bindService(mqttIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
Am I missing something that I should be doing at the onStop() to be able to resume the application after having fullscreen application on front?

Internet listener Android example [duplicate]

This question already has answers here:
Check INTENT internet connection
(13 answers)
Closed 3 months ago.
I am working on an Android app that will continuously remain connected to Internet. If Internet is dow, it should give an appropriate message to the User.
Is there any thing like Internet Listener? Or how to implement this event that whenever Internet connection is not available it should give alert.
The code from Chirag Raval above certainly works. The trouble is that the listener will get invoked even when the application is not running in foreground.
IMHO, the better approach is to register / unregister the receiver in the onResume() / onPause() methods of all your application activities. This code should do it:
private final NetworkStateReceiver stateReceiver = new NetworkStateReceiver();
#Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
registerReceiver(stateReceiver, filter);
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(stateReceiver);
}
Obviously, remove the registration from AndroidManifest.xml file.
Using this solution, the receiver will be called also when switching between activities of your application (assuming you are closing them). In such a case, use a static flag (being shared between all your activities) like in the example below (called online):
public class NetworkStateReceiver extends BroadcastReceiver {
private static boolean online = true; // we expect the app being online when starting
public static final String TAG = NetworkStateReceiver.class.getSimpleName();
public void onReceive(Context context, Intent intent) {
Log.d(TAG,"Network connectivity change");
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = manager.getActiveNetworkInfo();
if (ni == null || ni.getState() != NetworkInfo.State.CONNECTED) {
Log.d(TAG,"There's no network connectivity");
if (online) // don't show the message if already offline
Toast.makeText(context, R.string.noInternet, Toast.LENGTH_SHORT).show();
online = false;
} else {
Log.d(TAG,"Network "+ni.getTypeName()+" connected");
if (!online) // don't show the message if already online
Toast.makeText(context, R.string.backOnline, Toast.LENGTH_SHORT).show();
online = true;
}
}
}
If starting your app when being offline, the Toast message will appear; otherwise it appears only when losing / re-establishing the connection .

android bluetooth discovery: ACTION_FOUND happening after ACTION_DISCOVERY_FINISHED

I am implementing Bluetooth support via implementing a task which searches for devices in the background and provides a list when the search is complete. However, this list occasionally contains a No devices found entry (added only when ACTION_DISCOVERY_FINISHED is received with no devices already in the list) before listing other devices!
private BroadcastReceiver mBlueToothInfoDiscoveryListener = new BroadcastReceiver() {
/**
* This is an overridden function called by the framework whenever there
* is some broadcast message for Bluetooth info discovery listener
*/
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// If it's already paired, skip it, because it's been listed
// already
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
mNewBtDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
// When discovery is finished, change the Activity title
setProgressBarIndeterminateVisibility(false);
setTitle("device list");
if (mNewBtDevicesArrayAdapter.getCount() == 0) {
String noDevices = "No devices found";
mNewBtDevicesArrayAdapter.add(noDevices);
}
}
}
};
I don't expect ACTION_DISCOVERY_FINISHED to ever come before a ACTION_FOUND event, so why would the No devices found string be added to the list before a device is located?
Simply because the discovery task has a timeout to prevent endless searched. So, in case there is no available device around, you'll get your "No Devices found"...

Categories

Resources