Different broadcastreceiver depending on activity life - android

Some time ago, I was able to have 2 broadcastreceivers, one declared in my manifest, and the other one, declared in my activity.
Like here : What is the best way to handle callback from IntentService
But, since I have changed for LocalBroadcastReceiver, and changed sendOrderedBroadcast with sendBroadcast method, only the one registered in activity is only receiving the broadcast. I have read that localbroadcastreceiver can not be registered in manifest.
So how to wake up a broadcastreceiver which is not registered in an activity ?

I found my own answer, so I give the response for those who can be interested in.
I have two BroadcastReceiver class, one used when application is wake up, with :
ActivityBroadcastReceiver myReceiver = new ActivityBroadcastReceiver();
#Override
protected void onResume() {
LocalBroadcastManager.getInstance(this).registerReceiver(myReceiver, new IntentFilter("com.mybroadcast"));
super.onResume();
}
and
#Override
protected void onPause() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceiver);
super.onPause();
}
and in my manifest file :
<receiver
android:name="com.broadcastreceiver.NotificationBroadcastReceiver"
android:enabled="true" >
<intent-filter>
<action android:name="com.mybroadcast" />
</intent-filter>
</receiver>
To send my broadcast :
if(!LocalBroadcastManager.getInstance(context).sendBroadcast(broadcast))
context.sendBroadcast(broadcast);
I agree that with this, context.sendBroadcast() , everyone can received my broadcast, but in my code, sendBroadcast send only non-sensible data. That is the best solution I got for now.

Related

Kotlin - Broadcast Receiver for SmsReceiver issue in Android

I am using Broadcast Receive as below :
private val mSmsReceiver=SmsReceiver()
/*
* Default Activity life cycle method which registers Broadcast receiver named
* SmsReceiver for the intent filter SMS_RECEIVED.
* */
public override fun onResume() {
LogUtil.e("<<< onResume MESSAGE", "RECEIVED")
//if(PermissionUtil.hasPermissions(this#OTPUtilityActivity,READ_SMS)){
LocalBroadcastManager.getInstance(this).registerReceiver(
mSmsReceiver,
IntentFilter("android.provider.Telephony.SMS_RECEIVED")
)
super.onResume()
}
I am registering it as above.
Now, I am unregistered it as below when I got success in my web service:
LocalBroadcastManager.getInstance(this).unregisterReceiver(mSmsReceiver)
And yes, I have taken tag for it in manifest as below :
<receiver android:name=".ui.core.broadcast_receiver.SmsReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
The Issue is, Broadcast receiver's method also called when I have navigated to another screen on success of my service after unregistering receiver.
It's calling when any new message received which should not call since I have unregistered it.
How can I completely unregister it, so that it never call again when any sms receives in device ?
Note : I have tried removing receiver from Manifest. But, with that I can't receive a singal message.
Thanks.
Remove the intent filter from manifest. If you register, unregister from code, that's not necessary. As it would continue to listen to that broadcast at app level.

Receiver stops when force close

Hello I've made an app with a receiver to listen to incoming calls ,
My problem is that when i close (swipe off from list of apps) the receiver doesn't work anymore.
first thing i tried is the receiver itself defined in the android manifest like so:
<receiver
android:name=".demo.CallReceiver"
android:exported="true"
android:enabled="true">
<intent-filter android:priority="999">
<action android:name="android.intent.action.PHONE_STATE"/>
</intent-filter>
<intent-filter android:priority="999">
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
This works only when the app is open or in the background .
I looked online and saw this - https://stackoverflow.com/a/46889335/7079340
so i made a Service of my own like so (in the manifest):
<service android:name=".Service.CallService" android:enabled="true"
android:exported="false"> <intent-filter>
<action android:name="com.package.name.IRemoteConnection" />
</intent-filter>
</service>
and the class :
public class CallService extends Service {
private static BroadcastReceiver m_Receiver;
#Override
public IBinder onBind(Intent arg0)
{
Log.e("SERVICELOG","bind");
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("SERVICELOG","start command");
return START_STICKY;
}
#Override
public void onCreate()
{
Log.e("SERVICELOG","create");
Receiver();
}
#Override
public void onDestroy()
{
Log.e("SERVICELOG","destroy");
try{
unregisterReceiver(m_Receiver);}catch (Exception e){
Log.e("SERVICELOG"," "+e.getMessage());
}
}
private void Receiver()
{
m_Receiver = new CallReceiver();
}
}
Started it in the oncreate of my Splashscreen and it prints the logs and it works !
Any way to make this work without a service I'm afraid of battery issues and so on ? Thanks !
Android has had many changes from Marshmallow and above about apps that implicitly listener for broadcast in their manifest. The reasoning for this is because several apps would register for broadcast and a new process would be spun up for all the registered app's broadcast receiver to run in (very expensive) thus causing battery drain. What made this worse, was that users have no control over this behavior because the broadcast receiver couldn't be unregistered. To fix this, the engineering team behind Android, only allows for a select few broadcast to be implicitly registered. One is the Device Boot broadcast intent. By stopping apps from implicitly registering Broadcast's, apps have to be manually launched by the user to listen for intents they'd like to be notified of. This prevent several unnecessary apps from waking up to attempt to handle intent.
As for your concern, about "battery issues" I would recommend to you to use the preferred pattern of explicitly registering a BroadcastReciever in your Service and just performance tune to get your code to be as performant as possible. Services are definitely not free, but they aren't automatically heavy objects just by having one started and running; plus they do exist for this exact purpose. Just remember to not do unnecessary work in your service and you should be off to the right start.
When you close your app, it goes directly to onDestroy method. In your service code, you implemented this method. So, in your method you did stop your service programmatically. In short, you must remove it.

I want to use broadcast receiver even if the app is closed

I am trying to show a toast message when receiving an incoming call/outgoing call.
The receiver is not working if the app is closed.
I do not want to use Service. Please help me out.
'I am using the below receiver code'
public class CallReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent) {
if (isConnected(context)) {
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING)) {
Toast.makeText(context, "Call in progress", Toast.LENGTH_LONG).show();
}
}
}
'This is receiver registered in manifest'
<receiver android:name="com.example.android.testapplication.CallReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE"></action>
<action android:name="android.intent.action.new_outgoing_call"></action>
</intent-filter>
</receiver>
Try adding the phone state permission to your manifest.
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
By default when you register a BroadCastReceiver with AndroidOS that means Receiver always work as the Service part even your application is not working, since you do not have to worry about this problem.
I think the problem is the way you register you Receiver was not correct.
With in/out coming call you should use PhoneStateListener which has overrided method onCallStateChanged. You can use 3 states over there.
Maybe this example will be helpful.

How to Start an activity on receiving ACTION_SCREEN_ON message?

I am working on an application which will start an activity on receiving a ACTION_SCREEN_ON broadcast message.
How to implement this? Can anyone post the code for it?
I know that I have to use BroadcastReceiver. But I need a detailed explanation as I am a beginner.
Create in your application's AndroidManifest.xml a receiver with a intent-filter to catch android.intent.action.SCREEN_ON:
<receiver
android:name="your.app.packagename.Receiver" >
<intent-filter>
<action android:name="android.intent.action.SCREEN_ON" />
</intent-filter>
</receiver>
Then, create the receiver class:
package your.app.packagename;
// imports here
public class Receiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action != null && Intent.ACTION_SCREEN_ON.equals(action)) {
// Do whatever you need to be done when screen turns on
}
}
}
Realize that:
You need launch your app at least one time before it starts receiving the ACTION_SCREEN_ON broadcast.
The onReceive() method is expected to run fast. If you are going to do heavy work, launch an AsyncTask or a background thread for.

Detecting when a USB device is detached on Android

I've got an Android app that needs to detect when a USB peripheral is attached or detached. It works fine when the peripheral is first attached, but I don't receive any notification (i.e., I don't receive an Intent whose action is ACTION_USB_DEVICE_DETACHED) when it is subsequently detached.
Here's the relevant part of my AndroidManifest.xml:
<activity android:name=".LauncherActivity">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="#xml/device_filter" />
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" android:resource="#xml/device_filter" />
</activity>
It may also be worth noting that LauncherActivity only exists to start a Service when the device is attached, and to stop the service when it is detached. In either case, LauncherActivity always finishes itself immediately. All of this occurs in LauncherActivity.onCreate.
Any ideas?
USB_DEVICE_DETACHED is a broadcast intent, thus you may want to declare the BroadcastReceiver in manifest with the appropriate intent-filter for detached action, also with meta-data attached.
Same goes for USB_ACCESSORY_DETACHED, for who is interested.
Summary:
USB_XXX_ATTACHED is an activity intent
USB_XXX_DETACHED is a broadcast intent
(where XXX = DEVICE | ACCESSORY)
See: http://developer.android.com/guide/components/intents-filters.html
"There is no overlap within these messaging systems: Broadcast intents are delivered only to broadcast receivers, never to activities or services"
Try with USB_STATE as below.
It will fire both attached and detatched to same receiver and in receiver you can identify whether is was attached or detatched event.
IntentFilter filter = new IntentFilter();
filter.addAction("android.hardware.usb.action.USB_STATE");
Receiver:
public class USBReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (intent.getExtras().getBoolean("connected")) {
//do your stuff
}
}
}
So, I never got the ACTION_USB_DEVICE_DETACHED Intent to go to LauncherActivity; I don't know what the deal is there, probably something I don't properly understand about intent filters or the Activity lifecycle callbacks.
The solution I ended up using comes from the post linked by Pratik. I basically took everything about USB_DEVICE_DETACHED out of AndroidManifest.xml. Then, in the onCreate method of the Service, I registered a BroadcastReceiver like this:
#Override
public void onCreate() {
detachReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED))
stopSelf();
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(detachReceiver, filter);
}
A little clunky, and I'm still curious why just adding USB_DEVICE_DETACHED to the <intent-filter> of LauncherActivity wasn't working, but it does what I need.
The fix that worked for me was to unregister in onPause() and register again in onResume():
#Override
public void onPause()
{
super.onPause();
stopIOManager();
if(m_UsbReceiver!=null) unregisterReceiver(m_UsbReceiver);
}
#Override
public void onResume()
{
super.onResume();
startIOManager();
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(m_UsbReceiver, filter);
}
However, although the app seems to always receive the DETACH event, once in a while it doesn't get the ATTACHED event. I then need to plug and and unplug the USB connector, and it usually works after one or two attempts. I've put the blame of this strange behaviour on the OS, without certainty.
For what it's worth, I had this same issue because the activity is paused then resumed when the device is disconnected.
Since the receiver is unregistered in the OnPause() method just prior to receiving the ACTION_USB_DEVICE_DETACHED, your app never gets notified.

Categories

Resources