I have a broadcast receiver that detects when a USB device is attached/detached. The app opens when the device is connected however when i disconnect/connect the device to my android multiple times, i get the following ANR error: Does anyone know what is causing this?
ANR error
Here is my Broadcast Receiver code:
String USB_TAG = "USB_TAG";
String BROADCAST_TAG = "BROADCAST_TAG";
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(BROADCAST_TAG, "BroadcastReceiver Event");
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
Log.d(BROADCAST_TAG, "BroadcastReceiver DEVICE ATTACHED");
Toast.makeText(context, "Device Detected", Toast.LENGTH_SHORT).show();
new Thread(() -> {
try {
if(MainActivity.eMRO_Backend != null) {
if (MainActivity.eMRO_Backend.threadsClosed) {
MainActivity.eMRO_Backend = new eMRO_Backend(context);
}
}
} catch (Exception e){
Log.d(BROADCAST_TAG, "BroadcastReceiver attach ex: " + e.getMessage());
}
}).start();
} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
Toast.makeText(context, "Device Not Detected", Toast.LENGTH_SHORT).show();
new Thread(() -> {
Looper.prepare();
try {
MainActivity.powerStatusQueue.put(false);
MainActivity.laserKeyStatusQueue.put(false);
if(MainActivity.eMRO_Backend != null)
MainActivity.eMRO_Backend.shutDownThreads();
} catch (Exception e) {
Log.d(BROADCAST_TAG, "BroadcastReceiver detach ex: " + e.getMessage());
}
}).start();
}
}
}
It looks like your broadcast receiver is not the problem. The problem is that you've got code running on your main (UI) thread that is blocking the main (UI) thread. When Android tries to call your broadcast receiver's onReceive(), the call is blocked by something else and that is what is causing the ANR. What you are seeing is a symptom and not the actual cause of the problem.
Related
I can’t catch up - how to send Toast from Executors.newSingleThreadExecutor () in the run () method? In the debug I set a breakpoint, everything is fine, we go into the method, but the message does not appear in the emulator? And yet, in the same method, I send the intent to the receiver, the intent is sent, but the receiver does not receive it.
ExecutorService service:
public void start() {
service = Executors.newSingleThreadExecutor();
service.submit(new Runnable() {
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Intent intent = new Intent(ACTION_FOR_FRAGMENT);
sendBroadcast(intent);
service.shutdown();
}
});
}
I solved this problem, you can close the question. The essence of the problem was that I did not correctly implement the service methods.
I'm using an USB-Receiver to handle the Communication with a Temperature Sensor attached via USB to the Phone.
Everything is working fine so far, but if i restart the Phone, the App throws an USB-Permission pop-up directly after restarting, even if there isn't any USB-Device attached to the Phone at that Moment.
Has anyone an Idea of what's causing this strange Problem?
[ EDIT: I'm Sorry, the App isn't asking for USB Permission, the popup asks if i want to Open the app if "this device is connected" but there's obviously no device attached.]
Here is the Code of the USB-Receiver:
//Initial USB Settings Receiver
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
#Override
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
// is usb permission has been granted, try to open a connection
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
if (device != null) {
// call method to set up device communication
Constants result = mcp2221.open();
if (result != Constants.SUCCESS) {
//nothing by now
} else {
openConnectionToMCP2221();
}
}
}
}
}
if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
// close the connection and release all resources
closeAllResources();
// leave a bit of time for the COM thread to close
try {
Thread.sleep(20);
}catch(InterruptedException e){e.printStackTrace();}
mcp2221Comm = null;
Toast.makeText(getApplicationContext(), "Device detached",
Toast.LENGTH_SHORT).show();
}
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null) {
Toast.makeText(getApplicationContext(), "Device attached",
Toast.LENGTH_SHORT).show();
mStopUSBThread=false;
// only try to connect if an MCP2221 is attached
if (device.getVendorId() == MCP2221_VID && device.getProductId() == MCP2221_PID) {
Constants result = mcp2221.open();
switch (result) {
case SUCCESS:
openConnectionToMCP2221();
break;
case CONNECTION_FAILED:
Toast.makeText(getApplicationContext(), "ERROR: connection failed", Toast.LENGTH_SHORT).show();
break;
case NO_USB_PERMISSION:
Toast.makeText(getApplicationContext(), "ERROR: no USB permission", Toast.LENGTH_SHORT).show();
mcp2221.requestUsbPermission(mPermissionIntent);
break;
default:
break;
}
}
}
}
}
};
And here is the onCreate() part:
//USB Connection
mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
final IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
registerReceiver(mUsbReceiver, filter);
//Checking if theres a Device already connected
.......
Got it!
It was an
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
</intent-filter>
that was declared in AndroidManifest.xml under <activity>.
I don't fully understand, why it caused this Bug, but removing it kept the functionality of my App while getting rid of the Problem.
Only 'negative' aspect might be, that now the App doesn't ask to open if the Sensor is attached to the phone.
My app should just check, via bluetooth, if there is certain Arduino server around, and toast proper message.
This is the code when user presses button to search for server:
public void onClick(View v) {
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
if (device.getName().equals("ARD_SPP")) {
sendButton.setVisibility(View.VISIBLE);
Toast.makeText(ConnectActivity.this, "Arduino server found, please sign up 1111", Toast.LENGTH_SHORT);
break;
}
}
}
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(discoveryResult, filter);
mBluetoothAdapter.startDiscovery();
}
And code inside BroadcastReceiver:
public void onReceive(Context context, Intent intent) {
Boolean b = false;
String action = intent.getAction();
ProgressDialog dialog = new ProgressDialog(ConnectActivity.this);
if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)){
dialog.setMessage("Searching for Arduino server...");
dialog.show();
}
else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
dialog.dismiss();
if (!b)
Toast.makeText(ConnectActivity.this, "Server not found", Toast.LENGTH_SHORT).show();
}
else if (BluetoothDevice.ACTION_FOUND.equals(action)){
String deviceName = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
if (deviceName.equals("ARD_SPP")) {
Toast.makeText(ConnectActivity.this, "Arduino server found, please sign up 2222", Toast.LENGTH_SHORT).show();
sendButton.setVisibility(View.VISIBLE);
openButton.setVisibility(View.GONE);
b = true;
dialog.dismiss();
}
}
}
I've got three problems with this.
First, I have the problem with "Server not found" message. It is shown even when arduino is around. I really don't have idea where to put that line in my code. I tried to put it in different lilnes of code, but I couldn't get what is required.
Second, message that server is found is shown two times. I meam toast inside broadcast receiver, not toast inside pairedDevices(after this one I put 1111 to recognize which toast is shown). I don't understand what is the part of the code where that toast is executed for the second time.
And I also had problems with progress dialog. I couldn't remove dialog from the screen, it was still there even when the server is found. I put dialog.dismiss() both in discovery finished block and device found, but it is still on the screen.
Does anyone please can help me with this ?
You set your variable every time you received an intent.
Boolean b = false;
ProgressDialog dialog = new ProgressDialog(ConnectActivity.this);
This should not be put in the OnReceived() but must be setted as private variable of your BroadCastReceiver.
This will this the progress not dismiss and the "Server not found" toast, since b is always false when you received ACTION_DISCOVERY_FINISHED, and you try to dismiss a progressDialog not showed.
Concerning the multiple call of "Server found" call twice, check if you unregister your BroadcastReceiver when you don't need anymore.
Hope that help.
EDIT :
Set your broadcastReceiver like that, the progressDialog should be create in the ACTION_DISCOVERY_STARTED :
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
private boolean b = false;
private ProgressDialog dialog ;
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)){
dialog = new ProgressDialog(ConnectActivity.this);
dialog.setMessage("Searching for Arduino server...");
dialog.show();
}
else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
dialog.dismiss();
if (!b)
Toast.makeText(ConnectActivity.this, "Server not found", Toast.LENGTH_SHORT).show();
}
else if (BluetoothDevice.ACTION_FOUND.equals(action)){
String deviceName = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
if (deviceName.equals("ARD_SPP")) {
Toast.makeText(ConnectActivity.this, "Arduino server found, please sign up 2222", Toast.LENGTH_SHORT).show();
sendButton.setVisibility(View.VISIBLE);
openButton.setVisibility(View.GONE);
b = true;
dialog.dismiss();
}
}
}
}
I have a bluetooth device.
If:
They have already paired and connected to the device
it becomes unplugged
then it becomes plugged back in
I would like to auto-connect to it. That's why I'm listening to ACTION_FOUND.
My code is fairly simple. The ACTION_BOND_STATE_CHANGED and ACTION_ACL_DISCONNECTED work just fine. I am completely unable to get the ACTION_FOUND to catch though. My "INTENT RECEIVED" log message never prints…
I feel like I am missing something simple. Thanks!
public void registerReceiver() {
if (BuildConfig.DEBUG) Log.e(TAG, "REGISTERING RECEIVER");
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
mainActivity.registerReceiver(receiver, filter);
}
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BuildConfig.DEBUG) Log.e(TAG, "INTENT RECEIVED: " + String.valueOf(action));
if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// … some stuff …
} else if (BluetoothDevice.ACTION_FOUND.equals(action)) {
autoConnectDevice();
} else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
disconnectDevice();
}
}
};
public void unregisterReceiver() {
if (BuildConfig.DEBUG) Log.e(TAG, "UNREGISTERING RECEIVER");
mainActivity.unregisterReceiver(receiver);
}
I believe the ACTION_FOUND event only fires when you are running device discovery with the intent to pair your device to another. It would not fire when an already paired device comes back into range. Unfortunately, there does not appear to be an event for the case that you want.
Your best bet will be to start an AsycTask or Thread when the connection is lost and try to reconnect until successful or until you hit an arbitrary time limit and give up.
I need to handle the connectivity change broadcast in my app. Every thing is great except that when it comes for the broadcast the application crashes. I am using the following code in my Broadcast :
#Override
public void onReceive(Context context, Intent intent) {
Log.i("NET", "Broadcast started");
Intent startServiceIntent = new Intent(context, NewsService.class);
boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
if(noConnectivity) {
context.stopService(startServiceIntent);
Toast.makeText(context, "Connection is terminated!", Toast.LENGTH_LONG).show();
Log.i("NET", "Stopped");
}
else {
context.startService(startServiceIntent);
Toast.makeText(context, "Connection is ok!", Toast.LENGTH_LONG).show();
}
}
This code is supposed to stop a service when no internet connection is found and to start it whenever it finds a connection.
Lastly and after 2 days of searching I found the problem, it is about the package the broadcast is placed in I found it here