I'm trying to schedule notifications with AlarmManager It works perfectly when I schedule one notification but when I schedule two notification, the first notification is okay but the second one not works.
I figured out opening the app after few minutes will notify the second notification. I think something is wrong with my BroadcastReceiver
MainActivity.java
Intent intent = new Intent(context,NotificationClass.class);
intent.putExtra("notification_id", id);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,id,intent,PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),pendingIntent);
Notification.java
public class NotificationClass extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int id = intent.getIntExtra("notification_id",0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context,"1")
.setContentTitle("Notification")
.setContentText("Content")
.setSmallIcon(R.drawable.notif_ic);
Notification notification = builder.build();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("1","test", NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(id,notification);
}
AndroidManifest.xml
<receiver android:name=".NotificationClass" ></receiver>
I don't know what is wrong with my code. Can anybody help me with this?
Broadcast receiver to receive the data:
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String alertMessage = intent.getStringExtra("type");
doNotificationAlertWorkHere(alertMessage);
}
};
Register & Unregister your broadcast to avoid static leaks.
via the Android manifest file. (Statically)
<receiver android:name="YourBroadcastReceiverName"> </receiver>
via the Context.registerReceiver() and Context.unregisterReceiver() methods. (Dynamically)
#Override
protected void onPause() {
super.onPause();
// unregister broadcast
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
}
#Override
protected void onResume() {
super.onResume();
// register broadcast
IntentFilter filter = new IntentFilter(Constants.ACTION);
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filter);
}
Send Broadcast like:
// public static final String ACTION = "ALERT";
Intent intent = new Intent(Constants.ACTION);
intent.putExtra("type", "SUP BRO. Stay Inside");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Knowledge Note :- Broadcast receiver is like a Cannon-fire to score a hit, you have to determine what to fire (eg. msg), where to fire (eg. activity). Load & unload the cannon to score another hit. (eg. Register & Unregister)
I have tried it and it is working. Add your notification code inside onReceive.
Broadcast Receiver
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
/*
Your implementation
*/
}
}
Mainfest
<receiver
android:name=".AlarmReceiver"
android:exported="true"
android:enabled="true" />
Creating pending intents
val alarmManager = activity.getSystemService(Activity.ALARM_SERVICE) as AlarmManager
val alarmIntent = Intent(activity.applicationContext, AlarmReceiver::class.java) // AlarmReceiver1 = broadcast receiver
val calendar = Calendar.getInstance()
calendar.timeInMillis = timeInMilliSeconds
val pendingIntent = PendingIntent.getBroadcast(activity, timeInMilliSeconds.toInt(), alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT)
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, pendingIntent)
First, make sure your notification Id is difference every single time you create a notification
Second, you miss tag intent-filter inside tag receive in manifest. pls check this https://developer.android.com/guide/components/broadcasts.
Hope this help!
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 want to send notification everyday on a particular time. The code is working when the app is opened. But when it closed and remove, the notifications are not showing. I have used broadcast receiver and service to this. The code is given below. Can anyone help to clear this issue.
Manifest File
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true" />
<service
android:name=".MyService"
android:enabled="true"
android:exported="true" />
MyReceiver.java
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
intent = new Intent(context, MyService.class);
context.startService(intent);
}}
MyService.java
public class MyService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
createNotification();
return Service.START_STICKY;
}
private static final String NOTIFICATION_CHANNEL_ID = "Channel01";
private void createNotification() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
String name = preferences.getString("name", "User");
name = name.split(" ")[0];
String namee = "Remainder";
String description = "Remainder to update Wallet";
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, namee, importance);
notificationChannel.setDescription(description);
Intent notifyIntent = new Intent(getApplicationContext(), MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 1, notifyIntent, 0);
Notification notification = new Notification.Builder(getApplicationContext())
.setContentTitle("Remainder")
.setContentText("Hey " + name + ", Let's update your wallet")
.setSmallIcon(R.drawable.wallet)
.setChannelId(NOTIFICATION_CHANNEL_ID)
.setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), R.drawable.wallet_new))
.setContentIntent(pendingIntent)
.build();
NotificationManager notificationManager = (NotificationManager)getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(notificationChannel);
// Issue the notification.
notificationManager.notify(1 , notification);
}
}}
Activity.java
Intent notifyIntent = new Intent(getApplicationContext(), MyReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 1, notifyIntent, 0);
alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, timeMilli, timeInterval, pendingIntent);
You shouldn't use any part of application to do that. Services, JobScheduler, or Work Manager sooner or later will be killed by the system to prevent battery drain.
In my opinion the best way to send repeated notifications is to use firebase cloud messaging triggered with external cron job (e.g. php on firebase functions).
Also make sure to deliver the notification to the system tray not to the application. To do that use FCM DataMessages. Data messages are delivered to system tray and are always display - even if service is not running.
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 building an application whereby the notification will ring at a specific time and after which disappear if it is left unattended for 15 minutes. It works when i plug in my device and runs the code. However, once i unplug my device and runs the app, the notification works but it does not disappear after 15 minutes if it is left unattended. Please advice me how should i run the app like how it does when the device is plug into the computer. Also, it should work when the app is killed.
FYI, i'm using notification, alarmmanager, broadcast receiver and intentservice. Below is the snippet of my codes.
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Notification(context, "Wifi Connection On");
Intent background = new Intent(context, BackgroundService.class);
context.startService(background);
}
public void Notification(final Context context, String message) {
// notification codes
}
}
BackgroundService.java
public class BackgroundService extends IntentService {
public BackgroundService() {
super("BackgroundService");
}
#Override
protected void onHandleIntent(Intent intent) {
//countdown 15 minutes and cancel notification automatically
Timer timer=new Timer();
TimerTask task=new TimerTask() {
#Override
public void run() {
// Create Notification Manager
NotificationManager notificationmanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Dismiss Notification
notificationmanager.cancelAll();
}
};
timer.schedule(task, 900000);
}
}
Manifest.xml
<receiver android:name=".AlarmReceiver" android:process=":remote" />
<service android:name=".BackgroundService" />
Please provide me some suggestions. Thank you.
This service will run twice: first time it does nothing except rescheduling, second time it cancels notifications.
public class BackgroundService extends IntentService {
private static final int REQUEST_CODE = 42;
private static final String ACTION_CANCEL_NOTIFS = "CancelNotifications";
public BackgroundService() {
super("BackgroundService");
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null && ACTION_CANCEL_NOTIFS.equals(intent.getAction())) {
NotificationManager notificationmanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationmanager.cancelAll();
}
else {
reschedule();
}
}
private void reschedule() {
final Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.MINUTE, 15);
final Intent serviceIntent = new Intent(this, getClass());
serviceIntent.setAction(ACTION_CANCEL_NOTIFS);
PendingIntent pendingIntent = PendingIntent.getService(this, REQUEST_CODE, serviceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
final AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
}
Explanation:
In your code, I assume, you start your service with startService(new Intent(this, BackgroundService.class)). This intent is passed as a parameter in onHandleIntent(Intent), which means you can access it from inside your service.
Intent allows you to pass additional data, such as action (useful for IntentFilters) or extras. Because you haven't set any, the first time around the execution goes to the else branch of onHandleIntent() method. AlarmManager is then scheduled to run your service in 15 minutes with serviceIntent. Note serviceIntent.setAction(ACTION_CANCEL_NOTIFS). So the second time around the execution goes to the if branch and cancels notifications.
A better approach would be creating a pending intent right from inside your activity instead of starting a service with startService. That would make your service simpler and more cohesive.
Service only runs when CPU is awake. If CPU gets off, service will not run.
SO to make your service to be run if phone goes to sleep, you need to aquire wake lock.
BackgroundService class
public class BackgroundService extends IntentService {
private PowerManager.WakeLock wl;
public BackgroundService() {
super("BackgroundService");
}
#Override
protected void onHandleIntent(Intent intent) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Partial lock permission");
wl.acquire();
//countdown 15 minutes and cancel notification automatically
Timer timer=new Timer();
TimerTask task=new TimerTask() {
#Override
public void run() {
// Create Notification Manager
NotificationManager notificationmanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Dismiss Notification
notificationmanager.cancelAll();
wl.release();
}
};
timer.schedule(task, 900000);
}
}
If this does work out, try to give below permission in Android Manifest file
<uses-permission android:name="android.permission.WAKE_LOCK" />
I have build a simple app that show a notification when i click on a button. How can show a programmed notify?
The code that i call is:
Notification.Builder builder = new Notification.Builder(this)
.setTicker("Notifica")
.setSmallIcon(android.R.drawable.stat_notify_chat)
.setContentTitle("Notifica")
.setContentText("Hai una notifica!")
.setAutoCancel(true)
.setContentIntent(PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0));
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.notify("interstitial_tag", 1, builder.build());
You can use AlarmManager in bundle with BroadcastReceiver.
At first you must create pending intent and register it with AlarmManager.set somewhere.
And then create your broadcast receiver and receive that intent.
Update: here is the code I have promised.
At first you need to create broadcast receiver.
public class NotifyHandlerReceiver extends BroadcastReceiver {
public static final String ACTION = "me.pepyakin.defferednotify.action.NOTIFY";
public void onReceive(Context context, Intent intent) {
if (ACTION.equals(intent.getAction())) {
Notification.Builder builder = new Notification.Builder(context)
.setTicker("Notifica")
.setSmallIcon(android.R.drawable.stat_notify_chat)
.setContentTitle("Notifica")
.setContentText("Hai una notifica!")
.setAutoCancel(true)
.setContentIntent(PendingIntent.getActivity(context, 0,
new Intent(context, MainActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0));
NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify("interstitial_tag", 1, builder.build());
}
}
}
This is your broadcast receiver that can handle notification requests. For it can work, you must register it in your AndroidManifest.xml. If you don't do it, Android won't be able to handle your notification request.
Just add <receiver/> declaration into your <application/> tag.
<receiver android:name=".NotifyHandlerReceiver">
<intent-filter>
<action android:name="me.pepyakin.defferednotify.action.NOTIFY" />
</intent-filter>
</receiver>
Take a note, that action name be exactly as defined in NotifyHandlerReceiver.ACTION.
Then you can use this code
public static final int REQUEST_CODE_NOTIFY = 1;
public void scheduleNotification(long delayTimeMs) {
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
long currentTimeMs = SystemClock.elapsedRealtime();
PendingIntent pendingNotifyIntent = PendingIntent.getBroadcast(
this,
REQUEST_CODE_NOTIFY,
new Intent(NotifyHandlerReceiver.ACTION),
PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, currentTimeMs + delayTimeMs, pendingNotifyIntent);
}
from your activity to start a notification delayed on delayTimeMs amount of milliseconds.