I've been trying to use AlarmManager.RTC_WAKEUP to wake up my device to play some sounds.
Here's the alarm scheduling:
Intent intent = new Intent(Main.this, OneShotAlarm.class);
PendingIntent sender = PendingIntent.getBroadcast(Main.this, 0, intent, 0);
// I want the alarm to go off 60 seconds from now.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 60);
// Schedule the alarm!
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(), sender);
The OneShotAlarm BroadCastReceiver:
public class OneShotAlarm extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "OneShotAlarm Broadcast invoked", 1000).show();
intent = new Intent(context, ServiceClassToRun.class);
context.startService(intent);
}
}
The Service:
public class ServiceClassToRun extends Service {
protected static final int Rnd = 0;
public void onStart(Intent intent, int startId) {
//do some business here
}
And finally, my manifest:
<receiver android:name=".OneShotAlarm" android:process=":remote" />
<service android:name=".ServiceClassToRun "/>
My service works fine when device is in wake up state.
Any ideas are greatly appreciated. Has anyone else experienced this as
well? Thanks in advance.
PendingIntent sender = PendingIntent.getBroadcast(Main.this, 0, intent, 0);
change to
PendingIntent sender = PendingIntent.getBroadcast(Main.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
OR, If you miss the permission of alarm, than add these permission
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
Let me know, If it's work for you
I doubt that this is still relevant for the author, but maybe it will be useful for someone else.
Probably the reason for the issue is that you do not acquire any wakelocks. System holds a wakelock for you while OneShotAlarm.onReceive is called. You start a service by sending an intent. But after the OneShotAlarm.onReceive returns, there are no held wakelocks left and the device goes to sleep. Therefore your intent will be only delivered when you manually wake up the device.
You can see an example with a wakelock here https://github.com/yuriykulikov/AlarmClock/blob/develop/src/com/better/alarm/model/AlarmsService.java
Best regards,
Yuriy
Your Service - ServiceClassToRun will be called 1 minute after you have set the alarm..But you won't come to know it as you havn't done anything in onStart() method.Also override onBind and onCreate methods.
You may implement Notification or play sound when onStart method of Service is called
You can ask if you have any further queries.
Related
my mean goal is to run a task periodically at midnight (00:00:00)
but the user can set the period based on the interval (daily, weekly , monthly)
let's assume that this job is a backup Scheduling.
this task will triggred at midnight but based on the user preference (midnight everyday, every week , or monthly ), and if the phone was in the doze mode or even off , wait untill the next start and start backup.
when i start implementing the code , i started with JobService and JobScheduler , but unfortunately i learned that i can set the repetitive but i can't set the exact time, so the last solution was to work with alarmmanager.
i use this code for triggering the alarm :
public static void setTheTimeToStartBackup(Context context,String periode) {
int DATA_FETCHER_RC = 123;
AlarmManager mAlarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
Intent intent = new Intent(context, BackUpAlarmRecevier.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, DATA_FETCHER_RC,intent, PendingIntent.FLAG_UPDATE_CURRENT);
long interval = 0;
switch (periode){
case "never":
return;
case "daily":
alarmStartTime.set(Calendar.HOUR_OF_DAY, 0);
interval = AlarmManager.INTERVAL_DAY;
break;
case "weekly":
alarmStartTime.set(Calendar.DAY_OF_WEEK, 1);
interval = AlarmManager.INTERVAL_DAY*7;
break;
case "monthly":
alarmStartTime.set(Calendar.WEEK_OF_MONTH, 1);
interval = AlarmManager.INTERVAL_DAY*30;
break;
}
alarmStartTime.set(Calendar.HOUR_OF_DAY, 0);
alarmStartTime.set(Calendar.MINUTE, 0);
alarmStartTime.set(Calendar.SECOND, 0);
mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),interval, pendingIntent);
Log.e("Alarm","Set for midnight");
}
this is my receiver :
public class BackUpAlarmRecevier extends BroadcastReceiver {
SharedPreferences preferences;
#Override
public void onReceive(Context context, Intent intent) {
Log.e("BackUpAlarmReciver","Triggred");
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "TAG:APP");
wl.acquire();
sendNotification(context);// simple notification...
Toast.makeText(context, "Alarm !!", Toast.LENGTH_LONG).show();
startBackupProcess();
wl.release();
}}
the problem is task never start.
so i went to test it with less time interval (15min as the minimum possible as i read ), so i change my first function setTheTimeToStartBackup to this :
public static void setTheTimeToStartBackup(Context context,String periode) {
int DATA_FETCHER_RC = 123;
AlarmManager mAlarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.SECOND, 55);
Intent intent = new Intent(context, BackUpAlarmRecevier.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, DATA_FETCHER_RC,intent, PendingIntent.FLAG_UPDATE_CURRENT);
mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),AlarmManager.INTERVAL_FIFTEEN_MINUTES, pendingIntent);
Log.e("Alarm","Set for midnight");
}
and exactly the same problem , nothing started, no log , no notification , nothing.
and i already set the Receiver in my manifest with all permission like that :
<receiver android:name=".job.BackUpAlarmRecevier"
android:enabled="true"
android:process=":remote"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
what im doing wrong in both cases ? and if it work , this code will persist for ever or i need to set it again each time ?
thanks :)
EDIT:
i call my function setTheTimeToStartBackup in the MainActivity.
You could set it to occur at midnight if you did the appropriate time calculations. Dynamically get the current time and date, calculate when to register the broadcast for the alarm manager. Customize the onReceive method to set another alarm at 12pm again.
Either way you can trigger a broadcast receiver by registering your receiver manually.
Broadcast receiver class:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
System.out.println("Alarm received!! ");
// Register alarm again here.
}
}
Code to register a receiver with a custom intent filter.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AlarmManager mAlarmManager = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
getApplicationContext().registerReceiver(new AlarmReceiver(), new IntentFilter("AlarmAction"));
PendingIntent broadcast = PendingIntent.getBroadcast(this, 0, new Intent("AlarmAction"), 0);
// Add dynamic time calculations. For testing just +100 milli.
mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 100, broadcast);
;
}
You could achieve what you wanted through a background service.
My suggestion would be to turn the problem around a bit.
Create three topics on Firebase (daily, weekly, monthly). Subscribe users to appropriate topics. Have a Firebase function that is triggered by CRON job which sends the data notification down to the device, this data notification should schedule one-time WorkManager job for the update. This way you can control everything from server-side, if the phone is off, it will still execute as soon as it turns on and you don't need to manually take care of catching the Boot completed with alarm manager etc.
My ReminderService uses the AlarmManager to inform the user about an upcoming event at a specific time. Is it possible that the AlarmManager informs the same service (ReminderService) or do I need to start another service to catch the pending intent? Until now this mechanism looks like this
public class ReminderService extends Service {
// ...
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// ..
/* When the alarm goes off the NotifyService will be started. Is it possible to inform **this**
service (ReminderService) and to handle the alarm? */
Intent alarmIntent = new Intent(this, NotifyService.class);
alarmIntent.putExtra(TodoTask.PARCELABLE_KEY, task);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, alarmIntent, 0);
Calendar calendar = Calendar.getInstance();
Date date = new Date(reminderTimeStamp*1000);
calendar.setTime(date);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
}
yes u can. You just need to change this line:
Intent alarmIntent = new Intent(this, NotifyService.class);
to this:
Intent alarmIntent = new Intent(this, ReminderService.class);
that way the ReminderService will receive the intent with TodoTask.PARCELABLE_KEY inside this same method public int onStartCommand(Intent intent, int flags, int startId)
Remember that there no guarantee that this will be the same instance of the service. If the service you're running get killed by the system a new instance of it will be started to handle the intent.
Also remember all the sleep and doze mode stuff mentioned by Larry_Schiefer on his answer.
You can use the same Service (or other component) to receive an alarm. However, not that your alarm will not be guaranteed to be delivered on schedule when in low power. Use a WakefulReceiver or your own combination of BroadcastReceiver and a wakelock to get your Service going. See this article for more details on power state and alarms.
Also, note that starting with Android Marshmallow your wakelocks will be ignored if the device is in Doze mode. There are other things you'll have to do to wake the device at a certain time when in Doze.
I have some existing code that spawns a service intent which does a bunch of stuff in the background. This code does work...
Intent serviceIntent = new Intent(context, APMService.class);
serviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(serviceIntent);
My question is: how to change this to use the AlarmManager.setInexactRepeating(...) methods?
I have changed the above code to this:
Intent serviceIntent = new Intent(context, APMService.class);
serviceIntent.putExtra("STARTED_BY", starter);
serviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//Set up recurring alarm that restarts our service if
// it crashes or if it gets killed by the Android OS
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getService(context, 0, serviceIntent, 0);
//am.cancel(pi);
am.setInexactRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP //wake up the phone if it's asleep
, cal.getTimeInMillis()
, 10000
, pi);
And I have added these permissions to AndroidManifest.xml...
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
<uses-permission android:name="com.android.alarm.permission.WAKE_LOCK"/>
My understanding is that this is supposed to start the service immediately and then try to restart it again every 10 seconds. But this code isn't working properly.
Using this new code, the service never starts at all and I cannot see why not. To complicate matters the debugger never seems to attach to the app in time to see what's going on.
Can anyone see what I'm doing wrong?
Put AlarmManager code under onDestroy() function of service to schedule start of service as below:
#Override
public void onDestroy() {
/**
* Flag to restart service if killed.
* This flag specify the time which is ued by
* alarm manager to fire action.
*/
final int TIME_TO_INVOKE = 5 * 1000; // try to re-start service in 5 seconds.
// get alarm manager
AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AutoStartServiceReceiver.class);
PendingIntent pendingIntent = PendingIntent
.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
// set repeating alarm.
alarms.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() +
TIME_TO_INVOKE, TIME_TO_INVOKE, pendingIntent);
}
And handle starting of your service in AutoStartServiceReceiver as below:
public class AutoStartServiceReceiver extends BroadcastReceiver {
private static final String TAG = AutoStartServiceReceiver.class.getSimpleName();
#Override
public void onReceive(Context context, Intent intent) {
// check broadcast action whether action was
// boot completed or it was alarm action.
if (intent.getAction().equals(AppConstants.ACTION_ALARM_INTENT)) {
context.startActivity(new Intent(context, YourActivity.class));
// handle service restart event
LockerServiceHelper.handleServiceRestart(context);
}
}
}
Kindly note that, your service will not restart if you stop it manually from settings-apps-running apps-your app.
Your service is not starting because of AlarmManager.ELAPSED_REALTIME_WAKEUP, while it should be using AlarmManager.RTC_WAKEUP
If you want to run every 10s keep in mind that above API 21 alarm intervals below 60s are rounded up to 60s.
Also, consider using WakefulIntentService
https://github.com/commonsguy/cwac-wakeful
Hi a read other question retated to this but the responses never resolve my issue.
I want to start a service after a specific time with an Alarm Manager
alarmMgr = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmServiceIntent=new Intent(ListActivity.this, AlarmLevelServiceImproved.class);
alarmServiceIntent.putExtra("username",usernameID);
alarmServiceIntent.putExtra("password",userPass);
alarmIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, alarmServiceIntent, 0);
. . .
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND,10);
//calendar.set(Calendar.HOUR_OF_DAY, 19);
//alarmMgr.setInexactRepeating(AlarmManager.RTC,calendar.getTimeInMillis(),
// AlarmManager.INTERVAL_HALF_HOUR,alarmIntent);
//alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
// 1000 * 10, alarmIntent);
alarmMgr.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), alarmIntent);
Log.d("MioLog", "Alarm setted");
My service is:
public class AlarmLevelServiceImproved extends Service {
#Override
public void onCreate() {
Log.d("MioLog","MyAlarmService.onCreate()");
Toast.makeText(this, "MyAlarmService.onCreate()", Toast.LENGTH_LONG).show();
}
#Override
public IBinder onBind(Intent intent) {
Log.d("MioLog","MyAlarmService.onBind()");
Toast.makeText(this, "MyAlarmService.onBind()", Toast.LENGTH_LONG).show();
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("MioLog","MyAlarmService.onDestroy()");
Toast.makeText(this, "MyAlarmService.onDestroy()", Toast.LENGTH_LONG).show();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("MioLog","MyAlarmService.onStart()");
Toast.makeText(this, "MyAlarmService.onStart()", Toast.LENGTH_LONG).show();
return super.onStartCommand(intent, flags, startId);
}
}
And I add this on AndroidManifest.xml (The service class is on the sub-package "services"):
<service
android:name=".services.AlarmLevelServiceImproved"
android:enabled="true" />
But the service don't start and no log is printed.
Any idea how to start a Service with the AlarmManager?
I also suived this tutorial but I don't find any difference to my code
Thanks
To start a service with a PendingIntent, you need to use the static method PendingIntent.getService() to retrieve the appropriate PendingIntent.
Your code seems to be using PendingIntet.getBroadcast() for whatever reason. If you intend to have the AlarmManager indeed send a broadcast, you can start your service in your BroadcastReceiver, else change that line to getService():
from
alarmIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, alarmServiceIntent, 0);
to
alarmIntent = PendingIntent.getService(getApplicationContext(), 0, alarmServiceIntent, 0);
You are using getBroadcast() to create the PendingIntent, but the Intent points to a service. That combination will not work.
Since you are using RTC_WAKEUP, you need to use getBroadcast() and a WakeLock to get reliable results. One approach is to use WakefulBroadcastReceiver as the base class of your receiver, where you then forward the work onto an IntentService.
Also, please do not pass user names and passwords in extras, as those are visible to anything that gets its hands on the Intent or PendingIntent. In this case, that should just be your app and the core OS, but I would still aim to do something a bit more secure.
I have a app that takes care of certain silence functions, but I can't make it work when the phone is sleeping and not connected to the computer. Everything works fine when the screen is on, but it stops working when the phone sleeps.
Any idea what I'm doing wrong? I have checked 100 other posts here, but I just can't identify my problem.
My Alarm manager that makes the intent:
Intent intent2 = new Intent(this, Silence.class);
PendingIntent pendingIntent2 = PendingIntent.getBroadcast(this, 1000 + id, intent2, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am2 = (AlarmManager)getSystemService(Activity.ALARM_SERVICE);
am2.setRepeating(AlarmManager.RTC_WAKEUP, cal2.getTimeInMillis(), AlarmManager.INTERVAL_DAY * 7, pendingIntent2);
Broadcast Receiver:
public class MainSilenceCatcherVibrate extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent1) {
WakeLocker.acquire(context);
System.out.println("test");
WakeLocker.release();
}
}
Manifest usage:
<uses-permission android:name="android.permission.WAKE_LOCK" />
<receiver android:name=".Silence"></receiver>
<activity android:name=".ContactActivity"></activity>
i just cant identify my problem
Your event will happen once immediately, then not again for a week (AlarmManager.INTERVAL_DAY * 7,). Perhaps you did not wait a week.
Note that you do not need WakeLocker here -- so long as all your work is in onReceive(), the system will hold a WakeLock for you. If you have work that will take more than a millisecond or so, you will not want to do that in onReceive(), but in that case I would recommend WakefulBroadcastReceiver or my WakefulIntentService over rolling your own WakeLock solution.