I added a button inside a notification
but I don't know how to have it call a function when it's clicked.
I tried an approach like this https://code.google.com/p/languagepickerwidget/source/browse/trunk/trunk/src/org/gnvo/langpicker/LangPicker.java since it's also using a RemoteViews object but nothing happens when I click the button.
This is what I currently have:
private void createNotification(){
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager notificationManager = (NotificationManager) getSystemService(ns);
Notification notification = new Notification(R.drawable.ic_launcher, null, System.currentTimeMillis());
RemoteViews notificationView = new RemoteViews(getPackageName(), R.layout.notification_switch);
//the intent that is started when the notification is clicked (works)
Intent notificationIntent = new Intent(this, SettingsActivity.class);
PendingIntent pendingNotificationIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.contentView = notificationView;
notification.contentIntent = pendingNotificationIntent;
notification.flags |= Notification.FLAG_NO_CLEAR;
//this is the intent that is supposed to be called when the button is clicked
Intent switchIntent = new Intent(this, switchButtonListener.class);
PendingIntent pendingSwitchIntent = PendingIntent.getBroadcast(this, 0, switchIntent, 0);
notificationView.setOnClickPendingIntent(R.id.buttonswitch, pendingSwitchIntent);
notificationManager.notify(1, notification);
}
public static class switchButtonListener extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("TAG", "test");
}
}
I can start an activity with the button but I didn't succeed to have it call a simple function. What would be the best way to do this?
Edit:
I found out that I had to register "switchButtonListener" in AndroidManifest.xml
<receiver android:name="SettingsActivity$switchButtonListener" />
Source: Android Activity with no GUI
It works now.
I found out that I had to register "switchButtonListener" in AndroidManifest.xml
<receiver android:name="SettingsActivity$switchButtonListener" />
Source: Android Activity with no GUI
Later I found out that I can also use code like this to achieve the same thing without modifying the manifest.
switchButtonListener = new SwitchButtonListener();
registerReceiver(switchButtonListener, new IntentFilter(SWITCH_EVENT));
.
public class switchButtonListener extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("TAG", "test");
}
}
.
Intent switchIntent = new Intent(LangService.SWITCH_EVENT);
PendingIntent pendingSwitchIntent = PendingIntent.getBroadcast(context, 0, switchIntent, 0);
notificationView.setOnClickPendingIntent(R.id.buttonswitch, pendingSwitchIntent);
Note that this way I can declare the switchButtonListener class without the static attribute (if not static, it would crash in the previous example) giving me much more flexibility.
Don't forget to call unregisterReceiver() later.
In Kotlin you can register a receiver with an anonymous class.
const val STOP_ALARM_ACTION = "STOP_ALARM"
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// ...
registerReceiver(object : BroadcastReceiver() {
override fun onReceive(p0: Context?, p1: Intent?) {
stopAlarm();
}
}, IntentFilter(STOP_ALARM_ACTION))
}
private fun playAlarm() {
ringtone.stop()
val stopIntent = Intent(STOP_ALARM_ACTION)
val stopPendingIntent = PendingIntent.getBroadcast(this, 0, stopIntent, 0)
val notification = NotificationCompat.Builder(this, "Timer1_ALARM")
// ...
.addAction(android.R.drawable.ic_delete, "Stop", stopPendingIntent)
.build()
// ...
}
private fun stopAlarm() {
ringtone.stop()
}
}
I believe it is important to also unregister action. So my way of writing this nicely is:
val playButtonAction = register("play_button_action") {
main.looper?.player?.asStarted { it.stop() }
}
so you can do:
override fun onDestroy() {
super.onDestroy()
unregister(playButtonAction)
}
using:
fun Context.register(action: String, function: () -> void): BroadcastReceiver =
register(IntentFilter(action)) { _, _ -> function() }
fun Context.register(intent: IntentFilter,
function: (Intent, BroadcastReceiver) -> void): BroadcastReceiver {
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) = function(intent, this)
}
registerReceiver(receiver, intent)
return receiver
}
fun Context.unregister(receiver: BroadcastReceiver) {
unregisterReceiver(receiver)
}
And also u use playButtonAction:
val stopIntent = PendingIntent.getBroadcast(this, 0, Intent("play_button_action"),
FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE);
This is my complete Service class:
class LooperPlayNotificationService : Service() {
companion object {
val NOTIFICATIONS_CHANNEL = "${app.packageName} notifications"
}
override fun onBind(intent: Intent): IBinder? = null
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
start()
return START_STICKY
}
override fun onCreate() {
super.onCreate()
start()
}
private val playButtonActionId = "play_button_action"
private lateinit var playButtonAction: BroadcastReceiver
private var started = false
// https://stackoverflow.com/questions/6619143/start-sticky-foreground-android-service-goes-away-without-notice
// There's a bug in 2.3 (not sure if it was fixed yet) where when a Service is killed and restarted,
// its onStartCommand() will NOT be called again. Instead you're going to have to do any setting up in onCreate()
private fun start() {
if (started) return
started = true
startForeground(647823876, createNotification())
playButtonAction = register(playButtonActionId) {
main.looper?.player?.asStarted { it.stop() }
}
}
override fun onDestroy() {
super.onDestroy()
unregister(this.playButtonAction)
}
private fun createNotification() = Builder(this, NOTIFICATIONS_CHANNEL)
.setSmallIcon(outline_all_inclusive_24)
.setContentIntent(getActivity(this, 0, Intent<InstrumentsActivity>(this),
FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE))
.setPriority(PRIORITY_DEFAULT)
.setAutoCancel(false).setOngoing(true)
.addAction(ic_stop_circle_black_24dp, "Stop",
getBroadcast(this, 0, Intent(playButtonActionId),
FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE))
.setContentText(getString(R.string.app_name))
.setContentText(main.looper?.preset?.item?.value?.title?.value).build()
}
Related
i'm writing music app. I have service with MediaPlayer which shows notification with custom view (play, next, back buttons). onClick reaction for these buttons was implemented using broadcasting. Is there a way to get access to MediaPlayer object from service, to use it in my broadcast receiver class? Or should I use bind service?
My Receiver class:
class PlayerNotificationReceiver: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if(intent != null) {
val intentAction = intent.action
when(intentAction){
"PLAY_ACTION" -> {
// HOW TO GET ACCESS TO MEDIA PLAYER IN SERVICE ?????
Toast.makeText(context, "PLAY_ACTION", Toast.LENGTH_SHORT).show()
// TODO Change image button image in fragment
}
"BACK_ACTION" -> {
// TODO Notification back button implementation
Toast.makeText(context, "BACK_ACTION", Toast.LENGTH_SHORT).show()
}
"NEXT_ACTION" -> {
// TODO Notification next button implementation
Toast.makeText(context, "NEXT_ACTION", Toast.LENGTH_SHORT).show()
}
"PAUSE_ACTION" -> {
// TODO Notification pause button implementation
Toast.makeText(context, "PAUSE_ACTION", Toast.LENGTH_SHORT).show()
}
}
}
}
}
My Service class:
class PlayerService: Service() {
private var song: Int = 0
var songDuration: Long = 0
private lateinit var playerNotificationReceiver: PlayerNotificationReceiver
private val intentRequestCode: Int = 0
private var mediaPlayer: MediaPlayer = MediaPlayer()
private var isPlaying: Boolean = false
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
// Broadcast receiver
playerNotificationReceiver = PlayerNotificationReceiver()
// Registering broadcast receiver
registerReceiver(playerNotificationReceiver, IntentFilter(getString(R.string.PLAY_ACTION)))
registerReceiver(playerNotificationReceiver, IntentFilter(getString(R.string.PAUSE_ACTION)))
registerReceiver(playerNotificationReceiver, IntentFilter(getString(R.string.BACK_ACTION)))
registerReceiver(playerNotificationReceiver, IntentFilter(getString(R.string.NEXT_ACTION)))
song = intent?.getIntExtra("song", 0) ?: R.raw.taco_hemingway_europa
// onStartCommand implementation
if (!isPlaying) {
// Creating pending intent for notification
val intent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
this,
intentRequestCode,
intent,
PendingIntent.FLAG_IMMUTABLE
)
// Pending intent with broadcast for custom view back button on click
val nextIntent = Intent(getString(R.string.NEXT_ACTION))
nextIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
val nextPendingIntent = PendingIntent.getBroadcast(this, 0, nextIntent, PendingIntent.FLAG_IMMUTABLE)
// Pending intent with broadcast for custom view back button on click
val backIntent = Intent(getString(R.string.BACK_ACTION))
backIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
val backPendingIntent = PendingIntent.getBroadcast(this, 0, backIntent, PendingIntent.FLAG_IMMUTABLE)
// Pending intent with broadcast for custom view back button on click
val playIntent = Intent(getString(R.string.PLAY_ACTION))
playIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
val playPendingIntent = PendingIntent.getBroadcast(this, 0, playIntent, PendingIntent.FLAG_IMMUTABLE)
// Remote view
val playerNotificationLayout = RemoteViews(packageName, R.layout.player_small_notification)
val playerNotificationLayoutExpanded = RemoteViews(packageName, R.layout.player_large_notification)
// Building notification with custom view
val notificationBuilder = NotificationCompat.Builder(this, PLAYER_CHANNEL)
.setContentIntent(pendingIntent)
.setSmallIcon(R.drawable.app_notification_icon)
.setStyle(NotificationCompat.DecoratedCustomViewStyle())
.setCustomContentView(playerNotificationLayout)
.setCustomBigContentView(playerNotificationLayoutExpanded)
.setContentTitle("Title")
.setContentText("Name")
// Setting custom view button on click reaction
playerNotificationLayout.setOnClickPendingIntent(R.id.notificationPlayButton, playPendingIntent)
playerNotificationLayout.setOnClickPendingIntent(R.id.notificationBackButton, backPendingIntent)
playerNotificationLayout.setOnClickPendingIntent(R.id.notificationNextButton, nextPendingIntent)
// Notification manager
val notificationManager: NotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Creating notification
val notification = notificationBuilder.build()
// Post a notification to be shown in the status bar.
notificationManager.notify(1, notification)
// Creating media player and starting music - service main task
mediaPlayer = MediaPlayer.create(this, song)
//mediaPlayer.start()
//isPlaying = true
//songDuration = mediaPlayer.duration.toLong()
// Starting Service
startForeground(1, notification)
}
return Service.START_NOT_STICKY
}
override fun onDestroy() {
super.onDestroy()
// Stop playing music and set isPlaying to false
mediaPlayer.stop()
isPlaying = false
// Unregistering broadcast receiver
unregisterReceiver(playerNotificationReceiver)
}
My fragment class:
class PlayerFragment : Fragment() {
private lateinit var playerServiceIntent: Intent
private var isPlaying: Boolean = false
// Animation lazy initalization
private val rotateAnimation by lazy { AnimationUtils.loadAnimation(requireContext(), R.anim.player_button_rotation) }
// Binding
private var _binding: FragmentPlayerBinding? = null
private val binding
get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// playerServiceIntent
playerServiceIntent = Intent(activity , PlayerService::class.java)
playerServiceIntent.putExtra("song", R.raw.taco_hemingway_europa)
// Starting service
requireActivity().startService(playerServiceIntent)
}
override fun onResume() {
super.onResume()
}
override fun onPause() {
super.onPause()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = FragmentPlayerBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// playerServiceIntent
playerServiceIntent = Intent(activity , PlayerService::class.java)
playerServiceIntent.putExtra("song", R.raw.taco_hemingway_europa)
// Starting service
requireActivity().startService(playerServiceIntent)
binding.playerPlayButton.setOnClickListener {
if(isPlaying){
// Pending intent with broadcast for custom view play button on click
val playIntent = Intent(getString(R.string.PLAY_ACTION))
playIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
val backPendingIntent = PendingIntent.getBroadcast(context, 0, playIntent, PendingIntent.FLAG_IMMUTABLE)
binding.playerPlayButton.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.pause_button, null))
} else {
// Pending intent with broadcast for custom view pause button on click
val pauseIntent = Intent(getString(R.string.PAUSE_ACTION))
pauseIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
val backPendingIntent = PendingIntent.getBroadcast(context, 0, pauseIntent, PendingIntent.FLAG_IMMUTABLE)
binding.playerPlayButton.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.play_button, null))
// TODO Start animation
//binding.playerPlayButton.startAnimation(rotateAnimation)
}
}
// TODO Time bar implementation
/*
Timer implementation
val timer = Timer()
if(mediaPlayer != null && mediaPlayer.isPlaying){
timer.scheduleAtFixedRate(timerTask {
currentPosition = mediaPlayer.currentPosition.toLong()
binding.textView.text = currentPosition.toString()
},0,1000)
} else {
timer.cancel()
timer.purge()
}
*/
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
}
A BroadcastReceiver is short lived. You cannot bind to a Service in a BroadcastReceiver, as binding is an asynchronous process and your BroadcastReceiver will be gone before the binding completes.
You can request that the Service do something by calling startService() with an Intent that has some ACTION in it that tells the Service what you want to do.
Or you can just change your notification so that the actions go directly to the Service instead of going via your BroadcastReceiver.
As an alternative, (this is kinda hacky), you could store the MediaPlayer refrerence in a public static (global) variable and then you could use it directly from your BroadcastReceiver. This is not the recommended approach, but it does work.
I have a foreground service. It does some async work in the background and periodically issues a notification asking the user if the work should be stopped.
The notification has a button "Yes, please" and when clicked it must invoke stopAction method.
The code below is where I'm stuck. I'm maybe way off and this can't be done. Any advice?
MainService.kt
...
override fun onCreate() {
subscribeToStopActionRequest()
}
private fun subscribeToStopActionRequest () {
var eventReceiverHelper = EventReceiverHelper { stopAction() }
val filter = IntentFilter().apply {
addAction("${packageName}.stop_action_request")
}
registerReceiver(eventReceiverHelper, filter)
}
private fun stopAction () {
...
}
private fun showNotification () {
val intent = Intent(this, EventService::class.java)
val pendingIntent: PendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
var notification = NotificationCompat.Builder(this, state.notificationChannelId)
.setContentTitle("Want to stop?")
.addAction(R.drawable.stop_icon, "Yes, please", pendingIntent)
.build()
with(NotificationManagerCompat.from(this)) {
notify(1, notification)
}
}
Event receiver helper
class EventReceiverHelper(val cb: () -> Unit): BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
cb()
}
}
Define a constant:
private const val EXTRA_STOP = "stop";
Then create an intent for your service and put an extra flag:
val intent = Intent(context, YourService::class.java);
intent.putExtra(EXTRA_STOP, true);
Now you can create a pending intent as your handler:
val pendingIntent: PendingIntent = PendingIntent.getService(context, YOUR_REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE)
This pending intent will trigger the onStartCommand method on your service, where you can check whether the stop flag was set.
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent != null && intent.getBooleanExtra(EXTRA_STOP, false)) {
stopAction()
}
...
}
Using a virtual Pixel 5 (API 28 Android 9.0), I would like to pass the instance of my class MainActivity to the inner class MyAlarm, but since statically declaring the receiver in the manifest would result in an instantiation error, I decided to create it dynamically. I don't know what the argument action of IntentFilter is supposed to be in my case. I tried several things, but it is hard to troubleshoot without an error. onReceive() just doesn't get executed. Also, is IntentFilter even usable, because I want to set an exact alarm using AlarmManager? Here is a shorter version of my code:
class MainActivity : AppCompatActivity() {
companion object {
const val REQUEST_ID = 843
const val NOTIFICATION_ID = 349
const val NOTIFICATION_CHANNEL_ID = "9552"
}
lateinit var myAlarm : MyAlarm
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
myAlarm = MyAlarm(this)
val intentFilter = IntentFilter("")
registerReceiver(myAlarm, intentFilter)
setAlarm(System.currentTimeMillis() + 4000)
private fun setAlarm(timeInMillis: Long) {
val intent = Intent(this, myAlarm::class.java)
val pendingIntent = PendingIntent.getBroadcast(this, REQUEST_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, timeInMillis, pendingIntent)
override fun onStop() {
super.onStop()
unregisterReceiver(myAlarm)
}
class MyAlarm(var mainActivityInstance: MainActivity) : BroadcastReceiver() {
lateinit var mediaPlayer : MediaPlayer
override fun onReceive(
context: Context,
intent: Intent
) {
if (!this::mediaPlayer.isInitialized) {
mediaPlayer = MediaPlayer.create(context, R.raw.sea_waves)
mediaPlayer.isLooping = true
}
createNotificationChannel(context)
sendNotification(context, "ALARM", "Wake up", "")
mediaPlayer.start()
// Calling method of mainActivityInstance here
private fun createNotificationChannel(context: Context) {
val name = "Alarm Clock Light Channel"
val importance = NotificationManager.IMPORTANCE_HIGH
val channel = NotificationChannel(NOTIFICATION_CHANNEL_ID, name, importance)
NotificationManagerCompat.from(context).createNotificationChannel(channel)
}
private fun sendNotification(context: Context, title: String, text: String, detail_text: String) {
val builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(androidx.core.R.drawable.notification_icon_background)
.setContentTitle(title)
.setContentText(text)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setStyle(NotificationCompat.BigTextStyle().bigText(detail_text))
NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, builder.build())
}
}
Not sure what you want to do. Set an alarm and when it goes off open your media player activity to play a song or something?
Don't pass activity instances to broadcast receivers. They have very different lifecycle. Secondly dynamic broadcast receivers only exist while your process is alive. Use a fullscreen intent in your notification to let NotificationManager launch your activity.
See here: https://developer.android.com/training/notify-user/time-sensitive
Create a static receiver that reacts to your alarm. There post your notification with the fullscreen intent.
Why calling context.stopService(stopIntent) is going to execute onStartCommand am i missing something?
i had to do this in the onStartCommand
if (ACTION_STOP_SERVICE == intent?.action) { stopSelf() }
While the doc said specifically this:
onStartCommand Called by the system every time a client explicitly
starts the service by calling Context.startService
The code sample
#AndroidEntryPoint
class MyService : Service() {
private val ACTION_STOP_SERVICE: String = "ACTION_STOP_SERVICE"
private val ACTION_START_SERVICE: String = "ACTION_START_SERVICE"
#OptIn(InternalCoroutinesApi::class)
#ExperimentalCoroutinesApi
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (ACTION_START_SERVICE == intent?.action) {
// Start mqtt client "org.eclipse.paho:org.eclipse.paho.client"
}
if (ACTION_STOP_SERVICE == intent?.action) {
mqtt.disconnect()
stopSelf()
}
val stopIntent = Intent(this.applicationContext, BPSMqttService::class.java)
stopIntent.action = ACTION_STOP_SERVICE
val pStopIntent =
PendingIntent.getService(
BPSApp.instance.applicationContext,
0,
stopIntent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
val notificationIntent =
Intent(this.applicationContext, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
this.applicationContext,
0, notificationIntent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
val notification =
NotificationCompat.Builder(this.applicationContext, SERVICE_CHANNEL_ID)
.setContentTitle("My service")
.setContentText(input)
.setSmallIcon(R.drawable.ic_alarms_sync)
.setContentIntent(pendingIntent)
.addAction(0, "Stop", pStopIntent)
.build()
startForeground(1, notification)
return START_STICKY
}
override fun onDestroy() {
try {
super.onDestroy()
Log.d("MyService ", "onDestroy is done")
} catch (ex: Throwable) {
Log.d("MyService ", "onDestroy ${ex.message}")
}
}
override fun onCreate() {
try {
super.onCreate()
Log.d("MyService ", "nCreate is done")
} catch (ex: Throwable) {
Log.d("MyService ", "onCreate ${ex.message}")
}
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
}
And in other places other than the notification i am doing this to stop
val stopIntent = Intent(BPSApp.instance.applicationContext, BPSMqttService::class.java)
stopIntent.action = "ACTION_STOP_SERVICE"
BPSApp.instance.applicationContext.stopService(stopIntent)
And doing this to start
val startIntent = Intent(BPSApp.instance.applicationContext, BPSMqttService::class.java)
startIntent.action = "ACTION_START_SERVICE"
BPSApp.instance.applicationContext.startForegroundService(startIntent);
It looks like you are seeing onStartCommand() being called as a result of your Notification.
The notification action "stop" will call startService(), so that's what you are seeing. In the other places in the code, when you call stopService(), onStartCommand() will not be called.
I've been browsing many topics about resuming an activity from a foreground service without finding any concrete answer to my problem.
I'm trying to put a foreground service in my app, and I want the app to be resumed when clicking on the service notification instead of relaunching it. I've tried using the getLaunchIntentForPackage() method from PackageManager, which is the closest to what I want to do.
However, the activity's onCreate is still being called when resuming the app by clicking on the notification.
So here is my question, how to resume an app from a notification's content intent?
I'm starting my ForegroundService in the activity's onStop so it gets called when the app is killed or sent to background.
override fun onStop() {
super.onStop()
Log.v(TAG, "onStop")
ForegroundService.startService(this, "Hellooooooo, here is the background")
}
ForegroundService
class ForegroundService: Service() {
companion object {
private const val CHANNEL_ID = "ForegroundServiceChannel"
fun startService(context: Context, message: String) {
val startIntent = Intent(context, ForegroundService::class.java)
startIntent.putExtra("inputExtra", message)
ContextCompat.startForegroundService(context, startIntent)
}
fun stopService(context: Context) {
val stopIntent = Intent(context, ForegroundService::class.java)
context.stopService(stopIntent)
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val input = intent!!.getStringExtra("inputExtra")
val launchIntent = packageManager.getLaunchIntentForPackage(APP_PACKAGE)
val contentIntent = PendingIntent.getActivity(applicationContext, 0,
launchIntent, 0)
val notification: Notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText(input)
.setContentIntent(contentIntent)
.setSmallIcon(R.drawable.ic_call_to_action)
.setOngoing(true)
.build()
startForeground(1, notification)
createNotificationChannel()
return START_NOT_STICKY
}
override fun onBind(p0: Intent?): IBinder? {
return null
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val serviceChannel = NotificationChannel(
CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
)
val manager = getSystemService(
NotificationManager::class.java
)
manager?.createNotificationChannel(serviceChannel)
}
}
}
Try set in the manifest for activity android:launchMode="singleInstance".
Do not forget set some your action to your activity intent:
activityIntent.setAction(ACTION_STARTED_FROM_NOTIFICATION);
Override onNewIntent in the activity.
in onCreate and in onNewIntent do check
if(ACTION_STARTED_FROM_NOTIFICATION.equalsIgnoreCase(intent.getAction()))
{ do what you need }