I am trying to laod some tasks from DB on BOOT_COMPLETED and set alarm for each of them.
Alarm Manager is configured to receive BOOT_COMPLETED in AndroidMAnifest File.
Sometime I get these task via SMS, so i have a brodcastreceiver for sms receiving and processing, which builds task list and calls AlarmManager.setAlarms().
I am wondering that setAlarams works fine when called from OnReceive() method og SMSReceiver, but does not work properly when called from OnReceive() method of AlarmManager on Boot_Completed. it just sets one Alarm and ignores the rest of the list!
any help on this?
thanks in advance
public class AlarmManager extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
List <Task> taskList= db.loadFromDB();
setAlarms(context, taskList);
}
public static void setAlarms(Context context, List<Task> taskList) {
for each task in taskList{
int pendingIntentRequestCode = task.getid();;
Intent myIntent = new Intent(context, AlarmReceiver.class);
myIntent.putExtra("taskName", task.getName());
myIntent.putExtra("taskHour", task.getHour));
myIntent.putExtra("taskMinute", task.getMinute());
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
pendingIntentRequestCode,
myIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP,alarmTime, pendingIntent );
}
}
}
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String taskName = intent.getStringExtra("taskName");
int taskHour = intent.getIntExtra("taskHour", -1);
int taskMinute = intent.getIntExtra("taskMinute", -1);
Intent alarmIntent = new Intent(AlarmClock.ACTION_SET_ALARM);
alarmIntent.putExtra(AlarmClock.EXTRA_MESSAGE, taskName);
alarmIntent.putExtra(AlarmClock.EXTRA_HOUR, ataskHour);
alarmIntent.putExtra(AlarmClock.EXTRA_MINUTES, taskMinute);
alarmIntent.putExtra(AlarmClock.EXTRA_SKIP_UI, true);
alarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(alarmIntent);
}
}
public class SMSReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
SmsMessage[] msgs = null;
String messageReceived = "";
if (bundle != null) {
Object[] pdus = (Object[]) bundle.get("pdus");
msgs = new SmsMessage[pdus.length];
for (int i = 0; i < msgs.length; i++) {
msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
messageReceived += msgs[i].getMessageBody().toString();
sender = msgs[i].getOriginatingAddress();
messageReceived += "\n";
}
List <Task> taskList = MakeTaskListFromReceivedSMS(messageReceived);
AlarmManager.setAlarms(context, taskList);
}
}
}
According to the documentation:
If there is already an alarm scheduled for the same IntentSender, it
will first be cancelled.
Related
I have an app that schedules a bunch of notifications (user has to answer questionnaires) locally using AlarmManager. The notification should show at certain points in the future.
I schedule the notifications like this:
private void scheduleNotification(Notification notification, int delay, int scheduleId, int notificationId) {
Intent notificationIntent = new Intent(context, NotificationPublisher.class);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION_ID, notificationId);
notificationIntent.putExtra(NotificationPublisher.INTENT, notification);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, scheduleId, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.SECOND, delay);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
The intent is received by a BroadcastReceiver that calls notify on the notification attached to the intent.
public class NotificationPublisher extends BroadcastReceiver {
public static String NOTIFICATION_ID = "notification-id";
public static String INTENT = "notification";
#Override
public void onReceive(Context context, Intent intent) {
if (intent.hasExtra(INTENT)) {
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
Notification notification = intent.getParcelableExtra(INTENT);
int id = intent.getIntExtra(NOTIFICATION_ID, 0);
notificationManager.notify(id, notification);
}
}
}
This works fine so far. The problem that I'm facing is that I only want to show the notification if the app is currently not open/shown. If it's open I want to show an AlertDialog instead.
I know that it might be a better idea to put only the plain content of the notification into the intent and only build it when it should be displayed and I want to refactor that later on.
My main problem is, how do I determine in the onReceive of my broadcast receiver if the app is currently showing to decide if a notification or an alert should be displayed?
Or is there an entirely different approach that might work better (for example using WorkManager)?
I think you can handle it on your BroadcastReceiver
public void onReceive(Context context, Intent intent) {
if (isForeground(context))
// AlertDialog
else
// Notification
}
public boolean isForeground(Context mContext) {
ActivityManager activityManager = (ActivityManager)this.getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.AppTask> tasks = activityManager.getAppTasks();
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).getTaskInfo().topActivity;
return topActivity.getPackageName().equals(mContext.getPackageName());
}
return true;
}
I am working on an Android app and I want to activate a daily Alarm (I used 5 min interval just as an example to test).
I used a Brodacast receiver (Static one declared in the manifest file),
but the app still doesn't work. Here's my code:
The Manifest file:
</activity> <receiver android:name=".ExecutableService" android:enabled="true" ></receiver </application>
The AlarmHandler class:
public class AlarmHandler {
private Context context;
public AlarmHandler(Context context) {
this.context = context;
}
//This will active the alarm
public void setAlarmManager(){
Intent intent = new Intent(context,ExecutableService.class);
PendingIntent sender = PendingIntent.getBroadcast(context ,2,intent,0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if (alarmManager != null) {
long triggerAfter=60*5*1000;//this will trigger the service after 5 min
long triggerEvery=60*5*1000;//this will repeat alarm every 5 min after that
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,triggerAfter,triggerEvery,sender);
}
}
//This will cancel the alarm
public void cancelAlarm (){
Intent intent = new Intent(context,ExecutableService.class);
PendingIntent sender = PendingIntent.getBroadcast(context,2,intent,0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if (alarmManager != null) {
alarmManager.cancel(sender);
}
}
}
This is the Broadcast receiver:
import ...
public class ExecutableService extends BroadcastReceiver {
private static final String TAG="Executable Service";
#Override
public void onReceive(Context context, Intent intent) {
//this will be executed at selected interval Notification show
Toast.makeText(context, "Hello World 2! ", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onReceive: it worked ");
Vibrator v=(Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
v.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE));
} else {
//deprecated in API 26
v.vibrate(500);
}}}
And this is the MainActivty where I activate the alarm:
public class MainActivity2 extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
AlarmHandler alarmHandler = new AlarmHandler(this);
//cancel the previous scheduled alarm
alarmHandler.cancelAlarm();
//set the new alarm after one hour
alarmHandler.setAlarmManager();
Toast.makeText(this, "Alarm Set ! ", Toast.LENGTH_SHORT).show();
}
If this is not the way that I should use to run the app in the background and push a notification (or a simple toast at a specific time), what is the best way to do it?
I tried also jobscheduler services.
you set the alarm start time to long triggerAfter=60*5*1000;
I suggest changing this to
long triggerAfter =60*5*1000+ System.currentTimeMillis()
i am making an app that required to inform the user with a notification when a specific date is approaching.
I use a Client class as a 'middle man' between activity and a Service. Once i bind the service, i call a method that interacts with AlarmTask class that uses AlarmManager to set an alarm. And as a last step i send a PendingIntent to start my another class witch is a BroadcastReceiver for my notification.
My problem is that the onReceive() is not called. Code reaches all the way to alarmManager.set() correctly. I read many posts and tried different ways to register my BroadcastReceiver. Any ideas on what might be wrong?
AlarmTask
public class AlarmTask implements Runnable {
private final Calendar date;
private final AlarmManager alarmManager;
private final Context context;
private long mGoalId;
public AlarmTask(Context context, Calendar date, long goalId) {
this.context = context;
this.alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
this.date = date;
mGoalId = goalId;
}
#Override
public void run() {
Log.e("AlarmTask", "run executed with request code: " + mGoalId);
// Request to start the service when the alarm date is upon us
Intent intent = new Intent(context, NotificationReceiver.class);
intent.putExtra(NotificationReceiver.INTENT_NOTIFY, true);
// mGoalId is the unique goal id that is gonna be used for deletion
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, (int)mGoalId, intent, 0);
alarmManager.set(AlarmManager.RTC, date.getTimeInMillis(), pendingIntent);
}
}
NotificationReceiver
public class NotificationReceiver extends BroadcastReceiver {
// Unique id to identify the notification.
private static final int NOTIFICATION = 123;
public static final String INTENT_NOTIFY = "com.test.name.services.INTENT_NOTIFY";
private NotificationManager notificationManager;
#Override
public void onReceive(Context context, Intent intent) {
Log.e("onReceive", "Broadcast fired : " + intent);
CharSequence title = "Alarm!!";
int icon = R.drawable.goal;
CharSequence text = "Your notification time is upon us.";
long time = System.currentTimeMillis();
final NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setSmallIcon(icon);
builder.setContentTitle(title);
builder.setContentText(text);
builder.setVibrate(new long[] { 0, 200, 100, 200 });
final Notification notification = builder.build();
notificationManager.notify(NOTIFICATION, notification);
}
}
Manifest
<receiver android:name=".broadcasts.NotificationReceiver"></receiver>
Iv'e created several Alarms using an Intent and BroadcastReciever and placed them in an Array of Intents.
For each Intent Iv'e placed a String as in Intent.PutExtra("info", string); to be shown later as a Toast when Alarm is activated,
and gave each a different requestCode.
But when adding multiple Alarms, the Toast shows EVERY other Alarms' info as well.
MainActivity:
Intent newAlarmIntent = new Intent(this,AlarmReceiver.class);
newAlarmIntent.putExtra("info",editText.getText().toString());
alarmsArray[alarmCounter]=newAlarmIntent;
alarm.AlarmListSortAndSetNext(gameArrayList, alarmArray, this,alarmCounter,alarmsArray[alarmCounter]);
Alarm Class:
public void CreateNew (Context context, Long alarmTimeAsLong, int counter, Intent intent)
{
PendingIntent pendingIntent;
pendingIntent = PendingIntent.getBroadcast(context, counter, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager manager;
manager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
manager.set(AlarmManager.RTC_WAKEUP, (alarmTimeAsLong),pendingIntent);
Toast.makeText(context, "Alarm Set", Toast.LENGTH_SHORT).show();
}
public void AlarmListSortAndSetNext (ArrayList<Game> gameArrayList,Long[] alarmArray,Context context,int alarmCounter, Intent intent)
{
Long SystemTimeAsLong = System.currentTimeMillis();
//Sorting Long Array for NEXT ALARM
for (int i=0;i<10;i++)
{if(i<gameArrayList.size()){
alarmArray[i] = gameArrayList.get(i).getDateAndTimeAsLong();
}
else alarmArray[i]= 0L;
}
Arrays.sort(alarmArray);
//Setting next ALARM by Long Size
for(int i=0;i<10;i++)
{
if (alarmArray[i]>SystemTimeAsLong){
CreateNew(context,alarmArray[i],alarmCounter,intent);
alarmCounter++;}
}}
AlarmReceiver:
public class AlarmReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent)
{
PowerManager pm = (PowerManager) context.getApplicationContext().getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = pm.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "TAG");
wakeLock.acquire();
String gameInfo= intent.getStringExtra("info");
Toast.makeText(context, gameInfo, Toast.LENGTH_SHORT).show();
MediaPlayer mp = MediaPlayer.create(context, R.raw.bipbip);
mp.start();
wakeLock.release();}}
QUESTION: How can I make each Intent to have it's on "info"/PutExtra, or any other way to tell which one has been activate?
* Found the issue *
I had left the AlarmListSortAndSetNext method which initially was supposed to manage the Next Alarm. I no longer have to use this method since I have created multiple Intents. Something in the looping probably created multiple putExtra();
Thank you.
I've found many similar questions to this, but they're too complicated (too much code), at least I think.
Can this thing be done in a few code of lines? I want to fire an activity in 10 (let's say) minutes, that's it. Thank you.
To Set Alarm for 10 Minutes(let's say) Use this code
AlarmManager alarmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);
Intent intent = new Intent(this, ShortTimeEntryReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),10*60*1000, pendingIntent);
To Start Activity
public class ShortTimeEntryReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
try {
Bundle bundle = intent.getExtras();
String message = bundle.getString("alarm_message");
// Your activity name
Intent newIntent = new Intent(context, ReminderPopupMessage.class);
newIntent.putExtra("alarm_message", message);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(newIntent);
} catch (Exception e) {
e.printStackTrace();
}
}
}
In your Manifest File Add the following
<receiver android:name=".ShortTimeEntryReceiver"
android:enabled="true"
android:process=":remote">
</receiver>
This function I use sets or cancels an alarm depending on the "Set" parameter
public static void SetAlarm(Context c, long AlarmTime, int ItemID, String Message, Boolean Set) {
Intent intent = new Intent(c, AlarmReceiver.class);
intent.putExtra("Message", Message);
intent.putExtra("ItemID", ItemID);
PendingIntent sender = PendingIntent.getBroadcast(c, 8192 + ItemID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Clear the seconds to 0 for neatness
Calendar ca = Calendar.getInstance();
ca.setTimeInMillis(AlarmTime);
ca.set(Calendar.SECOND, 0);
AlarmTime = ca.getTimeInMillis();
// Get the AlarmManager service
AlarmManager am = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
if (Set) {
am.set(AlarmManager.RTC_WAKEUP, AlarmTime, sender);
} else {
am.cancel(sender);
}
}
You would then need a Broadcast Receiver to handle the alarm and do whatever it is you want to do.
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
Bundle bundle = intent.getExtras();
String Message = bundle.getString("Message");
int ItemID = bundle.getInt("ItemID");
// Do what you want to do, start an activity etc
} catch (Exception e) {
e.printStackTrace();
}
}
}