I'm trying out alarms and have hit a wall. I don't think my alarm is setting up properly because I never get a confirmation after the alarm is supposed to go off. Here's how I call on the alarm manager:
long alarmtime=new GregorianCalendar().getTimeInMillis()+10*1000;//run after 10 seconds
Intent i = new Intent(this, AlarmReceiver.class);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
AlarmManager alarmman = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmman.cancel(pi); // cancel any existing alarms
alarmman.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
alarmtime, 10 * 1000, pi);//run every 10 seconds
And here's my AlarmReceiver.java:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "TEST", Toast.LENGTH_LONG).show();
}
}
However, the TEST text does not appear, and I can't figure out why.
Since you are using the AlarmManager.ELAPSED_REALTIME_WAKEUP argument, your initial alarm-time should be base on the elapsed real time of the device:
long alarmtime = SystemClock.elapsedRealtime() + 10 * 1000;
alarmman.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmtime, 10 * 1000, pi);
(see this link).
For a BroadcastReceiver it's probably PendingIntent.getBroadcast() instead of PendingIntent.getService(). You are also cancelling the alarm, just update your PendingIntent like this and try not cancelling before:
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
Read the documentation thoroughly for further information.
Make sure that the BroadcastReceiver is being called by doing a System.out.println("TEST"); instead of Toast. If you are able to see that in your logcat, then the problem probably is that you need to run the Toast in UI thread.
Related
I'm currently working on a notification that has to show at a specific time chosen by the user.
BUT when I run it, notifications show but not at the selected time, only when I ask the time in a timepickerdialog appear, before even choosing a time.
Does anyone know how to change the code so that notifications only appear at the time selected?
showDialog(DIALOG_ID); //this is the dialog that asks for an hour and minute.
alarmMethod1();
private void alarmMethod1(){
Calendar calendari1 = Calendar.getInstance();
calendari1.set(Calendar.HOUR_OF_DAY, hour_x);
calendari1.set(Calendar.MINUTE, minute_x);
calendari1.set(Calendar.SECOND, 00);
Intent myIntent1 = new Intent(Main2Activity.this, NotifyService1.class);
AlarmManager alarmManager1 = (AlarmManager) getSystemService(ALARM_SERVICE);
pendingIntent1 = PendingIntent.getService(Main2Activity.this, 0, myIntent1, 0);
alarmManager1.setRepeating(AlarmManager.RTC_WAKEUP, calendari1.getTimeInMillis(), 24 * 60 * 60 * 1000, pendingIntent1);
}
Then here is the class where the intent goes:
public class NotifyService1 extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#Override
public void onCreate(){
Uri sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationManager nNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Intent intent1 = new Intent(this.getApplicationContext(),Main3Activity.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent1, 0);
Notification mNotify = new Notification.Builder(this)
.setContentTitle("Hora d'entrenar!")
.setContentText("Clica per començar entrenament de pit i braços")
.setSmallIcon(R.drawable.logofinal)
.setContentIntent(pIntent)
.setSound(sound)
.build();
nNM.notify(1,mNotify);
}
}
Since Android API 19, all alarms are inexact in order to reduce battery consumption, that means that your alarms will not be triggered exactly when you want, but if you really need to do it, you need to use setExact and then write the repeat alarm handler by yourself, there's no longer a "set exact and repeat". Please, see:
http://developer.android.com/reference/android/app/AlarmManager.html#setRepeating(int, long, long, android.app.PendingIntent)
http://developer.android.com/reference/android/app/AlarmManager.html#setExact(int, long, android.app.PendingIntent)
Sorry for my bad English. I faced with the problem. I try to create persistent alarm notification. Alarm notification must start every 10 seconds. I am using Alarm Manager,but it doest't work. What i am doing wrong?
public class RemindReceiver extends BroadcastReceiver {
private Class<?> activityClass;
public RemindReceiver() {
}
public RemindReceiver(Class<?> activityClass) {
this.activityClass = activityClass;
}
#Override
public void onReceive(Context context, Intent intent) {
NotificationManager notifyManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(R.mipmap.ic_launcher, "Some Text", System.currentTimeMillis());
Intent intentTL = new Intent(context, activityClass);
notification.setLatestEventInfo(context, "Title", "Some Text",
PendingIntent.getActivity(context, 0, intentTL, PendingIntent.FLAG_CANCEL_CURRENT));
notification.flags = Notification.DEFAULT_LIGHTS | Notification.FLAG_AUTO_CANCEL;
notifyManager.notify(1, notification);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, System.currentTimeMillis(), 1000 * 5, pendingIntent);
}
public void setRemind(Context context) {
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, RemindReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, System.currentTimeMillis(), 1000 * 5 , pendingIntent);
}}
Fragment:
public class PersonListFragment extends Fragment {
private RemindReceiver remindReceiver;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.person_list_fragment_layout, container, false);
Button nextButton = (Button) rootView.findViewById(R.id.next_button);
ListView personListView = (ListView) rootView.findViewById(R.id.name_list_view);
List<Person> personList = PersonListGenerator.generate();
PersonListAdapter adapter = new PersonListAdapter(getActivity(), personList);
personListView.setAdapter(adapter);
Context context = getActivity().getApplicationContext();
remindReceiver = new RemindReceiver(PersonListActivity.class);
remindReceiver.setRemind(context);
remindReceiver.onReceive(getActivity(), new Intent());
nextButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), ExpandablePersonListActivity.class);
startActivity(intent);
}
});
return rootView;
}}
And piece of my Android Manifest:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<receiver android:name=".utility.RemindReceiver"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
If you really want to wake up every 10 seconds, consider the note at setRepeating():
Note: for timing operations (ticks, timeouts, etc) it is easier and
much more efficient to use Handler.
Apart from that, if you just test with 10 seconds, it is inaccurate by design as of API 19:
Note: as of API 19, all repeating alarms are inexact. If your
application needs precise delivery times then it must use one-time
exact alarms, rescheduling each time as described above. Legacy
applications whose targetSdkVersion is earlier than API 19 will
continue to have all of their alarms, including repeating alarms,
treated as exact.
Thus, the alarm will not be delivered within the 10 seconds, because it will be delayed.
For me, that meant sometimes waiting a minute or more for my alarm, which worked pre-API-19.
Thus, you can expect exact alarm wakeup behavior only if you do not use setRepeating.
(Apart from that, #Damian has the right direction with his answer that the times need to be matched): use either
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 1000 * 5,
1000 * 5,
pendingIntent);
or try the current system time:
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + 1000 * 5,
1000 * 5,
pendingIntent);
Please change your code to include the +1000 * 5. Else the alarm is scheduled at the moment of execution, and thus, passes.
Can you try SystemClock.elapsedRealtime() ?
e.g.:
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), 1000 * 5, pendingIntent);
I vaguely remember AlarmManager.ELAPSED_REALTIME_WAKEUP needing SystemClock.elapsedRealtime() and not System.currentTimeMillis()
I can't however find where I read this before. I will update when I find it.
edit:
According to: AlarmManager.set(int type, long triggerAtMillis, PendingIntent operation) sdk docs..
Parameters
type: One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC, or RTC_WAKEUP. triggerAtMillis time in milliseconds that the alarm should
go off, using the
appropriate: clock (depending on the alarm type).
operation: Action to perform when the alarm goes off; typically comes from IntentSender.getBroadcast().
I have some doubts that I would like to clear regarding the AlarmManager class in Android.
I have an app that needs to:
Allow the user to set a time.
Start an alarm.
Then, even if the app is closed, it should start up on the preset time and do a certain function (like button.performClick()) in the main activity.
So, I have successfully created an activity called alarm.java, created the layout in res\layout and added it to AndroidManifest.xml. Also, I have successfully set the alarm as follows in my alarm.java class:
onCreate(){
alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
intent = new Intent(context, MyActivity.class);
pi = PendingIntent.getBroadcast(this.getApplicationContext(), ALARM_ID, intent, 0);
}
onClick(){
cal.setTimeInMillis(System.currentTimeMillis());
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, minute);
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi);
Toast.makeText(getApplicationContext(), "Alarm Set For " + hour + ":" + minute + " " + ampm, Toast.LENGTH_LONG).show();
}
Now, in my MyActivity.java class, which is the main activity, I have added the BroadcastReceiver
public BroadcastReceiver AlarmReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
/*This is the part I got from SO for starting an activity from `BroadcastReceiver`
Intent i = new Intent();
i.setClassName("com.kanishka.nightstalker.homeautomation", "com.kanishka.nightstalker.homeautomation.MainActivity");
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);*/
Toast.makeText(getApplicationContext(), "APP STARTED", Toast.LENGTH_LONG).show();
button.performClick();
}
};
Obviously, this method isn't working as I see no Toast popping up after elapsed time. I kinda understand what the issue is, and I should be using a Service for this. But from what I know, AlarmManager itself runs in the background and SHOULD trigger the BroadcastReceiver of MyActivity.java on elapsed time. Where am I going wrong?
Where am I going wrong?
You are using setInexactRepeating(). Here, "inexact" means "not exact", and so the alarm will occur sometime within INTERVAL_DAY of your requested time.
You are taking the current time, then setting the hour and minute, which could result in a time in the past.
You are creating an Intent for MyActivity, which is probably not a BroadcastReceiver (or, if it is, MyActivity is a very odd name to choose).
If you want the alarm to go off "even if the app is closed", then you need to use a BroadcastReceiver that is registered in the manifest.
It is not possible to "do a certain function (like button.performClick()) in the main activity", as there will not be an activity "if the app is closed".
I am registering an Alarm manager in the onResume() state in my MainActivity.java (which is the main activity where the program start)
protected void onResume() {
super.onResume();
if (Helper.isNetworkAvailable(this)) {
Intent intent = new Intent(this, NewsIntentService.class);
PendingIntent pi = PendingIntent.getService(this, 0, intent, 0);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC, System.currentTimeMillis(),
10 * 60 * 1000, pi);
} else {
// nothing done
}
}
However I was getting inconsistent results, the following code runs good and with no errors, it shows that the PendingIntent should be fired at every 10 minutes but the results where on the following from logcat for example:
It starts working good:
2:00 pm (fired), 2:10 pm (fired), 2:30 pm (fired), ...
But after some time:
3:20 pm (fired), 3:27 pm (fired), 3:33 pm (fired), 3:38 pm (fired) ...
The question is at what life cycle of the activity it is best to register an AlarmManager and if what I did is correct what is the reason for the inconsistent run.
use the following code it worked for me:
1- private SharedPreferences prefs;
2-
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Launch SharedPreferences
prefs = getSharedPreferences("Alarm", MODE_PRIVATE);
3-
protected void onResume() {
super.onResume();
if(!prefs.getBoolean(Helper.ALARM_SET, false)) {
Intent intent = new Intent(this, NewsIntentService.class);
PendingIntent pi = PendingIntent.getService(this, 0, intent, 0);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC, System.currentTimeMillis(),
10 * 60 * 1000, pi);
Log.i(Helper.ALARM_SET, "Alarm is set.");
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(Helper.ALARM_SET, true);
editor.commit();
}
}
Explanation:
The Use SharedPreferences to save a boolean value AlARM_SET, simple precise and this code will work even if the phone has restarted or turned off.
Your onResume is getting called at those times, hence triggering the alarm and once again setting it for next ten minutes.
If your end result is to invoke a functionality on Alarm, try to set the next alarm there, call your alarm once in onCreate of your MainActivity.(Check for the first run, use a File for the same or just Shared Preference) Let the rest be handled by the service/function/code which is run upon triggering the alarm.
Check here for complete implementation.
The flow would be something like:
MainActivity--> onCreate--> Check if first run--> Yes--> Register Alarm and execute immediately--> Invoke function/code-->Let this code set the next alarm.
The docs for AlarmManager clearly state that repeating alarms are inexact -- hence the drift you observe via Logcat.
Note: as of API 19, all repeating alarms are inexact. If your application needs precise delivery times then it must use one-time exact alarms, rescheduling each time as described above. Legacy applications whose targetSdkVersion is earlier than API 19 will continue to have all of their alarms, including repeating alarms, treated as exact.
A block of the code that you can use:
public void schedule(final Context context) {
int alarmCode = YOUR_ALARM_CODE;
final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, alarmCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
final Calendar calendar = yourCalendar();
final AlarmManager alarm = (AlarmManager) context.getSystemService(Activity.ALARM_SERVICE);
final long time = calendar.getTimeInMillis();
alarm.set(AlarmManager.RTC_WAKEUP, time, pendingIntent);
}
I followed the instructions in this thread to create a daily alarm that starts a service at 12:30 each day which shows a notification. The problem I'm having is that setting the alarm also triggers the service (=> and the notification) every time the app starts.
Since I figured that the alarm will run only at the specified time (12:30) then I have no problem setting it when the app starts.
I realize that setting the alarm from scratch every time the app is launched is a bit ineffective since it only needs to be set once (I made it set on device boot as well), but it seemed like the easiest way.
So what's the best way to fix this? is there a way to set the alarm for the specified time without running the intent when setting?
Here's the code if you are interested (this function is called every time when launching the app):
public static void setAlarm(Context context)
{
Intent intent = new Intent(context, AlarmReceiver.class);
intent.setAction("com.Rani.app.SET_NOTIFICATION_ALARM");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
Calendar dailyCheckTime = Calendar.getInstance();
dailyCheckTime.setTimeZone(TimeZone.getTimeZone("GMT"));
dailyCheckTime.set(Calendar.HOUR_OF_DAY, 12);
dailyCheckTime.set(Calendar.MINUTE, 30);
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarm.cancel(pendingIntent);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, dailyCheckTime.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
}
thanks in advance.
After trying several things, I used the information in this thread to preform a check if an alarm already exists, and setting one only if there isn't one already.
code:
public static void setAlarm(Context context)
{
Intent intent = new Intent(context, AlarmReceiver.class);
intent.setAction("com.Rani.app.SET_NOTIFICATION_ALARM");
boolean alarmUp = (PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_NO_CREATE) != null);
// check if an alarm already exists
if (alarmUp == false)
{
// set an alarm in case there isnt one already set
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
Calendar dailyCheckTime = Calendar.getInstance();
dailyCheckTime.set(Calendar.HOUR_OF_DAY, 12);
dailyCheckTime.set(Calendar.MINUTE, 30);
if (dailyCheckTime.getTimeInMillis() < Calendar.getInstance()
.getTimeInMillis()) {
dailyCheckTime.set(Calendar.DATE,
dailyCheckTime.get(Calendar.DATE) + 1);
}
AlarmManager alarm = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
alarm.cancel(pendingIntent);
alarm.setRepeating(AlarmManager.RTC_WAKEUP,
dailyCheckTime.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
}
}