diff --git a/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt b/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt index c7531c88..ee6ba869 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt @@ -588,6 +588,8 @@ class BaresipService: Service() { CallHistoryNew.clearRecordings() CallHistoryNew.save() Message.save() + Blocked.save() + BlockRule.save() if (recordings.exists()) recordings.deleteRecursively() restored.delete() @@ -595,28 +597,21 @@ class BaresipService: Service() { File(filesDir, "recordings").mkdir() File(filesDir, "tmp").mkdir() - }.start() - hotSpotAddresses = Utils.hotSpotAddresses() - linkAddresses = linkAddresses() - var addresses = "" - for (la in linkAddresses) - addresses = "$addresses;${la.key};${la.value}" - Log.i(TAG, "Link addresses: $addresses") - activeNetwork = cm.activeNetwork - Log.i(TAG, "Active network: $activeNetwork") + hotSpotAddresses = Utils.hotSpotAddresses() + linkAddresses = linkAddresses() + var addresses = "" + for (la in linkAddresses) + addresses = "$addresses;${la.key};${la.value}" + Log.i(TAG, "Link addresses: $addresses") - registerPhoneAccount() + val userAgent = Config.variable("user_agent") + val software = if (userAgent != "") + userAgent + else + "baresip v${BuildConfig.VERSION_NAME} " + + "(Android ${VERSION.RELEASE}/${System.getProperty("os.arch") ?: "?"})" - Log.i(TAG, "AEC/AGC/NS available = $aecAvailable/$agcAvailable/$nsAvailable") - - val userAgent = Config.variable("user_agent") - val software = if (userAgent != "") - userAgent - else - "baresip v${BuildConfig.VERSION_NAME} " + - "(Android ${VERSION.RELEASE}/${System.getProperty("os.arch") ?: "?"})" - Thread { baresipStart( filesPath, addresses.removePrefix(";"), @@ -627,6 +622,15 @@ class BaresipService: Service() { isServiceRunning = true + activeNetwork = cm.activeNetwork + Log.i(TAG, "Active network: $activeNetwork") + + registerPhoneAccount() + + Log.i(TAG, "AEC/AGC/NS available = $aecAvailable/$agcAvailable/$nsAvailable") + + isServiceRunning = true + if (linkAddresses.isEmpty()) toast(getString(R.string.no_network), Toast.LENGTH_LONG) @@ -1796,11 +1800,15 @@ class BaresipService: Service() { @Keep fun started() { Log.d(TAG, "Received 'started' from baresip") - isNativeReady = true Handler(Looper.getMainLooper()).post { + isNativeReady = true addMobileUserAgent() Account.saveAccounts() + CallHistoryNew.save() + Message.save() + Blocked.save() + BlockRule.save() if (VERSION.SDK_INT >= 29) updateMobileStatus() @@ -2400,15 +2408,13 @@ class BaresipService: Service() { mobileUa.let { ua -> val isAirplaneModeOn = Utils.isAirplaneModeOn(this) - val status = newStatus ?: if (ua.status == circleGreen.getValue(colorblind)) - ua.status - else if (isAirplaneModeOn) + val status = newStatus ?: if (isAirplaneModeOn) R.drawable.circle_white - else if (ua.status == R.drawable.circle_white) - // Show "Red" (not yet in service) - circleRed.getValue(colorblind) + else if (previousMobileServiceState == ServiceState.STATE_IN_SERVICE) + circleGreen.getValue(colorblind) else - ua.status + circleRed.getValue(colorblind) + if (ua.status != status) { Log.d(TAG, "Updating Mobile status to $status") ua.updateStatus(status) @@ -3222,6 +3228,8 @@ class BaresipService: Service() { var addressFamily = "" var dnsServers = listOf() + val messagesLock = Any() + // of those accounts that have auth username without auth password val aorPasswords = mutableMapOf() var aecAvailable = false diff --git a/app/src/main/kotlin/com/tutpro/baresip/BlockRule.kt b/app/src/main/kotlin/com/tutpro/baresip/BlockRule.kt index dce3f0ee..5e285660 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/BlockRule.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/BlockRule.kt @@ -26,6 +26,7 @@ class BlockRule(val aor: String = "", val pattern: String) { } fun save() { + if (!BaresipService.isNativeReady) return Log.d(TAG, "Saving ${BaresipService.blockRules.size} block rules") val file = File(BaresipService.filesPath + "/blocking") try { @@ -46,7 +47,11 @@ class BlockRule(val aor: String = "", val pattern: String) { if (file.exists()) try { val jsonString = file.readText() - BaresipService.blockRules = Json.decodeFromString>(jsonString) + val blockRules = Json.decodeFromString>(jsonString) + synchronized(BaresipService.blockRules) { + BaresipService.blockRules.clear() + BaresipService.blockRules.addAll(blockRules) + } Log.d(TAG, "Restored ${BaresipService.blockRules.size} block rules") } catch (e: Exception) { Log.e(TAG, "Deserialization exception: $e") diff --git a/app/src/main/kotlin/com/tutpro/baresip/Blocked.kt b/app/src/main/kotlin/com/tutpro/baresip/Blocked.kt index f0197f51..cf2f5743 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/Blocked.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/Blocked.kt @@ -33,6 +33,7 @@ class Blocked ( } fun save() { + if (!BaresipService.isNativeReady) return Log.d(TAG, "Saving ${BaresipService.blocked.size} blocked calls and messages") val file = File(BaresipService.filesPath + "/blocked") try { @@ -54,7 +55,10 @@ class Blocked ( try { val jsonString = file.readText() val blockedList = Json.decodeFromString>(jsonString) - BaresipService.blocked = ArrayList(blockedList) + synchronized(BaresipService.blocked) { + BaresipService.blocked.clear() + BaresipService.blocked.addAll(blockedList) + } Log.d(TAG, "Restored ${BaresipService.blocked.size} blocked calls and messages") } catch (e: Exception) { Log.e(TAG, "Deserialization exception: $e") diff --git a/app/src/main/kotlin/com/tutpro/baresip/CallHistory.kt b/app/src/main/kotlin/com/tutpro/baresip/CallHistory.kt index 899e785a..33914f24 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/CallHistory.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/CallHistory.kt @@ -76,6 +76,7 @@ class CallHistoryNew(val aor: String, val peerUri: String, val direction: String } fun save() { + if (!BaresipService.isNativeReady) return val historyCopy = synchronized(BaresipService.callHistory) { ArrayList(BaresipService.callHistory) } @@ -105,7 +106,10 @@ class CallHistoryNew(val aor: String, val peerUri: String, val direction: String if (content.startsWith("[")) { try { val restoredHistory = Json.decodeFromString>(content) - BaresipService.callHistory = ArrayList(restoredHistory) + synchronized(BaresipService.callHistory) { + BaresipService.callHistory.clear() + BaresipService.callHistory.addAll(restoredHistory) + } Log.d(TAG, "Restored history of ${BaresipService.callHistory.size} calls from JSON") return } catch (e: Exception) { @@ -118,7 +122,10 @@ class CallHistoryNew(val aor: String, val peerUri: String, val direction: String @Suppress("UNCHECKED_CAST") val restoredHistory = ois.readObject() as? List if (restoredHistory != null) { - BaresipService.callHistory = ArrayList(restoredHistory) + synchronized(BaresipService.callHistory) { + BaresipService.callHistory.clear() + BaresipService.callHistory.addAll(restoredHistory) + } Log.d(TAG, "Restored history of ${BaresipService.callHistory.size} calls from Java") save() } diff --git a/app/src/main/kotlin/com/tutpro/baresip/CallsScreen.kt b/app/src/main/kotlin/com/tutpro/baresip/CallsScreen.kt index 6f484562..98814fb9 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/CallsScreen.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/CallsScreen.kt @@ -341,7 +341,7 @@ private fun Calls( secondAction.value = { if (ua.account.isMobile && ua.status != circleGreen.getValue(colorblind)) { alertTitle.value = ctx.getString(R.string.notice) - alertMessage.value = ctx.getString(R.string.airplane_mode) + alertMessage.value = Utils.mobileStatusMessage(ctx, ua.status) showAlert.value = true } else { @@ -357,8 +357,7 @@ private fun Calls( if (ua.account.isMobile) { if (ua.status != circleGreen.getValue(colorblind)) { alertTitle.value = ctx.getString(R.string.notice) - alertMessage.value = - ctx.getString(R.string.airplane_mode) + alertMessage.value = Utils.mobileStatusMessage(ctx, ua.status) showAlert.value = true } else if (!Utils.isDefaultSmsApp(ctx)) { diff --git a/app/src/main/kotlin/com/tutpro/baresip/ChatScreen.kt b/app/src/main/kotlin/com/tutpro/baresip/ChatScreen.kt index 0cff5a36..7b9b7a2f 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/ChatScreen.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/ChatScreen.kt @@ -488,7 +488,6 @@ private fun NewMessage( val showDialog = remember { mutableStateOf(false) } val dialogMessage = remember { mutableStateOf("") } - val airplaneMode = stringResource(R.string.airplane_mode) val messageFailed = stringResource(R.string.message_failed) val noTelephonyProvider = stringResource(R.string.no_telephony_provider) @@ -570,7 +569,7 @@ private fun NewMessage( addMessage(msg) if (ua.account.isMobile) { if (ua.status != circleGreen.getValue(colorblind)) { - dialogMessage.value = airplaneMode + dialogMessage.value = Utils.mobileStatusMessage(ctx, ua.status) showDialog.value = true } else { diff --git a/app/src/main/kotlin/com/tutpro/baresip/ContactScreen.kt b/app/src/main/kotlin/com/tutpro/baresip/ContactScreen.kt index 93ab06b9..1fa9c38c 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/ContactScreen.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/ContactScreen.kt @@ -732,7 +732,7 @@ private fun UrisSection( onClick = { if (ua.account.isMobile && ua.status != circleGreen.getValue(colorblind)) { alertTitle.value = ctx.getString(R.string.notice) - alertMessage.value = ctx.getString(R.string.airplane_mode) + alertMessage.value = Utils.mobileStatusMessage(ctx, ua.status) showAlert.value = true } else if (ua.account.isMobile && !Utils.isDefaultSmsApp(ctx)) { @@ -770,7 +770,7 @@ private fun UrisSection( onClick = { if (ua.account.isMobile && ua.status != circleGreen.getValue(colorblind)) { alertTitle.value = ctx.getString(R.string.notice) - alertMessage.value = ctx.getString(R.string.airplane_mode) + alertMessage.value = Utils.mobileStatusMessage(ctx, ua.status) showAlert.value = true } else { diff --git a/app/src/main/kotlin/com/tutpro/baresip/MainScreen.kt b/app/src/main/kotlin/com/tutpro/baresip/MainScreen.kt index 7134e4fd..233ff2da 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/MainScreen.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/MainScreen.kt @@ -2119,7 +2119,7 @@ private fun makeCall(ctx: Context, viewModel: ViewModel, uriText: String, } else if (ua.account.isMobile && ua.status != circleGreen.getValue(colorblind)) { alertTitle.value = ctx.getString(R.string.notice) - alertMessage.value = ctx.getString(R.string.airplane_mode) + alertMessage.value = Utils.mobileStatusMessage(ctx, ua.status) showAlert.value = true return } diff --git a/app/src/main/kotlin/com/tutpro/baresip/Message.kt b/app/src/main/kotlin/com/tutpro/baresip/Message.kt index bacbca6b..60356690 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/Message.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/Message.kt @@ -10,7 +10,7 @@ class Message(val aor: String, val peerUri: String, val message: String, val tim var new: Boolean): java.io.Serializable { fun add() { - val updatedMessages = synchronized(BaresipService.messages) { + val updatedMessages = synchronized(BaresipService.messagesLock) { BaresipService.messages.toMutableList() } updatedMessages.add(this) @@ -26,18 +26,18 @@ class Message(val aor: String, val peerUri: String, val message: String, val tim } if (remove != null) updatedMessages.remove(remove) - synchronized(BaresipService.messages) { + synchronized(BaresipService.messagesLock) { BaresipService.messages = updatedMessages.toList() } save() } fun delete() { - val updatedMessages = synchronized(BaresipService.messages) { + val updatedMessages = synchronized(BaresipService.messagesLock) { BaresipService.messages.toMutableList() } updatedMessages.remove(this) - synchronized(BaresipService.messages) { + synchronized(BaresipService.messagesLock) { BaresipService.messages = updatedMessages.toList() } save() @@ -55,25 +55,25 @@ class Message(val aor: String, val peerUri: String, val message: String, val tim } fun clearMessagesOfAor(aor: String) { - val updatedMessages = synchronized(BaresipService.messages) { + val updatedMessages = synchronized(BaresipService.messagesLock) { BaresipService.messages.toMutableList() } val it = updatedMessages.iterator() while (it.hasNext()) if (it.next().aor == aor) it.remove() - synchronized(BaresipService.messages) { + synchronized(BaresipService.messagesLock) { BaresipService.messages = updatedMessages.toList() } save() } fun deleteAorMessage(aor: String, time: Long) { - val updatedMessages = synchronized(BaresipService.messages) { + val updatedMessages = synchronized(BaresipService.messagesLock) { BaresipService.messages.toMutableList() } for (message in updatedMessages.reversed()) if (message.aor == aor && message.timeStamp == time) { updatedMessages.remove(message) - synchronized(BaresipService.messages) { + synchronized(BaresipService.messagesLock) { BaresipService.messages = updatedMessages.toList() } save() @@ -82,13 +82,13 @@ class Message(val aor: String, val peerUri: String, val message: String, val tim } fun updateAorMessage(aor: String, time: Long) { - val updatedMessages = synchronized(BaresipService.messages) { + val updatedMessages = synchronized(BaresipService.messagesLock) { BaresipService.messages.toMutableList() } for (message in updatedMessages.reversed()) if (message.aor == aor && message.timeStamp == time) { message.new = false - synchronized(BaresipService.messages) { + synchronized(BaresipService.messagesLock) { BaresipService.messages = updatedMessages.toList() } save() @@ -97,7 +97,7 @@ class Message(val aor: String, val peerUri: String, val message: String, val tim } fun unreadMessages(aor: String): Boolean { - synchronized(BaresipService.messages) { + synchronized(BaresipService.messagesLock) { for (message in BaresipService.messages.reversed()) if (message.aor == aor && message.new) return true @@ -106,7 +106,7 @@ class Message(val aor: String, val peerUri: String, val message: String, val tim } fun unreadMessagesFromPeer(aor: String, peerUri: String): Boolean { - synchronized(BaresipService.messages) { + synchronized(BaresipService.messagesLock) { for (message in BaresipService.messages.reversed()) if (message.aor == aor && message.peerUri == peerUri && message.new) return true @@ -115,7 +115,7 @@ class Message(val aor: String, val peerUri: String, val message: String, val tim } fun updateMessagesFromPearRead(aor: String, peerUri: String): Boolean { - val updatedMessages = synchronized(BaresipService.messages) { + val updatedMessages = synchronized(BaresipService.messagesLock) { BaresipService.messages.toMutableList() } var updated = false @@ -125,7 +125,7 @@ class Message(val aor: String, val peerUri: String, val message: String, val tim updated = true } if (updated) { - synchronized(BaresipService.messages) { + synchronized(BaresipService.messagesLock) { BaresipService.messages = updatedMessages.toList() } save() @@ -134,7 +134,8 @@ class Message(val aor: String, val peerUri: String, val message: String, val tim } fun save() { - val messagesCopy = synchronized(BaresipService.messages) { + if (!BaresipService.isNativeReady) return + val messagesCopy = synchronized(BaresipService.messagesLock) { BaresipService.messages.toList() } val file = File(BaresipService.filesPath, "messages") @@ -143,7 +144,7 @@ class Message(val aor: String, val peerUri: String, val message: String, val tim file.writeText(jsonString) Log.d(TAG, "Saved ${messagesCopy.size} messages in JSON") } catch (e: Exception) { - Log.e(TAG, "Serialization exception", e) + Log.e(TAG, "Serialization exception: $e") try { val fos = FileOutputStream(file) val oos = ObjectOutputStream(fos) @@ -164,7 +165,9 @@ class Message(val aor: String, val peerUri: String, val message: String, val tim if (content.startsWith("[")) { try { val restoredMessages = Json.decodeFromString>(content) - BaresipService.messages = restoredMessages + synchronized(BaresipService.messagesLock) { + BaresipService.messages = restoredMessages + } Log.d(TAG, "Restored ${BaresipService.messages.size} messages from JSON") return } catch (e: Exception) { @@ -177,7 +180,9 @@ class Message(val aor: String, val peerUri: String, val message: String, val tim @Suppress("UNCHECKED_CAST") val restoredMessages = ois.readObject() as? List if (restoredMessages != null) { - BaresipService.messages = restoredMessages + synchronized(BaresipService.messagesLock) { + BaresipService.messages = restoredMessages + } Log.d(TAG, "Restored ${BaresipService.messages.size} messages from Java") save() } diff --git a/app/src/main/kotlin/com/tutpro/baresip/Utils.kt b/app/src/main/kotlin/com/tutpro/baresip/Utils.kt index 733d70d6..77c0fee7 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/Utils.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/Utils.kt @@ -903,6 +903,13 @@ object Utils { ) != 0 } + fun mobileStatusMessage(ctx: Context, status: Int): String { + return if (status == R.drawable.circle_white) + ctx.getString(R.string.airplane_mode) + else + ctx.getString(R.string.mobile_service_not_available) + } + @Suppress("unused") fun isPSTNCallActive(ctx: Context): Boolean { val tm = ctx.getSystemService(Context.TELECOM_SERVICE) as? TelecomManager ?: return false diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index b134ee6f..31202374 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -642,6 +642,7 @@ Et voi käyttää tätä sovellusta ilman Ilmoitukset-lupaa. Laite on lentotilassa. Poista lentotila, jos haluat käyttää mobiilitiliä. + Mobiilipalvelu ei ole käytettävissä. Et voi soittaa puheluita tai vastata niihin ilman Mikrofoni-lupaa. Salli Kamera-lupa jotta voit soittaa videopuheluita ja vastata niihin. Et voi tallentaa sovelluksen tietoja ilman Tallennustila-lupaa. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4c843d95..1f68785b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -627,6 +627,7 @@ You are not able to use this application without \"Notifications\" permission. Airplane mode is ON. Turn it OFF to use mobile account. + Mobile service is not available. baresip needs \"Microphone\" permission for voice calls. Grant \"Camera\" permission to make or answer video calls. You are not able create backup without \"Storage\" permission.