I have done an app as tutorial to learn how to restart deleted alarms after phone is rebooted. After reboot BroadcastReceiver receives BOOT_COMPLETED action and launches a service, which restarts all alarms. Alarms create notification when they are called. After first tests I have received notifications at expected time and then forgot about this tutorial app and didn't turn the phone off.
However, I'm still getting notifications on my screen as if the app has restarted alarms again. During the day I have received twice and all of them are unclear why. The only thing that may launch the restarting alarms is BOOT_COMPLETED action. What's going wrong here?
Manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.marat.recyclerviewtutorial">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
// list of activities
<service android:name=".BootService"/>
<receiver android:name=".AlarmBroadcastReceiver"/>
<receiver android:name=".RestartAlarmsReceiver" android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
RestartAlarmsReceiver.java
public class RestartAlarmsReceiver extends BroadcastReceiver {
private static final String TAG = "myTag";
#Override
public void onReceive(Context context, Intent intent) {
if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
Intent i = new Intent(context, BootService.class);
ComponentName service = context.startService(i);
if (null == service) {
// something really wrong here
Log.e(TAG, "Could not start service ");
}
else {
Log.e(TAG, "Successfully started service ");
}
} else {
Log.e(TAG, "Received unexpected intent " + intent.toString());
}
}
}
BootService.java
public class BootService extends Service {
private static final String TAG = "myTag";
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
Database db = new Database(this);
db.open();
ArrayList<ArrayList<String>> data = new ArrayList<ArrayList<String>>();
data = db.getData();
db.close();
Log.d(TAG, "db is openned");
for (int i=0; i<data.size(); i++) {
Intent notif = new Intent(this, AlarmBroadcastReceiver.class);
notif.putExtra("Text", data.get(i).get(2));
notif.putExtra("Position", data.get(i).get(0));
int sec = Integer.parseInt(data.get(i).get(3));
Log.d(TAG, "intent is openned");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, Integer.parseInt(data.get(i).get(0)), notif, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (sec * 1000), pendingIntent);
Log.d(TAG, "Alarm is restarted");
}
Log.d(TAG, "before returning service");
return Service.START_STICKY;
}
}
It's already huge portion of code. But if you will need other parts of my app I will include them.
Thanks in advance!
I think this is because of START_STICKY. I think during the day the system closes your running Service to free resources, and START_STICKY forces it to restart. And on restart onStartCommand() is triggered again.
The decision may to use IntentService instead. I don't see the need of using Service here.
Related
I have a broadcast receiver registered to receive SMS inside a service. The intention of the Application is to get the SMS on receive and save the contents of SMS from expected sender in Sqlite storage. The App need to capture the SMS received also even when the App is not running in background.
public class SMSService extends Service {
private final BroadcastReceiver receiver = new BroadcastReceiver() {
public static final String SMS_BUNDLE = "pdus";
ContentValues userValues;
Object[] sms;
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("android.provider.Telephony.SMS_RECEIVED")) {
Log.d("~~~ SMS !!!", "~~~ SMS ~~~ SMS ~~~ SMS~~~ SMS ~~~");
AsyncSmsHandler asyncSmsHandler = new AsyncSmsHandler(context, intent);
asyncSmsHandler.execute("");
}
}
class AsyncSmsHandler extends AsyncTask<String, Void, String> {
Context context;
Intent intent;
public AsyncSmsHandler(Context context, Intent intent) {
this.context = context;
this.intent = intent;
}
#Override
protected String doInBackground(String... params) {
String smsBody = "", address = "";
Bundle intentExtras = intent.getExtras();
SmsMessage smsMessage = null;
if (intentExtras != null) {
sms = (Object[]) intentExtras.get(SMS_BUNDLE);
String smsMessageStr = "";
for (int i = 0; i < sms.length; ++i) {
smsMessage = SmsMessage.createFromPdu((byte[]) sms[i]);
smsBody = smsBody + smsMessage.getMessageBody();
smsMessageStr += smsBody + "\n";
}
address = smsMessage.getOriginatingAddress();
Log.d("SMS RECEIVER NUMBER", " " + smsBody + " -- " + sms.length);
//SAVE THE MESSAGE AND NUMBER
}
return "";
}
#Override
protected void onPostExecute(String result) {
// Create an explicit intent for an Activity in your app
Intent intent = new Intent(context, AquaOrderList.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "CHANNEL_ID")
.setSmallIcon(R.drawable.logo)
.setContentTitle(“TITLE”)
.setContentText(“Message”)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
// notificationId is a unique int for each notification that you must define
notificationManager.notify(1, builder.build());
}
}
};
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
IntentFilter filter = new IntentFilter();
filter.addAction("android.provider.Telephony.SMS_RECEIVED");
registerReceiver(receiver, filter);
}
#Override
public void onDestroy() {
unregisterReceiver(receiver);
}
}
In this way registering the receiver in onCreate and unregisterReceiver on onDestroy methods.
This work as expected but when I kill the App and after a while, If I receive SMS, it is not getting triggered. If I open the App again, after that SMS starts saving in the storage.
Is the service getting destroyed ? I checked in the "Running Services" in mobile and I can see the service running.
I have also added the permissions in manifest file.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xyz.app”>
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<service
android:name=".SMSService"
android:enabled="true"
android:exported="true"></service>
<activity
android:name=".OrderList"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="#string/title_activity_order_list"
android:theme="#style/FullscreenTheme"></activity>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I want to have the Application listening for incoming SMS even the App is not in the stack. What can be the approach I can follow to get this done.
I am not in total agreement with #Ranjan's comments. Yes, services are
destroyed and kept running by android & yeah, it is difficult to run a
service permanently. However if you have done everything correctly,
how many ever times your service is destroyed, it would be launched
again (automatically), and on launch, your receiver should be
registered.
My tips are:
Firstly, make sure your are NOT targeting latest SDK. I am using targetSDK 10, minSDK 17, and compileSDK 26. That could make a difference on how your services are treated. Play around with these values to check if this alone makes it work.
Next, please follow this thread HERE and try to create your receiver properly.
I'm not sure about what your problem is exactly, however I can tell you, that we have a video conferencing application, that listens to incoming calls and messages. So of course, the BroadcastReceiver needs to be registered and Service should be running in the background. This app is a little old, and was developed with targetSDK 10 etc. So they are doing it in the way that was common then. We still haven't ported our application, so we don't know what problems exist in newer Android. As I mentioned, our app compiles with SDK26.
Code Sample:
public SampleService() {
super();
Log.d(TAG, "SampleService: Constructor");
final HandlerThread mHandlerThread = new HandlerThread(BR_THREAD_NAME, Process.THREAD_PRIORITY_BACKGROUND);
mHandlerThread.start();
bgLooper = mHandlerThread.getLooper();
mBRHandler = new Handler(bgLooper);
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate: ");
registerReceiver();
}
private void registerReceiver() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(SOME_ACTION);
myReceiver = new MyReceiver();
registerReceiver(myReceiver, intentFilter, null, mBRHandler);
}
This should be good enough
Post Android 7, my alarm receiver is not receiving the broadcast receiver if the app is killed by swiping it off from the recent tasks list.
Following is the piece from my AlarmReceiver, which extends BroadCastReceiver.
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(Constants.TAG, "event received");
setContext(context);
/*
*** My logic here ***
*/
Log.d(Constants.TAG, "alarm received");
}
}
The place I am setting the alarm and registering the AlarmReceiver class for the alarm.
public class UnityNotificationManager
{
public static void SetNotification(int id, long delayMs, String title, String message, String ticker, int sound, int vibrate,
int lights, String largeIconResource, String smallIconResource, int bgColor, String bundle, String dataString)
{
Context currentActivity = UnityPlayer.currentActivity;
AlarmManager am = (AlarmManager)currentActivity.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(Constants.ALARM_RECEIVER);
intent.setClass(currentActivity, AlarmReceiver.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.putExtra("ticker", ticker);
intent.putExtra("title", title);
intent.putExtra("message", message);
intent.putExtra("id", id);
intent.putExtra("color", bgColor);
intent.putExtra("sound", sound == 1);
intent.putExtra("vibrate", vibrate == 1);
intent.putExtra("lights", lights == 1);
intent.putExtra("l_icon", largeIconResource);
intent.putExtra("s_icon", smallIconResource);
intent.putExtra("bundle", bundle);
intent.putExtra("dataString", dataString);
PendingIntent pendingIntent = PendingIntent.getBroadcast(currentActivity,
id, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
am.cancel(pendingIntent);
long finalTime = System.currentTimeMillis() + delayMs;
if (Build.VERSION.SDK_INT < 23) {
am.set(AlarmManager.RTC_WAKEUP,finalTime, pendingIntent);
} else {
am.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,finalTime, pendingIntent);
}
Log.d(Constants.TAG, "event fired finalTime = "+ finalTime);
}
}
The value of the above used Constants.ALARM_RECEIVER is same as the action name defined in manifest for the broadcast AlarmReceiver will listen to.
<receiver android:name="com.example.app.AlarmReceiver">
<intent-filter>
<action android:name="com.example.app.alarm.action.trigger" />
</intent-filter>
</receiver>
The reason for using an explicit broadcast is that the android docs state that post Android Oreo, android applications won't be able to use implicit broadcasts in the background to improve performance. The link for the same: https://developer.android.com/about/versions/oreo/background.html#broadcasts
I also tried using a WakefulBroadCastReceiver to avoid optimizations made by Doze mode on android devices, but it turns out that this class has been deprecated in Android Oreo. The link for the same: https://developer.android.com/reference/android/support/v4/content/WakefulBroadcastReceiver.html
The aforementioned code works for nearly every other manufacturer except One Plus devices, which run on oxygen os. Is there any way to fix this issue as notifications for applications like WhatsApp continue to work if app is killed the same way.
Additional Information:
1. I ran the command adb shell dumpsys package <package_name> | grep stopped on One Plus 5T and it returned the following output:
User 0: ceDataInode=2039857 installed=true hidden=false suspended=false stopped=false notLaunched=false enabled=0 instant=false
which, in turn suggests that the app is not stopped on swiping the app from the recent tasks list. Also, the "Force Stop" button is enabled on the application information page, suggesting that the app hasn't been force stopped.
I was able to make the notifications work if I manually changed the Battery Optimizations setting from 'Optimized' to 'Not Optimized', but since notifications for other applications worked even when they are in the Optimized state, I don't believe this to be the solution for my problem.
Can someone please suggest any fixes or work-arounds to fix the notification issue on devices running Android 7 or above on Oxygen OS?
I have observed the same behaviour. The bug seems to be that Oxygen OS is not allowing the broadcast receiver to start from the PendingIntent. The solution was to use a Service instead on BroadcastReceiver.
Move your code from BroadcastReceiver's onReceive() to a Service's onStartCommand() method and then set this Service class in the PendingIntent.
...
intent.setClass(currentActivity, AlarmService.class);
...
PendingIntent pendingIntent = PendingIntent.getService(currentActivity, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
...
Hope this helps.
Yes, I also found it hard to get reference sample codes, as 8.0 onwards there are restrictions on always running tasks.
Do not place any intent-actions in Manifest.xml like this :
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".Receiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service
android:name=".CatchNumbers"
android:enabled="true"
android:exported="true" />
<service
android:name=".WatchMan"
android:enabled="true"
android:exported="true" >
</service>
<activity android:name=".developer_activity" />
<activity android:name=".WhiteListActivity" />
<activity android:name=".Contacts" />
</application>
please note
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
are not inserted by me, android studio inserted it automatically when i registered runtime receiver in service. It is necessary.
From my receiver.java on every boot_complete i registers receivers runtime in a foreground service. It is must if you want your receiver to work :
package com.example.rushi.instapromo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;
public class Receiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Log.d("BootTest : ", "\nOnBootReceiver - Received a broadcast!");
Toast.makeText(context, "OnBootReceiver Received a broadcast!!", Toast.LENGTH_LONG).show();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
context.startForegroundService(new Intent(context, WatchMan.class));
}
else
{
context.startService(new Intent(context, WatchMan.class));
}
}
}
Note that Watchman.java is foreground service which registers runtime receiver, if you do not go with this method, it will never work. I have tried a lot and invented this is the way only.
Register receivers in foreground service like
public class WatchMan extends Service
{
NotificationManager mNotifyManager;
NotificationCompat.Builder mBuilder;
NotificationChannel notificationChannel;
String NOTIFICATION_CHANNEL_ID = "17";
private BroadcastReceiver mCallBroadcastReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
String PhoneNumber = "UNKNOWN";
Log.d("RECEIVER : ","IS UP AGAIN....");
try
{
String action = intent.getAction();
if(action.equalsIgnoreCase("android.intent.action.PHONE_STATE"))
{
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING))
{
PhoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
Log.d("RECEIVER : ","Incoming number : "+PhoneNumber);
// update in database and goto catchnumber to sms
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
context.startForegroundService(new Intent(context, CatchNumbers.class));
}
else
{
context.startService(new Intent(context, CatchNumbers.class));
}
}
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_IDLE))
{
PhoneNumber = "UNKNOWN";
}
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK))
{
Log.d("RECEIVER : ","OUTGOING CALL RECEIVED....");
// UPDATED in database and JUST GOTO catchnumber to sms
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
context.startForegroundService(new Intent(context, CatchNumbers.class));
}
else
{
context.startService(new Intent(context, CatchNumbers.class));
}
}
}
if(action.equalsIgnoreCase("android.intent.action.NEW_OUTGOING_CALL"))
{
PhoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.d("RECEIVER : ","Outgoing number : "+PhoneNumber);
// update in database and BUT DO NOT GOTO catchnumber to sms
}
}
catch (Exception e)
{
e.printStackTrace();
Log.e("RECEIVER : ", "Exception is : ", e);
}
}
};
public WatchMan() { }
#Override
public void onCreate()
{
super.onCreate();
Log.d("WatchMan : ", "\nOnCreate...");
IntentFilter CallFilter = new IntentFilter();
CallFilter.addAction("android.intent.action.NEW_OUTGOING_CALL");
CallFilter.addAction("android.intent.action.PHONE_STATE");
this.registerReceiver(mCallBroadcastReceiver, CallFilter);
Log.d("WatchMan : ", "\nmCallBroadcastReceiver Created....");
mNotifyManager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this, null);
mBuilder.setContentTitle("Insta Promo")
.setContentText("InstaPromo Service ready")
.setTicker("InstaPromo Service ready")
.setSmallIcon(R.drawable.ic_launcher_background)
.setPriority(Notification.PRIORITY_HIGH)
.setDefaults(Notification.DEFAULT_ALL)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setOngoing(true)
.setAutoCancel(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Notifications", NotificationManager.IMPORTANCE_HIGH);
// Configure the notification channel.
notificationChannel.setDescription("Channel description");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
notificationChannel.enableVibration(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
mNotifyManager.createNotificationChannel(notificationChannel);
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
startForeground(17, mBuilder.build());
}
else
{
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
//startForeground(17, mBuilder.build());
mNotifyManager.notify(17, mBuilder.build());
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d("WatchMan : ", "\nmCallBroadcastReceiver Listening....");
//return super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onDestroy()
{
this.unregisterReceiver(mCallBroadcastReceiver);
Log.d("WatchMan : ", "\nDestroyed....");
Log.d("WatchMan : ", "\nWill be created again....");
}
#Override
public IBinder onBind(Intent intent)
{
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
Please note how i registered and unregistered NEW_OUTGOING_CALL and PHONE_STATE intent actions. CatchNumbers is another service which i am using to do whatever i want to with incoming and outgoing numbers.
Your intent actions might be different than me.., But this is the only way if you want it to implement in 8.0 onwards. Tested and and i am working with this code. It supports 4.2 to Android P api level 29 also. On every reboot these 2 intent filters and receivers are ready fro me to use in my CatchNumbers. Hope it really helps you. or some one else.
I am having some difficulties to implement a service that should run periodically.
The app works fine when the screen is on, and even if the app is removed from the recent tasks. But when the device is locked, the app stops and even when the screen turns on again the service does not return.
I had implemented a WakefulBroadcastReceiver with an action to SCREEN_ON, but it works only when the application is alive, it does not work when there is only a service running.
The Service and the WakefulBroadcastReceiver are declared like this in my AndroidManifest:
<service android:name=".FeedService" />
<receiver android:name=".AutoStart">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.SCREEN_ON" />
</intent-filter>
</receiver>
I also added the following permissions to my AndroidManifest file:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
This is my WakefulBroadcastReceiver:
public class AutoStart extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Feed", "AutoStart.onReceive");
context.startService(new Intent(context, FeedService.class));
}
}
And this is my Service:
public class FeedService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("Feed", "FeedService.onStartCommand");
stopSelf();
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
Log.d("Feed", "FeedService.onBind");
return null;
}
#Override
public void onDestroy() {
// I want to restart this service again in 5 seconds
AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE);
alarm.set(
alarm.RTC_WAKEUP,
System.currentTimeMillis() + (5000),
PendingIntent.getService(this, 0, new Intent(this, FeedService.class), 0)
);
}
}
In my MainActivity I start the service with:
AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE);
alarm.set(
alarm.RTC_WAKEUP,
System.currentTimeMillis() + (5000),
PendingIntent.getService(this, 0, new Intent(this, FeedService.class), 0)
);
It's critical to my application keep this service running and I don't understand why it is not happening.
Could someone explain me how can I solve this?
I found an answer to my problem.
For some reason, even if I had requested WAKE_LOCK in the manifest file and registered my BroadcastReceiver in the Activity, my app does not have a permission to continues alive after the screen lock. I found an option on my device where it can be specified in settings>protected apps. So I just checked this option e now my service is working fine. I do not know if this option is checked automaticaly when the app is installed from Google Play (I hope so), but this option wasn't checked in my case.
I need to have a periodic polling mechanism to detect new orders (after the last order the user has seen) for which
I have setup a couple of broadcast recievers(one for boot activate,and other for executing recurring task) and a service.I use Alarmmanager to periodically call the PeriodicTaskReciever.
Now I need to know how to communicate with such a remote broadcast reciever(A flag parameter indicating the last user seen order needs updation). I've tried shared preferences and as indicated in a lot of articles remote process is unable to read updated values of SP
<service android:name=".OrderService" />
<receiver android:name=".BootReciever" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
<receiver android:name=".PeriodicTaskReciever"
android:process=":remote"
/>
My PeriodicTask Reciever is
public class PeriodicTaskReceiver extends BroadcastReceiver
{ private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
static int lastOrder;
int NOTIFICATION_COUNTID=100;
public void onReceive(final Context context, Intent intent)
{
Log.d("DataHandlerService", "Service hbeat");
if(intent.getIntExtra("update",0)!=0){
lastOrder=intent.getIntExtra("update",0);
Log.d("DataHandlerService", "Last order updated");
}
else{
if(Utils.isNetworkAvailable(AppController.getInstance().getApplicationContext())){
Uri.Builder uri = new Uri.Builder();
uri.scheme("http");
uri.authority(Constants.URL_API_HOST);
uri.path(Constants.URL_API_ORDERPATH);
uri.appendQueryParameter("lastorder",getLastOrderFromSharedPref());
String url=uri.build().toString();
Log.d("DataHandlerService", "Service hbeat"+url);
JsonObjectRequest jsonObjectRequest=new JsonObjectRequest(url,null,new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject jsonObject) {
try {
if(!jsonObject.isNull("status") && jsonObject.getString("status").equals("success")){
if(Integer.parseInt(jsonObject.getString("data"))>0){
displayNotification("You have "+ Integer.parseInt(jsonObject.getString("data"))+ " new orders ",context);
}}
} catch (Exception e) {
}
}
},new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
}
});
AppController.getInstance().addToRequestQueue(jsonObjectRequest,"PollOrders");}}
}
public void SetAlarm(Context context)
{
AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, PeriodicTaskReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 , pi); // Millisec * Second * Minute
}
public void CancelAlarm(Context context)
{
Intent intent = new Intent(context, PeriodicTaskReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
Am I misusing the remote. I need to notify users pretty much from the background when my app isnt running. And once the users click on a notification or dismiss it the lastOrder value gets updated.
There is no work of android:process=":remote" for a BroadcastReceiver. So remove that and here you are no using intent-filter for receiver so you need to export that BroadcastReceiver.
Instead of doing
<receiver android:name=".PeriodicTaskReciever"
android:process=":remote"
/>
export your receiver. like
<receiver android:name=".PeriodicTaskReciever"
android:exported="true"
/>
I'm working on the app that will start two alarms as the following:
Repeating alarm at every hour once it's started
Non-repeating alarm at either 1 to 10 hours based on the user selection
Both of the alarms are using ELAPSED_REALTIME_WAKEUP type. The problem I'm facing now is that the same codes work fine on Android 2.3.5 but Android 4.0.4. I have done some research on google and the problem doesn't seem to link to the issue of "no broadcast receiver will be triggered until the app is launched manually for the first time".
The following are the codes for setting up the pending intent for both the alarms:
private class AlarmEvent {
private Intent mIntent;
private PendingIntent mPendingIntent;
protected AlarmEvent(Context ctx, Class<?> cls, int pendingIntentType,
int requestCode, int flags, String intentAction) {
mIntent = new Intent(ctx, cls);
mIntent.setAction(intentAction);
switch(pendingIntentType) {
case PENDING_BROADCAST:
mPendingIntent = PendingIntent.getBroadcast(ctx, requestCode, mIntent, flags);
break;
case PENDING_SERVICE:
mPendingIntent = PendingIntent.getService(ctx, requestCode, mIntent, flags);
break;
default:
Log.w(TAG, "AlarmEvent:Invalid pending intent type=" + pendingIntentType);
}
}
protected PendingIntent getPendingIntent() {
return mPendingIntent;
}
}
The following are the codes to create the AlarmEvent:
//Create polling event
mPollingEvent = new AlarmEvent(mCtx, EventRouter.class, PENDING_BROADCAST,
POLLING_REQUEST_CODE, PendingIntent.FLAG_CANCEL_CURRENT,
EventRouter.POLLING_ACTION);
//Create monitor event
mReminderEvent = new AlarmEvent(mCtx, EventRouter.class, PENDING_BROADCAST,
REMINDER_REQUEST_CODE, PendingIntent.FLAG_CANCEL_CURRENT,
EventRouter.REMINDER_ACTION);
The following are the codes to start the alarms:
//Get AlarmManager instance
AlarmManager alarm = (AlarmManager)mCtx.getSystemService(AS);
long triggerAtTime = 0;
//Process the request
switch(type) {
case POLLING:
triggerAtTime = SystemClock.elapsedRealtime();
alarm.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime,
POLLING_INTERVAL_MS, mPollingEvent.getPendingIntent());
Log.d(TAG, "alarmRequest:Polling starts at " + System.currentTimeMillis());
break;
case REMINDER:
triggerAtTime = SystemClock.elapsedRealtime() + when;
alarm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, mReminderEvent.getPendingIntent());
Log.d(TAG, "alarmRequest:Reminder to be fired after " + when + " ms");
break;
}
The following are the codes of the EventRouter:
public class EventRouter extends BroadcastReceiver {
public static final String POLLING_ACTION = "com.xxxxxx.POLLING";
public static final String REMINDER_ACTION = "com.xxxxxx.REMINDER";
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "onReceive:Action=" + action);
if(POLLING_ACTION.equals(action)) {
//TODO: Polling handling
}
else if(REMINDER_ACTION.equals(action)) {
//TODO: Reminder handling to fire a status bar notification
}
}
}
The Android manifest for my app:
<application
...
...>
<activity
android:name=".AlarmActivity"
...>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<receiver android:name=".EventRouter" android:enabled="true" android:exported="true"/>
</application>
Both of the alarms are registered properly by executing the following command on terminal:
adb -d shell dumpsys alarm
However, only the POLLING alarm is delivered to my receiver. I have been struggling on this issue for a while and could not find a solution. Can you help to review the way I set up my pending intent to see if there is any mistake?
You should add your actions as an intent filter to your receiver declaration in your manifest file so that it can capture those actions.
<receiver android:name=".EventRouter" android:enabled="true" android:exported="true"
<intent-filter>
<action android:name="your.receiver.package.name.POLLING_ACTION"></action>
</intent-filter>
<intent-filter>
<action android:name="your.receiver.package.name.REMINDER_ACTION"></action>
</intent-filter>
<receiver/>
This is the first mistake that caught my eye.