onReceive in BroadcastReceiver doesn't get called sometimes - android

I registered receiver in onCreate, but onReceive sometimes get called, sometimes not.
public class MyReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Log.v("receiver","get called");
}
}
Here is how I register receiver in onCreate
PROCESS_RESPONSE = getBaseContext().getResources().getString(R.string.serviceResponse);
IntentFilter filter = new IntentFilter(PROCESS_RESPONSE);
filter.addCategory(Intent.CATEGORY_DEFAULT);
receiver = new MyReceiver();
registerReceiver(receiver, filter);
Here is how I send broadcast:
Intent broadcastIntent = new Intent();
PROCESS_RESPONSE=getBaseContext().getResources().getString(R.string.serviceResponse);
broadcastIntent.setAction(PROCESS_RESPONSE);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
sendBroadcast(broadcastIntent);

Try this:
broadcastIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
The reason it sometimes works and doesn't work is
because Android 3.0 introduced a launch control security measure that prevents components of stopped applications from being launched via an intent. An application is considered to be in a stopped state if the application has either just been installed and not previously launched, or been manually stopped by the user using the application manager on the device. To get around this, however, a flag can be added to the intent before it is sent to indicate that the intent is to be allowed to start a component of a stopped application.
Quote source
So when you try a fresh install (launching from IDE) the application is considered in the stop state for a while, then later is not. So it sometimes doesn't work when you try to broadcast. Let me know if this works, and of course ensure you have registered the BroadcastReciever (I'm sure you have if it works, at least some of the time).

Related

Run service on incoming SMS in android Oreo

I'm developing an app which needs to run some code (Networking) whenever an SMS is received.
In API 25 and lower it's fine, I register an implicit receiver in Manifest file and start my service in the specified class which extended BroadcastReceiver. In API 26 however you cannot register android.provider.Telephony.SMS_RECEIVED in a receiver since it won't work.
From Android documentation:
Note: If your app targets API level 26 or higher, you cannot use the manifest to declare a receiver for implicit broadcasts (broadcasts that do not target your app specifically), except for a few implicit broadcasts that are exempted from that restriction. In most cases, you can use scheduled jobs instead.
I've read several articles like this one on medium. There are solutions like JobScheduler or Explicit Receiver, however the first one is used for changes in network state and I couldn't find a way to trigger the job on SMS_RECEIVED event and the second one is valid until your activity is up and running.
Because of the nature of my application I need to listen for incoming SMS whether the app is running or not. How to do that in API 26+?
Edit
Maybe the code in JobInfoBuilder doc on android website could help. It monitors the changes in the photos on a device and start the job on change. However I cannot find a proper Uri to do the same with the SMS (not even sure if it's possible to monitor SMS via ContentObserver)
Since there are lots of ways to do the job in android O, I post this answer and mention my approach to solve the problem. Obviously by problem I mean the general problem not the SMS_RECEIVED receiver itself.
I start a foreground service and in there I register a dynamic or explicit receiver to listen to the incoming calls (for instance):
In MainActivity.java:
String action = "START"
final Intent intent = new Intent(this, CallMonitorService.class);
intent.setAction(action);
startService(intent);
In CallMonitorService.javas onCreate() method where I have BroadcastReceiver callExplicitReceiver as a field:
final IntentFilter intentFilter = new IntentFilter();
intentFilter.setPriority(2147483647);
intentFilter.addAction("android.intent.action.PHONE_STATE");
this.callExplicitReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
// do the stuff here
}
}
};
registerReceiver(callExplicitReceiver, intentFilter);
and then in onStartCommand():
if (intent.getAction().equals("START")) {
Intent callServiceNotificationIntent = new Intent(this, MainActivity.class);
callServiceNotificationIntent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent
.getActivity(this, CALL_SERVICE_REQUEST_CODE,
callServiceNotificationIntent, CALL_SERVICE_FLAG);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle(CALL_NOTIFICATION_CONTENT_TITLE)
.setTicker(CALL_NOTIFICATION_TICKER)
.setContentText(CALL_NOTIFICATION_CONTENT_TEXT)
.setSmallIcon(R.drawable.ic_info_outline_black_24dp)
.setContentIntent(pendingIntent)
.setOngoing(true)
.build();
startForeground(CALL_NOTIFICATION_ID, notification);
}
and finally:
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(callExplicitReceiver);
}
I think of this as a good approach since the user is notified of the running service because of the undismissable notification and that's what android Oreo wants, however through a button in the app user could stop the service and the monitoring receiver as a direct result of destroying service (I cleared that part of code).
I think for now you are safe as SMS_RECEIVED_ACTION is present in the current exempted implicit broadcast list. Also, upon receiving the system broadcast you can either start a foreground service or schedule a job (to perform network operation in your case). Moreover, I am also using the same action and upon testing it seems to work okay.

How to intercept Intent ACTION_MEDIA_MOUNTED broadcast in Android?

I have an Android app that handles plug-ins of my specific storage device. I want to be able to show the contents of the storage device in a specific way with my Display activity when the device is mounted on the system. The problem I'm having is that on some phones the system also handles the ACTION_MEDIA_MOUNTED broadcast and then automatically brings up the Android file explorer (which takes the screen away from my app). This is what I am trying to prevent if at all possible. I am registering a broadcast receiver to listen for the ACTION_MEDIA_MOUNTED broadcast and then starting my Display activity as soon as I receive this broadcast like so:
BroadcastReceiver mediaMountedReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
Log.d("debug", "HEAR YE! HEAR YE! THE MEDIA HAS BEEN MOUNTED!");
if (isOrderedBroadcast()) {
abortBroadcast();
}
Intent i = new Intent(getApplicationContext(), Display.class);
startActivity(i);
}
};
...
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
filter.addDataScheme("file");
filter.setPriority(999);
registerReceiver(mediaMountedReceiver, filter);
I receive the broadcast alright and I try to cancel it by calling abortBroadcast() but apparently ACTION_MEDIA_MOUNTED is not an ordered broadcast. Is there any way to stop propagation of this broadcast or to direct all storage mount/unmount broadcasts to my app?
If this is not possible does anyone have tips or workarounds on how to deal with this?

How do I communicate information from a BroadcastReceiver to an Activity in Android

I'm trying to write something similar to a custom app store, and I'm having a very hard time hearing the results of the installation.
I've tried a variety of things, and none of them have functioned as it appears they should.
In my main activity class, I have the installation code as follows:
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setDataAndType(Uri.fromFile(apkFile),
"application/vnd.android.package-archive");
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true);
intent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, getApplicationInfo().packageName);
startActivityForResult(intent, resultIndex);
That's pretty straightforward. The first thing I tried to get the result is to override the onActivityResult function in my main activity. That function never gets called (a logger statement on the first line never prints).
Hence, I tried creating a receiver in the manifest.
<receiver android:name=".PackageReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="package" />
</intent-filter>
</receiver>
And then in the PackageReceiver class, I overrode the onReceive function. This worked in the sense that the PackageReceiver's function did get called, but I'm now stuck with the problem of how to notify the main activity that something has happened (for the purposes of my project, I need to know). I can't instantiate the PackageReciever; Android does that for me because it's in the manifest.
I tried creating a new broadcast, so my PackageReceiver's onReceive function looks like this:
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_INSTALL_PACKAGE) ||
action.equals(Intent.ACTION_PACKAGE_ADDED) ||
action.equals(Intent.ACTION_PACKAGE_CHANGED) ){
logger.debug("Caught action of type " + action);
Intent i2 = new Intent();
i2.setAction("MY.CUSTOM.ACTION");
context.sendBroadcast(i2);
}
}
Then, over in my main activity, I created a new BroadcastReceiver:
BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
logger.warn("I made it!!!! HOORAY!!");
}
};
And registered that receiver in the onResume (and unregistered in the onPause) function, like this:
#Override
protected void onResume() {
IntentFilter filter = new IntentFilter();
filter.addAction("MY.CUSTOM.ACTION");
registerReceiver(myReceiver, filter);
logger.debug("Registering receiver in onResume.");
super.onResume();
}
It sounded like a nice solution, but "myReceiver" never has its onRecieve function called. I've tried making sure I don't unregister when I don't want to by simply removing the unregistration, moving the registration to the onCreate method of the activity, and none of that works. The net result there is that exceptions get thrown in the logger saying I've leaked an IntentFilter, "Did you forget to unregister?" (No, I very purposefully didn't unregister... but... nevermind).
I'm running out of ideas as to how to bridge this gap. Also, I can't just poll the installed applications and check version numbers. For reasons I can't get into here, we don't use version numbers. I need to know whether or not the user completed the installation that I kicked off.
How can I send information from the PackageReceiver to the main activity? Or, how can I catch the result of the installation in the main activity itself?
Thanks to all who give it a stab. I checked other stackoverflow questions, but none seem to have the answers I'm looking for.
If you register myReceiver in onResume() and unregister it in onPause() it will never get called because when the package installation occurs your app is paused.
You need to register MyReceiver in onCreate() and don't unregister it until onDestroy().
Also, you don't need so many components to do this. In your main activity, just before you go off to install a package you can register the receiver to listen for the package installer results:
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addCategory(Intent.CATEGORY_DEFAULT);
filter.addDataScheme("package");
registerReceiver(myReceiver, filter);
// Now launch the package installer...

Android long running service with alarm manager and inner broadcast receiver

I have a Service that uses a custom Connection class (extends thread) to a hardware controller. When the User prefers, I wish to maintain this connection on a permanent basis. I already have the code to handle when the Android device loses its internet connection, switches between wi-fi, etc.
In order to stay connected, the controller requires that you speak to it within every 5 minutes. I currently, within the Connection class start a thread that runs in a while(), and checks the system time and the last time it communicated, and when > 4 minutes it requests a status. For some reason, at different times the communication doesn't occur in time. i.e., occurs after 5 minutes. The Service doesn't die, as far as I can tell but the "Ping" to the controller is late. This doesn't happen when I have the phone plugged into the charger (or debugger). Additionally, the behavior is the same when I move the Service to the foreground.
Does the phone slow down it's processor when it goes to sleep?
Is there a better way?
I'm thinking it's the AlarmManger, but I'm having trouble getting it to work with an inner-class, within the Service. I tried using the API demos as a starting point, but I can't seem to figure out how to get the Broadcast receiver registered. I am trying to register the receiver programmatically, with no changes to the manifest.
public class DeviceConnectionService extends Service {
#Override
public void onCreate() {
Intent intent = new Intent(this, PingConnection.class);
intent.setAction("KEEP_CONNECTION_ALIVE");
PendingIntent sender = PendingIntent.getBroadcast(this,
0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// We want the alarm to go off 30 seconds from now.
long firstTime = SystemClock.elapsedRealtime();
firstTime += 15*1000;
// Schedule the alarm!
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
firstTime, 15*1000, sender);
// register to listen to the Alarm Manager
if (mPingConnectionReceiver == null) {
mPingConnectionReceiver = new PingConnection();
getApplicationContext().registerReceiver(mPingConnectionReceiver,
new IntentFilter("KEEP_CONNECTION_ALIVE"));
}
}
// ...
public class PingConnection extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (dBug) Log.i("PingConnection", "Pinging Controller");
// do real work here
}
}
}
Does the phone slow down it's processor when it goes to sleep?
The phone shuts down its processor when it goes to sleep. That is the definition of "sleep".
I'm thinking it's the AlarmManger, but I'm having trouble getting it to work with an inner-class, within the Service. I tried using the API demos as a starting point, but I can't seem to figure out how to get the Broadcast receiver registered. I am trying to register the receiver programatically, with no changes to the manifest.
That is an unusual approach for AlarmManager. That being said, since you declined to describe "having trouble" in any detail, it is difficult to help you.
Get rid of getApplicationContext() (you don't need it and really don't want it in this case). I would register the receiver before touching AlarmManager. Before you go to production, please choose an action name that has your package name in it (e.g., com.something.myapp.KEEP_CONNECTION_ALIVE).
Beyond that, check LogCat for warnings.
UPDATE
In your LogCat, you should have a warning from AlarmManager complaining about not being able to talk to your BroadcastReceiver.
Replace:
Intent intent = new Intent(this, PingConnection.class);
intent.setAction("KEEP_CONNECTION_ALIVE");
with:
Intent intent = new Intent("KEEP_CONNECTION_ALIVE");
and you may have better luck.
you can't register AlarmManager in a Service.
All you can do is declare it as global in the Manifest.xml.
You can start the alarm from service in this way, by declaring it in Manifest.xml
If you have a remote service and you close the launcher activity, the AlarmManager will still run, but don't forget to stop it on onDestroy() method of the service.
I've tried to register only in the Service the AlarmManager as I didn't used it for the main activity, but no success!
It didn't work as registering as a normal BroadCastReceiver.
that's how the things are, you have to declare it in Manifest.xml as global
I know it's late, but maybe it's useful for someone else.
You can register it, the problem is when the Intent tries to call it.
Instead of calling it like this:
Intent intent = new Intent(this, PingConnection.class);
Create an empty intent and add an action you are going to listen to:
Intent intent = new Intent();
intent.setAction("value you want to register");
Then create the pending intent and send the broadcast like you have it.
Create an attribute for the receiver so you can access it in the whole class and unregister if necessary (if the pendingIntent is also an attribute you can unregister any time):
private PingConnection pingConnection = new PingConnection();
Register it like this:
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("the value you used before");
getApplicationContext().registerReceiver(pingConnection, filter);
Now you won't get any errors, and the class is not static, and it's an inner class.

What's the right way to send messages from my IntentService back to an Activity?

I have an app in which the main Activity starts an AlarmReceiver that calls an IntentService that runs in the background and does stuff. I'm unclear on what the correct way is to check on the IntentService's actions and present the end-user with some feedback in the visible Activity that they're in, on the IntentService's current state. In my ideal world there can be an icon somewhere on the screen that I can set to notify the user of what's going on with the IntentService. I don't need the user to be able to *do anything, just have feedback.
All advice welcome.
Android has a notification API, which is even easy to use - Creating Status Bar Notifications.
If you want your activity to receive updates from the service, I would suggest using broadcasts and broadcast receivers.
How to send a broadcast intent:
Intent i = new Intent("your.action");
sendBroadcast(i);
To receive this broadcast within your activity, you have to implement a broadcast receiver:
private BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//
}
};
which you have to register...
registerReceiver(myReceiver, new IntentFilter("your.action"));

Categories

Resources