Add stop button in background service notification
This commit is contained in:
parent
3562362916
commit
fc46326deb
|
@ -17,6 +17,7 @@ import sushi.hardcore.aira.adapters.Session
|
||||||
import sushi.hardcore.aira.adapters.SessionAdapter
|
import sushi.hardcore.aira.adapters.SessionAdapter
|
||||||
import sushi.hardcore.aira.background_service.AIRAService
|
import sushi.hardcore.aira.background_service.AIRAService
|
||||||
import sushi.hardcore.aira.background_service.FilesReceiver
|
import sushi.hardcore.aira.background_service.FilesReceiver
|
||||||
|
import sushi.hardcore.aira.background_service.NotificationBroadcastReceiver
|
||||||
import sushi.hardcore.aira.databinding.ActivityMainBinding
|
import sushi.hardcore.aira.databinding.ActivityMainBinding
|
||||||
import sushi.hardcore.aira.databinding.DialogIpAddressesBinding
|
import sushi.hardcore.aira.databinding.DialogIpAddressesBinding
|
||||||
import sushi.hardcore.aira.utils.FileUtils
|
import sushi.hardcore.aira.utils.FileUtils
|
||||||
|
@ -145,6 +146,9 @@ class MainActivity : ServiceBoundActivity() {
|
||||||
}
|
}
|
||||||
setOnScrollListener(onSessionsScrollListener)
|
setOnScrollListener(onSessionsScrollListener)
|
||||||
}
|
}
|
||||||
|
if (intent.action == NotificationBroadcastReceiver.ACTION_LOGOUT) {
|
||||||
|
askLogOut()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
serviceConnection = object : ServiceConnection {
|
serviceConnection = object : ServiceConnection {
|
||||||
override fun onServiceConnected(name: ComponentName?, service: IBinder) {
|
override fun onServiceConnected(name: ComponentName?, service: IBinder) {
|
||||||
|
@ -209,18 +213,7 @@ class MainActivity : ServiceBoundActivity() {
|
||||||
}
|
}
|
||||||
R.id.close -> {
|
R.id.close -> {
|
||||||
if (isServiceInitialized()) {
|
if (isServiceInitialized()) {
|
||||||
AlertDialog.Builder(this, R.style.CustomAlertDialog)
|
askLogOut()
|
||||||
.setTitle(R.string.warning)
|
|
||||||
.setMessage(R.string.ask_log_out)
|
|
||||||
.setPositiveButton(R.string.yes) { _, _ ->
|
|
||||||
airaService.logOut()
|
|
||||||
if (AIRADatabase.isIdentityProtected(Constants.getDatabaseFolder(this))) {
|
|
||||||
startActivity(Intent(this, LoginActivity::class.java))
|
|
||||||
}
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
.setNegativeButton(R.string.cancel, null)
|
|
||||||
.show()
|
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -334,6 +327,21 @@ class MainActivity : ServiceBoundActivity() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun askLogOut() {
|
||||||
|
AlertDialog.Builder(this, R.style.CustomAlertDialog)
|
||||||
|
.setTitle(R.string.warning)
|
||||||
|
.setMessage(R.string.ask_log_out)
|
||||||
|
.setPositiveButton(R.string.yes) { _, _ ->
|
||||||
|
airaService.logOut()
|
||||||
|
if (AIRADatabase.isIdentityProtected(Constants.getDatabaseFolder(this))) {
|
||||||
|
startActivity(Intent(this, LoginActivity::class.java))
|
||||||
|
}
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
private fun askShareFileTo(session: Session) {
|
private fun askShareFileTo(session: Session) {
|
||||||
var uris: ArrayList<Uri>? = null
|
var uris: ArrayList<Uri>? = null
|
||||||
when (intent.action) {
|
when (intent.action) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package sushi.hardcore.aira.background_service
|
package sushi.hardcore.aira.background_service
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.*
|
import android.app.*
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
@ -22,6 +23,7 @@ import java.io.IOException
|
||||||
import java.net.*
|
import java.net.*
|
||||||
import java.nio.channels.*
|
import java.nio.channels.*
|
||||||
|
|
||||||
|
@SuppressLint("UnspecifiedImmutableFlag")
|
||||||
class AIRAService : Service() {
|
class AIRAService : Service() {
|
||||||
private external fun releaseIdentity()
|
private external fun releaseIdentity()
|
||||||
|
|
||||||
|
@ -36,6 +38,7 @@ class AIRAService : Service() {
|
||||||
const val MESSAGE_SEND_NAME = 3
|
const val MESSAGE_SEND_NAME = 3
|
||||||
const val MESSAGE_SEND_AVATAR = 4
|
const val MESSAGE_SEND_AVATAR = 4
|
||||||
const val MESSAGE_CANCEL_FILE_TRANSFER = 5
|
const val MESSAGE_CANCEL_FILE_TRANSFER = 5
|
||||||
|
const val FLAG_PENDING_INTENT = PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
|
|
||||||
var isServiceRunning = false
|
var isServiceRunning = false
|
||||||
}
|
}
|
||||||
|
@ -360,7 +363,7 @@ class AIRAService : Service() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendNotification(sessionId: Int, msgContent: ByteArray) {
|
private fun sendNotification(sessionId: Int, msgContent: ByteArray) {
|
||||||
val notificationBuilder = NotificationCompat.Builder(this, MESSAGES_NOTIFICATION_CHANNEL_ID)
|
val notification = NotificationCompat.Builder(this, MESSAGES_NOTIFICATION_CHANNEL_ID)
|
||||||
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
|
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
|
||||||
.setSmallIcon(R.drawable.ic_launcher)
|
.setSmallIcon(R.drawable.ic_launcher)
|
||||||
.setContentTitle(getNameOf(sessionId))
|
.setContentTitle(getNameOf(sessionId))
|
||||||
|
@ -374,49 +377,35 @@ class AIRAService : Service() {
|
||||||
.setContentIntent(
|
.setContentIntent(
|
||||||
PendingIntent.getActivity(this, 0, Intent(this, ChatActivity::class.java).apply {
|
PendingIntent.getActivity(this, 0, Intent(this, ChatActivity::class.java).apply {
|
||||||
putExtra("sessionId", sessionId)
|
putExtra("sessionId", sessionId)
|
||||||
}, 0)
|
}, FLAG_PENDING_INTENT)
|
||||||
)
|
)
|
||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
.setDefaults(Notification.DEFAULT_ALL)
|
.setDefaults(Notification.DEFAULT_ALL)
|
||||||
.apply {
|
.apply {
|
||||||
priority = NotificationCompat.PRIORITY_HIGH
|
priority = NotificationCompat.PRIORITY_HIGH
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
|
.addAction(NotificationCompat.Action(
|
||||||
val markReadIntent = PendingIntent.getBroadcast(this, 0,
|
R.drawable.ic_launcher,
|
||||||
Intent(this, NotificationBroadcastReceiver::class.java).apply {
|
getString(R.string.mark_read),
|
||||||
val bundle = Bundle()
|
newActionPendingIntent {
|
||||||
bundle.putBinder("binder", AIRABinder())
|
it.putBinder(sessionId)
|
||||||
bundle.putInt("sessionId", sessionId)
|
it.action = NotificationBroadcastReceiver.ACTION_MARK_READ
|
||||||
putExtra("bundle", bundle)
|
}
|
||||||
action = NotificationBroadcastReceiver.ACTION_MARK_READ
|
))
|
||||||
}, PendingIntent.FLAG_UPDATE_CURRENT)
|
.addAction(
|
||||||
notificationBuilder.addAction(
|
NotificationCompat.Action.Builder(R.drawable.ic_launcher, getString(R.string.reply), newActionPendingIntent {
|
||||||
NotificationCompat.Action(
|
it.putBinder(sessionId)
|
||||||
R.drawable.ic_launcher,
|
it.action = NotificationBroadcastReceiver.ACTION_REPLY
|
||||||
getString(R.string.mark_read),
|
})
|
||||||
markReadIntent
|
.addRemoteInput(
|
||||||
|
RemoteInput.Builder(NotificationBroadcastReceiver.KEY_TEXT_REPLY)
|
||||||
|
.setLabel(getString(R.string.reply))
|
||||||
|
.build()
|
||||||
)
|
)
|
||||||
)
|
.build()
|
||||||
val replyPendingIntent: PendingIntent =
|
)
|
||||||
PendingIntent.getBroadcast(this, 0,
|
.build()
|
||||||
Intent(this, NotificationBroadcastReceiver::class.java).apply {
|
notificationManager.notify(notificationIdManager.getMessageNotificationId(sessionId), notification)
|
||||||
val bundle = Bundle()
|
|
||||||
bundle.putBinder("binder", AIRABinder())
|
|
||||||
bundle.putInt("sessionId", sessionId)
|
|
||||||
putExtra("bundle", bundle)
|
|
||||||
action = NotificationBroadcastReceiver.ACTION_REPLY
|
|
||||||
}, PendingIntent.FLAG_UPDATE_CURRENT)
|
|
||||||
notificationBuilder.addAction(
|
|
||||||
NotificationCompat.Action.Builder(R.drawable.ic_launcher, getString(R.string.reply), replyPendingIntent)
|
|
||||||
.addRemoteInput(
|
|
||||||
RemoteInput.Builder(NotificationBroadcastReceiver.KEY_TEXT_REPLY)
|
|
||||||
.setLabel(getString(R.string.reply))
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
notificationManager.notify(notificationIdManager.getMessageNotificationId(sessionId), notificationBuilder.build())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initFileTransferNotification(sessionId: Int, fileTransferNotification: FileTransferNotification, file: PendingFile) {
|
private fun initFileTransferNotification(sessionId: Int, fileTransferNotification: FileTransferNotification, file: PendingFile) {
|
||||||
|
@ -425,15 +414,19 @@ class AIRAService : Service() {
|
||||||
file.fileName,
|
file.fileName,
|
||||||
file.fileSize.toInt(),
|
file.fileSize.toInt(),
|
||||||
Intent(this, NotificationBroadcastReceiver::class.java).apply {
|
Intent(this, NotificationBroadcastReceiver::class.java).apply {
|
||||||
val bundle = Bundle()
|
putBinder(sessionId)
|
||||||
bundle.putBinder("binder", AIRABinder())
|
|
||||||
bundle.putInt("sessionId", sessionId)
|
|
||||||
putExtra("bundle", bundle)
|
|
||||||
action = NotificationBroadcastReceiver.ACTION_CANCEL_FILE_TRANSFER
|
action = NotificationBroadcastReceiver.ACTION_CANCEL_FILE_TRANSFER
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Intent.putBinder(sessionId: Int) {
|
||||||
|
val bundle = Bundle()
|
||||||
|
bundle.putBinder("binder", AIRABinder())
|
||||||
|
bundle.putInt("sessionId", sessionId)
|
||||||
|
putExtra("bundle", bundle)
|
||||||
|
}
|
||||||
|
|
||||||
private fun saveMsg(sessionId: Int, timestamp: Long, msg: ByteArray) {
|
private fun saveMsg(sessionId: Int, timestamp: Long, msg: ByteArray) {
|
||||||
var msgSaved = false
|
var msgSaved = false
|
||||||
contacts[sessionId]?.uuid?.let { uuid ->
|
contacts[sessionId]?.uuid?.let { uuid ->
|
||||||
|
@ -768,7 +761,7 @@ class AIRAService : Service() {
|
||||||
.setContentIntent(
|
.setContentIntent(
|
||||||
PendingIntent.getActivity(this, 0, Intent(this, ChatActivity::class.java).apply {
|
PendingIntent.getActivity(this, 0, Intent(this, ChatActivity::class.java).apply {
|
||||||
putExtra("sessionId", sessionId)
|
putExtra("sessionId", sessionId)
|
||||||
}, 0)
|
}, FLAG_PENDING_INTENT)
|
||||||
)
|
)
|
||||||
.setDefaults(Notification.DEFAULT_ALL)
|
.setDefaults(Notification.DEFAULT_ALL)
|
||||||
.apply {
|
.apply {
|
||||||
|
@ -875,6 +868,7 @@ class AIRAService : Service() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
keys.clear()
|
||||||
}
|
}
|
||||||
for (session in sessions.values) {
|
for (session in sessions.values) {
|
||||||
session.close()
|
session.close()
|
||||||
|
@ -928,21 +922,37 @@ class AIRAService : Service() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun newActionPendingIntent(intentBuilder: (Intent) -> Unit): PendingIntent {
|
||||||
|
return PendingIntent.getBroadcast(this, 0,
|
||||||
|
Intent(this, NotificationBroadcastReceiver::class.java).apply {
|
||||||
|
intentBuilder(this)
|
||||||
|
}, FLAG_PENDING_INTENT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
notificationManager = NotificationManagerCompat.from(this)
|
notificationManager = NotificationManagerCompat.from(this)
|
||||||
val notificationBuilder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
createNotificationChannels()
|
createNotificationChannels()
|
||||||
Notification.Builder(this, SERVICE_NOTIFICATION_CHANNEL_ID)
|
|
||||||
} else {
|
|
||||||
@Suppress("Deprecation")
|
|
||||||
Notification.Builder(this)
|
|
||||||
}
|
}
|
||||||
|
val notificationBuilder = NotificationCompat.Builder(this, SERVICE_NOTIFICATION_CHANNEL_ID)
|
||||||
val notification: Notification = notificationBuilder
|
val notification: Notification = notificationBuilder
|
||||||
.setContentTitle(getString(R.string.background_service))
|
.setContentTitle(getString(R.string.background_service))
|
||||||
.setSmallIcon(R.drawable.ic_launcher)
|
.setSmallIcon(R.drawable.ic_launcher)
|
||||||
.setContentIntent(
|
.setContentIntent(
|
||||||
PendingIntent.getActivity(this, 0, Intent(this, MainActivity::class.java), 0)
|
PendingIntent.getActivity(this, 0,
|
||||||
|
Intent(this, MainActivity::class.java).apply {
|
||||||
|
setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||||
|
},
|
||||||
|
FLAG_PENDING_INTENT)
|
||||||
)
|
)
|
||||||
|
.addAction(NotificationCompat.Action(
|
||||||
|
R.drawable.ic_launcher,
|
||||||
|
getString(R.string.stop),
|
||||||
|
newActionPendingIntent {
|
||||||
|
it.action = NotificationBroadcastReceiver.ACTION_LOGOUT
|
||||||
|
}
|
||||||
|
))
|
||||||
.build()
|
.build()
|
||||||
startForeground(1, notification)
|
startForeground(1, notification)
|
||||||
|
|
||||||
|
|
|
@ -4,28 +4,38 @@ import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.core.app.RemoteInput
|
import androidx.core.app.RemoteInput
|
||||||
|
import sushi.hardcore.aira.MainActivity
|
||||||
|
|
||||||
class NotificationBroadcastReceiver: BroadcastReceiver() {
|
class NotificationBroadcastReceiver: BroadcastReceiver() {
|
||||||
companion object {
|
companion object {
|
||||||
|
const val ACTION_LOGOUT = "logout"
|
||||||
const val ACTION_MARK_READ = "mark_read"
|
const val ACTION_MARK_READ = "mark_read"
|
||||||
const val ACTION_CANCEL_FILE_TRANSFER = "cancel"
|
const val ACTION_CANCEL_FILE_TRANSFER = "cancel"
|
||||||
const val ACTION_REPLY = "reply"
|
const val ACTION_REPLY = "reply"
|
||||||
const val KEY_TEXT_REPLY = "key_text_reply"
|
const val KEY_TEXT_REPLY = "key_text_reply"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onReceive(context: Context?, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
intent.getBundleExtra("bundle")?.let { bundle ->
|
if (intent.action == ACTION_LOGOUT) {
|
||||||
(bundle.getBinder("binder") as AIRAService.AIRABinder?)?.let { binder ->
|
context.startActivity(Intent(context, MainActivity::class.java).apply {
|
||||||
val sessionId = bundle.getInt("sessionId")
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
val airaService = binder.getService()
|
action = ACTION_LOGOUT
|
||||||
when (intent.action) {
|
})
|
||||||
ACTION_MARK_READ -> airaService.setSeen(sessionId, true)
|
context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
|
||||||
ACTION_CANCEL_FILE_TRANSFER -> airaService.cancelFileTransfer(sessionId)
|
} else {
|
||||||
ACTION_REPLY -> RemoteInput.getResultsFromIntent(intent)?.getString(KEY_TEXT_REPLY)?.let { reply ->
|
intent.getBundleExtra("bundle")?.let { bundle ->
|
||||||
airaService.sendOrAddToPending(sessionId, Protocol.newMessage(reply))
|
(bundle.getBinder("binder") as AIRAService.AIRABinder?)?.let { binder ->
|
||||||
airaService.setSeen(sessionId, true)
|
val sessionId = bundle.getInt("sessionId")
|
||||||
|
val airaService = binder.getService()
|
||||||
|
when (intent.action) {
|
||||||
|
ACTION_MARK_READ -> airaService.setSeen(sessionId, true)
|
||||||
|
ACTION_CANCEL_FILE_TRANSFER -> airaService.cancelFileTransfer(sessionId)
|
||||||
|
ACTION_REPLY -> RemoteInput.getResultsFromIntent(intent)?.getString(KEY_TEXT_REPLY)?.let { reply ->
|
||||||
|
airaService.sendOrAddToPending(sessionId, Protocol.newMessage(reply))
|
||||||
|
airaService.setSeen(sessionId, true)
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
}
|
}
|
||||||
else -> {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,6 +99,11 @@
|
||||||
<string name="github_summary">AIRA-android repository on GitHub.</string>
|
<string name="github_summary">AIRA-android repository on GitHub.</string>
|
||||||
<string name="gitea">Gitea</string>
|
<string name="gitea">Gitea</string>
|
||||||
<string name="gitea_summary">AIRA-android repository on the Gitea instance of the Chapril project. Unlike GitHub, Gitea is fully free software and self-hosted.</string>
|
<string name="gitea_summary">AIRA-android repository on the Gitea instance of the Chapril project. Unlike GitHub, Gitea is fully free software and self-hosted.</string>
|
||||||
|
<string name="offline_warning_title">Your contact seems to be offline.</string>
|
||||||
|
<string name="offline_warning_msg">Sent messages will be stored until a connection is established.</string>
|
||||||
|
<string name="pending_messages">Pending messages:</string>
|
||||||
|
<string name="sending_pending_messages">Sending pending messages…</string>
|
||||||
|
<string name="stop">Stop</string>
|
||||||
|
|
||||||
<!--accessibility strings-->
|
<!--accessibility strings-->
|
||||||
<string name="send_file">Send file</string>
|
<string name="send_file">Send file</string>
|
||||||
|
@ -108,9 +113,5 @@
|
||||||
<string name="clickable_indicator">Clickable indicator</string>
|
<string name="clickable_indicator">Clickable indicator</string>
|
||||||
<string name="avatar">Avatar</string>
|
<string name="avatar">Avatar</string>
|
||||||
<string name="name">Name</string>
|
<string name="name">Name</string>
|
||||||
<string name="offline_warning_title">Your contact seems to be offline.</string>
|
|
||||||
<string name="offline_warning_msg">Sent messages will be stored until a connection is established.</string>
|
|
||||||
<string name="warning_desc">Warning icon</string>
|
<string name="warning_desc">Warning icon</string>
|
||||||
<string name="pending_messages">Pending messages:</string>
|
|
||||||
<string name="sending_pending_messages">Sending pending messages…</string>
|
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in New Issue