I'm creating intent like this
val tapIntent = Intent(context, TaskActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val id = createID()
tapIntent.putExtra("timestamp", currentTime)
val notificationIntent: PendingIntent = PendingIntent.getActivity(context, 0, tapIntent, 0)
val builder = NotificationCompat.Builder(context, "com.task")
.setSmallIcon(R.drawable.ic_android_black_24dp)
.setContentTitle(context.resources.getString(R.string.new_task_available))
.setContentIntent(notificationIntent)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_MAX)
with(NotificationManagerCompat.from(context)) {
notify(id, builder.build())
}
This notifications are generated few times a day.
And when testing it, I've found out that if I'm not closing activity, but just swiping out of it, next time I open this activity from intent, I see that intent stores timestamp of a previous notification and not a current one.
Code for reading data from intent is quite simple:
val timestamp = intent.getLongExtra("timestamp", System.currentTimeMillis())
val hourFormatter = SimpleDateFormat("dd/MM/yyyy HH:mm", Locale.getDefault())
Toast.makeText(this, hourFormatter.format(Date(timestamp)), LENGTH_LONG).show()
As far as I understand Intent.FLAG_ACTIVITY_CLEAR_TASK should clear all the old info. So I don't understand why this is happening.
What sould I do to receive current intent instead of the original one?
When generating the PendingIntent for the Notification, you need to do this:
PendingIntent.getActivity(context, 0, tapIntent,
PendingIntent.FLAG_UPDATE_CURRENT)
Otherwise you will just be using the previous (old) PendingIntent instead of creating a new one.
Related
I thought requestCode was some kind of indentifier for which Intent was just called for or something like that, please correct me if i'm wrong. But if this is the case, why is that if the requestCode for my pendingintent is 2, it acts differently when I have pass the requestcode as 0. I don't have another pendingintent in which is passed 2 as the requestcode.
Say I start my app and then I get a notification, when I click this notification ...
requestCode = 2
...a new activity is created and brought to the foreground, when I press the back button I go back to the activity I was on in the same state before backing out of the app
requestCode = 0
...I go straight back to the activity I was on in the same state before backing out of the app. No new activity is created
This isn't really a big issue, I could just pass 0 and the app will work how I want it to but I just wanna know why this happens.
In MainActivity.kt
private fun startAlarm (cal : Calendar){
val alarmManager :AlarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent (this, AlertReceiver().javaClass)
val pendingIntent : PendingIntent = PendingIntent.getBroadcast(this, 1, intent, 0)
alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal.timeInMillis, pendingIntent)
}
}
AlertReceiver.kt
class AlertReceiver(): BroadcastReceiver() {
#RequiresApi(Build.VERSION_CODES.O)
override fun onReceive(context: Context?, intent: Intent?) {
val notificationObj : Notification = Notification(context)
val notif : NotificationCompat.Builder = notificationObj.createNotification()
notificationObj.getManager().notify(1, notif.build())
}
}
In Notification.kt
fun createNotification(): NotificationCompat.Builder{
val main: Intent = Intent (this, MainActivity().javaClass).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
//-------------------talking about this line--------------------------------
val pendingMain: PendingIntent = PendingIntent.getActivity(this, 2, main, 0)
val notif : NotificationCompat.Builder = NotificationCompat.Builder(applicationContext, channelID)
.setSmallIcon(R.drawable.ic_android_black_24dp)
.setContentTitle("test:")
.setContentText("testing")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingMain)
.setAutoCancel((true))
return notif
}
When you are passing data from multiple Fragments to an Activity using onActivityResult(), that Activity identifies the child Fragment via request code
I have an Android application which will receive push notification. The notification have wearable support hence the notification will also be visible in Android wear with action button.
I am looking to pass data when the notification reaches onMessageReceived in FirebaseMessagingService class. Tried setting data in Intent and passed that with Pending Intent.
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
intent.data = Uri.parse("12345")
intent.putExtra("user_id", "USER ID")
intent.putExtra("date", "DATE")
val pendingIntent = PendingIntent.getActivity(
applicationContext,
System.currentTimeMillis().toInt() , intent,
0
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationChannel =
NotificationChannel(CHANNEL_ID,
CHANNEL_NAME,
CHANNEL_IMPORTANCE)
val notificationManager =
this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(notificationChannel)
val notificationBuilder = NotificationCompat.Builder(this,CHANNEL_ID)
.setContentTitle(getString(R.string.app_name))
.setContentText(body)
.setAutoCancel(true)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent)
.extend(NotificationCompat.WearableExtender()
.addAction(NotificationCompat.Action(R.drawable.icon,
"Explore",
pendingIntent))
)
notificationManager.notify(0, notificationBuilder.build())
}
When click on the notification from Wear, capturing the intent in onNewIntent to get the data passed. But couldn't find the data which were passed.
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
setIntent(intent)
// intent.getStringExtra("date")
// intent.extras.getString("date")
// intent.extras.get("date")
// intent.data
}
Couldn't get the data. Is there any way to get the intent passed with the pending intent ? Or how to get the values passed with Pending Intent.
My assumption is that onNewIntent() is not being called.
If you specify FLAG_ACTIVITY_CLEAR_TOP and your app is already running and there is an instance of MainActivity in the task stack, Android will remove the existing instance of MainActivity and create a new one. The Intent with "extras" will then be delivered in onCreate() and onNewIntent() will not be called.
If your app is not running, tapping the notification will start your app and create a new instance of MainActivity and the Intent with the "extras" will be delived in onCreate() and onNewIntent() will not be called.
Also, since the Intent that you put in the PendingIntent will be used by Android to launch an Activity from a non-Activity context, you need to specify Intent.FLAG_ACTIVITY_NEW_TASK.
Also, you should always specify FLAG_UPDATE_CURRENT when getting a PendingIntent with "extras", because if you do not, you may get an existing PendingIntent with some old "extras" or maybe none at all. Using FLAG_UPDATE_CURRENT will ensure that your Intent "extras" are copied into the PendingIntent even if it already exists. Like this:
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_CLEAR_TOP)
intent.data = Uri.parse("12345")
intent.putExtra("user_id", "USER ID")
intent.putExtra("date", "DATE")
val pendingIntent = PendingIntent.getActivity(
applicationContext,
System.currentTimeMillis().toInt() , intent,
PendingIntent.FLAG_UPDATE_CURRENT
)
I set on my application the notification every 7 hours in this way:
alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(this, AlarmBroadcastReceiver::class.java)
pendingIntent = PendingIntent.getBroadcast(this, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
// Setting the specific time for the alarm manager to trigger the intent, in this example, the alarm is set to go off at 23:30, update the time according to your need
val calendar = Calendar.getInstance()
val next= calendar.get(Calendar.HOUR_OF_DAY) + 7
calendar.timeInMillis = System.currentTimeMillis()
calendar.set(Calendar.HOUR_OF_DAY, next)
calendar.set(Calendar.MINUTE, 0)
calendar.set(Calendar.SECOND, 0)
// Starts the alarm manager
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
AlarmManager.INTERVAL_DAY,
pendingIntent
)
with this class AlarmBroadcastReceiver :
class AlarmBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Create the NotificationChannel
val name = "Alarme"
val descriptionText = "Detalhes do Alarme"
val importance = NotificationManager.IMPORTANCE_DEFAULT
val mChannel = NotificationChannel("AlarmId", name, importance)
mChannel.description = descriptionText
val notificationManager = context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(mChannel)
}
// Create the notification to be shown
val mBuilder = NotificationCompat.Builder(context!!, "AlarmId")
.setSmallIcon(R.mipmap.ic_food)
.setContentTitle("Synchronize Fitbit")
.setContentText("Synchronize Fitbit data and log-in SugarFree for don't lose daily data")
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
// Get the Notification manager service
val am = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Generate an Id for each notification
val id = System.currentTimeMillis() / 1000
// Show a notification
am.notify(id.toInt(), mBuilder.build())
The notifications working well, I enter in the application, set the alarm and after 7 hours arrive the notification and so on. I wish that when arrive the notification i can click on it and open the app (maybe in my current home activity) so this alarm wish set automatically after 7 hours.
I saw that I must modify the pendingIntent with my home intent... but I have a
val intent = Intent(this, AlarmBroadcastReceiver::class.java)
that need to call the Alarm Receiver class.
Can anyone help me out?
All you need is to add .setContentIntent in your notification builder.
// Create the notification to be shown
val mBuilder = NotificationCompat.Builder(context!!, "AlarmId")
.setSmallIcon(R.mipmap.ic_food)
.setContentTitle("Synchronize Fitbit")
.setContentText("Synchronize Fitbit data and log-in SugarFree for don't lose daily data")
.setAutoCancel(true)
.setContentIntent(PendingIntent.getActivity(
context, // Context from onReceive method.
0,
Intent(context, HomeActivity::class.java), // Activity you want to launch onClick.
0
)
)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build()
You can find out more here the docs have more information about how to handle tasks such as only single Activity opens at a time.
You need create and set pending intent -
// Create an Intent for the activity you want to start
val resultIntent = Intent(this, YourMainActivity::class.java)
// Create the TaskStackBuilder
val resultPendingIntent: PendingIntent? = TaskStackBuilder.create(this).run {
// Add the intent, which inflates the back stack
addNextIntentWithParentStack(resultIntent)
// Get the PendingIntent containing the entire back stack
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}
and then set it -
val builder = NotificationCompat.Builder(this, CHANNEL_ID).apply {
setContentIntent(resultPendingIntent)
...
}
with(NotificationManagerCompat.from(this)) {
notify(NOTIFICATION_ID, builder.build())
}
Hope this will work for you.
I have a notification and when I tap it I want to launch application if it is still not running, but if application already running, I do not want to relaunch it.
So, I am using PendingIntent.FLAG_UPDATE_CURRENT flag when creating PendingIntent.
My code:
private val notificationManager by lazy { NotificationManagerCompat.from(this) }
fun testPush() {
val notificationBuilder = NotificationCompat.Builder(this, BuildConfig.APPLICATION_ID)
.setSmallIcon(R.drawable.ill_launcher)
notificationBuilder
.setContentTitle("Title")
.setContentText("Test text")
.setContentIntent(buildPendingIntent())
notificationBuilder
.setAutoCancel(true)
.priority = NotificationCompat.PRIORITY_DEFAULT
notificationManager.notify(1, notificationBuilder.build())
}
private fun buildPendingIntent(): PendingIntent {
val intent = Intent(this, RootActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
intent.putExtra("action", RootActivity.DEFAULT_INTENT)
return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
But when I launch the application and click on the notification, the activity is recreates.
Instead of building the Intent for RootActivity like you are doing, you need to create a "launch Intent" for your application. The easiest way to do this is to call PackageManager.getLaunchIntentForPackage() and pass your own package name. Use the returned Intent in the call to PendingIntent.getActivity().
This will launch your app if it isn't running, otherwise, if it is already running, it will just bring the existing task containing your app to the foreground.
I want to pass a long value using a PendingIntent something like this
Intent intentForPending = new Intent(context, NewBlaBlaActivity.class);
long courseId = 15252;
intentForPending.putExtra("courseId", courseId);
intentForPending.putExtra("isFromPushNotification", true);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, intentForPending, 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
context).setSmallIcon(R.drawable.appicon)
.setContentTitle("BlaBla")
.setStyle(new NotificationCompat.BigTextStyle().bigText(message))
.setContentText(message)
.setAutoCancel(true);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
And get the value as below
Intent intent = getIntent();
if(intent.getBooleanExtra("isFromPushNotification", false)) {
long courseId = intent.getLongExtra("courseId", 0);
}
But I always get 0 from the intent. The weird thing is while I can get the boolean value with 'isFromPushNotification' key from the intent, I cannot get the long value from the same intent.
This drives me crazy. As you can see, it is a PushNotification and this code runs when I tap on the notification.
I tried all the way I can get from the forums and questions in stackoverflow, adding L suffix on def and original value on long objects. But I think PendingIntent is wet blanket.
I am waiting for your godlike advices. Thanks!
If you are going to use extras with a PendingIntent, always use a flag in the last parameter of the PendingIntent factory method (getActivity() in your case). Probably you want FLAG_UPDATE_CURRENT, to indicate to replace any existing PendingIntent contents with the new extras.