- added support detecting (mwi) and listening of voicemails

- activated via account's voicemail uri
This commit is contained in:
Juha Heinanen
2018-09-18 13:41:53 +03:00
parent 0076fd9f5c
commit f6732395e2
13 changed files with 252 additions and 27 deletions
@@ -10,6 +10,10 @@ class Account(val accp: String) {
var audioCodec = ArrayList<String>()
var regint = account_regint(accp)
var mediaenc = account_mediaenc(accp)
var vmUri = account_vm_uri(accp)
var vmNew = 0
var vmOld = 0
var missedCalls = false
init {
var i = 0
@@ -69,11 +73,45 @@ class Account(val accp: String) {
if (mediaenc != "") res = res + ";mediaenc=${mediaenc}"
if (vmUri == "")
res = res + ";mwi=no"
else
res = res + ";vm_uri=\"$vmUri\""
res = res + ";ptime=20;regint=${regint};regq=0.5;pubint=0;answermode=manual"
return res
}
fun vmMessage() : String {
var new = ""
var old = ""
if (vmNew > 0)
if (vmNew == 1)
new = "$vmNew new message"
else
new = "$vmNew new messages"
if (vmOld > 0)
if (vmOld == 1)
old = "$vmOld old message"
else
old = "$vmOld old messages"
var msg = "You have"
if (new != "") {
msg = "$msg $new"
if (old != "") msg = "$msg and $old"
} else {
if (old != "")
msg = "$msg $old"
else
msg = "$msg no messages"
}
return "$msg."
}
fun host() : String {
return aor.split("@")[1]
}
companion object {
fun accounts(): ArrayList<Account> {
@@ -124,4 +162,6 @@ external fun account_regint(acc: String): Int
external fun account_set_regint(acc: String, regint: Int): Int
external fun account_mediaenc(acc: String): String
external fun account_set_mediaenc(acc: String, mencid: String): Int
external fun account_set_audio_codecs(acc: String, codecs: String): Int
external fun account_set_audio_codecs(acc: String, codecs: String): Int
external fun account_set_mwi(acc: String, value: String): Int
external fun account_vm_uri(acc: String): String
@@ -9,6 +9,7 @@ import android.view.MenuItem
import android.view.View
import android.widget.LinearLayout.LayoutParams
import android.widget.*
import kotlinx.android.synthetic.main.activity_account.*
class AccountActivity : AppCompatActivity() {
@@ -21,6 +22,7 @@ class AccountActivity : AppCompatActivity() {
internal lateinit var outbound2: EditText
internal lateinit var regCheck: CheckBox
internal lateinit var mediaEnc: String
internal lateinit var vmUri: EditText
private var newCodecs = ArrayList<String>()
private var save = false
@@ -113,6 +115,10 @@ class AccountActivity : AppCompatActivity() {
override fun onNothingSelected(parent: AdapterView<*>) {
}
}
vmUri = findViewById(R.id.voicemailUri) as EditText
vmUri.setText(acc.vmUri)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
@@ -259,6 +265,24 @@ class AccountActivity : AppCompatActivity() {
}
}
var vmUri = voicemailUri.text.toString().trim()
if (vmUri != acc.vmUri) {
if (vmUri != "") {
if (!vmUri.startsWith("sip:")) vmUri = "sip:$vmUri"
if (!vmUri.contains("@")) vmUri = "$vmUri@${acc.host()}"
if (!Utils.checkSipUri(vmUri)) {
Utils.alertView(this, "Notice",
"Invalid Voicemail URI: $vmUri")
return false
}
account_set_mwi(acc.accp, "yes")
} else {
account_set_mwi(acc.accp, "no")
}
acc.vmUri = vmUri
save = true
}
if (save) {
AccountsActivity.saveAccounts()
if (UserAgent.ua_update_account(MainActivity.uas[uaIndex].uap) != 0)
@@ -308,6 +332,10 @@ class AccountActivity : AppCompatActivity() {
Utils.alertView(this, "Media Encryption",
getText(R.string.mediaEnc).toString())
}
findViewById(R.id.VoicemailUriTitle) as TextView -> {
Utils.alertView(this, "Voicemail URI",
getText(R.string.vmUri).toString())
}
}
}
@@ -23,8 +23,7 @@ import android.support.v4.content.LocalBroadcastManager
import android.os.Build
import android.support.v4.app.NotificationCompat.VISIBILITY_PRIVATE
import java.nio.charset.StandardCharsets
import android.net.Uri
import android.provider.Settings
import java.io.InputStream
class BaresipService: Service() {
@@ -125,6 +124,25 @@ class BaresipService: Service() {
Utils.copyAssetToFile(applicationContext, a, "$path/$a")
} else {
Log.d(LOG_TAG, "Asset $a already copied")
if (a == "config") {
val inputStream: InputStream = file.inputStream()
var contents = inputStream.bufferedReader().use { it.readText() }
inputStream.close()
var write = false
if (!contents.contains("zrtp_hash")) {
contents = "${contents}zrtp_hash yes\n"
write = true
}
if (contents.contains(Regex("#module_app[ ]+mwi.so"))) {
contents = contents.replace(Regex("#module_app[ ]+mwi.so"),
"module_app mwi.so")
write = true
}
if (write) {
Log.d(LOG_TAG, "Writing $contents")
Utils.putFileContents(file, contents)
}
}
}
}
@@ -239,7 +257,7 @@ class BaresipService: Service() {
} else {
Log.d(LOG_TAG, "Ua ${ua.account.aor} is NOT registered")
MainActivity.images.add(R.drawable.dot_yellow)
ua.register()
// ua.register()
}
val intent = Intent("service event")
intent.putExtra("event", "ua added")
@@ -31,6 +31,8 @@ class CallsActivity : AppCompatActivity() {
val listview = findViewById(R.id.calls) as ListView
val aor = intent.extras.getString("aor")
val ua = Account.findUa(aor)
aorGenerateHistory(aor)
val adapter = CallListAdapter(this, uaHistory)
@@ -84,6 +86,7 @@ class CallsActivity : AppCompatActivity() {
}
listview.isLongClickable = true
ua!!.account.missedCalls = false
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
@@ -2,8 +2,7 @@ package com.tutpro.baresip
import android.Manifest
import android.app.NotificationManager
import android.content.BroadcastReceiver
import android.content.Intent
import android.content.*
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.support.v7.app.AlertDialog
@@ -12,8 +11,6 @@ import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.content.Context
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.graphics.Color
import android.media.AudioManager
@@ -46,6 +43,7 @@ class MainActivity : AppCompatActivity() {
internal lateinit var answerButton: ImageButton
internal lateinit var rejectButton: ImageButton
internal lateinit var holdButton: ImageButton
internal lateinit var voicemailButton: ImageButton
internal lateinit var contactsButton: ImageButton
internal lateinit var messagesButton: ImageButton
internal lateinit var callsButton: ImageButton
@@ -84,6 +82,7 @@ class MainActivity : AppCompatActivity() {
rejectButton = findViewById(R.id.rejectButton) as ImageButton
holdButton = findViewById(R.id.holdButton) as ImageButton
dtmf = findViewById(R.id.dtmf) as EditText
voicemailButton = findViewById(R.id.voicemailButton) as ImageButton
contactsButton = findViewById(R.id.contactsButton) as ImageButton
messagesButton = findViewById(R.id.messagesButton) as ImageButton
callsButton = findViewById(R.id.callsButton) as ImageButton
@@ -196,6 +195,19 @@ class MainActivity : AppCompatActivity() {
}
}
}
if (acc.vmUri != "") {
if (acc.vmNew > 0)
voicemailButton.setImageResource(R.drawable.voicemail_new)
else
voicemailButton.setImageResource(R.drawable.voicemail)
voicemailButton.visibility = View.VISIBLE
} else {
voicemailButton.visibility = View.INVISIBLE
}
if (acc.missedCalls)
callsButton.setImageResource(R.drawable.calls_missed)
else
callsButton.setImageResource(R.drawable.calls)
}
override fun onNothingSelected(parent: AdapterView<*>) {
@@ -339,14 +351,45 @@ class MainActivity : AppCompatActivity() {
}
}
voicemailButton.setOnClickListener {
if (aorSpinner.selectedItemPosition >= 0) {
val ua = uas[aorSpinner.selectedItemPosition]
val acc = ua.account
if (acc.vmUri != "") {
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
when (which) {
DialogInterface.BUTTON_NEGATIVE -> {
val callIntent = Intent(this, MainActivity::class.java)
callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
callIntent.putExtra("action", "call")
callIntent.putExtra("uap", ua.uap)
callIntent.putExtra("peer", acc.vmUri)
startActivity(callIntent)
}
DialogInterface.BUTTON_POSITIVE -> {
}
}
}
val builder = AlertDialog.Builder(this@MainActivity,
R.style.Theme_AppCompat)
builder.setTitle("Voicemail Messages")
builder.setMessage(acc.vmMessage())
.setPositiveButton("Cancel", dialogClickListener)
.setNegativeButton("Check", dialogClickListener)
.show()
}
}
}
contactsButton.setOnClickListener {
val i = Intent(this@MainActivity, ContactsActivity::class.java)
val b = Bundle()
if (aorSpinner.selectedItemPosition >= 0)
b.putString("aor", uas[aorSpinner.selectedItemPosition].account.aor)
else
b.putString("aor", "")
i.putExtras(b)
val b = Bundle()
if (aorSpinner.selectedItemPosition >= 0)
b.putString("aor", uas[aorSpinner.selectedItemPosition].account.aor)
else
b.putString("aor", "")
i.putExtras(b)
startActivityForResult(i, CONTACTS_CODE)
}
@@ -366,7 +409,7 @@ class MainActivity : AppCompatActivity() {
val b = Bundle()
b.putString("aor", uas[aorSpinner.selectedItemPosition].account.aor)
i.putExtras(b)
startActivityForResult(i, HISTORY_CODE)
startActivityForResult(i, CALLS_CODE)
}
}
@@ -439,6 +482,10 @@ class MainActivity : AppCompatActivity() {
if (CallHistory.aorHistory(history, aor) > HISTORY_SIZE)
CallHistory.aorRemoveHistory(history, aor)
history.add(CallHistory(aor, peer_uri, "in", false))
acc.missedCalls = true
if (ua == uas[aorSpinner.selectedItemPosition]) {
callsButton.setImageResource(R.drawable.calls_missed)
}
} else {
Log.d("Baresip", "Incoming call $uap/$callp/$peer_uri")
calls.add(new_call)
@@ -600,9 +647,14 @@ class MainActivity : AppCompatActivity() {
}
calls.remove(call)
if (!call.hasHistory) {
if (CallHistory.aorHistory(history, aor) > HISTORY_SIZE)
CallHistory.aorRemoveHistory(history, aor)
history.add(CallHistory(aor, call.peerURI, call.dir,false))
if (CallHistory.aorHistory(history, aor) > HISTORY_SIZE)
CallHistory.aorRemoveHistory(history, aor)
history.add(CallHistory(aor, call.peerURI, call.dir,false))
if (call.dir == "in") {
acc.missedCalls = true
if (ua == uas[aorSpinner.selectedItemPosition])
callsButton.setImageResource(R.drawable.calls_missed)
}
}
if (calls.size == 0) am.mode = AudioManager.MODE_NORMAL
if (am.isSpeakerphoneOn) {
@@ -635,6 +687,22 @@ class MainActivity : AppCompatActivity() {
startActivity(i)
}
}
"mwi notify" -> {
val lines = ev[1].split("\n")
for (line in lines) {
if (line.startsWith("Voice-Message:")) {
val counts = (line.split(" ")[1]).split("/")
acc.vmNew = counts[0].toInt()
acc.vmOld = counts[1].toInt()
break
}
}
if (ua == uas[aorSpinner.selectedItemPosition])
if (acc.vmNew > 0)
voicemailButton.setImageResource(R.drawable.voicemail_new)
else
voicemailButton.setImageResource(R.drawable.voicemail)
}
else -> Log.w("Baresip", "Unknown event '${ev[0]}'")
}
break
@@ -727,7 +795,7 @@ class MainActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
// Log.d("Baresip", "Resumed")
Log.d("Baresip", "Resumed")
imm.hideSoftInputFromWindow(callUri.windowToken, 0)
visible = true
if (answerCall != "") {
@@ -814,10 +882,33 @@ class MainActivity : AppCompatActivity() {
ACCOUNTS_CODE -> {
uaAdapter.notifyDataSetChanged()
val acc = uas[aorSpinner.selectedItemPosition].account
if (acc.vmUri != "") {
if (acc.vmNew > 0)
voicemailButton.setImageResource(R.drawable.voicemail_new)
else
voicemailButton.setImageResource(R.drawable.voicemail)
voicemailButton.visibility = View.VISIBLE
} else {
voicemailButton.visibility = View.INVISIBLE
}
baresipService.setAction("UpdateNotification")
startService(baresipService)
}
ACCOUNT_CODE -> {
val acc = uas[aorSpinner.selectedItemPosition].account
if (acc.vmUri != "") {
if (acc.vmNew > 0)
voicemailButton.setImageResource(R.drawable.voicemail_new)
else
voicemailButton.setImageResource(R.drawable.voicemail)
voicemailButton.visibility = View.VISIBLE
} else {
voicemailButton.visibility = View.INVISIBLE
}
}
CONTACTS_CODE -> {
callUri.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item,
ContactsActivity.contacts.map{Contact -> Contact.name}))
@@ -834,7 +925,8 @@ class MainActivity : AppCompatActivity() {
}
}
HISTORY_CODE -> {
CALLS_CODE -> {
val acc = uas[aorSpinner.selectedItemPosition].account
if (resultCode == RESULT_OK) {
if (data != null) {
(findViewById(R.id.uri) as EditText).setText(data.getStringExtra("peer_uri"))
@@ -842,10 +934,11 @@ class MainActivity : AppCompatActivity() {
}
if (resultCode == RESULT_CANCELED) {
Log.d("Baresip", "History canceled")
if (CallHistory.aorHistory(history, uas[aorSpinner.selectedItemPosition].account.aor) == 0) {
if (CallHistory.aorHistory(history, acc.aor) == 0) {
holdButton.visibility = View.INVISIBLE
}
}
callsButton.setImageResource(R.drawable.calls)
}
ABOUT_CODE -> {
@@ -972,7 +1065,7 @@ class MainActivity : AppCompatActivity() {
const val ACCOUNTS_CODE = 1
const val CONTACTS_CODE = 2
const val EDIT_CONFIG_CODE = 3
const val HISTORY_CODE = 4
const val CALLS_CODE = 4
const val ABOUT_CODE = 5
const val ACCOUNT_CODE = 6
const val CONTACT_CODE = 7
@@ -1,7 +1,6 @@
package com.tutpro.baresip
import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup