diff --git a/app/src/main/java/sushi/hardcore/aira/MainActivity.kt b/app/src/main/java/sushi/hardcore/aira/MainActivity.kt index 0fd10b5..b167067 100644 --- a/app/src/main/java/sushi/hardcore/aira/MainActivity.kt +++ b/app/src/main/java/sushi/hardcore/aira/MainActivity.kt @@ -17,6 +17,7 @@ import sushi.hardcore.aira.adapters.Session import sushi.hardcore.aira.adapters.SessionAdapter import sushi.hardcore.aira.background_service.AIRAService 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.DialogIpAddressesBinding import sushi.hardcore.aira.utils.FileUtils @@ -145,6 +146,9 @@ class MainActivity : ServiceBoundActivity() { } setOnScrollListener(onSessionsScrollListener) } + if (intent.action == NotificationBroadcastReceiver.ACTION_LOGOUT) { + askLogOut() + } } serviceConnection = object : ServiceConnection { override fun onServiceConnected(name: ComponentName?, service: IBinder) { @@ -209,18 +213,7 @@ class MainActivity : ServiceBoundActivity() { } R.id.close -> { if (isServiceInitialized()) { - 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() + askLogOut() } 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) { var uris: ArrayList? = null when (intent.action) { diff --git a/app/src/main/java/sushi/hardcore/aira/background_service/AIRAService.kt b/app/src/main/java/sushi/hardcore/aira/background_service/AIRAService.kt index 225bc52..6655a65 100644 --- a/app/src/main/java/sushi/hardcore/aira/background_service/AIRAService.kt +++ b/app/src/main/java/sushi/hardcore/aira/background_service/AIRAService.kt @@ -1,5 +1,6 @@ package sushi.hardcore.aira.background_service +import android.annotation.SuppressLint import android.app.* import android.content.Context import android.content.Intent @@ -22,6 +23,7 @@ import java.io.IOException import java.net.* import java.nio.channels.* +@SuppressLint("UnspecifiedImmutableFlag") class AIRAService : Service() { private external fun releaseIdentity() @@ -36,6 +38,7 @@ class AIRAService : Service() { const val MESSAGE_SEND_NAME = 3 const val MESSAGE_SEND_AVATAR = 4 const val MESSAGE_CANCEL_FILE_TRANSFER = 5 + const val FLAG_PENDING_INTENT = PendingIntent.FLAG_UPDATE_CURRENT var isServiceRunning = false } @@ -360,7 +363,7 @@ class AIRAService : Service() { } 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) .setSmallIcon(R.drawable.ic_launcher) .setContentTitle(getNameOf(sessionId)) @@ -374,49 +377,35 @@ class AIRAService : Service() { .setContentIntent( PendingIntent.getActivity(this, 0, Intent(this, ChatActivity::class.java).apply { putExtra("sessionId", sessionId) - }, 0) + }, FLAG_PENDING_INTENT) ) .setAutoCancel(true) .setDefaults(Notification.DEFAULT_ALL) .apply { priority = NotificationCompat.PRIORITY_HIGH } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { - val markReadIntent = PendingIntent.getBroadcast(this, 0, - Intent(this, NotificationBroadcastReceiver::class.java).apply { - val bundle = Bundle() - bundle.putBinder("binder", AIRABinder()) - bundle.putInt("sessionId", sessionId) - putExtra("bundle", bundle) - action = NotificationBroadcastReceiver.ACTION_MARK_READ - }, PendingIntent.FLAG_UPDATE_CURRENT) - notificationBuilder.addAction( - NotificationCompat.Action( - R.drawable.ic_launcher, - getString(R.string.mark_read), - markReadIntent + .addAction(NotificationCompat.Action( + R.drawable.ic_launcher, + getString(R.string.mark_read), + newActionPendingIntent { + it.putBinder(sessionId) + it.action = NotificationBroadcastReceiver.ACTION_MARK_READ + } + )) + .addAction( + NotificationCompat.Action.Builder(R.drawable.ic_launcher, getString(R.string.reply), newActionPendingIntent { + it.putBinder(sessionId) + it.action = NotificationBroadcastReceiver.ACTION_REPLY + }) + .addRemoteInput( + RemoteInput.Builder(NotificationBroadcastReceiver.KEY_TEXT_REPLY) + .setLabel(getString(R.string.reply)) + .build() ) - ) - val replyPendingIntent: PendingIntent = - PendingIntent.getBroadcast(this, 0, - Intent(this, NotificationBroadcastReceiver::class.java).apply { - 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()) + .build() + ) + .build() + notificationManager.notify(notificationIdManager.getMessageNotificationId(sessionId), notification) } private fun initFileTransferNotification(sessionId: Int, fileTransferNotification: FileTransferNotification, file: PendingFile) { @@ -425,15 +414,19 @@ class AIRAService : Service() { file.fileName, file.fileSize.toInt(), Intent(this, NotificationBroadcastReceiver::class.java).apply { - val bundle = Bundle() - bundle.putBinder("binder", AIRABinder()) - bundle.putInt("sessionId", sessionId) - putExtra("bundle", bundle) + putBinder(sessionId) 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) { var msgSaved = false contacts[sessionId]?.uuid?.let { uuid -> @@ -768,7 +761,7 @@ class AIRAService : Service() { .setContentIntent( PendingIntent.getActivity(this, 0, Intent(this, ChatActivity::class.java).apply { putExtra("sessionId", sessionId) - }, 0) + }, FLAG_PENDING_INTENT) ) .setDefaults(Notification.DEFAULT_ALL) .apply { @@ -875,6 +868,7 @@ class AIRAService : Service() { } } } + keys.clear() } for (session in sessions.values) { 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 { 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() - 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 .setContentTitle(getString(R.string.background_service)) .setSmallIcon(R.drawable.ic_launcher) .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() startForeground(1, notification) diff --git a/app/src/main/java/sushi/hardcore/aira/background_service/NotificationBroadcastReceiver.kt b/app/src/main/java/sushi/hardcore/aira/background_service/NotificationBroadcastReceiver.kt index 5587fdb..4d85dd9 100644 --- a/app/src/main/java/sushi/hardcore/aira/background_service/NotificationBroadcastReceiver.kt +++ b/app/src/main/java/sushi/hardcore/aira/background_service/NotificationBroadcastReceiver.kt @@ -4,28 +4,38 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import androidx.core.app.RemoteInput +import sushi.hardcore.aira.MainActivity class NotificationBroadcastReceiver: BroadcastReceiver() { companion object { + const val ACTION_LOGOUT = "logout" const val ACTION_MARK_READ = "mark_read" const val ACTION_CANCEL_FILE_TRANSFER = "cancel" const val ACTION_REPLY = "reply" const val KEY_TEXT_REPLY = "key_text_reply" } - override fun onReceive(context: Context?, intent: Intent) { - intent.getBundleExtra("bundle")?.let { bundle -> - (bundle.getBinder("binder") as AIRAService.AIRABinder?)?.let { binder -> - 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) + override fun onReceive(context: Context, intent: Intent) { + if (intent.action == ACTION_LOGOUT) { + context.startActivity(Intent(context, MainActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + action = ACTION_LOGOUT + }) + context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) + } else { + intent.getBundleExtra("bundle")?.let { bundle -> + (bundle.getBinder("binder") as AIRAService.AIRABinder?)?.let { binder -> + 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 -> {} } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5065d8b..7e511e4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -99,6 +99,11 @@ AIRA-android repository on GitHub. Gitea AIRA-android repository on the Gitea instance of the Chapril project. Unlike GitHub, Gitea is fully free software and self-hosted. + Your contact seems to be offline. + Sent messages will be stored until a connection is established. + Pending messages: + Sending pending messages… + Stop Send file @@ -108,9 +113,5 @@ Clickable indicator Avatar Name - Your contact seems to be offline. - Sent messages will be stored until a connection is established. Warning icon - Pending messages: - Sending pending messages… \ No newline at end of file