Alarm just wont get called - android

I am calling a Alarm from a service ScheduleAdvanceBookingService to call another service SendRequestAdvanceBookingService at a predetermined time.
Manifest file has
<service
android:name=".ScheduleAdvanceBookingService"
android:enabled="true"
android:label="#string/app_name" />
<service
android:name=".SendRequestAdvanceBookingService"
android:enabled="true"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.NOTIFY" />
</intent-filter>
</service>
My calling code has
public class ScheduleAdvanceBookingService extends IntentService {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
protected void onHandleIntent(Intent intent) {
Intent newIntent = new Intent(this,
SendRequestAdvanceBookingService.class);
Date startTime = (Date) intent.getSerializableExtra("startTime");
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
newIntent.setAction("android.intent.action.NOTIFY");
autoBookingAlarm = (AlarmManager) this
.getSystemService(Context.ALARM_SERVICE);
autoBookingPendingIntent = PendingIntent.getService(this, 0, newIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
Calendar cal = Calendar.getInstance();
cal.setTime(startTime);
long alarmCallTime = cal.getTimeInMillis();
autoBookingAlarm.set(AlarmManager.RTC_WAKEUP, alarmCallTime,
autoBookingPendingIntent);
Log.d("Taxeeta", "Scheduled a Auto Advance Booking #"
+ cal.getTime().toLocaleString());
My future alarm'ed Service is
public class SendRequestAdvanceBookingService extends Service {
public SendRequestAdvanceBookingService() {
super();
handler = new Handler();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("Taxeeta", "Start - SEND REQUEST.");
Debug statement to check the date
08-20 13:40:14.008: D/Taxeeta(31578): Scheduled a Auto Advance Booking #20 Aug 2014 13:41:37
What am I missing here ?
I have tried
Removing the intent-fiter and the addAction, still wont fire
Using startTime directly instead of using cal.setTime(startTime) cal.getTimeInMilli()

The fix was simple and non documented anywhere.
I ran ./adb shell dumpsys alarm > ~/dump.txt and searched for my alarms on my device. I found many pending alarms on the device for my app. This prompted me to clean up, and a Force Close from Settings->Application->MyApp->Force Close, cleaned up the alarms.
Then I ran my app, and it worked. Only after a while I realized that phones that did not have the app running earlier worked well, and that hinted me to the cleanup again.
So all I needed to do was
autoBookingAlarm.cancle(autoBookingPendingIntent);
before the
autoBookingAlarm.set(AlarmManager.RTC_WAKEUP, alarmCallTime,
autoBookingPendingIntent);
This will cancel previous alarms before scheduling a new one.

Related

Alarm is killed when OS kills app

My alarm is killed when OS kills the app. I thought that was one of the points of an Alarm, that it would keep running even though OS killed the app? I check the life of the Alarm using the "./adb shell dumpsys alarm" command, and every time OS kills my app, the Alarm is also gone. How I start my Alarm:
public static void startLocationAlarm(Context context){
if(ActivityLifecycleHandler.isApplicationInForeground()) {
return; // If App is in foreground do not start alarm!
}
String alarm = Context.ALARM_SERVICE;
AlarmManager am = ( AlarmManager ) context.getSystemService( alarm );
Intent intent = new Intent(locationBroadcastAction);
PendingIntent pi = PendingIntent.getBroadcast( context.getApplicationContext(), 0, intent, 0 );
int type = AlarmManager.ELAPSED_REALTIME_WAKEUP;
long interval = ONE_MINUTE;
long triggerTime = SystemClock.elapsedRealtime() + interval;
am.setRepeating(type, triggerTime, ONE_MINUTE, pi );
}
To add some more context, I am trying do some location operation in a service (not IntentService) in background. Here is my receiver. Used Wakeful because I did not want the service to be killed before it was done.
public class LocationBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent ) {
Intent myIntent = new Intent( context, LocationServiceAlarmOwnGoogleClient.class );
//context.startW( myIntent );
LocationBroadcastReceiver.startWakefulService(context, myIntent);
}
}
For some more information: I cancel the alarm in OnStart method of several activities that the user can return to after having it in the background. I do not know if that can cause this weird behaviour? Here is my cancel method:
public static void stopLocationAlarm(Context context){
Intent intent = new Intent(locationBroadcastAction);
PendingIntent sender = PendingIntent.getBroadcast(context.getApplicationContext(), 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
You can add service which listens to the phone's turning on callback.
add this permission into the manifest
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
and register reciever
<receiver android:name=".util.notification.local.MyBootCompletedService">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
public class MyBootCompletedService extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
AlarmReceiver.startLocalNotificationService(context);
}
}
The error that caused the Alarm to be canceled had actually nothing to do with the code, but had to do with special battery settings on Huawei devices. If your app is not set as "protected" in "protected apps", the system will cancel your alarm when it kills the app. Adding your app to "protected apps" will solve this problem. Same goes for Xiaomi devices. Have to add them to "Protected apps", then the Alarm will work as intended. Thank you #CommonsWare for leading me to the solution.

How to really update a widget precisely every minute

I'm stumped. I know this question has already been answered a hundred times but nothing I've tried works.
My question: I made an Android widget that needs to refresh precisely at each minute, much like all clock widgets do. (This widget tells me in how many minutes are left before my train leaves, a one minute error makes it useless).
Here are my attempts to far, and the respective outcomes:
I put android:updatePeriodMillis="60000" in my appwidget_info.xml. However, as specified in API Docs, "Updates requested with updatePeriodMillis will not be delivered more than once every 30 minutes" and indeed that's about how often my widget gets updated.
I tried using an AlarmManager. In my WidgetProvider.onEnabled:
AlarmManager am = (AlarmManager)context.getSystemService
(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
long now = System.currentTimeMillis();
// start at the next minute
calendar.setTimeInMillis(now + 60000 - (now % 60000));
am.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), 60000,
createUpdateIntent(context));
however as stated in the API docs, "as of API 19, all repeating alarms are inexact" and indeed my widget actually gets updated every five minutes or so.
Based on the previous point I tried setting targetSdkVersion to 18 and saw no difference (updates every five minutes or so).
The setRepeating documentation seems to recommend using setExact. I tried the following. At the end of my update logic:
Calendar calendar = Calendar.getInstance();
long now = System.currentTimeMillis();
long delta = 60000 - (now % 60000);
Log.d(LOG_TAG, "Scheduling another update in "+ (delta/1000) +" seconds");
calendar.setTimeInMillis(now + delta);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setExact(AlarmManager.RTC, calendar.getTimeInMillis(), //UPDATE_PERIOD_SECONDS * 1000,
createUpdateIntent(context));
It works perfectly for a couple minutes and then reverts to updating every five minutes or so (and not even near minute changes). Here are some timestamps of when the update intent is received:
21:44:17.962
21:52:37.232
21:59:13.872
22:00:00.012 ← hey suddenly it becomes exact again??
22:01:47.352
22:02:25.132
22:06:56.202
Some recommend using a Handler. I defined a Service which I start when the widget provider is enabled, and does this after update code:
int delay = (int)(60000 - (System.currentTimeMillis() % 60000));
Log.d(LOG_TAG, "Scheduling another update in " + delay/1000 + " seconds");
new Handler().postDelayed(new Runnable() {
public void run() {
Log.d(LOG_TAG, "Scheduled update running");
updateAppWidget();
}
}, delay);
and this one works perfectly for several hours, but then the service gets suddenly killed and gets "scheduled to restart after HUGE delay". Concretely, the widget just gets stuck at some point and doesn't get updated at all.
Some other options I've seen online: the linked post above suggests creating a foreground service (which, if I understand correctly, means having a permanently visible icon in my already crowded status bar. I don't have one permanent icon for each clock widget I use so that should not be necessary). Another suggestion is to run a high priority thread from the service, which feels awfully overkill.
I've also seen recommendations to use Timers and BroadcastReceivers but the former is said to be "not appropriate for the task" and I remember having trouble doing the latter. I think I had to do it in a service and then the service gets killed just like when I use Handlers.
It should be noted that the AlarmManager seems to work well when the phone is connected to the computer (presumably because it means the battery is charging), which doesn't help because most of the time I want to know when my train will leave is when I'm already on the way...
As the Handler is perfectly accurate but just stops working after a while, and the AlarmManager option is too inaccurate but does not stop working, I'm thinking of combining them by having AlarmManager start a service every ten minutes or so, and have that service use a Handler to update the display each minute. Somehow I feel this will get detected by Android as a power hog and get killed, and anyway I'm sure I must be missing something obvious. It shouldn't be that hard to do what's essentially a text-only clock widget.
EDIT: if it matters, I'm using my widget on a Samsung Galaxy Note 4 (2016-06-01) with Android 6.0.1.
Sorry, i totally forgot, was busy.. Well, i hope you got the idea of what you need, snippets are following, hope i dod not forgot something.
on the widget provider class.
public static final String ACTION_TICK = "CLOCK_TICK";
public static final String SETTINGS_CHANGED = "SETTINGS_CHANGED";
public static final String JOB_TICK = "JOB_CLOCK_TICK";
#Override
public void onReceive(Context context, Intent intent){
super.onReceive(context, intent);
preferences = PreferenceManager.getDefaultSharedPreferences(context);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
ComponentName thisAppWidget = new ComponentName(context.getPackageName(), WidgetProvider.class.getName());
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget);
if (intent.getAction().equals(SETTINGS_CHANGED)) {
onUpdate(context, appWidgetManager, appWidgetIds);
if (appWidgetIds.length > 0) {
restartAll(context);
}
}
if (intent.getAction().equals(JOB_TICK) || intent.getAction().equals(ACTION_TICK) ||
intent.getAction().equals(AppWidgetManager.ACTION_APPWIDGET_UPDATE)
|| intent.getAction().equals(Intent.ACTION_DATE_CHANGED)
|| intent.getAction().equals(Intent.ACTION_TIME_CHANGED)
|| intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
restartAll(context);
onUpdate(context, appWidgetManager, appWidgetIds);
}
}
private void restartAll(Context context){
Intent serviceBG = new Intent(context.getApplicationContext(), WidgetBackgroundService.class);
context.getApplicationContext().startService(serviceBG);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
scheduleJob(context);
} else {
AppWidgetAlarm appWidgetAlarm = new AppWidgetAlarm(context.getApplicationContext());
appWidgetAlarm.startAlarm();
}
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void scheduleJob(Context context) {
ComponentName serviceComponent = new ComponentName(context.getPackageName(), RepeatingJob.class.getName());
JobInfo.Builder builder = new JobInfo.Builder(0, serviceComponent);
builder.setPersisted(true);
builder.setPeriodic(600000);
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
int jobResult = jobScheduler.schedule(builder.build());
if (jobResult == JobScheduler.RESULT_SUCCESS){
}
}
#Override
public void onEnabled(Context context){
restartAll(context);
}
#Override
public void onDisabled(Context context){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.cancelAll();
} else {
// stop alarm
AppWidgetAlarm appWidgetAlarm = new AppWidgetAlarm(context.getApplicationContext());
appWidgetAlarm.stopAlarm();
}
Intent serviceBG = new Intent(context.getApplicationContext(), WidgetBackgroundService.class);
serviceBG.putExtra("SHUTDOWN", true);
context.getApplicationContext().startService(serviceBG);
context.getApplicationContext().stopService(serviceBG);
}
WidgetBackgroundService
public class WidgetBackgroundService extends Service {
private static final String TAG = "WidgetBackground";
private static BroadcastReceiver mMinuteTickReceiver;
#Override
public IBinder onBind(Intent arg0){
return null;
}
#Override
public void onCreate(){
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent != null) {
if (intent.hasExtra("SHUTDOWN")) {
if (intent.getBooleanExtra("SHUTDOWN", false)) {
if(mMinuteTickReceiver!=null) {
unregisterReceiver(mMinuteTickReceiver);
mMinuteTickReceiver = null;
}
stopSelf();
return START_NOT_STICKY;
}
}
}
if(mMinuteTickReceiver==null) {
registerOnTickReceiver();
}
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
#Override
public void onDestroy(){
if(mMinuteTickReceiver!=null) {
unregisterReceiver(mMinuteTickReceiver);
mMinuteTickReceiver = null;
}
super.onDestroy();
}
private void registerOnTickReceiver() {
mMinuteTickReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent){
Intent timeTick=new Intent(WidgetProvider.ACTION_TICK);
sendBroadcast(timeTick);
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(mMinuteTickReceiver, filter);
}
}
RepeatingJob class
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class RepeatingJob extends JobService {
private final static String TAG = "RepeatingJob";
#Override
public boolean onStartJob(JobParameters params) {
Log.d(TAG, "onStartJob");
Intent intent=new Intent(WidgetProvider.JOB_TICK);
sendBroadcast(intent);
return false;
}
#Override
public boolean onStopJob(JobParameters params) {
return false;
}
}
AppWidgetAlarm class
public class AppWidgetAlarm {
private static final String TAG = "AppWidgetAlarm";
private final int ALARM_ID = 0;
private static final int INTERVAL_MILLIS = 240000;
private Context mContext;
public AppWidgetAlarm(Context context){
mContext = context;
}
public void startAlarm() {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MILLISECOND, INTERVAL_MILLIS);
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(WidgetProvider.ACTION_TICK);
PendingIntent removedIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
Log.d(TAG, "StartAlarm");
alarmManager.cancel(removedIntent);
// needs RTC_WAKEUP to wake the device
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), INTERVAL_MILLIS, pendingIntent);
}
public void stopAlarm()
{
Log.d(TAG, "StopAlarm");
Intent alarmIntent = new Intent(WidgetProvider.ACTION_TICK);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
}
manifest
<receiver android:name=".services.SlowWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<intent-filter>
<action android:name="CLOCK_TICK" />
</intent-filter>
<intent-filter>
<action android:name="JOB_CLOCK_TICK" />
</intent-filter>
<intent-filter>
<action android:name="SETTINGS_CHANGED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.TIME_SET" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.TIMEZONE_CHANGED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.DATE_CHANGED" />
</intent-filter>
<intent-filter>
<action android:name="android.os.action.DEVICE_IDLE_MODE_CHANGED"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.ACTION_DREAMING_STOPPED" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/slow_widget_info" />
</receiver>
<service
android:name=".services.RepeatingJob"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true"/>
<service android:name=".services.WidgetBackgroundService" />
The code snippets provided by #Nikiforos was a blessing for me, although I've felt into many problems when using them on Android 8, thus I decided to let you know how I've solved my issues. There are two problems related with the snippets provided:
they use BackgroundService which is now forbidden in some cases in Android 8
they use implicit broadcasts which have also been restricted in Android O (you can read about why it happened here)
To address first issue I had to switch from BackgroundService to ForegroundService. I know this is not possible in many cases, but for those who can do the change here are the instructions to modify the codes:
Change the restartAll() function as follows:
private void restartAll(Context context){
Intent serviceBG = new Intent(context.getApplicationContext(), WidgetBackgroundService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// for Android 8 start the service in foreground
context.startForegroundService(serviceBG);
} else {
context.startService(serviceBG);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
scheduleJob(context);
} else {
AppWidgetAlarm appWidgetAlarm = new AppWidgetAlarm(context.getApplicationContext());
appWidgetAlarm.startAlarm();
}
}
Update the onStartCommand() function in your WidgetBackgroundService code:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// for Android 8 bring the service to foreground
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
startForeground(1, buildForegroundNotification("Test 3"));
if(intent != null) {
if (intent.hasExtra("SHUTDOWN")) {
if (intent.getBooleanExtra("SHUTDOWN", false)) {
if(mMinuteTickReceiver!=null) {
unregisterReceiver(mMinuteTickReceiver);
mMinuteTickReceiver = null;
}
stopSelf();
return START_NOT_STICKY;
}
}
}
if(mMinuteTickReceiver==null) {
registerOnTickReceiver();
}
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
Add sendImplicitBroadcast() function to your WidgetBackgroundService:
private static void sendImplicitBroadcast(Context ctxt, Intent i) {
PackageManager pm=ctxt.getPackageManager();
List<ResolveInfo> matches=pm.queryBroadcastReceivers(i, 0);
for (ResolveInfo resolveInfo : matches) {
Intent explicit=new Intent(i);
ComponentName cn=
new ComponentName(resolveInfo.activityInfo.applicationInfo.packageName,
resolveInfo.activityInfo.name);
explicit.setComponent(cn);
ctxt.sendBroadcast(explicit);
}
}
Modify registerOnTickReceiver() function in the following way:
private void registerOnTickReceiver() {
mMinuteTickReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent){
Intent timeTick=new Intent(LifeTimerClockWidget.ACTION_TICK);
// for Android 8 send an explicit broadcast
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
sendImplicitBroadcast(context, timeTick);
else
sendBroadcast(timeTick);
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(mMinuteTickReceiver, filter);
}
Hope it helps!
Use the widget itself as the host for the delayed runnable. Widgets have a postDelayed method.
If the widget is killed and recreated, then also recreate the runnable as part of the basic initialization.
Edit:
The above suggestion was based on the inaccurate assumption that the OP was writing a custom view, not an app widget. For an app widget my best suggestion is:
create a foreground service with ONE icon.
the service manages all widgets and clicking on the notification icon will show the various reminders that are active and/allow them to be managed
There is no correct and fully working answer to widget update every minute. Android OS developer purposely exclude such feature or api in order to save the battery and workload.
For my case, I tried to create clock homescreen appwidget and tried many attempt on alarm manager, service etc.
None of them are working correctly.
For those who want to create Clock Widget, which need update time everyminute precisely.
Just use
<TextClock
android:id="#+id/clock"
style="#style/widget_big_thin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|top"
android:ellipsize="none"
android:format12Hour="#string/lock_screen_12_hour_format"
android:format24Hour="#string/lock_screen_24_hour_format"
android:includeFontPadding="false"
android:singleLine="true"
android:textColor="#color/white" />
for digital clock text view and
For Analog Clock
<AnalogClock xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/analog_appwidget"
android:dial="#drawable/appwidget_clock_dial"
android:hand_hour="#drawable/appwidget_clock_hour"
android:hand_minute="#drawable/appwidget_clock_minute"
android:layout_width="match_parent"
android:layout_height="match_parent" />
I've found those code from Google Desk Clock Opensource Project. You may already know Google Clock has such widget which update precisely every minute.
To learn more
Google Desk Clock Opensource Repo
Try this code
Intent intent = new Intent(ACTION_AUTO_UPDATE_WIDGET);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) + 1);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmMgr.setInexactRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), 60 * 1000, alarmIntent);

Android Service stops automatically

I am making an application with a feature of alarms in it. I am using service for this which keeps checking the current time of device against the times in my DB.
My problem is that this service stops if the app removed from the background or if the device is rebooted. I have used START_STICKY to keep it running in background and used a broadcast receiver to start it on reboot.
The major concern is that whatever I have coded is working on a MOTO G device. Reboot, clearing from background, everything, the service is running fine. But in Xiomi phones and Huawei Honour, It stops once cleared from background or rebooted.
The Service code:
public class RemindService extends Service {
final long delayMillis=500;
Handler h=null;
Runnable r;
SharedPreferences sp;
PendingIntent pendingIntent;
private static final int NOTIFY_ME_ID=1337;
#Override
public void onCreate() {
h=new Handler(Looper.getMainLooper());
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags,int startId) {
r = new Runnable() {
public void run() {
//SOME OF MY IF-ELSE CONDITIONS
Intent myIntent = new Intent(RemindService.this, ReminderPopUp.class);
int randomPIN = (int)(Math.random()*9000)+1000;
pendingIntent = PendingIntent.getActivity(RemindService.this, randomPIN, myIntent,PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager)getSystemService(Activity.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC|AlarmManager.RTC_WAKEUP, System.currentTimeMillis() , pendingIntent);
h.postDelayed(this, delayMillis);
}
};
h.post(r);
return Service.START_STICKY;
}
#Override
public void onDestroy() {
h.removeCallbacks(r);
}
}
My Manifest declarations:
<service
android:name="test.aguai.medieazy.RemindService"
android:enabled="true" />
<intent-filter>
<action android:name="test.aguai.medieazy.START_SERVICE" />
</intent-filter>
Has anybody else faced this problem? I think it is a problem of modified OS, but anyways my app is not working properly. Please Help.
Rather than poll the device database constantly, I would make use of the AlarmManager service as I described in this answer:
Android Polling from a Server periodically
Set up the alarm to fire at the first scheduled time. When it fires, set up the next time and so on. There is no need to set up every alarm at once as only one can ever fire at a time.
When the alarm fires, you can start a service to perform whatever task you need (including the setting of the next alarm)
Try Lik this it will Work
// for Every 6 minutes exact repeating service
Intent myIntent2 = new Intent(sign_in.this,MyAlarmService.class);
pendingintent3 = PendingIntent.getService(sign_in.this, 2,myIntent2, 2);
AlarmManager alarmManager2 = (AlarmManager) getSystemService(ALARM_SERVICE);
Calendar calendar2 = Calendar.getInstance();
calendar2.setTimeInMillis(System.currentTimeMillis());
calendar2.add(Calendar.SECOND, 30);
alarmManager2.set(AlarmManager.RTC_WAKEUP,calendar2.getTimeInMillis(), pendingintent3);
alarmManager2.setRepeating(AlarmManager.RTC_WAKEUP,calendar2.getTimeInMillis(), 360 * 1000,pendingintent3);
manifest permission
<!-- Web data Sync Service -->
<service android:name="com.example.MyAlarmService" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</service>
If you want your service to be running until explicitly stopped then consider calling startService(), to start the service. This allows the service to run indefinitely, and also allow a client to bind to the service by calling bindService().
Remember you must explicitly stop the service, by calling stopSelf() or stopService().

Android Service won't run from AlarmManager

I have a problem with running a service from Alarm manager.
I am building an app that notifies the owner on the namedays of his facebook friends. It all works nicely, but the notification won't show up.
I've set up an AlarmTask that creates the PendingIntent and sets the AlarmManager, like this:
public void run() {
// Request to start are service when the alarm date is upon us
Intent intent = new Intent(context, NotifyService.class);
intent.putExtra(NotifyService.INTENT_NOTIFY, true);
intent.putExtra("notifyID", ID);
PendingIntent pendingIntent = PendingIntent.getService(context, ID, intent, 0);
// Sets an alarm - note this alarm will be lost if the phone is turned off and on again
am.set(AlarmManager.RTC_WAKEUP, date.getTimeInMillis(), pendingIntent);
}
The ID is specific for every nameday.
Now in my NotifyService, I have set up these:
#Override
public void onCreate() {
super.onCreate();
System.out.println("NOTIFICATION SERVICE onCreate()");
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
System.out.println("INTENT RECIEVED: " + intent + " " + flags + " " + startId);
// If this service was started by out AlarmTask intent then we want to show our notification
if(intent.getBooleanExtra(INTENT_NOTIFY, false)){
int ID = intent.getIntExtra("notifyID", -1);
showNotification(ID);
}
// We don't care if this service is stopped as we have already delivered our notification
return START_STICKY;
}
Both the methods are executed once when I start the app, but when the notification should come up, nothing happens.
Is there a way to test if the AlarmManager really executes the PendingIntent?
Should I rather use IntentService? Why/how?
Thanks a lot.
I tried to change it to BroadcastReciever, looking like this:
public class NotificationBroadcastReciever extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
System.out.println("BROADCAST RECIEVED");
}
}
The AlarmTask bit is changed to this:
Intent intent = new Intent("NotificationBroadcast");
intent.putExtra(NotifyService.INTENT_NOTIFY, true);
intent.putExtra("notifyID", ID);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), ID, intent, 0);
System.out.println("date for notification: " + date.get(Calendar.DAY_OF_MONTH) + "." + date.get(Calendar.MONTH) + "." + date.get(Calendar.YEAR));
System.out.println("epoch time in milils: " + date.getTimeInMillis());
// Sets an alarm - note this alarm will be lost if the phone is turned off and on again
am.set(AlarmManager.RTC_WAKEUP, date.getTimeInMillis(), pendingIntent);
and relevant manifest part looks like this:
<receiver
android:name="cz.cvut.kubispe2.jmeniny.NotificationBroadcastReciever"
android:exported="false">
<intent-filter>
<action android:name="NotificationBroadcast" />
</intent-filter>
</receiver>
I checked if the date that is to be set is equal to the epoch time and it is, but still, the onRecieve method is never called.
Both the methods are executed once when I start the app, but when the notification should come up, nothing happens.
_WAKEUP alarms are only guaranteed to wake up the device if they route to a BroadcastReceiver, not a Service. So long as what you are doing is very short (1-2 milliseconds), you can safely do that work in onReceive() of a BroadcastReceiver. The work you are presently doing in your Service would qualify.
Beyond that, use adb shell dumpsys alarm to confirm that your alarm is scheduled for when you think it is.
Should I rather use IntentService?
It would certainly be a better option than a regular Service, which you are leaking in your current implementation. However, the _WAKEUP limitation still holds, which is why I wrote WakefulIntentService, to help bridge the gap. Again, though, with the current limited work you are doing, just using a BroadcastReceiver should suffice.
try using application context.
PendingIntent pendingIntent = PendingIntent.getService(context.getApplicationContext(), ID, intent, 0);
And work with android logs. Then you will see if it's running in your console
Seems like I finally resolved it, I used the broadcast reciever, and found out where the error was - Calendar takes the month argument from 0 to 11, instead of 1-12, which I thought, since all the other arguments are dealt with normally. So I was just putting up a notification for the end of May, instead of today, when testing.
Anyway, thank you all for help, it was very appreciated.

Stop unBound service in Android

I have a service that autoupdates a database in a given time interval. To do this it gets information from the Internet.
I need to have it unbound, so that It runs over all activities. But when the application is closed, it would be nice to terminate the service. To prevent battery drain. How can this be achieved?
I think that you should let your service be started by a boot broadcastReceiver, then ask AlarmManager to relaunch it every now and then.
public class DbUpdateService extends Service {
//compat to support older devices
#Override
public void onStart(Intent intent, int startId) {
onStartCommand(intent, 0, startId);
}
#Override
public int onStartCommand (Intent intent, int flags, int startId){
//your method to update the database
UpdateTheDatabaseOnceNow();
//reschedule me to check again tomorrow
Intent serviceIntent = new Intent(DbUpdateService.this,DbUpdateService.class);
PendingIntent restartServiceIntent = PendingIntent.getService(DbUpdateService.this, 0, serviceIntent,0);
AlarmManager alarms = (AlarmManager)getSystemService(ALARM_SERVICE);
// cancel previous alarm
alarms.cancel(restartServiceIntent);
// schedule alarm for today + 1 day
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, 1);
// schedule the alarm
alarms.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), restartServiceIntent);
return Service.START_STICKY;
}
}
To start your service at boot time use this :
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class serviceAutoLauncher extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(context,DbUpdateService.class);
context.startService(serviceIntent);
}
}
Finally add this to your manifest to schedule your serviceAutoLauncher to be launched at each boot:
<receiver android:name="serviceAutoLauncher">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
<category android:name="android.intent.category.HOME"></category>
</intent-filter>
</receiver>
Use the stopService method.
It depends on how you start the service. If you start it when your Activity is opened, then call stopService in your Activities onDestroy().

Categories

Resources