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
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 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?
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 want to notify at midnight. So I used alrammanager. the alrammanager is working well when it is in foreground or background. But the problem is occured when my app is killed. The alrammanager sometimes works or not. I don't understand this weird happening...
For example, when the notification occurs every three minutes, the app works well even if it is in the foreground or background. But when the app kiiled, the notification is occured or not even though there is no change in code. Please help me...
MainActivity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val picker = findViewById(R.id.timePicker) as TimePicker
picker.setIs24HourView(true)
val nextNotifyTime: Calendar = GregorianCalendar()
val nextDate: Date = nextNotifyTime.getTime()
val currentTime: Date = nextNotifyTime.getTime()
val HourFormat = SimpleDateFormat("kk", Locale.getDefault())
val MinuteFormat = SimpleDateFormat("mm", Locale.getDefault())
val pre_hour: Int = HourFormat.format(currentTime).toInt()
val pre_minute: Int = MinuteFormat.format(currentTime).toInt()
if (Build.VERSION.SDK_INT >= 23) {
picker.hour = pre_hour
picker.minute = pre_minute
} else {
picker.currentHour = pre_hour
picker.currentMinute = pre_minute
}
val button: Button = findViewById(R.id.button) as Button
button.setOnClickListener {
val hour: Int
val hour_24: Int
val minute: Int
if (Build.VERSION.SDK_INT >= 23) {
hour_24 = picker.hour
minute = picker.minute
} else {
hour_24 = picker.currentHour
minute = picker.currentMinute
}
if (hour_24 > 12) {
hour = hour_24
}
else {
hour = hour_24- 12
}
val calendar: Calendar = Calendar.getInstance().apply {
set(Calendar.HOUR_OF_DAY, hour)
set(Calendar.MINUTE, minute)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}
if(calendar.after(Calendar.getInstance())) {
//calendar.add(Calendar.DATE, 1)
}
diaryNotification(calendar)
}
}
fun diaryNotification(calendar: Calendar) {
val pm = this.packageManager
val receiver = ComponentName(this, DeviceBootReceiver::class.java)
val alarmIntent = Intent(this, AlarmReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0)
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, 60*1000, pendingIntent)
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP)
}
AlarmReceiver
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notificationIntent = Intent(context, MainActivity::class.java)
notificationIntent.flags = (Intent.FLAG_ACTIVITY_CLEAR_TOP
or Intent.FLAG_ACTIVITY_SINGLE_TOP)
var notification = CustomNotification.getNotificationBuilderInstance(context)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelName = "channel name"
val importance = NotificationManager.IMPORTANCE_LOW
val channel = NotificationChannel(CHANNEL_ID, channelName, importance)
notificationManager.createNotificationChannel(channel)
}
notificationManager.notify(NOTIFICATION_ID, notification.build())
}
}
DeviceBootReceiver
class DeviceBootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (Objects.equals(intent.action, "android.intent.action.BOOT_COMPLETED")) {
val alarmIntent = Intent(context, AlarmReceiver::class.java)
val pendingIntent =
PendingIntent.getBroadcast(context, 0, alarmIntent, 0)
val manager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val millis = Calendar.getInstance().timeInMillis
manager.setRepeating(
AlarmManager.RTC_WAKEUP, millis,
60*1000, pendingIntent
)
}
}
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.haii.alarmdemo">
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:name=".GlobalApplication"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".DeviceBootReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".AlarmReceiver" />
</application>
</manifest>
go to settings -> app -> YOUR APK NAME -> enable AUTOSTART (or something similar)
now even if your app is killed you will receive your notification
Also I suggest you to take a look at this link: LINK
Hope this "solution" can help you, cya ;)
I am using the Firebase Cloud Messaging, the problem is if application is on foreground, after clicking the application will open, but if application is not on foreground, then after clicking the application will not open.
I have tried almost every solution posted here and combination of every flag but it is not working:
Open application after clicking on Notification
GCM Notification onclick does not open specified activity
FCM Notification onclick does not open desired activity
This is fragment code of manifest:
<activity
android:name=".ui.activities.StartActivity"
android:screenOrientation="portrait"
android:theme="#style/LightThemeTransparentStatusBar">
<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>
This my example code:
class MyFirebaseMessagingService: FirebaseMessagingService {
constructor() : super()
override fun onMessageReceived(p0: RemoteMessage?) {
super.onMessageReceived(p0)
try {
val notificationManager=getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notificationId = Random().nextInt(60000)
val bitmap = getBitmapFromURL(p0!!.data.get("image-url"))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationManager.createNotificationChannel(setupChannels())
}
val intent = Intent(this#MyFirebaseMessagingService,StartActivity::class.java)
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
val pendingIntent=PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_ONE_SHOT)
val notificationBuilder = NotificationCompat.Builder(this, ADMIN_CHANNEL_ID)
.setLargeIcon(bitmap)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(p0.notification!!.title)
.setContentText(p0.notification!!.body)
.setAutoCancel(true)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setContentIntent(pendingIntent)
notificationManager.notify(notificationId,notificationBuilder.build())
}catch (ex:java.lang.Exception){
Log.e(TAG,ex.message)
}
}
fun getBitmapFromURL(imageURL: String?): Bitmap? {
try {
val url = URL(imageURL)
val connection = url.openConnection() as HttpURLConnection
connection.doInput = true
connection.connect()
val input = connection.inputStream
return BitmapFactory.decodeStream(input)
} catch (e: Exception) {
e.printStackTrace()
return null
}
}
#RequiresApi(api = Build.VERSION_CODES.O)
private fun setupChannels() : NotificationChannel {
val adminChannelName = "Global channel"
val adminChannel: NotificationChannel
adminChannel = NotificationChannel(ADMIN_CHANNEL_ID, adminChannelName, NotificationManager.IMPORTANCE_LOW)
adminChannel.enableLights(true)
adminChannel.lightColor = Color.RED
adminChannel.enableVibration(true)
return adminChannel
}
companion object {
private val TAG=MyFirebaseMessagingService::class.java.name
private val ADMIN_CHANNEL_ID = "admin_channel"
}
}