- simplified user interface by using same layout row for incoming and

outgoing calls
- dtmf digits can now be send also during incoming calls
- removed unused function uag_current()
- removed soft keyboard when call button is clicked and when call is closed
- increased version numbers
This commit is contained in:
Juha Heinanen
2018-09-02 09:27:16 +03:00
parent 098e71925b
commit bca33c3556
5 changed files with 299 additions and 482 deletions
+2 -2
View File
@@ -8,8 +8,8 @@ android {
applicationId = 'com.tutpro.baresip' applicationId = 'com.tutpro.baresip'
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 26 targetSdkVersion 26
versionCode = 18 versionCode = 19
versionName = '2.3.2' versionName = '2.4.0'
externalNativeBuild { externalNativeBuild {
cmake { cmake {
cFlags '-DHAVE_INTTYPES_H' cFlags '-DHAVE_INTTYPES_H'
-13
View File
@@ -801,7 +801,6 @@ JNIEXPORT void JNICALL
Java_com_tutpro_baresip_MainActivity_uag_1current_1set(JNIEnv *env, jobject thiz, Java_com_tutpro_baresip_MainActivity_uag_1current_1set(JNIEnv *env, jobject thiz,
jstring javaUA) jstring javaUA)
{ {
struct ua *new_current_ua;
const char *native_ua = (*env)->GetStringUTFChars(env, javaUA, 0); const char *native_ua = (*env)->GetStringUTFChars(env, javaUA, 0);
struct ua *ua = (struct ua *)strtoul(native_ua, NULL, 10); struct ua *ua = (struct ua *)strtoul(native_ua, NULL, 10);
(*env)->ReleaseStringUTFChars(env, javaUA, native_ua); (*env)->ReleaseStringUTFChars(env, javaUA, native_ua);
@@ -810,18 +809,6 @@ Java_com_tutpro_baresip_MainActivity_uag_1current_1set(JNIEnv *env, jobject thiz
return; return;
} }
JNIEXPORT jstring JNICALL
Java_com_tutpro_baresip_MainActivity_uag_1current(JNIEnv *env, jobject thiz)
{
struct ua *current_ua = uag_current();
char ua_buf[256];
if (current_ua == NULL)
ua_buf[0] = '\0';
else
sprintf(ua_buf, "%lu", (unsigned long)current_ua);
return (*env)->NewStringUTF(env, ua_buf);
}
JNIEXPORT jstring JNICALL JNIEXPORT jstring JNICALL
Java_com_tutpro_baresip_Api_call_1peeruri(JNIEnv *env, jobject thiz, jstring javaCall) Java_com_tutpro_baresip_Api_call_1peeruri(JNIEnv *env, jobject thiz, jstring javaCall)
{ {
@@ -6,7 +6,7 @@ import java.util.ArrayList
class Call(val callp: String, val ua: UserAgent, val peerURI: String, val dir: String, class Call(val callp: String, val ua: UserAgent, val peerURI: String, val dir: String,
var status: String, val dtmfWatcher: TextWatcher?) { var status: String, val dtmfWatcher: TextWatcher?) {
var hold = false var onhold = false
var security = 0 var security = 0
var zid = "" var zid = ""
var hasHistory = false var hasHistory = false
@@ -23,9 +23,8 @@ class Call(val callp: String, val ua: UserAgent, val peerURI: String, val dir: S
fun uaCalls(calls: ArrayList<Call>, ua: UserAgent, dir: String): ArrayList<Call> { fun uaCalls(calls: ArrayList<Call>, ua: UserAgent, dir: String): ArrayList<Call> {
val result = ArrayList<Call>() val result = ArrayList<Call>()
for (i in calls.indices) { for (i in calls.indices)
if ((calls[i].ua == ua) && (calls[i].dir == dir)) result.add(calls[i]) if ((calls[i].ua == ua) && ((dir == "") || calls[i].dir == dir)) result.add(calls[i])
}
return result return result
} }
@@ -36,9 +35,5 @@ class Call(val callp: String, val ua: UserAgent, val peerURI: String, val dir: S
return null return null
} }
fun uaCallIndex(calls: ArrayList<Call>, ua: UserAgent, call: Call, dir: String): Int {
return uaCalls(calls, ua, dir).indexOf(call)
}
} }
} }
@@ -38,9 +38,13 @@ class MainActivity : AppCompatActivity() {
lateinit var appContext: Context lateinit var appContext: Context
internal lateinit var layout: RelativeLayout internal lateinit var layout: RelativeLayout
internal lateinit var baresipService: Intent internal lateinit var baresipService: Intent
internal lateinit var callee: AutoCompleteTextView internal lateinit var callTitle: TextView
internal lateinit var callUri: AutoCompleteTextView
internal lateinit var securityButton: ImageButton internal lateinit var securityButton: ImageButton
internal lateinit var callButton: ImageButton internal lateinit var callButton: ImageButton
internal lateinit var hangupButton: ImageButton
internal lateinit var answerButton: ImageButton
internal lateinit var rejectButton: ImageButton
internal lateinit var holdButton: ImageButton internal lateinit var holdButton: ImageButton
internal lateinit var contactsButton: ImageButton internal lateinit var contactsButton: ImageButton
internal lateinit var messagesButton: ImageButton internal lateinit var messagesButton: ImageButton
@@ -71,14 +75,18 @@ class MainActivity : AppCompatActivity() {
appContext = applicationContext appContext = applicationContext
layout = findViewById(R.id.mainActivityLayout) as RelativeLayout layout = findViewById(R.id.mainActivityLayout) as RelativeLayout
callee = findViewById(R.id.callee) as AutoCompleteTextView callTitle = findViewById(R.id.callTitle) as TextView
callUri = findViewById(R.id.uri) as AutoCompleteTextView
securityButton = findViewById(R.id.securityButton) as ImageButton securityButton = findViewById(R.id.securityButton) as ImageButton
callButton = findViewById(R.id.callButton) as ImageButton callButton = findViewById(R.id.callButton) as ImageButton
hangupButton = findViewById(R.id.hangupButton) as ImageButton
answerButton = findViewById(R.id.answerButton) as ImageButton
rejectButton = findViewById(R.id.rejectButton) as ImageButton
holdButton = findViewById(R.id.holdButton) as ImageButton holdButton = findViewById(R.id.holdButton) as ImageButton
dtmf = findViewById(R.id.dtmf) as EditText
contactsButton = findViewById(R.id.contactsButton) as ImageButton contactsButton = findViewById(R.id.contactsButton) as ImageButton
messagesButton = findViewById(R.id.messagesButton) as ImageButton messagesButton = findViewById(R.id.messagesButton) as ImageButton
callsButton = findViewById(R.id.callsButton) as ImageButton callsButton = findViewById(R.id.callsButton) as ImageButton
dtmf = findViewById(R.id.dtmf) as EditText
am = getSystemService(Context.AUDIO_SERVICE) as AudioManager am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
val rtUri = RingtoneManager.getActualDefaultRingtoneUri(applicationContext, val rtUri = RingtoneManager.getActualDefaultRingtoneUri(applicationContext,
@@ -115,56 +123,78 @@ class MainActivity : AppCompatActivity() {
Log.d("Baresip", "Setting $aor current") Log.d("Baresip", "Setting $aor current")
uag_current_set(uas[position].uap) uag_current_set(uas[position].uap)
val callsOut = Call.uaCalls(calls, ua, "out") val callsOut = Call.uaCalls(calls, ua, "out")
if (callsOut.size == 0) { val callsIn = Call.uaCalls(calls, ua, "in")
callee.text.clear() if ((callsOut.size == 0) && (callsIn.size == 0)) {
callee.hint = "Callee" callTitle.text = "Outgoing call to ..."
callButton.tag = "Call" callUri.text.clear()
callButton.setImageResource(R.drawable.call_green) callUri.hint = "Callee"
securityButton.visibility = View.INVISIBLE securityButton.visibility = View.INVISIBLE
callButton.visibility = View.VISIBLE
hangupButton.visibility = View.INVISIBLE
answerButton.visibility = View.INVISIBLE
rejectButton.visibility = View.INVISIBLE
dtmf.visibility = View.INVISIBLE dtmf.visibility = View.INVISIBLE
} else { } else {
callee.setText(callsOut[0].peerURI) val call: Call
callButton.tag = callsOut[0].status if (callsOut.size > 0) {
if (callsOut[0].status == "Hangup") { callTitle.text = "Outgoing call to ..."
if (callsOut[0].hold) { call = callsOut[0]
} else {
callTitle.text = "Incoming call from ..."
call = callsIn[0]
}
callUri.setText(call.peerURI)
when (call.status) {
"outgoing" -> {
securityButton.visibility = View.INVISIBLE
callButton.visibility = View.INVISIBLE
hangupButton.visibility = View.VISIBLE
answerButton.visibility = View.INVISIBLE
rejectButton.visibility = View.INVISIBLE
holdButton.visibility = View.INVISIBLE
dtmf.visibility = View.INVISIBLE
}
"incoming" -> {
securityButton.visibility = View.INVISIBLE
callButton.visibility = View.INVISIBLE
hangupButton.visibility = View.INVISIBLE
answerButton.visibility = View.VISIBLE
answerButton.isEnabled = true
rejectButton.visibility = View.VISIBLE
rejectButton.isEnabled = true
holdButton.visibility = View.INVISIBLE
dtmf.visibility = View.INVISIBLE
if (answerCall == call.callp) {
answerCall = ""
answerButton.performClick()
}
if (rejectCall == call.callp) {
rejectCall = ""
rejectButton.performClick()
moveTaskToBack(true)
}
}
"connected" -> {
securityButton.setImageResource(call.security)
setSecurityButtonTag(securityButton, call.security)
if ((acc.mediaenc == "zrtp") || (acc.mediaenc == "dtls_srtpf"))
securityButton.visibility = View.VISIBLE
else
securityButton.visibility = View.INVISIBLE
callButton.visibility = View.INVISIBLE
hangupButton.visibility = View.VISIBLE
answerButton.visibility = View.INVISIBLE
rejectButton.visibility = View.INVISIBLE
if (call.onhold) {
holdButton.setImageResource(R.drawable.play) holdButton.setImageResource(R.drawable.play)
} else { } else {
holdButton.setImageResource(R.drawable.pause) holdButton.setImageResource(R.drawable.pause)
} }
holdButton.visibility = View.VISIBLE holdButton.visibility = View.VISIBLE
securityButton.setImageResource(callsOut[0].security)
setSecurityButtonTag(securityButton, callsOut[0].security)
if ((acc.mediaenc == "zrtp") || (acc.mediaenc == "dtls_srtpf"))
securityButton.visibility = View.VISIBLE
else
securityButton.visibility = View.INVISIBLE
dtmf.visibility = View.VISIBLE dtmf.visibility = View.VISIBLE
dtmf.requestFocus() dtmf.requestFocus()
} else {
holdButton.visibility = View.INVISIBLE
securityButton.visibility = View.INVISIBLE
dtmf.visibility = View.INVISIBLE
} }
} }
val view_count = layout.childCount
// Log.d("Baresip", "View count is $view_count")
if (view_count > 6)
layout.removeViews(6, view_count - 6)
for (c in Call.uaCalls(calls, ua, "in"))
for (call_index in Call.uaCalls(calls, ua, "in").indices) {
val startIndex = (call_index + 1) * 10
addCallViews(ua, c, startIndex)
if (answerCall == c.callp) {
answerCall = ""
val answerButton = layout.findViewById(startIndex + 5) as ImageButton
answerButton.performClick()
}
if (rejectCall == c.callp) {
rejectCall = ""
val rejectButton = layout.findViewById(startIndex + 6) as ImageButton
rejectButton.performClick()
moveTaskToBack(true)
}
} }
} }
@@ -211,11 +241,11 @@ class MainActivity : AppCompatActivity() {
unverifyDialog.setMessage("This call is SECURE and peer is VERIFIED! " + unverifyDialog.setMessage("This call is SECURE and peer is VERIFIED! " +
"Do you want to unverify the peer?") "Do you want to unverify the peer?")
unverifyDialog.setPositiveButton("Unverify") { dialog, _ -> unverifyDialog.setPositiveButton("Unverify") { dialog, _ ->
val outCalls = Call.uaCalls(calls, uas[aorSpinner.selectedItemPosition], "out") val calls = Call.uaCalls(calls, uas[aorSpinner.selectedItemPosition], "")
if (outCalls.size > 0) { if (calls.size > 0) {
if (Api.cmd_exec("zrtp_unverify " + outCalls[0].zid) != 0) { if (Api.cmd_exec("zrtp_unverify " + calls[0].zid) != 0) {
Log.w("Baresip", Log.w("Baresip",
"Command 'zrtp_unverify ${outCalls[0].zid}' failed") "Command 'zrtp_unverify ${calls[0].zid}' failed")
} else { } else {
securityButton.setImageResource(R.drawable.box_yellow) securityButton.setImageResource(R.drawable.box_yellow)
securityButton.tag = "yellow" securityButton.tag = "yellow"
@@ -231,17 +261,13 @@ class MainActivity : AppCompatActivity() {
} }
} }
callButton.tag = "Call"
callButton.setOnClickListener { callButton.setOnClickListener {
val ua = uas[aorSpinner.selectedItemPosition] val ua = uas[aorSpinner.selectedItemPosition]
val aor = ua.account.aor val aor = ua.account.aor
when (callButton.tag) {
"Call" -> {
if (!ONE_CALL_ONLY || calls.isEmpty()) { if (!ONE_CALL_ONLY || calls.isEmpty()) {
val calleeText = (findViewById(R.id.callee) as EditText).text.toString() val uriText = (findViewById(R.id.uri) as EditText).text.toString().trim()
.trim() if (uriText.length > 0) {
if (calleeText.length > 0) { var uri = ContactsActivity.findContactURI(uriText)
var uri = ContactsActivity.findContactURI(calleeText)
if (!uri.startsWith("sip:")) { if (!uri.startsWith("sip:")) {
uri = "sip:$uri" uri = "sip:$uri"
if (!uri.contains("@")) { if (!uri.contains("@")) {
@@ -250,51 +276,66 @@ class MainActivity : AppCompatActivity() {
} }
} }
if (!Utils.checkSipUri(uri)) if (!Utils.checkSipUri(uri))
Utils.alertView(this,"Notice", Utils.alertView(this,"Notice","Invalid SIP URI '$uri'")
"Invalid SIP URI '$uri'")
else else
call(ua, uri) call(ua, uri)
} else { } else {
val latest = CallHistory.aorLatestHistory(history, aor) val latest = CallHistory.aorLatestHistory(history, aor)
if (latest != null) if (latest != null)
if (Utils.uriHostPart(latest.peerURI) == Utils.uriHostPart(aor)) if (Utils.uriHostPart(latest.peerURI) == Utils.uriHostPart(aor))
callee.setText(Utils.uriUserPart(latest.peerURI)) callUri.setText(Utils.uriUserPart(latest.peerURI))
else else
callee.setText(latest.peerURI) callUri.setText(latest.peerURI)
}
}
}
"Cancel" -> {
val callp = Call.calls(calls, "out")[0].callp
Log.d("Baresip", "Canceling AoR $aor call $callp to " +
(findViewById(R.id.callee) as EditText).text)
ua_hangup(ua.uap, callp, 486, "Rejected")
}
"Hangup" -> {
val callp = Call.calls(calls, "out")[0].callp
Log.d("Baresip", "Hanging up AoR $aor call $callp to " +
(findViewById(R.id.callee) as EditText).text)
callButton.isEnabled = false
ua_hangup(ua.uap, callp, 0, "")
} }
} }
} }
holdButton.tag = "Hold" hangupButton.setOnClickListener {
holdButton.visibility = View.INVISIBLE val ua = uas[aorSpinner.selectedItemPosition]
val aor = ua.account.aor
val callp = Call.uaCalls(calls, ua,"")[0].callp
Log.d("Baresip", "AoR $aor hanging up call $callp with " +
(findViewById(R.id.uri) as EditText).text)
hangupButton.isEnabled = false
ua_hangup(ua.uap, callp, 0, "")
}
answerButton.setOnClickListener {
val ua = uas[aorSpinner.selectedItemPosition]
val aor = ua.account.aor
val callp = Call.uaCalls(calls, ua,"in")[0].callp
Log.d("Baresip", "AoR $aor answering call $callp from " +
(findViewById(R.id.uri) as EditText).text)
answerButton.isEnabled = false
ua_answer(ua.uap, callp)
}
rejectButton.setOnClickListener {
val ua = uas[aorSpinner.selectedItemPosition]
val aor = ua.account.aor
val callp = Call.uaCalls(calls, ua,"in")[0].callp
Log.d("Baresip", "AoR $aor rejecting call $callp from " +
(findViewById(R.id.uri) as EditText).text)
rejectButton.isEnabled = false
ua_hangup(ua.uap, callp, 486, "Rejected")
}
holdButton.setOnClickListener { holdButton.setOnClickListener {
when (holdButton.tag) { val ua = uas[aorSpinner.selectedItemPosition]
"Hold" -> { val aor = ua.account.aor
holdCallAt(Call.calls(calls, "out")[0], holdButton) val call = Call.uaCalls(calls, ua,"")[0]
} if (call.onhold) {
"Resume" -> { Log.d("Baresip", "AoR $aor resuming call ${call.callp} with " +
Log.d("Baresip", "Resuming " + (findViewById(R.id.callee) as EditText).text) (findViewById(R.id.uri) as EditText).text)
val call = Call.calls(calls, "out")[0]
call_unhold(call.callp) call_unhold(call.callp)
call.hold = false call.onhold = false
holdButton.tag = "Hold"
holdButton.setImageResource(R.drawable.pause) holdButton.setImageResource(R.drawable.pause)
} } else {
Log.d("Baresip", "AoR $aor holding call ${call.callp} with " +
(findViewById(R.id.uri) as EditText).text)
call_hold(call.callp)
call.onhold = true
holdButton.setImageResource(R.drawable.play)
} }
} }
@@ -335,8 +376,8 @@ class MainActivity : AppCompatActivity() {
startService(baresipService) startService(baresipService)
} }
callee.threshold = 2 callUri.threshold = 2
callee.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item, callUri.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item,
ContactsActivity.contacts.map { Contact -> Contact.name })) ContactsActivity.contacts.map { Contact -> Contact.name }))
if (intent.hasExtra("onStartup")) if (intent.hasExtra("onStartup"))
@@ -390,7 +431,8 @@ class MainActivity : AppCompatActivity() {
return return
} }
val peer_uri = Api.call_peeruri(callp) val peer_uri = Api.call_peeruri(callp)
val new_call = Call(callp, ua, peer_uri, "in", "Answer", null) val new_call = Call(callp, ua, peer_uri, "in", "incoming",
dtmfWatcher(callp))
if (ONE_CALL_ONLY && (calls.size > 0)) { if (ONE_CALL_ONLY && (calls.size > 0)) {
Log.d("Baresip", "Auto-rejecting incoming call $uap/$callp/$peer_uri") Log.d("Baresip", "Auto-rejecting incoming call $uap/$callp/$peer_uri")
ua_hangup(uap, callp, 486, "Busy Here") ua_hangup(uap, callp, 486, "Busy Here")
@@ -400,10 +442,21 @@ class MainActivity : AppCompatActivity() {
} else { } else {
Log.d("Baresip", "Incoming call $uap/$callp/$peer_uri") Log.d("Baresip", "Incoming call $uap/$callp/$peer_uri")
calls.add(new_call) calls.add(new_call)
if (ua != uas[aorSpinner.selectedItemPosition]) if (ua != uas[aorSpinner.selectedItemPosition]) {
aorSpinner.setSelection(account_index) aorSpinner.setSelection(account_index)
else } else {
addCallViews(ua, new_call, Call.uaCalls(calls, ua, "in").size * 10) callTitle.text = "Incoming call from ..."
callUri.setText(new_call.peerURI)
securityButton.visibility = View.INVISIBLE
callButton.visibility = View.INVISIBLE
hangupButton.visibility = View.INVISIBLE
answerButton.visibility = View.VISIBLE
answerButton.isEnabled = true
rejectButton.visibility = View.VISIBLE
rejectButton.isEnabled = true
holdButton.visibility = View.INVISIBLE
dtmf.visibility = View.INVISIBLE
}
startRinging() startRinging()
if (Utils.isVisible()) { if (Utils.isVisible()) {
Log.d("Baresip", "Baresip is visible") Log.d("Baresip", "Baresip is visible")
@@ -420,17 +473,11 @@ class MainActivity : AppCompatActivity() {
Log.e("Baresip", "Established call $callp not found") Log.e("Baresip", "Established call $callp not found")
return return
} }
if (call.dir == "out") { Log.d("Baresip", "AoR $aor call $callp established")
Log.d("Baresip", "Outbound call $callp established") call.status = "connected"
call.status = "Hangup" call.onhold = false
call.hold = false
call.security = R.drawable.box_red call.security = R.drawable.box_red
if (ua == uas[aorSpinner.selectedItemPosition]) { if (ua == uas[aorSpinner.selectedItemPosition]) {
callButton.tag = "Hangup"
callButton.setImageResource(R.drawable.hangup)
holdButton.tag = "Hold"
holdButton.setImageResource(R.drawable.pause)
holdButton.visibility = View.VISIBLE
if (acc.mediaenc == "") { if (acc.mediaenc == "") {
securityButton.visibility = View.INVISIBLE securityButton.visibility = View.INVISIBLE
} else { } else {
@@ -438,40 +485,27 @@ class MainActivity : AppCompatActivity() {
securityButton.tag = "red" securityButton.tag = "red"
securityButton.visibility = View.VISIBLE securityButton.visibility = View.VISIBLE
} }
callButton.visibility = View.INVISIBLE
hangupButton.visibility = View.VISIBLE
hangupButton.isEnabled = true
answerButton.visibility = View.INVISIBLE
rejectButton.visibility = View.INVISIBLE
holdButton.setImageResource(R.drawable.pause)
holdButton.visibility = View.VISIBLE
dtmf.setText("") dtmf.setText("")
dtmf.hint = "DTMF" dtmf.hint = "DTMF"
dtmf.visibility = View.VISIBLE dtmf.visibility = View.VISIBLE
dtmf.requestFocus() dtmf.requestFocus()
dtmf.addTextChangedListener(call.dtmfWatcher) dtmf.addTextChangedListener(call.dtmfWatcher)
} }
history.add(CallHistory(aor, call.peerURI, "out", true)) history.add(CallHistory(aor, call.peerURI, call.dir, true))
call.hasHistory = true call.hasHistory = true
} else {
Log.d("Baresip", "Inbound call $callp established")
call.status = "Hangup"
call.security = R.drawable.box_red
if (ua == uas[aorSpinner.selectedItemPosition]) {
if (acc.mediaenc != "") {
val inIndex = Call.uaCallIndex(calls, ua, call, "in")
val view_id = (inIndex + 1) * 10 + 3
val securityButton = findViewById(view_id) as ImageButton
securityButton.setImageResource(R.drawable.box_red)
securityButton.tag = "red"
securityButton.visibility = View.VISIBLE
val rejectButton = findViewById(view_id + 3) as ImageButton
rejectButton.tag = "Hold"
rejectButton.setImageResource(R.drawable.pause)
}
}
history.add(CallHistory(aor, call.peerURI, "in", true))
call.hasHistory = true
}
if (rtTimer != null) { if (rtTimer != null) {
rtTimer!!.cancel() rtTimer!!.cancel()
rtTimer = null rtTimer = null
if (rt.isPlaying) rt.stop() if (rt.isPlaying) rt.stop()
} }
am.mode = AudioManager.MODE_IN_COMMUNICATION am.mode = AudioManager . MODE_IN_COMMUNICATION
requestAudioFocus(STREAM_VOICE_CALL) requestAudioFocus(STREAM_VOICE_CALL)
am.isSpeakerphoneOn = false am.isSpeakerphoneOn = false
// am.setStreamVolume(AudioManager.STREAM_VOICE_CALL, // am.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
@@ -500,37 +534,21 @@ class MainActivity : AppCompatActivity() {
} }
call.security = security call.security = security
call.zid = ev[3] call.zid = ev[3]
if (call.dir == "out") {
securityButton.setImageResource(security)
setSecurityButtonTag(securityButton, security)
securityButton.visibility = View.VISIBLE
} else {
if (ua == uas[aorSpinner.selectedItemPosition]) { if (ua == uas[aorSpinner.selectedItemPosition]) {
val view_id = (Call.uaCallIndex(calls, ua, call, "in") + 1) * 10 + 3
val securityButton = layout.findViewById(view_id) as ImageButton
securityButton.setImageResource(security) securityButton.setImageResource(security)
setSecurityButtonTag(securityButton, security) setSecurityButtonTag(securityButton, security)
securityButton.visibility = View.VISIBLE securityButton.visibility = View.VISIBLE
}
}
dialog.dismiss() dialog.dismiss()
} }
}
verifyDialog.setNegativeButton("No") { dialog, _ -> verifyDialog.setNegativeButton("No") { dialog, _ ->
call.security = R.drawable.box_yellow call.security = R.drawable.box_yellow
call.zid = ev[3] call.zid = ev[3]
if (call.dir == "out") {
securityButton.setImageResource(R.drawable.box_yellow)
securityButton.tag = "yellow"
securityButton.visibility = View.VISIBLE
} else {
if (ua == uas[aorSpinner.selectedItemPosition]) { if (ua == uas[aorSpinner.selectedItemPosition]) {
val view_id = (Call.uaCallIndex(calls, ua, call, "in") + 1) * 10 + 3
val securityButton = layout.findViewById(view_id) as ImageButton
securityButton.setImageResource(R.drawable.box_yellow) securityButton.setImageResource(R.drawable.box_yellow)
securityButton.tag = "yellow" securityButton.tag = "yellow"
securityButton.visibility = View.VISIBLE securityButton.visibility = View.VISIBLE
} }
}
dialog.dismiss() dialog.dismiss()
} }
verifyDialog.create().show() verifyDialog.create().show()
@@ -551,21 +569,11 @@ class MainActivity : AppCompatActivity() {
tag = "green" tag = "green"
call.zid = ev[1] call.zid = ev[1]
} }
if (call.dir == "out") {
if (ua == uas[aorSpinner.selectedItemPosition]) { if (ua == uas[aorSpinner.selectedItemPosition]) {
securityButton.setImageResource(call.security) securityButton.setImageResource(call.security)
securityButton.tag = tag securityButton.tag = tag
securityButton.visibility = View.VISIBLE securityButton.visibility = View.VISIBLE
} }
} else {
if (ua == uas[aorSpinner.selectedItemPosition]) {
val view_id = (Call.uaCallIndex(calls, ua, call, "in") + 1) * 10 + 3
val securityButton = layout.findViewById(view_id) as ImageButton
securityButton.setImageResource(call.security)
securityButton.tag = tag
securityButton.visibility = View.VISIBLE
}
}
} }
"call closed" -> { "call closed" -> {
val callp = params[1] val callp = params[1]
@@ -574,57 +582,27 @@ class MainActivity : AppCompatActivity() {
Log.d("Baresip", "Call $callp that is closed is not found") Log.d("Baresip", "Call $callp that is closed is not found")
return return
} }
if (call.dir == "in") { Log.d("Baresip", "Removing call ${uap}/${callp}/" + call.peerURI)
Log.d("Baresip", "Removing inbound call ${uap}/${callp}/" +
call.peerURI)
val inIndex = Call.uaCallIndex(calls, ua, call, "in")
val view_id = (inIndex + 1) * 10
val remove_count = Call.uaCalls(calls, ua, "in").size - inIndex
calls.remove(call)
if (ua == uas[aorSpinner.selectedItemPosition]) {
if (callButton.tag == "Call") {
callee.setOnKeyListener(null)
}
val caller_heading = layout.findViewById(view_id) as TextView?
if (caller_heading != null) {
val view_index = layout.indexOfChild(caller_heading)
layout.removeViews(view_index, 3 * remove_count)
val callsIn = Call.uaCalls(calls, ua, "in")
for (i in inIndex until callsIn.size) {
addCallViews(ua, callsIn[i], (i + 1) * 10)
}
}
}
if (!call.hasHistory) {
if (CallHistory.aorHistory(history, aor) > HISTORY_SIZE)
CallHistory.aorRemoveHistory(history, aor)
history.add(CallHistory(aor, call.peerURI, "in", false))
}
stopRinging() stopRinging()
} else {
Log.d("Baresip", "Removing outgoing call $uap/$callp/" +
call.peerURI)
if (ua == uas[aorSpinner.selectedItemPosition]) { if (ua == uas[aorSpinner.selectedItemPosition]) {
callButton.tag = "Call" callTitle.text = "Outgoing call to ..."
callButton.setImageResource(R.drawable.call_green) callUri.setText("")
callButton.isEnabled = true callUri.hint = "Callee"
callee.setText("")
callee.hint = "Callee"
holdButton.visibility = View.INVISIBLE
if (currentFocus == dtmf) {
imm.hideSoftInputFromWindow(dtmf.windowToken, 0)
}
securityButton.visibility = View.INVISIBLE securityButton.visibility = View.INVISIBLE
dtmf.removeTextChangedListener(call.dtmfWatcher) callButton.visibility = View.VISIBLE
hangupButton.visibility = View.INVISIBLE
answerButton.visibility = View.INVISIBLE
rejectButton.visibility = View.INVISIBLE
holdButton.visibility = View.INVISIBLE
dtmf.visibility = View.INVISIBLE dtmf.visibility = View.INVISIBLE
imm.hideSoftInputFromWindow(dtmf.windowToken, 0)
dtmf.removeTextChangedListener(call.dtmfWatcher)
} }
calls.remove(call) calls.remove(call)
if (!call.hasHistory) { if (!call.hasHistory) {
if (CallHistory.aorHistory(history, aor) > HISTORY_SIZE) if (CallHistory.aorHistory(history, aor) > HISTORY_SIZE)
CallHistory.aorRemoveHistory(history, aor) CallHistory.aorRemoveHistory(history, aor)
history.add(CallHistory(aor, call.peerURI, "out", history.add(CallHistory(aor, call.peerURI, call.dir,false))
false))
}
} }
if (calls.size == 0) am.mode = AudioManager.MODE_NORMAL if (calls.size == 0) am.mode = AudioManager.MODE_NORMAL
if (am.isSpeakerphoneOn) { if (am.isSpeakerphoneOn) {
@@ -750,22 +728,18 @@ class MainActivity : AppCompatActivity() {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
// Log.d("Baresip", "Resumed") // Log.d("Baresip", "Resumed")
imm.hideSoftInputFromWindow(callee.windowToken, 0) imm.hideSoftInputFromWindow(callUri.windowToken, 0)
visible = true visible = true
if ((answerCall != "") && (layout.childCount > 6)) { if (answerCall != "") {
answerCall = "" answerCall = ""
/* if multiple calls, right answer button needs to be searched */
val answerButton = layout.findViewById(10 + 5) as ImageButton
answerButton.performClick() answerButton.performClick()
} }
if ((rejectCall != "") && (layout.childCount > 6)) { if (rejectCall != "") {
rejectCall = "" rejectCall = ""
/* if multiple calls, right reject button needs to be searched */
val rejectButton = layout.findViewById(10 + 6) as ImageButton
rejectButton.performClick() rejectButton.performClick()
} }
if (makeCall != "") { if (makeCall != "") {
callee.setText(makeCall) callUri.setText(makeCall)
makeCall = "" makeCall = ""
callButton.performClick() callButton.performClick()
} }
@@ -845,7 +819,7 @@ class MainActivity : AppCompatActivity() {
} }
CONTACTS_CODE -> { CONTACTS_CODE -> {
callee.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item, callUri.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item,
ContactsActivity.contacts.map{Contact -> Contact.name})) ContactsActivity.contacts.map{Contact -> Contact.name}))
} }
@@ -863,7 +837,7 @@ class MainActivity : AppCompatActivity() {
HISTORY_CODE -> { HISTORY_CODE -> {
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
if (data != null) { if (data != null) {
(findViewById(R.id.callee) as EditText).setText(data.getStringExtra("peer_uri")) (findViewById(R.id.uri) as EditText).setText(data.getStringExtra("peer_uri"))
} }
} }
if (resultCode == RESULT_CANCELED) { if (resultCode == RESULT_CANCELED) {
@@ -886,209 +860,40 @@ class MainActivity : AppCompatActivity() {
"You have not granted microphone permission.", Toast.LENGTH_SHORT).show() "You have not granted microphone permission.", Toast.LENGTH_SHORT).show()
return return
} }
(findViewById(R.id.callee) as EditText).setText(uri) (findViewById(R.id.uri) as EditText).setText(uri)
val call = ua_connect(ua.uap, uri) callButton.visibility = View.INVISIBLE
if (call != "") { val callp = ua_connect(ua.uap, uri)
Log.d("Baresip", "Adding outgoing call ${ua.uap}/$call/$uri") if (callp != "") {
val dtmfWatcher = object : TextWatcher { Log.d("Baresip", "Adding outgoing call ${ua.uap}/$callp/$uri")
calls.add(Call(callp, ua, uri, "out", "outgoing", dtmfWatcher(callp)))
imm.hideSoftInputFromWindow(callUri.windowToken, 0)
securityButton.visibility = View.INVISIBLE
callButton.visibility = View.INVISIBLE
hangupButton.visibility = View.VISIBLE
hangupButton.isEnabled = true
answerButton.visibility = View.INVISIBLE
rejectButton.visibility = View.INVISIBLE
holdButton.visibility = View.INVISIBLE
dtmf.visibility = View.INVISIBLE
} else {
Log.w("Baresip", "ua_connect ${ua.uap}/$uri failed")
callButton.visibility = View.VISIBLE
}
}
private fun dtmfWatcher(callp: String): TextWatcher {
return object : TextWatcher {
override fun beforeTextChanged(sequence: CharSequence, start: Int, count: Int, after: Int) {} override fun beforeTextChanged(sequence: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(sequence: CharSequence, start: Int, before: Int, count: Int) { override fun onTextChanged(sequence: CharSequence, start: Int, before: Int, count: Int) {
val digit = sequence.subSequence(start, start + count).toString() val digit = sequence.subSequence(start, start + count).toString()
Log.d("Baresip", "Got DTMF digit '" + digit + "'") Log.d("Baresip", "Got DTMF digit '" + digit + "'")
if (digit.isNotEmpty()) call_send_digit(call, digit[0]) if (digit.isNotEmpty()) call_send_digit(callp, digit[0])
} }
override fun afterTextChanged(sequence: Editable) { override fun afterTextChanged(sequence: Editable) {
call_send_digit(call, 4.toChar()) call_send_digit(callp, 4.toChar())
} }
} }
calls.add(Call(call, ua, uri, "out", "Cancel", dtmfWatcher))
callButton.tag = "Cancel"
callButton.setImageResource(R.drawable.hangup)
holdButton.visibility = View.INVISIBLE
} else {
Log.w("Baresip", "ua_connect ${ua.uap}/$uri failed")
}
}
private fun addCallViews(ua: UserAgent, call: Call, id: Int) {
Log.d("Baresip", "Adding incoming views for UA ${ua.uap} Call ${call.callp}")
val acc = ua.account
val caller_heading = TextView(appContext)
caller_heading.text = "Incoming call from ..."
caller_heading.setTextColor(Color.BLACK)
caller_heading.textSize = 20f
caller_heading.setPadding(10, 20, 0, 0)
caller_heading.id = id
val heading_params = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
if (id == 10)
heading_params.addRule(RelativeLayout.BELOW, callButton.id)
else
heading_params.addRule(RelativeLayout.BELOW, id - 10 + 4)
caller_heading.layoutParams = heading_params
// Log.d("Baresip", "Adding incoming call heading at ${caller_heading.id}")
layout.addView(caller_heading)
val caller_row = LinearLayout(applicationContext)
caller_row.id = caller_heading.id + 1
caller_row.setOrientation(LinearLayout.HORIZONTAL)
val caller_row_params = LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT)
caller_row_params.addRule(RelativeLayout.BELOW, id)
caller_row.layoutParams = caller_row_params
val caller_uri = TextView(applicationContext)
caller_uri.text = ContactsActivity.contactName(call.peerURI)
caller_uri.setTextColor(Color.BLUE)
caller_uri.textSize = 20f
caller_uri.setPadding(10, 10, 0, 10)
caller_uri.id = caller_row.id + 1
val caller_uri_params = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT, 1.0f)
caller_uri.layoutParams = caller_uri_params
// Log.d("Baresip", "Adding caller uri at ${caller_uri.id}")
caller_row.addView(caller_uri)
val security_button = ImageButton(applicationContext)
security_button.id = caller_uri.id + 1
val dp24px = ((24 * applicationContext.resources.displayMetrics.density) + 0.5).toInt()
val security_button_params = LinearLayout.LayoutParams(dp24px, dp24px, 0.0f)
security_button_params.gravity = Gravity.CENTER_VERTICAL
security_button.layoutParams = security_button_params
if ((call.security != 0) && (acc.mediaenc != "")) {
security_button.setImageResource(call.security)
setSecurityButtonTag(securityButton, call.security)
security_button.visibility = View.VISIBLE
} else {
security_button.visibility = View.INVISIBLE
}
security_button.setOnClickListener {
when (security_button.tag) {
"red" -> {
Utils.alertView(this, "Alert", "This call is NOT secure!")
}
"yellow" -> {
Utils.alertView(this, "Alert",
"This call is SECURE, but peer is NOT verified!")
}
"green" -> {
val unverifyDialog = AlertDialog.Builder(this)
unverifyDialog.setMessage("This call is SECURE and peer is VERIFIED! " +
"Do you want to unverify the peer?")
unverifyDialog.setPositiveButton("Unverify") { dialog, _ ->
if (Api.cmd_exec("zrtp_unverify " + call.zid) != 0) {
Log.w("Baresip", "Command 'zrtp_unverify ${call.zid}' failed")
} else {
security_button.setImageResource(R.drawable.box_yellow)
security_button.tag = "yellow"
}
dialog.dismiss()
}
unverifyDialog.setNegativeButton("No") { dialog, _ ->
dialog.dismiss()
}
unverifyDialog.create().show()
}
}
}
// Log.d("Baresip", "Adding security button at ${security_button.id}")
caller_row.addView(security_button)
// Log.d("Baresip", "Adding caller row at ${caller_row.id}")
layout.addView(caller_row)
val answer_row = LinearLayout(applicationContext)
answer_row.id = security_button.id + 1
answer_row.setOrientation(LinearLayout.HORIZONTAL)
val answer_row_params = LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT)
answer_row_params.addRule(RelativeLayout.BELOW, caller_row.id)
answer_row.layoutParams = answer_row_params
val answer_button = ImageButton(applicationContext)
answer_button.tag = call.status
if (call.status == "Answer")
answer_button.setImageResource(R.drawable.call_green)
else
answer_button.setImageResource(R.drawable.hangup)
answer_button.background = null
answer_button.id = answer_row.id + 1
answer_button.setOnClickListener { v ->
when ((v as ImageButton).tag) {
"Answer" -> {
Log.d("Baresip", "UA ${ua.uap} accepting incoming call ${call.callp}")
ua_answer(ua.uap, call.callp)
if (call.dir == "in") {
call.status = "Hangup"
call.hold = false
answer_button.tag = "Hangup"
answer_button.setImageResource(R.drawable.hangup)
val reject_button = layout.findViewById(answer_button.id + 1) as ImageButton
reject_button.tag = "Hold"
reject_button.setImageResource(R.drawable.pause)
}
}
"Hangup" -> {
Log.d("Baresip", "UA ${call.ua.uap} hanging up call ${call.callp}")
answer_button.isEnabled = false
ua_hangup(call.ua.uap, call.callp, 200, "OK")
}
else -> Log.e("Baresip", "Invalid answer button tag: " + v.tag)
}
}
val answer_button_params = LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT)
answer_button_params.setMargins(3, 10, 0, 0)
answer_button.layoutParams = answer_button_params
answer_button.setPadding(0, 0, 0, 0)
// Log.d("Baresip", "Adding answer button at ${answer_button.id}")
answer_row.addView(answer_button)
val reject_button = ImageButton(appContext)
if (call.status == "Answer") {
reject_button.tag = "Reject"
reject_button.setImageResource(R.drawable.hangup)
} else {
if (call.hold) {
reject_button.tag = "Resume"
reject_button.setImageResource(R.drawable.play)
} else {
reject_button.tag = "Hold"
reject_button.setImageResource(R.drawable.pause)
}
}
reject_button.background = null
reject_button.id = answer_button.id + 1
reject_button.setOnClickListener { v ->
when ((v as ImageButton).tag) {
"Reject" -> {
Log.d("Baresip", "UA ${call.ua} rejecting incoming call ${call.callp}")
reject_button.isEnabled = false
answer_button.isEnabled = false
ua_hangup(call.ua.uap, call.callp, 486, "Rejected")
}
"Hold" -> {
holdCallAt(call, reject_button)
}
"Resume" -> {
call_unhold(call.callp)
v.tag = "Hold"
reject_button.setImageResource(R.drawable.pause)
call.hold = false
}
}
}
val reject_button_params = RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT)
reject_button_params.topMargin = 10
reject_button_params.addRule(RelativeLayout.ALIGN_PARENT_END)
reject_button.layoutParams = reject_button_params
reject_button.setPadding(50, 0, 0, 0)
reject_button.background = null
// Log.d("Baresip", "Adding reject button at ${reject_button.id}")
answer_row.addView(reject_button)
// Log.d("Baresip", "Adding answer row at ${answer_row.id}")
layout.addView(answer_row)
} }
private fun setSecurityButtonTag(button: ImageButton, security: Int) { private fun setSecurityButtonTag(button: ImageButton, security: Int) {
@@ -1105,14 +910,6 @@ class MainActivity : AppCompatActivity() {
} }
} }
private fun holdCallAt(call: Call, button: ImageButton) {
Log.d("Baresip", "Holding call with ${call.peerURI} at ${button.id}")
call_hold(call.callp)
call.hold = true
button.tag = "Resume"
button.setImageResource(R.drawable.play)
}
private fun requestAudioFocus(stream: Int) { private fun requestAudioFocus(stream: Int) {
if (!audioFocused) { if (!audioFocused) {
val res = am.requestAudioFocus(null, stream, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) val res = am.requestAudioFocus(null, stream, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
@@ -1148,7 +945,6 @@ class MainActivity : AppCompatActivity() {
} }
} }
external fun uag_current(): String
external fun uag_current_set(uap: String) external fun uag_current_set(uap: String)
external fun ua_connect(uap: String, peer_uri: String): String external fun ua_connect(uap: String, peer_uri: String): String
external fun ua_answer(uap: String, callp: String) external fun ua_answer(uap: String, callp: String)
+46 -7
View File
@@ -31,7 +31,7 @@
android:spinnerMode="dropdown"/> android:spinnerMode="dropdown"/>
<TextView <TextView
android:id="@+id/outTitle" android:id="@+id/callTitle"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/AoRList" android:layout_below="@id/AoRList"
@@ -43,14 +43,14 @@
</TextView> </TextView>
<LinearLayout <LinearLayout
android:id="@+id/calleeRow" android:id="@+id/uriRow"
android:orientation="horizontal" android:orientation="horizontal"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/outTitle" > android:layout_below="@id/callTitle" >
<AutoCompleteTextView <AutoCompleteTextView
android:id="@+id/callee" android:id="@+id/uri"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight = "1" android:layout_weight = "1"
@@ -76,21 +76,60 @@
android:id="@+id/callButton" android:id="@+id/callButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/calleeRow" android:layout_below="@id/uriRow"
android:padding="0dp" android:padding="0dp"
android:background="@null" android:background="@null"
android:src="@drawable/call_green" > android:src="@drawable/call_green" >
</ImageButton> </ImageButton>
<ImageButton
android:id="@+id/hangupButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/uriRow"
android:padding="0dp"
android:background="@null"
android:src="@drawable/hangup"
android:clickable="false"
android:visibility="invisible" >
</ImageButton>
<ImageButton
android:id="@+id/answerButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/uriRow"
android:padding="0dp"
android:background="@null"
android:src="@drawable/call_green"
android:clickable="false"
android:visibility="invisible" >
</ImageButton>
<ImageButton
android:id="@+id/rejectButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/uriRow"
android:padding="0dp"
android:background="@null"
android:layout_marginStart="70dp"
android:src="@drawable/hangup"
android:clickable="false"
android:visibility="invisible" >
</ImageButton>
<ImageButton <ImageButton
android:id="@+id/holdButton" android:id="@+id/holdButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/calleeRow" android:layout_below="@id/uriRow"
android:padding="0dp" android:padding="0dp"
android:src="@drawable/pause" android:src="@drawable/pause"
android:background="@null" android:background="@null"
android:layout_marginStart="70dp" android:layout_marginStart="70dp"
android:clickable="false"
android:visibility="invisible" > android:visibility="invisible" >
</ImageButton> </ImageButton>
@@ -98,7 +137,7 @@
android:id="@+id/dtmf" android:id="@+id/dtmf"
android:layout_width="@dimen/button_width" android:layout_width="@dimen/button_width"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/calleeRow" android:layout_below="@id/uriRow"
android:layout_marginStart="140dp" android:layout_marginStart="140dp"
android:inputType="phone" android:inputType="phone"
android:textSize="20sp" android:textSize="20sp"