I have the following structure:
Main Class
private fun scheduleNotification()
{
val intent = Intent(applicationContext, Notification::class.java)
val title = binding.titleET.text.toString()
val message = binding.messageET.text.toString()
intent.putExtra(titleExtra, title)
intent.putExtra(messageExtra, message)
val pendingIntent = PendingIntent.getBroadcast(
applicationContext,
1 + (Random.nextInt(1, 100)),
intent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val time = getTime()
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
time,
pendingIntent
)
showAlert(time, title, message)
}
Notification Class
class Notification : BroadcastReceiver(){
override fun onReceive(context: Context, intent: Intent)
{
val notification = NotificationCompat.Builder(context, channelID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(intent.getStringExtra(titleExtra))
.setContentText(intent.getStringExtra(messageExtra))
.build()
val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.notify(notificationID, notification)
}
}
Android Manifest
<receiver
android:name=".Notification"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
With this I am able to SCHEDULE a NOTIFICATION with DATE and TIME. But when the device is restarted all scheduled notifications are erased.
I tried to solve it by adding:
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
Indeed it "works" but I get an empty notification and outside the scheduled time and I understand that it is an Android behavior, but is there any solution?
Related
I want open special activity when the app is closed and user tap on notification. But the special didnt open. When user will click to notification i want open TestActivity but instead of this MainActivity opening all time.
In the manifest i have this code:
<service
android:name=".services.firebase.notification.AppFirebaseMessaging"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
.
.
.
<activity
android:name=".MainActivity"
android:exported="true"
android:screenOrientation="portrait"
tools:ignore="LockedOrientationActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
.
.
.
<activity android:name=".TestActivity"
android:launchMode="singleTask"
android:taskAffinity=""
android:excludeFromRecents="true"/>
this is my AppFirebaseMessaging
class AppFirebaseMessaging : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
// here parsing RemoteMessage object,
sendNotification("title", "description")
}
private fun sendNotification(title: String, description: String) {
val random = System.currentTimeMillis().toInt()
val notificationBuilder: NotificationCompat.Builder = notificationBuilder(title, description)
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as? NotificationManager
// Since android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationManager?.createNotificationChannel(getChannel(title))
}
notificationManager?.notify(random, notificationBuilder.build())
}
private fun notificationBuilder(title: String, description: String): NotificationCompat.Builder {
val random = System.currentTimeMillis().toInt()
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val notifyIntent = Intent(this, TestActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val notifyPendingIntent = PendingIntent.getActivity(
this, 0, notifyIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val notificationBuilder: NotificationCompat.Builder = NotificationCompat.Builder(this, random.toString())
.setSmallIcon(R.drawable.icon_notification)
.setContentTitle(title)
.setContentText(description)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.apply {
setContentIntent(notifyPendingIntent)
}
return notificationBuilder
}
}
When user will click to notification, MainActivity will be open, dont understand why
Tapping on Notification will always open the activity that has the following intent filter attributes.
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
If you can't make the 'TestActivity' the Main activity, you could try as follows.
Keep the MainActivity as the Main.
There set the launch mode to singleTop in MainActivity.
<activity
android:name=".MainActivity"
android:launchMode="singleTop"/>
Then Override the 'onNewIntent' inside MainActivity,
#Override
protected void onNewIntent(#NonNull Intent intent) {
super.onNewIntent(intent);
// here send intent to open TestActivity
}
I'm trying to create an alarm Manager that sends notification every 24 hours at specific time consulted other Stackoverflow code. I tried this code below but onReceive() never gets executed. What i'm doing wrong?
private var HOUR_TO_SHOW_PUSH = 21
private var MINUTE_TO_SHOW_PUSH = 0
private val REQUEST_CODE = 100
private lateinit var alarmManager: AlarmManager
private lateinit var pendingIntent: PendingIntent
class MainActivity : AppCompatActivity() {
...
alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(this, AlertReceiver::class.java)
pendingIntent = PendingIntent.getBroadcast(this, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val calendar = GregorianCalendar.getInstance().apply {
if (get(Calendar.HOUR_OF_DAY) >= HOUR_TO_SHOW_PUSH) {
add(Calendar.DAY_OF_MONTH, 1)
}
set(Calendar.HOUR_OF_DAY, HOUR_TO_SHOW_PUSH)
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
AlarmManager.INTERVAL_DAY,
pendingIntent
)
AlertReceiver
class AlertReceiver: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
override fun onReceive(context: Context?, intent: Intent?) {
Toast.makeText(context, "Alarm", Toast.LENGTH_LONG).show()
println("Alarm")
Log.e("Alarm","Alarm Triggered")
}
Manifest
<receiver
android:name=".AlertReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
<action android:name="MyBroadcastReceiverAction"/>
</intent-filter
</receiver>
Normally you would register your receiver in the AndroidManifest like this:
<receiver android:name=".MyBroadcastReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
</intent-filter>
</receiver>
https://developer.android.com/guide/components/broadcasts
it depends on the battery optimization applied to the app by the device, it varies from a device manufacturer to other
Normally you will find it in Settings > Apps > "your app name" > Battery Saver Set it to No Restrictions
I have an Android app where i schedule some notifications at specific times every day with alarmManager and receiver like this
fun addNot() {
val alarmMgr = context!!.getSystemService(Context.ALARM_SERVICE) as AlarmManager?
val intent = Intent(this.context!!, MyAlarmReceiverTest::class.java)
val pendingIntent = PendingIntent.getBroadcast(this.context!!, 0, intent, 0)
val current = Calendar.getInstance()
val time = createDate("13:58:00")
if(time < current) {
time.add(Calendar.DATE,1)
}
alarmMgr!!.setRepeating(AlarmManager.RTC_WAKEUP, time.timeInMillis ,AlarmManager.INTERVAL_DAY,pendingIntent)
}
fun createDate(str: String):Calendar {
val separated = str.split(":").toTypedArray()
val datetimeToAlarm = Calendar.getInstance()
datetimeToAlarm.set(Calendar.HOUR_OF_DAY,separated[0].toInt())
datetimeToAlarm.set(Calendar.MINUTE,separated[1].toInt())
datetimeToAlarm.set(Calendar.SECOND,separated[2].toInt())
return datetimeToAlarm
}
With this receiver
class MyAlarmReceiverTest : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val notification = Notification.Builder(MyApplication.appContext)
.setContentTitle("title goes here")
.setContentText("this is content")
.setSmallIcon(R.mipmap.app_logo_final)
.setLargeIcon(
BitmapFactory.decodeResource(
MyApplication.appContext.getResources(),
R.mipmap.app_logo_final
)
)
.setContentIntent(null)
.build()
notification.sound = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + MyApplication.appContext.getPackageName() + "/raw/a")
var notificationManager = MyApplication.appContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager?.notify(45545454, notification)
}
}
And the manifest
<receiver
android:name=".MyAlarmReceiverTest"
android:enabled="true"
android:stopWithTask="false">
<intent-filter>
<action android:name="com.simplemobiletools.applauncher.sendbroadcast" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
Questions :
1- the above notification sometimes triggers and sometimes not , why ?
2- should i use job or workmanager for this ?
App support is from api 21 if this matters
I'm writing a time tracker app that starts an unbound foreground service to keep the user informed about the elapsed time.
The service runs smoothly and everything works like a charm... EXCEPT for one thing!
When the user clicks on the notification the apps main activity should start.
According to Androids documentation (https://developer.android.com/training/notify-user/navigation) this code should work, but it just starts the Android Settings Activity for the app.
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(TAG, "Started")
isRunning = true
val channelID = createNotificationChannel()
val pendingIntent: PendingIntent = Intent(this, MainActivity::class.java).let { notificationIntent ->
PendingIntent.getActivity(this, 0, notificationIntent, FLAG_UPDATE_CURRENT)
}
val notification: Notification = NotificationCompat.Builder(this, channelID)
.setContentTitle(CHANNEL_NAME)
.setContentText("My wonderful Text")
.setPriority(PRIORITY_LOW)
.setContentIntent(pendingIntent)
.build()
startForeground(FOREGROUND_ID, notification)
timer.scheduleAtFixedRate(TimedTask(), 0, 1000)
return super.onStartCommand(intent, flags, startId)
}
private fun createNotificationChannel(): String{
val chan = NotificationChannel(CHANNEL_ID,
CHANNEL_NAME, NotificationManager.IMPORTANCE_NONE)
chan.lightColor = Color.BLUE
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
service.createNotificationChannel(chan)
return CHANNEL_ID
}
The manifest.xml looks like this:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.maybe.tima">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".TimerService"
android:label="#string/app_name"
/>
</application>
</manifest>
Any ideas why this happens? Your help is very appreciated :)
The only change I've done to make your code work - is to add method "setSmallIcon" to your notificationBulider (but I couldn't find in official documentation any mention about such kind of affection of this method):
val notification: Notification = NotificationCompat.Builder(this, channelID)
.setContentTitle(CHANNEL_NAME)
.setContentText("My wonderful Text")
.setPriority(PRIORITY_LOW)
.setSmallIcon(R.drawable.ic_launcher_background) // line added
.setContentIntent(pendingIntent)
.build()
I'm trying to save Firebase notification into the Room Dao when app in the background. Send notification with Postman, but onMessage received called only when app is foreground and message have notification : {} body. Can any help me with this problem please :3
My FirebaseMessagingService implementation :
class NotificationService : FirebaseMessagingService() {
override fun onMessageReceived(p0: RemoteMessage) {
val title = p0.notification?.title ?: return
val message = p0.notification?.body ?: return
Log.e("TAG","Notification: $title: $message")
Log.e("TAG","Data from notification : ${p0.data["key_1"]}")
Log.e("TAG","MessageReceived")
CoroutineScope(Dispatchers.IO).launch {
NotificationApp.db?.notificationDao()?.setNotification(Notification(data = p0.data["key_1"]))
}
showNotification(p0)
}
fun showNotification(data: RemoteMessage) {
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT)
val notificationBuilder = NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_input_get)
.setContentTitle(data.notification?.title)
.setContentText(data.notification?.body)
.setContentIntent(pendingIntent)
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(CHANNEL_ID, "test_notification_channel_id", NotificationManager.IMPORTANCE_HIGH)
manager.createNotificationChannel(channel)
}
manager.notify(0, notificationBuilder.build())
}
Manifest :
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#drawable/ic_launcher_background" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="#color/colorPrimary" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="#string/notification_main_chanel_id" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".NotificationService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="#string/notification_main_chanel_id" />
And notification example in Postman :
{
"data": {
"title": "I'd tell you a chemistry joke",
"message": "but I know I wouldn't get a reaction",
"image-url":
"https://docs.centroida.co/wp-content/uploads/2017/05/notification.png",
"key_1" : "Heh message"
},
"to": "DEVICE_TOKEN",
"priority": "high"
}