Can't separate methods from MainActivity class - java

Created new Java class where trying to implement AlarmManager class method. I want to create functionality for creating, editing and deleting alarms. Everything has worked fine while all the code was in MainActivity class.
New class has constructor where context is passed. While application builds successfully, the alarm is not working.
I'm calling setShowDataEvent method at MainActivity:
AlarmController alarmController = new AlarmController(this);
alarmController.setShowDataEvent(startTime, finishTime);
Here is AlarmController class:
private final String TAG = "AlarmController";
Context context;
PendingIntent pendingIntent;
AlarmManager mAlarmManager;
public AlarmController(Context context){
this.context = context;
this.mAlarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
}
public void setShowDataEvent(long startTime, long finishTime){
newAlarmIntentData(startTime);
mAlarmManager.setExact(AlarmManager.RTC, startTime, pendingIntent);
newAlarmIntentData(finishTime);
mAlarmManager.setExact(AlarmManager.RTC, finishTime, pendingIntent);
Log.d(TAG, "setShowDataEvent has been executed");
}
private void newAlarmIntentData(long time){
Intent intent = new Intent(context, AlarmReceiver.class);
intent.putExtra("showData", true);
intent.putExtra("time", time);
pendingIntent = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_ONE_SHOT);
}

After moving AlarmManager to constructor and restarting AndroidStudio all begin to work. I have added same data to intent, so now there are a two different PendingIntent's.
intent.setData(Uri.parse("myalarms://" + time));

Related

Do I still need database in setting multiple alarms or reminders?

So I'm developing this Android application which has many features, and one of them is the workout reminder. We used firebase database in setting up login authentication, and the user's information.
Now for the last feature, I made a workout reminder which consists of Task Name and Time which also has a notification and. It only sets one alarm and I assume that if I applied and displayed it in a Recycler View, it will set multiple alarms. Unfortunately, it doesn't. When the reminder is displayed in the Recycler View, and when I restart the application, the reminder is gone.
I just want to humbly ask if I need to store it in a database and then retrieve it?
Thank you in advance!
Here is my code below:
public class AlertReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
NotificationHelper notificationHelper = new NotificationHelper(context);
NotificationCompat.Builder nb = notificationHelper.getChannel1Notification(reminderAddFragment.getTitle(), reminderAddFragment.getMessage());
notificationHelper.getManager().notify(1, nb.build());
}
}
private void startAlarm(Calendar cal) {
AlarmManager alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getActivity(), AlertReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), 1, intent, 0);
alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent);
}
Solved it by setting different requestCode everytime I set an alarm.
private void startAlarm(Calendar cal) {
AlarmManager alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getActivity(), AlertReceiver.class);
final int id = (int) System.currentTimeMillis();
PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), id, intent, PendingIntent.FLAG_MUTABLE);
alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent);
}
Yes, you need to persist the state of alarms set by your app and display the same to the user. Once set we cannot retrieve the alarms set by the system at the app level. All we can do is dump them using adb shell using:
adb shell dumpsys alarm > alarms_dump.txt

Show alert instead of scheduled notification if the app is currently opened

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;
}

Alarm Manager not starting after 60 seconds

I'm trying to set my alarm manager working, just simple schedule, firing toast every minute, but it's not working, what's wrong with the code?
Main Activity :
public void klik(View view) {
startalarm();
}
public void startalarm(){
AlarmManager manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent;
PendingIntent pendingIntent;
intent = new Intent(this, AlarmToastReciever.class);
pendingIntent = PendingIntent.getBroadcast(this,0,intent,0);
manager.setRepeating(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime()+3000,+60000,pendingIntent);
}
}
AlarmToastReciever class :
public class AlarmToastReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent){
Toast.makeText(context,"GOWNO", Toast.LENGTH_SHORT).show();
}
}
As stated in documentation
As of Android 4.4 (API Level 19), all repeating alarms are inexact. Note that while setInexactRepeating() is an improvement over setRepeating(), it can still overwhelm a server if every instance of an app hits the server around the same time. Therefore, for network requests, add some randomness to your alarms, as discussed above.
You can use "setInexactRepeating()" or set an exact one time alarm then set next alarm in On Receive method
Also make sure you added your receiver to the manifest file, between application tag, like
<receiver android:name=".AlarmToastReciever"
android:enabled="true">
<intent-filter>
</intent-filter>
</receiver>
Use this code to initialize alarm manager.
public void setupAlarm() {
final Calendar calNow = Calendar.getInstance();
final Calendar calSet = (Calendar) calNow.clone();
calSet.set(Calendar.HOUR_OF_DAY, calNow.get(Calendar.HOUR_OF_DAY));
calSet.set(Calendar.MINUTE, calNow.get(Calendar.MINUTE) + 1);
calSet.set(Calendar.SECOND, calNow.get(Calendar.SECOND));
final Intent intent = new Intent(this, UploadStarterReceiver.class);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1,
intent, 0);
final AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, calSet.getTimeInMillis(),
60 * 1000, pendingIntent);
}

BroadcastReceiver is not working properly while in others it does

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>

Unable to cancel the alarm from AlarmManager

I have an AlarmManager that notifies me every 10 seconds. Everything works just fine but for some reason I can't cancel the alarm. Here's my code.
public class AlarmNotifReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
//things
}
public void SetAlarm(Context context)
{
AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, AlarmNotifReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 10*1000, pi); // Millisec * Second
}
public void CancelAlarm(Context context)
{
Intent i = new Intent(context, AlarmNotifReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.cancel(pi);
}
}
as expected I call this CancelAlarm() method from my other classes but for some reason it does not cancel and keep notifying me like nothing happened.
Note: SetAlarm() also works just fine.
Thanks in advance.
Alarm should be created and cancelled on Same Pending intent.In your case you are creating Pending Intent Twice.
Your code should look like below.
public class AlarmNotifReceiver extends BroadcastReceiver {
PendingIntent pi;
AlarmManager am;
Intent i;
#Override
public void onReceive(Context context, Intent intent) {
pi = PendingIntent.getBroadcast(context, 0, i, 0);
am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
i = new Intent(context, AlarmNotifReceiver.class);
//things
}
public void SetAlarm(Context context) {
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 10 * 1000, pi);
}
public void CancelAlarm(Context context) {
am.cancel(pi);
}
}
Try to cancel Pendingintent--
PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT).cancel();
Hope this helps
Try this.
Android: Get all PendingIntents set with AlarmManager
To cancel all alarm, first you have to find all the pending intent for that and cancel alarm using that.
Try like this
public class AlarmNotifReceiver extends BroadcastReceiver {
AlarmManager am = null;
#Override
public void onReceive(Context context, Intent intent)
{
Intent i = new Intent(context, AlarmNotifReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
//things
}
public void SetAlarm(Context context)
{
am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 10*1000, pi); // Millisec * Second
}
public void CancelAlarm(Context context)
{
am.cancel(pi);
}
}
Your problem is that you're creating a NEW intent instead of cancelling the existing one. Function SetAlarm should place the intent into a "global" variable and the CancelAlarm function should just call
am.cancel(global_pi);
The above worked for me in a service, but:
If this is impossible (since that's a Receiver), try setting a new alarm with the (new) intent first.

Categories

Resources