- 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

View File

@ -8,8 +8,8 @@ android {
applicationId = 'com.tutpro.baresip'
minSdkVersion 21
targetSdkVersion 26
versionCode = 18
versionName = '2.3.2'
versionCode = 19
versionName = '2.4.0'
externalNativeBuild {
cmake {
cFlags '-DHAVE_INTTYPES_H'

View File

@ -801,7 +801,6 @@ JNIEXPORT void JNICALL
Java_com_tutpro_baresip_MainActivity_uag_1current_1set(JNIEnv *env, jobject thiz,
jstring javaUA)
{
struct ua *new_current_ua;
const char *native_ua = (*env)->GetStringUTFChars(env, javaUA, 0);
struct ua *ua = (struct ua *)strtoul(native_ua, NULL, 10);
(*env)->ReleaseStringUTFChars(env, javaUA, native_ua);
@ -810,18 +809,6 @@ Java_com_tutpro_baresip_MainActivity_uag_1current_1set(JNIEnv *env, jobject thiz
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
Java_com_tutpro_baresip_Api_call_1peeruri(JNIEnv *env, jobject thiz, jstring javaCall)
{

View File

@ -6,7 +6,7 @@ import java.util.ArrayList
class Call(val callp: String, val ua: UserAgent, val peerURI: String, val dir: String,
var status: String, val dtmfWatcher: TextWatcher?) {
var hold = false
var onhold = false
var security = 0
var zid = ""
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> {
val result = ArrayList<Call>()
for (i in calls.indices) {
if ((calls[i].ua == ua) && (calls[i].dir == dir)) result.add(calls[i])
}
for (i in calls.indices)
if ((calls[i].ua == ua) && ((dir == "") || calls[i].dir == dir)) result.add(calls[i])
return result
}
@ -36,9 +35,5 @@ class Call(val callp: String, val ua: UserAgent, val peerURI: String, val dir: S
return null
}
fun uaCallIndex(calls: ArrayList<Call>, ua: UserAgent, call: Call, dir: String): Int {
return uaCalls(calls, ua, dir).indexOf(call)
}
}
}

View File

@ -38,9 +38,13 @@ class MainActivity : AppCompatActivity() {
lateinit var appContext: Context
internal lateinit var layout: RelativeLayout
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 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 contactsButton: ImageButton
internal lateinit var messagesButton: ImageButton
@ -71,14 +75,18 @@ class MainActivity : AppCompatActivity() {
appContext = applicationContext
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
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
dtmf = findViewById(R.id.dtmf) as EditText
contactsButton = findViewById(R.id.contactsButton) as ImageButton
messagesButton = findViewById(R.id.messagesButton) as ImageButton
callsButton = findViewById(R.id.callsButton) as ImageButton
dtmf = findViewById(R.id.dtmf) as EditText
am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
val rtUri = RingtoneManager.getActualDefaultRingtoneUri(applicationContext,
@ -115,57 +123,79 @@ class MainActivity : AppCompatActivity() {
Log.d("Baresip", "Setting $aor current")
uag_current_set(uas[position].uap)
val callsOut = Call.uaCalls(calls, ua, "out")
if (callsOut.size == 0) {
callee.text.clear()
callee.hint = "Callee"
callButton.tag = "Call"
callButton.setImageResource(R.drawable.call_green)
val callsIn = Call.uaCalls(calls, ua, "in")
if ((callsOut.size == 0) && (callsIn.size == 0)) {
callTitle.text = "Outgoing call to ..."
callUri.text.clear()
callUri.hint = "Callee"
securityButton.visibility = View.INVISIBLE
callButton.visibility = View.VISIBLE
hangupButton.visibility = View.INVISIBLE
answerButton.visibility = View.INVISIBLE
rejectButton.visibility = View.INVISIBLE
dtmf.visibility = View.INVISIBLE
} else {
callee.setText(callsOut[0].peerURI)
callButton.tag = callsOut[0].status
if (callsOut[0].status == "Hangup") {
if (callsOut[0].hold) {
holdButton.setImageResource(R.drawable.play)
} else {
holdButton.setImageResource(R.drawable.pause)
}
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.requestFocus()
val call: Call
if (callsOut.size > 0) {
callTitle.text = "Outgoing call to ..."
call = callsOut[0]
} else {
holdButton.visibility = View.INVISIBLE
securityButton.visibility = View.INVISIBLE
dtmf.visibility = View.INVISIBLE
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)
} else {
holdButton.setImageResource(R.drawable.pause)
}
holdButton.visibility = View.VISIBLE
dtmf.visibility = View.VISIBLE
dtmf.requestFocus()
}
}
}
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)
}
}
}
override fun onNothingSelected(parent: AdapterView<*>) {
@ -211,11 +241,11 @@ class MainActivity : AppCompatActivity() {
unverifyDialog.setMessage("This call is SECURE and peer is VERIFIED! " +
"Do you want to unverify the peer?")
unverifyDialog.setPositiveButton("Unverify") { dialog, _ ->
val outCalls = Call.uaCalls(calls, uas[aorSpinner.selectedItemPosition], "out")
if (outCalls.size > 0) {
if (Api.cmd_exec("zrtp_unverify " + outCalls[0].zid) != 0) {
val calls = Call.uaCalls(calls, uas[aorSpinner.selectedItemPosition], "")
if (calls.size > 0) {
if (Api.cmd_exec("zrtp_unverify " + calls[0].zid) != 0) {
Log.w("Baresip",
"Command 'zrtp_unverify ${outCalls[0].zid}' failed")
"Command 'zrtp_unverify ${calls[0].zid}' failed")
} else {
securityButton.setImageResource(R.drawable.box_yellow)
securityButton.tag = "yellow"
@ -231,70 +261,81 @@ class MainActivity : AppCompatActivity() {
}
}
callButton.tag = "Call"
callButton.setOnClickListener {
val ua = uas[aorSpinner.selectedItemPosition]
val aor = ua.account.aor
when (callButton.tag) {
"Call" -> {
if (!ONE_CALL_ONLY || calls.isEmpty()) {
val calleeText = (findViewById(R.id.callee) as EditText).text.toString()
.trim()
if (calleeText.length > 0) {
var uri = ContactsActivity.findContactURI(calleeText)
if (!uri.startsWith("sip:")) {
uri = "sip:$uri"
if (!uri.contains("@")) {
val host = aor.substring(aor.indexOf("@") + 1)
uri = "$uri@$host"
}
}
if (!Utils.checkSipUri(uri))
Utils.alertView(this,"Notice",
"Invalid SIP URI '$uri'")
else
call(ua, uri)
} else {
val latest = CallHistory.aorLatestHistory(history, aor)
if (latest != null)
if (Utils.uriHostPart(latest.peerURI) == Utils.uriHostPart(aor))
callee.setText(Utils.uriUserPart(latest.peerURI))
else
callee.setText(latest.peerURI)
if (!ONE_CALL_ONLY || calls.isEmpty()) {
val uriText = (findViewById(R.id.uri) as EditText).text.toString().trim()
if (uriText.length > 0) {
var uri = ContactsActivity.findContactURI(uriText)
if (!uri.startsWith("sip:")) {
uri = "sip:$uri"
if (!uri.contains("@")) {
val host = aor.substring(aor.indexOf("@") + 1)
uri = "$uri@$host"
}
}
}
"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, "")
if (!Utils.checkSipUri(uri))
Utils.alertView(this,"Notice","Invalid SIP URI '$uri'")
else
call(ua, uri)
} else {
val latest = CallHistory.aorLatestHistory(history, aor)
if (latest != null)
if (Utils.uriHostPart(latest.peerURI) == Utils.uriHostPart(aor))
callUri.setText(Utils.uriUserPart(latest.peerURI))
else
callUri.setText(latest.peerURI)
}
}
}
holdButton.tag = "Hold"
holdButton.visibility = View.INVISIBLE
hangupButton.setOnClickListener {
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 {
when (holdButton.tag) {
"Hold" -> {
holdCallAt(Call.calls(calls, "out")[0], holdButton)
}
"Resume" -> {
Log.d("Baresip", "Resuming " + (findViewById(R.id.callee) as EditText).text)
val call = Call.calls(calls, "out")[0]
call_unhold(call.callp)
call.hold = false
holdButton.tag = "Hold"
holdButton.setImageResource(R.drawable.pause)
}
val ua = uas[aorSpinner.selectedItemPosition]
val aor = ua.account.aor
val call = Call.uaCalls(calls, ua,"")[0]
if (call.onhold) {
Log.d("Baresip", "AoR $aor resuming call ${call.callp} with " +
(findViewById(R.id.uri) as EditText).text)
call_unhold(call.callp)
call.onhold = false
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)
}
callee.threshold = 2
callee.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item,
callUri.threshold = 2
callUri.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item,
ContactsActivity.contacts.map { Contact -> Contact.name }))
if (intent.hasExtra("onStartup"))
@ -390,7 +431,8 @@ class MainActivity : AppCompatActivity() {
return
}
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)) {
Log.d("Baresip", "Auto-rejecting incoming call $uap/$callp/$peer_uri")
ua_hangup(uap, callp, 486, "Busy Here")
@ -400,10 +442,21 @@ class MainActivity : AppCompatActivity() {
} else {
Log.d("Baresip", "Incoming call $uap/$callp/$peer_uri")
calls.add(new_call)
if (ua != uas[aorSpinner.selectedItemPosition])
if (ua != uas[aorSpinner.selectedItemPosition]) {
aorSpinner.setSelection(account_index)
else
addCallViews(ua, new_call, Call.uaCalls(calls, ua, "in").size * 10)
} else {
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()
if (Utils.isVisible()) {
Log.d("Baresip", "Baresip is visible")
@ -420,58 +473,39 @@ class MainActivity : AppCompatActivity() {
Log.e("Baresip", "Established call $callp not found")
return
}
if (call.dir == "out") {
Log.d("Baresip", "Outbound call $callp established")
call.status = "Hangup"
call.hold = false
call.security = R.drawable.box_red
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 == "") {
securityButton.visibility = View.INVISIBLE
} else {
securityButton.setImageResource(R.drawable.box_red)
securityButton.tag = "red"
securityButton.visibility = View.VISIBLE
}
dtmf.setText("")
dtmf.hint = "DTMF"
dtmf.visibility = View.VISIBLE
dtmf.requestFocus()
dtmf.addTextChangedListener(call.dtmfWatcher)
Log.d("Baresip", "AoR $aor call $callp established")
call.status = "connected"
call.onhold = false
call.security = R.drawable.box_red
if (ua == uas[aorSpinner.selectedItemPosition]) {
if (acc.mediaenc == "") {
securityButton.visibility = View.INVISIBLE
} else {
securityButton.setImageResource(R.drawable.box_red)
securityButton.tag = "red"
securityButton.visibility = View.VISIBLE
}
history.add(CallHistory(aor, call.peerURI, "out", 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
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.hint = "DTMF"
dtmf.visibility = View.VISIBLE
dtmf.requestFocus()
dtmf.addTextChangedListener(call.dtmfWatcher)
}
history.add(CallHistory(aor, call.peerURI, call.dir, true))
call.hasHistory = true
if (rtTimer != null) {
rtTimer!!.cancel()
rtTimer = null
if (rt.isPlaying) rt.stop()
}
am.mode = AudioManager.MODE_IN_COMMUNICATION
am.mode = AudioManager . MODE_IN_COMMUNICATION
requestAudioFocus(STREAM_VOICE_CALL)
am.isSpeakerphoneOn = false
// am.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
@ -500,36 +534,20 @@ class MainActivity : AppCompatActivity() {
}
call.security = security
call.zid = ev[3]
if (call.dir == "out") {
if (ua == uas[aorSpinner.selectedItemPosition]) {
securityButton.setImageResource(security)
setSecurityButtonTag(securityButton, security)
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(security)
setSecurityButtonTag(securityButton, security)
securityButton.visibility = View.VISIBLE
}
dialog.dismiss()
}
dialog.dismiss()
}
verifyDialog.setNegativeButton("No") { dialog, _ ->
call.security = R.drawable.box_yellow
call.zid = ev[3]
if (call.dir == "out") {
if (ua == uas[aorSpinner.selectedItemPosition]) {
securityButton.setImageResource(R.drawable.box_yellow)
securityButton.tag = "yellow"
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(R.drawable.box_yellow)
securityButton.tag = "yellow"
securityButton.visibility = View.VISIBLE
}
}
dialog.dismiss()
}
@ -551,20 +569,10 @@ class MainActivity : AppCompatActivity() {
tag = "green"
call.zid = ev[1]
}
if (call.dir == "out") {
if (ua == uas[aorSpinner.selectedItemPosition]) {
securityButton.setImageResource(call.security)
securityButton.tag = tag
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
}
if (ua == uas[aorSpinner.selectedItemPosition]) {
securityButton.setImageResource(call.security)
securityButton.tag = tag
securityButton.visibility = View.VISIBLE
}
}
"call closed" -> {
@ -574,57 +582,27 @@ class MainActivity : AppCompatActivity() {
Log.d("Baresip", "Call $callp that is closed is not found")
return
}
if (call.dir == "in") {
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) {
Log.d("Baresip", "Removing call ${uap}/${callp}/" + call.peerURI)
stopRinging()
if (ua == uas[aorSpinner.selectedItemPosition]) {
callTitle.text = "Outgoing call to ..."
callUri.setText("")
callUri.hint = "Callee"
securityButton.visibility = View.INVISIBLE
callButton.visibility = View.VISIBLE
hangupButton.visibility = View.INVISIBLE
answerButton.visibility = View.INVISIBLE
rejectButton.visibility = View.INVISIBLE
holdButton.visibility = View.INVISIBLE
dtmf.visibility = View.INVISIBLE
imm.hideSoftInputFromWindow(dtmf.windowToken, 0)
dtmf.removeTextChangedListener(call.dtmfWatcher)
}
calls.remove(call)
if (!call.hasHistory) {
if (CallHistory.aorHistory(history, aor) > HISTORY_SIZE)
CallHistory.aorRemoveHistory(history, aor)
history.add(CallHistory(aor, call.peerURI, "in", false))
}
stopRinging()
} else {
Log.d("Baresip", "Removing outgoing call $uap/$callp/" +
call.peerURI)
if (ua == uas[aorSpinner.selectedItemPosition]) {
callButton.tag = "Call"
callButton.setImageResource(R.drawable.call_green)
callButton.isEnabled = true
callee.setText("")
callee.hint = "Callee"
holdButton.visibility = View.INVISIBLE
if (currentFocus == dtmf) {
imm.hideSoftInputFromWindow(dtmf.windowToken, 0)
}
securityButton.visibility = View.INVISIBLE
dtmf.removeTextChangedListener(call.dtmfWatcher)
dtmf.visibility = View.INVISIBLE
}
calls.remove(call)
if (!call.hasHistory) {
if (CallHistory.aorHistory(history, aor) > HISTORY_SIZE)
CallHistory.aorRemoveHistory(history, aor)
history.add(CallHistory(aor, call.peerURI, "out",
false))
}
history.add(CallHistory(aor, call.peerURI, call.dir,false))
}
if (calls.size == 0) am.mode = AudioManager.MODE_NORMAL
if (am.isSpeakerphoneOn) {
@ -750,22 +728,18 @@ class MainActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
// Log.d("Baresip", "Resumed")
imm.hideSoftInputFromWindow(callee.windowToken, 0)
imm.hideSoftInputFromWindow(callUri.windowToken, 0)
visible = true
if ((answerCall != "") && (layout.childCount > 6)) {
if (answerCall != "") {
answerCall = ""
/* if multiple calls, right answer button needs to be searched */
val answerButton = layout.findViewById(10 + 5) as ImageButton
answerButton.performClick()
}
if ((rejectCall != "") && (layout.childCount > 6)) {
if (rejectCall != "") {
rejectCall = ""
/* if multiple calls, right reject button needs to be searched */
val rejectButton = layout.findViewById(10 + 6) as ImageButton
rejectButton.performClick()
}
if (makeCall != "") {
callee.setText(makeCall)
callUri.setText(makeCall)
makeCall = ""
callButton.performClick()
}
@ -845,7 +819,7 @@ class MainActivity : AppCompatActivity() {
}
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}))
}
@ -863,7 +837,7 @@ class MainActivity : AppCompatActivity() {
HISTORY_CODE -> {
if (resultCode == RESULT_OK) {
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) {
@ -886,209 +860,40 @@ class MainActivity : AppCompatActivity() {
"You have not granted microphone permission.", Toast.LENGTH_SHORT).show()
return
}
(findViewById(R.id.callee) as EditText).setText(uri)
val call = ua_connect(ua.uap, uri)
if (call != "") {
Log.d("Baresip", "Adding outgoing call ${ua.uap}/$call/$uri")
val dtmfWatcher = object : TextWatcher {
override fun beforeTextChanged(sequence: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(sequence: CharSequence, start: Int, before: Int, count: Int) {
val digit = sequence.subSequence(start, start + count).toString()
Log.d("Baresip", "Got DTMF digit '" + digit + "'")
if (digit.isNotEmpty()) call_send_digit(call, digit[0])
}
override fun afterTextChanged(sequence: Editable) {
call_send_digit(call, 4.toChar())
}
}
calls.add(Call(call, ua, uri, "out", "Cancel", dtmfWatcher))
callButton.tag = "Cancel"
callButton.setImageResource(R.drawable.hangup)
(findViewById(R.id.uri) as EditText).setText(uri)
callButton.visibility = View.INVISIBLE
val callp = ua_connect(ua.uap, uri)
if (callp != "") {
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 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)
private fun dtmfWatcher(callp: String): TextWatcher {
return object : TextWatcher {
override fun beforeTextChanged(sequence: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(sequence: CharSequence, start: Int, before: Int, count: Int) {
val digit = sequence.subSequence(start, start + count).toString()
Log.d("Baresip", "Got DTMF digit '" + digit + "'")
if (digit.isNotEmpty()) call_send_digit(callp, digit[0])
}
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()
}
override fun afterTextChanged(sequence: Editable) {
call_send_digit(callp, 4.toChar())
}
}
// 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) {
@ -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) {
if (!audioFocused) {
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 ua_connect(uap: String, peer_uri: String): String
external fun ua_answer(uap: String, callp: String)

View File

@ -31,7 +31,7 @@
android:spinnerMode="dropdown"/>
<TextView
android:id="@+id/outTitle"
android:id="@+id/callTitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/AoRList"
@ -43,14 +43,14 @@
</TextView>
<LinearLayout
android:id="@+id/calleeRow"
android:id="@+id/uriRow"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/outTitle" >
android:layout_below="@id/callTitle" >
<AutoCompleteTextView
android:id="@+id/callee"
android:id="@+id/uri"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight = "1"
@ -76,21 +76,60 @@
android:id="@+id/callButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/calleeRow"
android:layout_below="@id/uriRow"
android:padding="0dp"
android:background="@null"
android:src="@drawable/call_green" >
</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
android:id="@+id/holdButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/calleeRow"
android:layout_below="@id/uriRow"
android:padding="0dp"
android:src="@drawable/pause"
android:background="@null"
android:layout_marginStart="70dp"
android:clickable="false"
android:visibility="invisible" >
</ImageButton>
@ -98,7 +137,7 @@
android:id="@+id/dtmf"
android:layout_width="@dimen/button_width"
android:layout_height="wrap_content"
android:layout_below="@id/calleeRow"
android:layout_below="@id/uriRow"
android:layout_marginStart="140dp"
android:inputType="phone"
android:textSize="20sp"