Consistent graceful disconnect from Bluetooth server when receiving BluetoothAdapter.STATE_TURNING_OFF - android

I am having trouble disconnecting gracefully from a server when the user turns off the bluetooth. Android generates an event when that happens that you are supposed to use to send a final disconnection message to the server; before your app loses access to bluetooth functionality.
I register the event like this:
context.registerReceiver(this, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
Then I listen for the specific event:
public void onReceive(Context context, Intent intent) {
final int state =
intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
switch (state) {
case BluetoothAdapter.STATE_TURNING_OFF:
_bt.stop();
break;
//...
}
}
This works some times but not every time. I tried giving the thread a higher priority to see if it would help with (alternatively) both of these:
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
... but no luck. Any ideas on how to accomplish this consistently are welcome, thanks!

So, what ended up working for me is to use both priority statements and try to send the message as soon as the event is generated. This way, I consistently get a graceful disconnection from the server. This is how my code ended up looking:
public void onReceive(Context context, Intent intent) {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
final int state =
intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
switch (state) {
case BluetoothAdapter.STATE_TURNING_OFF:
// send disconnection message
_bt.stop();
break;
//...
}
}
Hope it helps someone else.

Related

Bluetooth enable time

I am using the below code as per requirement from client to internally enable Bluetooth and disable it when exit the application.
if (!bluetoothAdapter.isEnabled()) {
MMLogger.logInfo(MMLogger.LOG_BLUETOOTH, "BluetoothSyncController - Bluetooth was OFF, so Turn it ON");
bluetoothAdapter.enable();
try {
Thread.sleep(WAIT_FOR_SOMETIME_TO_START_BLUETOOTH);
} catch (InterruptedException ignore) {
}
MMLogger.logInfo(MMLogger.LOG_BLUETOOTH, "BluetoothSyncController - Bluetooth turned ON");
}
IS there any standard time for WAIT_FOR_SOMETIME_TO_START_BLUETOOTH ? I mean any documentation ?
You might try this answer. There seem to be some standard bluetooth events and handlers out there.
From that source: There are events that your activity can manage such as
STATE_OFF, STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF
and you can catch these with a BroadcastReciever. First you want to make sure that you grant permissions for bluetooth inside of your manifest with:
<uses-permission android:name="android.permission.BLUETOOTH" />
Then you can create a custom broadcast receiver that has the following onReceive():
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
switch(state) {
case BluetoothAdapter.STATE_OFF:
..
break;
case BluetoothAdapter.STATE_TURNING_OFF:
..
break;
case BluetoothAdapter.STATE_ON:
..
break;
case BluetoothAdapter.STATE_TURNING_ON:
..
break;
}
}
}
Then instead of making a thread to wait you can have a receive event trigger the code you want to run. For more info on using a BroadcastReciever, see the link I provided or go straight to the android documentation.

Android: App/broadcast receiver is getting killed sometimes when I receive an incoming call

I have written an interceptor to access a call data when there is an incoming call. I listen to state change action to decide whether it is a missed call or received call. I have written a code to do things whenever call ends.
public class PhoneStateBroadcastReceiver extends BroadcastReceiver {
public static final String TAG = "PHONE STATE";
private static String mLastState = TelephonyManager.CALL_STATE_IDLE;
#Override
public void onReceive(Context context, Intent intent) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (!state.equals(mLastState)) {
mLastState = state;
Log.e(TAG, state);
return;
}
//Code to do stuff based on last state and state
}
}
The code works fine. But I noticed my app failed to process some of the calls. As this issue was hard to reproduce, I monitored my app for a whole day based on my call activity. When I debugged the issue, I found out that mLastState wasn't changing in such cases. It was still IDLE in case when incoming call ends where it should have been RINGING or OFFHOOK. The reason for that was my app was getting killed and mLastState was being reinitialized. So I was losing the last state.
How to handle this situation? First solution came to my mind was to persist a mLastState to a sharedpreference. Is there any other way to handle this?

Detecting State changes made by Bluetooth adapter through a background service

I have been trying to develop a service that detects BLE devices in the background. The background service runs seemlesly when bluetooth is enabled. However when bluetooth is not running i turn on bluetooth via
bluetoothAdapter.enable();
In order to listen to changes made by the bluetooth adapter i declare a broadcastreceiver in my service in the onCreate() method like this:
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(receiver, filter);
My broadcast receiver looks like this:
private final BroadcastReceiver receiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
Log.v("Broadcast called", "in service");
if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED))
{
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
switch (state) {
case BluetoothAdapter.STATE_OFF:
Log.v("Bluetooth state", "Off");
break;
case BluetoothAdapter.STATE_TURNING_OFF:
Log.v("Bluetooth state", "Turning Off");
break;
case BluetoothAdapter.STATE_ON:
Log.v("Bluetooth state", "Turned On");
scanLeDevice(true) ;
break;
case BluetoothAdapter.STATE_TURNING_ON:
Log.v("Bluetooth state", "Turning On");
break;
}
}
}
};
the adapter.enable() call turns bluetooth on successfully however the problem i am facing here is that the onReceive method in the receiver never gets triggered as a result of which i cannot run and scan for BLE devices.
When i do these exact same steps in an activity everything works perfectly.
At first i thought that the onReceive is not triggered because the service is in a background thread. So i also triggered the service via a WakefullBroadcastReceiver but that made no change in behavior.
I would like to understand what i am doing wrong here and some help in solving this.

When to check internet connection in Mobile Applications

I would like to know recommended and best practices of checking internet connection in mobile applications.
In most of the apps I developed with my team mates, we check the internet connection before any action that requires internet connection. But I see many applications that notifies when device is disconnected from internet.
I would like to get a clear understanding about this topic and I believe so many developers like me hesitate about how to make this check properly when they are developing an application.
Any help or ideas will be appreciated.
You can use broadcast reciever to handle wifi changes.
Reciever code:
private BroadcastReceiver WifiStateChangedReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
int extraWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN);
switch (extraWifiState) {
case WifiManager.WIFI_STATE_DISABLED: {
handler.sendEmptyMessage(DATA_DISCONNECTED);
}
break;
case WifiManager.WIFI_STATE_DISABLING: {
}
break;
case WifiManager.WIFI_STATE_ENABLED: {
handler.sendEmptyMessage(DATA_CONNECTED);
}
break;
case WifiManager.WIFI_STATE_ENABLING: {
}
break;
case WifiManager.WIFI_STATE_UNKNOWN: {
}
break;
}
}
};
Registering reciever:
this.registerReceiver(this.WifiStateChangedReceiver,
new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION));
To check mobile data connection changes You can use TelephonyManager:
PhoneStateListener pslCell = new PhoneStateListener() {
#Override
public void onDataConnectionStateChanged(int state) {
switch (state) {
case TelephonyManager.DATA_DISCONNECTED: {
handler.sendEmptyMessage(DATA_DISCONNECTED);
}
break;
case TelephonyManager.DATA_SUSPENDED: {
handler.sendEmptyMessage(DATA_CONNECTED);
}
break;
}
}
};
telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(pslCell, PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
I recommend You to store network status in static variables. Also You need to check network status every application start.
It is always related to the project We are doing.
If you are only doing the application which requires only internet connection at the time of any action then checking internet connection before perfoming the action is better it will remove the overhead of checking internet Connection every time
I prefer this method
But if we really requires full net connection every time if we need to load the latest news or chat applications we need to notify at every time.
For this we have to use the Appropriate Connection Api of every Mobile Platform
Android Provides Connection BroadCast Recivers For this
It totally depends upon your Applications requirements that what kind of your Application is.
Some times:
1) We have to check the internet connection before any action that requires it.
2) We periodically check the internet connection after some specific defined interval.
3) We need immediate response of internet connection's status, so our App continuously checking it out and immediately send us notification status of internet failure or success, so we are able to tackle our App in such scenario.
Hope it helps.

Intent.ACTION_HEADSET_PLUG is received when activity starts

I am trying to pause music that is playing when the headset is unplugged.
I have created a BroadcastReceiver that listens for ACTION_HEADSET_PLUG intents and acts upon them when the state extra is 0 (for unplugged). My problem is that an ACTION_HEADSET_PLUG intent is received by my BroadcastReceiver whenever the activity is started. This is not the behavior that I would expect. I would expect the Intent to be fired only when the headset is plugged in or unplugged.
Is there a reason that the ACTION_HEADSET_PLUG Intent is caught immediately after registering a receiver with that IntentFilter? Is there a clear way that I can work with this issue?
I would assume that since the default music player implements similar functionality when the headset is unplugged that it would be possible.
What am I missing?
This is the registration code
registerReceiver(new HeadsetConnectionReceiver(),
new IntentFilter(Intent.ACTION_HEADSET_PLUG));
This is the definition of HeadsetConnectionReceiver
public class HeadsetConnectionReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Log.w(TAG, "ACTION_HEADSET_PLUG Intent received");
}
}
Thanks for the reply Jake. I should have updated the original post to indicate that I discovered the issue that I was having. After a bit of research, I discovered that the ACTION_HEADSET_PLUG Intent is broadcast using the sendStickyBroadcast method in Context.
Sticky Intents are held by the system after being broadcast. That Intent will be caught whenever a new BroadcastReceiver is registered to receive it. It is triggered immediately after registration containing the last updated value. In the case of the headset, this is useful to be able to determine that the headset is already plugged in when you first register your receiver.
This is the code that I used to receive the ACTION_HEADSET_PLUG Intent:
private boolean headsetConnected = false;
public void onReceive(Context context, Intent intent) {
if (intent.hasExtra("state")){
if (headsetConnected && intent.getIntExtra("state", 0) == 0){
headsetConnected = false;
if (isPlaying()){
stopStreaming();
}
} else if (!headsetConnected && intent.getIntExtra("state", 0) == 1){
headsetConnected = true;
}
}
}
I use a different approach to stop playback when headset is unplug. I do not want you to use it since you are already fine, but some other people may find it useful. If you get control of audio focus, then Android will send you an event audio becoming noisy, so if you write a receiver for this event it will look like
public void onReceive(Context context, Intent intent) {
if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
if (isPlaying()){
stopStreaming();
}
}
}
I ran into the same issue. I'm not sure what causes it, but at least in my testing it seems to be consistent, which means you can work around it. I did just that by adding a boolean member variable that starts as true, and is set to false on the first onReceive(Context, Intent) call. This flag then controls whether I actually process the unplug event or not.
For your reference, here is the code I use to do just that, which is available in context here.
private boolean isFirst;
public void onReceive(Context context, Intent intent)
{
if(!isFirst)
{
// Do stuff...
}
else
{
Log.d("Hearing Saver", "First run receieved.");
isFirst = false;
}
}

Categories

Resources