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().
Related
I currently have a small project running in Android Studio that I need help with. I want to include a reminder function with notifications.
I have a total of 4 time pickers for each of which I want to set an alarm at the corresponding selected time.
With my current code the planned feature works only halfway, with the following problem:
If I select one time, then I sometimes get a notification at this time as desired. However, not always on time. Most of the time the alert doesn't appear and if it does, then half a minute to a minute later. And if I set all 4 alarms, in the best case I get a notification at the last selected time. In the worst case nothing happens.
But all I want is to get daily notifications at the selected 4 times.
About my code, I use an alarm manager which I call 4 times for the 4 alarms. I also use a broadcast receiver in which the notification is triggered. And I use a different RequestCode for each PendingIntent.
I really searched all relevant posts on SO, but not one of them worked for me. Maybe I have included it in the wrong way. I hope someone can help me. Here are my methods:
Alarm method from Activity.class
(UhrzeitInMillis describes the chosen time by timepicker, for example 16.03):
public void SetAlarm(Context context, long UhrzeitInMillis) {
Intent intent = new Intent(context, Optionen_Alarm.class);
final int id = (int) System.currentTimeMillis();
PendingIntent pendingIntent = PendingIntent.getBroadcast(
this.getApplicationContext(), id, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, UhrzeitInMillis, AlarmManager.INTERVAL_DAY, pendingIntent);
}
BroadcastReceiver (Optionen_Alarm.java):
public class Optionen_Alarm extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "myapp:mywakelocktag");
wl.acquire();
createNotificationChannel(context);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "1");
builder.setContentTitle("titel");
builder.setContentText("text!");
builder.setSmallIcon(R.drawable.picture);
builder.setColor(context.getResources().getColor(R.color.red));
builder.setVibrate(new long[]{0, 300, 300, 300});
builder.setLights(Color.WHITE, 1000, 5000);
builder.setAutoCancel(true);
builder.setPriority(NotificationCompat.PRIORITY_HIGH);
builder.setStyle(new NotificationCompat.BigTextStyle().bigText("text!"));
Intent notifyIntent = new Intent(context, Activity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 2, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(pendingIntent);
Notification notificationCompat = builder.build();
NotificationManagerCompat managerCompat = NotificationManagerCompat.from(context);
managerCompat.notify(15, notificationCompat);
wl.release();
private void createNotificationChannel(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "name";
String description = "description";
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel("1", name, importance);
channel.setDescription(description);
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
}
```java
For battery reason, from android 6.0 the time you set on the alarm manager will not be guaranteed to trigger at the exact same time you have set. You could use the method '''setExactAndAllowWhileIdle()''' to make the alarm behave like you want.
You can read more about this here https://developer.android.com/training/scheduling/alarms
A lot of questions on this topic have outdated answers (1-4 years old).
How To give notifications on android on specific time?
How To give notifications on android on specific time in Android Oreo?
Repeat notification every day 12h
The documentation for android did not lead me to specific solutions but helped me understand AlarmManager and the NotificationCompat. My code looks like this in my MainActivity
Intent notifyIntent = new Intent(this, MyReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, NOTIFICATION_REMINDER,
notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, hours);
calendar.set(Calendar.MINUTE, minutes);
calendar.set(Calendar.SECOND, seconds);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY,
pendingIntent);
My BroadcastReceiver looks like this
public class MyReceiver extends BroadcastReceiver {
public MyReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Test", "RAN");
Intent intent1 = new Intent(context, MyNewIntentService.class);
context.startService(intent1);
}
}
My IntentService looks like this
public class MyNewIntentService extends IntentService {
private static final int NOTIFICATION_ID = 3;
public MyNewIntentService() {
super("MyNewIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("SH",
"Simple",
NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription("Notifs");
mNotificationManager.createNotificationChannel(channel);
}
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext(), "SH")
.setSmallIcon(R.mipmap.ic_launcher) // notification icon
.setContentTitle("Title") // title for notification
.setContentText("Message")// message for notification
.setAutoCancel(true); // clear notification after click
Intent intent1 = new Intent(getApplicationContext(), MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pi);
mNotificationManager.notify(0, mBuilder.build());
}
}
I've added these to my AndroidManifest.xml right under my activity within the application tag
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true" >
</receiver>
<service
android:name=".MyNewIntentService"
android:exported="false" >
</service>
The notification fires for me but does not when the app is closed. In the android documentation, it seems like android has tried to limit the amount of background processing and timing of apps and the AlarmManager does not run at an accurate time because of this.
How do I make this into a reliable notification reminder for my app that runs at nearly the same time every day even when the app is closed?
You are almost there. Very close just one more thing.
Instead of startService() you should use startForegrounService(). In that case your alarm will always fire. Just a few tips:
you should declare the foreground service in your manifest
You have to use alarmManager.setExactAndAllowWhileIdle for API level higher than 23
You can also check this out for more information.
Update: This method worked forme on Xiaomi Redme note 8, but the just suddenly stopped working! It may not be a very dependable solution for custom OS devices at the moment. Hope google come up with a solid solution.
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)
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.
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);
}