Use LiveData to observe service events

Avoid bluetooth related error
This commit is contained in:
Juha Heinanen
2022-01-27 18:30:44 +02:00
parent 8598a6f67f
commit 06dd814a27
4 changed files with 124 additions and 114 deletions
@@ -26,7 +26,6 @@ import androidx.annotation.Keep
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import java.io.File import java.io.File
import java.net.InetAddress import java.net.InetAddress
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
@@ -75,7 +74,7 @@ class BaresipService: Service() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
Log.d(TAG, "At onCreate") Log.d(TAG, "BaresipService onCreate")
intent = Intent("com.tutpro.baresip.EVENT") intent = Intent("com.tutpro.baresip.EVENT")
intent.setPackage("com.tutpro.baresip") intent.setPackage("com.tutpro.baresip")
@@ -555,12 +554,14 @@ class BaresipService: Service() {
else else
status[account_index] = R.drawable.dot_green status[account_index] = R.drawable.dot_green
updateStatusNotification() updateStatusNotification()
if (isMainVisible)
registrationUpdate.postValue(System.currentTimeMillis()) registrationUpdate.postValue(System.currentTimeMillis())
return return
} }
"registering failed" -> { "registering failed" -> {
status[account_index] = R.drawable.dot_red status[account_index] = R.drawable.dot_red
updateStatusNotification() updateStatusNotification()
if (isMainVisible)
registrationUpdate.postValue(System.currentTimeMillis()) registrationUpdate.postValue(System.currentTimeMillis())
if (Utils.isVisible()) { if (Utils.isVisible()) {
val reason = if (ev.size > 1) { val reason = if (ev.size > 1) {
@@ -577,6 +578,7 @@ class BaresipService: Service() {
"unregistering" -> { "unregistering" -> {
status[account_index] = R.drawable.dot_white status[account_index] = R.drawable.dot_white
updateStatusNotification() updateStatusNotification()
if (isMainVisible)
registrationUpdate.postValue(System.currentTimeMillis()) registrationUpdate.postValue(System.currentTimeMillis())
return return
} }
@@ -708,7 +710,7 @@ class BaresipService: Service() {
call.onhold = false call.onhold = false
if (ua.account.callHistory) if (ua.account.callHistory)
call.startTime = GregorianCalendar() call.startTime = GregorianCalendar()
if (!Utils.isVisible()) if (!isMainVisible)
return return
} }
"call update" -> { "call update" -> {
@@ -716,6 +718,8 @@ class BaresipService: Service() {
"0", "1" -> call!!.held = true "0", "1" -> call!!.held = true
"2", "3" -> call!!.held = false "2", "3" -> call!!.held = false
} }
if (!isMainVisible || call!!.status != "connected")
return
} }
"call verified", "call secure" -> { "call verified", "call secure" -> {
if (ev[0] == "call secure") { if (ev[0] == "call secure") {
@@ -724,7 +728,7 @@ class BaresipService: Service() {
call!!.security = R.drawable.box_green call!!.security = R.drawable.box_green
call.zid = ev[1] call.zid = ev[1]
} }
if (!Utils.isVisible()) if (!isMainVisible)
return return
} }
"call transfer" -> { "call transfer" -> {
@@ -782,7 +786,10 @@ class BaresipService: Service() {
Log.d(TAG, "AoR $aor call $callp transfer failed: ${ev[1]}") Log.d(TAG, "AoR $aor call $callp transfer failed: ${ev[1]}")
stopMediaPlayer() stopMediaPlayer()
call!!.referTo = "" call!!.referTo = ""
if (!Utils.isVisible()) return if (Utils.isVisible())
toast("${getString(R.string.transfer_failed)}: ${ev[1].trim()}")
if (!isMainVisible)
return
} }
"call closed" -> { "call closed" -> {
nm.cancel(CALL_NOTIFICATION_ID) nm.cancel(CALL_NOTIFICATION_ID)
@@ -813,7 +820,8 @@ class BaresipService: Service() {
NewCallHistory.save() NewCallHistory.save()
ua.account.missedCalls = ua.account.missedCalls || missed ua.account.missedCalls = ua.account.missedCalls || missed
} }
if (!Utils.isVisible() && missed) { if (!Utils.isVisible()) {
if (missed) {
val caller = Utils.friendlyUri(ContactsActivity.contactName(call.peerUri), val caller = Utils.friendlyUri(ContactsActivity.contactName(call.peerUri),
Utils.aorDomain(aor)) Utils.aorDomain(aor))
val intent = Intent(applicationContext, MainActivity::class.java) val intent = Intent(applicationContext, MainActivity::class.java)
@@ -858,18 +866,22 @@ class BaresipService: Service() {
.priority = Notification.PRIORITY_HIGH .priority = Notification.PRIORITY_HIGH
} }
nm.notify(CALL_MISSED_NOTIFICATION_ID, nb.build()) nm.notify(CALL_MISSED_NOTIFICATION_ID, nb.build())
}
return return
} }
val reason = ev[1].trim()
if ((reason != "") && (Call.uaCalls(ua, "").size == 0)) {
if (reason[0].isDigit())
toast("${getString(R.string.call_failed)}: $reason")
else
toast("${getString(R.string.call_closed)}: $reason")
} }
} }
} }
} }
if (newEvent == null) newEvent = event }
val intent = Intent("service event") serviceEvent.postValue(Event(ServiceEvent(newEvent ?: event, arrayListOf(uap, callp),
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP System.currentTimeMillis())))
intent.putExtra("event", newEvent)
intent.putExtra("params", arrayListOf(uap, callp))
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
} }
@SuppressLint("UnspecifiedImmutableFlag") @SuppressLint("UnspecifiedImmutableFlag")
@@ -886,9 +898,10 @@ class BaresipService: Service() {
Log.w(TAG, "messageEvent did not find ua $uap") Log.w(TAG, "messageEvent did not find ua $uap")
return return
} }
val timeStamp = System.currentTimeMillis().toString() val timeStamp = System.currentTimeMillis()
Log.d(TAG, "Message event for $uap from $peer at $timeStamp") val timeStampString = timeStamp.toString()
Message(ua.account.aor, peer, text, timeStamp.toLong(), Log.d(TAG, "Message event for $uap from $peer at $timeStampString")
Message(ua.account.aor, peer, text, timeStamp,
R.drawable.arrow_down_green, 0, "", true).add() R.drawable.arrow_down_green, 0, "", true).add()
Message.save() Message.save()
ua.account.unreadMessages = true ua.account.unreadMessages = true
@@ -934,13 +947,13 @@ class BaresipService: Service() {
val saveIntent = Intent(this, BaresipService::class.java) val saveIntent = Intent(this, BaresipService::class.java)
saveIntent.action = "Message Save" saveIntent.action = "Message Save"
saveIntent.putExtra("uap", uap) saveIntent.putExtra("uap", uap)
.putExtra("time", timeStamp) .putExtra("time", timeStampString)
val savePendingIntent = PendingIntent.getService(this, val savePendingIntent = PendingIntent.getService(this,
SAVE_REQ_CODE, saveIntent, PendingIntent.FLAG_UPDATE_CURRENT) SAVE_REQ_CODE, saveIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val deleteIntent = Intent(this, BaresipService::class.java) val deleteIntent = Intent(this, BaresipService::class.java)
deleteIntent.action = "Message Delete" deleteIntent.action = "Message Delete"
deleteIntent.putExtra("uap", uap) deleteIntent.putExtra("uap", uap)
.putExtra("time", timeStamp) .putExtra("time", timeStampString)
val deletePendingIntent = PendingIntent.getService(this, val deletePendingIntent = PendingIntent.getService(this,
DELETE_REQ_CODE, deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT) DELETE_REQ_CODE, deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT)
nb.addAction(R.drawable.ic_stat_reply, "Reply", rpi) nb.addAction(R.drawable.ic_stat_reply, "Reply", rpi)
@@ -950,11 +963,8 @@ class BaresipService: Service() {
return return
} }
nt.play() nt.play()
val intent = Intent("service event") serviceEvent.postValue(Event(ServiceEvent("message show", arrayListOf(uap, peer),
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP timeStamp)))
intent.putExtra("event", "message show")
intent.putExtra("params", arrayListOf(uap, peer))
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
} }
@Keep @Keep
@@ -993,10 +1003,8 @@ class BaresipService: Service() {
fun started() { fun started() {
Log.d(TAG, "Received 'started' from baresip") Log.d(TAG, "Received 'started' from baresip")
Api.net_debug() Api.net_debug()
val intent = Intent("service event") serviceEvent.postValue(Event(ServiceEvent("started", arrayListOf(callActionUri),
intent.putExtra("event", "started") System.currentTimeMillis())))
intent.putExtra("params", arrayListOf(callActionUri))
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
callActionUri = "" callActionUri = ""
if (VERSION.SDK_INT >= 23) if (VERSION.SDK_INT >= 23)
Log.d(TAG, "Battery optimizations are ignored: " + Log.d(TAG, "Battery optimizations are ignored: " +
@@ -1009,10 +1017,8 @@ class BaresipService: Service() {
fun stopped(error: String) { fun stopped(error: String) {
Log.d(TAG, "Received 'stopped' from baresip with param '$error'") Log.d(TAG, "Received 'stopped' from baresip with param '$error'")
isServiceRunning = false isServiceRunning = false
val intent = Intent("service event") serviceEvent.postValue(Event(ServiceEvent("stopped", arrayListOf(error),
intent.putExtra("event", "stopped") System.currentTimeMillis())))
intent.putExtra("params", arrayListOf(error))
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
stopForeground(true) stopForeground(true)
stopSelf() stopSelf()
} }
@@ -1133,10 +1139,14 @@ class BaresipService: Service() {
} }
} }
@SuppressLint("MissingPermission")
private fun isBluetoothHeadsetConnected(): Boolean { private fun isBluetoothHeadsetConnected(): Boolean {
return (btAdapter != null) && btAdapter!!.isEnabled && return if (VERSION.SDK_INT < 31)
(btAdapter!!.getProfileConnectionState(BluetoothHeadset.HEADSET) == btAdapter != null && btAdapter!!.isEnabled &&
BluetoothHeadset.STATE_CONNECTED) btAdapter!!.getProfileConnectionState(BluetoothHeadset.HEADSET) == BluetoothHeadset.STATE_CONNECTED
else
// getProfileConnectionState requires asking fot BLUETOOTH_CONNECT permission
true
} }
private fun isAudioFocused(): Boolean { private fun isAudioFocused(): Boolean {
@@ -1447,18 +1457,14 @@ class BaresipService: Service() {
val activities = mutableListOf<String>() val activities = mutableListOf<String>()
var dnsServers = listOf<InetAddress>() var dnsServers = listOf<InetAddress>()
var serviceEvent = MutableLiveData<Event<ServiceEvent>>()
} }
init { init {
messageUpdate.postValue(System.currentTimeMillis())
registrationUpdate.postValue(System.currentTimeMillis())
if (!libraryLoaded) { if (!libraryLoaded) {
Log.d(TAG, "Loading baresip library") Log.d(TAG, "Loading baresip library")
System.loadLibrary("baresip") System.loadLibrary("baresip")
libraryLoaded = true libraryLoaded = true
} }
} }
} }
@@ -0,0 +1,15 @@
package com.tutpro.baresip
import java.util.concurrent.atomic.AtomicBoolean
open class Event<out T>(private val content: T) {
private val hasBeenHandled = AtomicBoolean(false)
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled.get()) {
null
} else {
hasBeenHandled.set(true)
content
}
}
}
@@ -29,7 +29,6 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
@@ -39,7 +38,6 @@ import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.io.FileOutputStream import java.io.FileOutputStream
import java.net.URLDecoder import java.net.URLDecoder
import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlin.system.exitProcess import kotlin.system.exitProcess
import android.content.IntentFilter import android.content.IntentFilter
@@ -73,8 +71,8 @@ class MainActivity : AppCompatActivity() {
private lateinit var nm: NotificationManager private lateinit var nm: NotificationManager
private lateinit var am: AudioManager private lateinit var am: AudioManager
private lateinit var kgm: KeyguardManager private lateinit var kgm: KeyguardManager
private lateinit var serviceEventReceiver: BroadcastReceiver
private lateinit var screenEventReceiver: BroadcastReceiver private lateinit var screenEventReceiver: BroadcastReceiver
private lateinit var serviceEventObserver: Observer<Event<ServiceEvent>>
private lateinit var quitTimer: CountDownTimer private lateinit var quitTimer: CountDownTimer
private lateinit var stopState: String private lateinit var stopState: String
private var micIcon: MenuItem? = null private var micIcon: MenuItem? = null
@@ -116,7 +114,7 @@ class MainActivity : AppCompatActivity() {
binding = ActivityMainBinding.inflate(layoutInflater) binding = ActivityMainBinding.inflate(layoutInflater)
val extraAction = intent.getStringExtra("action") val extraAction = intent.getStringExtra("action")
Log.d(TAG, "MainActivity onCreate ${intent.action}/${intent.data}/$extraAction") Log.d(TAG, "Main onCreate ${intent.action}/${intent.data}/$extraAction")
if (intent?.action == ACTION_CALL && !BaresipService.isServiceRunning) if (intent?.action == ACTION_CALL && !BaresipService.isServiceRunning)
BaresipService.callActionUri = URLDecoder.decode(intent.data.toString(), "UTF-8") BaresipService.callActionUri = URLDecoder.decode(intent.data.toString(), "UTF-8")
@@ -159,15 +157,15 @@ class MainActivity : AppCompatActivity() {
am = getSystemService(AUDIO_SERVICE) as AudioManager am = getSystemService(AUDIO_SERVICE) as AudioManager
kgm = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager kgm = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
serviceEventReceiver = object : BroadcastReceiver() { serviceEventObserver = Observer<Event<ServiceEvent>> {
override fun onReceive(context: Context, intent: Intent) { val serviceEvent = it.getContentIfNotHandled()
handleServiceEvent(intent.getStringExtra("event")!!, if (serviceEvent != null) {
intent.getStringArrayListExtra("params")!!) Log.d(TAG, "Observed event ${serviceEvent.event}")
handleServiceEvent(serviceEvent.event, serviceEvent.params)
} }
} }
LocalBroadcastManager.getInstance(this).registerReceiver(serviceEventReceiver, BaresipService.serviceEvent.observeForever(serviceEventObserver)
IntentFilter("service event"))
screenEventReceiver = object : BroadcastReceiver() { screenEventReceiver = object : BroadcastReceiver() {
override fun onReceive(contxt: Context, intent: Intent) { override fun onReceive(contxt: Context, intent: Intent) {
@@ -729,7 +727,7 @@ class MainActivity : AppCompatActivity() {
super.onDestroy() super.onDestroy()
Log.d(TAG, "Main onDestroy") Log.d(TAG, "Main onDestroy")
this.unregisterReceiver(screenEventReceiver) this.unregisterReceiver(screenEventReceiver)
LocalBroadcastManager.getInstance(this).unregisterReceiver(serviceEventReceiver) BaresipService.serviceEvent.removeObserver(serviceEventObserver)
BaresipService.activities.clear() BaresipService.activities.clear()
} }
@@ -960,8 +958,9 @@ class MainActivity : AppCompatActivity() {
showCall(ua, Call.ofCallp(callp)) showCall(ua, Call.ofCallp(callp))
} else { } else {
Log.d(TAG, "Reordering to front") Log.d(TAG, "Reordering to front")
BaresipService.activities.clear()
val i = Intent(applicationContext, MainActivity::class.java) val i = Intent(applicationContext, MainActivity::class.java)
i.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK i.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
i.putExtra("action", "call show") i.putExtra("action", "call show")
i.putExtra("callp", callp) i.putExtra("callp", callp)
startActivity(i) startActivity(i)
@@ -1040,11 +1039,17 @@ class MainActivity : AppCompatActivity() {
} }
"call transfer", "transfer show" -> { "call transfer", "transfer show" -> {
val callp = params[1] val callp = params[1]
val call = Call.ofCallp(callp) if (!BaresipService.isMainVisible) {
if (call == null) { Log.d(TAG, "Reordering to front")
Log.w(TAG, "Call $callp to be transferred is not found") BaresipService.activities.clear()
val i = Intent(applicationContext, MainActivity::class.java)
i.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
i.putExtra("action", event)
i.putExtra("callp", callp)
startActivity(i)
return return
} }
val call = Call.ofCallp(callp)!!
val titleView = View.inflate(this, R.layout.alert_title, null) as TextView val titleView = View.inflate(this, R.layout.alert_title, null) as TextView
titleView.text = getString(R.string.transfer_request) titleView.text = getString(R.string.transfer_request)
val target = Utils.friendlyUri(ContactsActivity.contactName(ev[1]), val target = Utils.friendlyUri(ContactsActivity.contactName(ev[1]),
@@ -1069,19 +1074,12 @@ class MainActivity : AppCompatActivity() {
"transfer accept" -> { "transfer accept" -> {
val callp = params[1] val callp = params[1]
val call = Call.ofCallp(callp) val call = Call.ofCallp(callp)
if (call == null) {
Log.w(TAG, "Call $callp to be transferred is not found")
return
}
if (call in Call.calls()) if (call in Call.calls())
Api.ua_hangup(uap, callp, 0, "") Api.ua_hangup(uap, callp, 0, "")
call(ua, ev[1]) call(ua, ev[1])
showCall(ua) showCall(ua)
} }
"transfer failed" -> { "transfer failed" -> {
Toast.makeText(applicationContext,
"${getString(R.string.transfer_failed)}: ${ev[1].trim()}",
Toast.LENGTH_LONG).show()
showCall(ua) showCall(ua)
} }
"call closed" -> { "call closed" -> {
@@ -1097,18 +1095,6 @@ class MainActivity : AppCompatActivity() {
} }
if (speakerIcon != null) if (speakerIcon != null)
speakerIcon!!.setIcon(R.drawable.speaker_off) speakerIcon!!.setIcon(R.drawable.speaker_off)
val param = ev[1].trim()
if ((param != "") && (Call.uaCalls(ua, "").size == 0)) {
if (param[0].isDigit())
Toast.makeText(applicationContext,
"${getString(R.string.call_failed)}: $param",
Toast.LENGTH_LONG).show()
else
Toast.makeText(applicationContext,
"${getString(R.string.call_closed)}: $param",
Toast.LENGTH_LONG).show()
}
restoreActivities()
if ((Build.VERSION.SDK_INT >= 22 && kgm.isDeviceLocked) || if ((Build.VERSION.SDK_INT >= 22 && kgm.isDeviceLocked) ||
(Build.VERSION.SDK_INT < 22 && kgm.isKeyguardLocked && kgm.isKeyguardSecure)) (Build.VERSION.SDK_INT < 22 && kgm.isKeyguardLocked && kgm.isKeyguardSecure))
Utils.setShowWhenLocked(this, false) Utils.setShowWhenLocked(this, false)
@@ -0,0 +1,3 @@
package com.tutpro.baresip
class ServiceEvent (val event: String, val params: ArrayList<String>, val timeStamp: Long)