- Upgraded target Android API level to 28 (Android 9)

- Moved some non-UI functionality from main activity to baresip service
- Simplified implementation of call transfer
- Modified baresip launcher and status bar images
This commit is contained in:
Juha Heinanen
2019-04-08 18:47:59 +03:00
parent eb4cfbcece
commit cf5680b52b
19 changed files with 409 additions and 298 deletions

View File

@ -1,14 +1,15 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion = 27
compileSdkVersion = 28
defaultConfig {
applicationId = 'com.tutpro.baresip'
minSdkVersion 21
targetSdkVersion 27
versionCode = 49
versionName = '6.1.0'
targetSdkVersion 28
versionCode = 50
versionName = '6.2.0'
externalNativeBuild {
cmake {
cFlags '-DHAVE_INTTYPES_H'
@ -27,7 +28,7 @@ android {
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'),
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
}
}
@ -43,14 +44,12 @@ android {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support:design:28.0.0'
}
repositories {
mavenCentral()
}
apply plugin: 'kotlin-android-extensions'

View File

@ -2,6 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tutpro.baresip">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
@ -95,6 +96,7 @@
<service
android:name=".BaresipService"
android:permission="android.permission.FOREGROUND_SERVICE"
android:enabled="true" >
</service>
@ -102,7 +104,7 @@
android:name=".RunOnStartup"
android:enabled="true"
android:exported="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
android:permission="android.permission.RECEIVE_BOOT_COMPLETED" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="com.tutpro.baresip.Restart" />

View File

@ -977,7 +977,6 @@ Java_com_tutpro_baresip_Api_uag_1current_1set(JNIEnv *env, jobject thiz, jstring
(*env)->ReleaseStringUTFChars(env, javaUA, native_ua);
LOGD("running uag_current_set on %s\n", native_ua);
uag_current_set(ua);
return;
}
JNIEXPORT jstring JNICALL

View File

@ -41,8 +41,9 @@ class AccountListAdapter(private val cxt: Context, private val rows: ArrayList<A
val deleteDialog = AlertDialog.Builder(cxt)
deleteDialog.setMessage("Do you want to delete account ${ua.account.aor}?")
deleteDialog.setPositiveButton("Delete") { dialog, _ ->
if (Api.ua_isregistered(ua.uap)) Api.ua_unregister(ua.uap)
Api.ua_destroy(ua.uap)
if (Api.ua_isregistered(ua.uap))
Api.ua_unregister(ua.uap)
// Api.ua_destroy(ua.uap)
UserAgent.remove(ua)
AccountsActivity.generateAccounts()
AccountsActivity.saveAccounts()

View File

@ -101,7 +101,8 @@ class BaresipService: Service() {
action = "Start"
Log.d(LOG_TAG, "Received onStartCommand with null intent")
} else {
action = intent.getAction()
// Utils.dumpIntent(intent)
action = intent.action!!
Log.d(LOG_TAG, "Received onStartCommand action $action")
}
@ -162,6 +163,92 @@ class BaresipService: Service() {
showStatusNotification()
}
"Call Show", "Call Answer" -> {
val newIntent = Intent(this, MainActivity::class.java)
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
newIntent.putExtra("action", action.toLowerCase())
newIntent.putExtra("callp", intent!!.getStringExtra("callp"))
startActivity(newIntent)
}
"Call Reject" -> {
val callp = intent!!.getStringExtra("callp")
val call = Call.find(callp)
if (call == null) {
Log.w(LOG_TAG, "onStartCommand did not find call $callp")
} else {
val peerUri = call.peerURI
val aor = call.ua.account.aor
Log.i(LOG_TAG, "Aor $aor rejected incoming call $callp from $peerUri")
Api.ua_hangup(call.ua.uap, callp, 486, "Rejected")
CallHistory.add(CallHistory(aor, peerUri, "in", false))
CallHistory.save(filesPath)
}
}
"Transfer Show", "Transfer Accept" -> {
val uap = intent!!.getStringExtra("uap")
val ua = UserAgent.find(uap)
if (ua == null) {
Log.w(LOG_TAG, "onStartCommand did not find ua $uap")
} else {
val newIntent = Intent(this, MainActivity::class.java)
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
newIntent.putExtra("action", action.toLowerCase())
newIntent.putExtra("callp", intent.getStringExtra("callp"))
newIntent.putExtra("uri", intent.getStringExtra("uri"))
startActivity(newIntent)
nm.cancel(BaresipService.TRANSFER_NOTIFICATION_ID)
}
}
"Transfer Deny" -> {
val callp = intent!!.getStringExtra("callp")
val call = Call.find(callp)
if (call == null)
Log.w(LOG_TAG, "onStartCommand did not find call $callp")
else
Api.call_notify_sipfrag(callp, 603, "Decline")
nm.cancel(BaresipService.TRANSFER_NOTIFICATION_ID)
}
"Message Show", "Message Reply" -> {
val newIntent = Intent(this, MainActivity::class.java)
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
newIntent.putExtra("action", action.toLowerCase())
newIntent.putExtra("uap", intent!!.getStringExtra("uap"))
newIntent.putExtra("time", intent.getStringExtra("time"))
startActivity(newIntent)
nm.cancel(BaresipService.MESSAGE_NOTIFICATION_ID)
}
"Message Save" -> {
val uap = intent!!.getStringExtra("uap")
val ua = UserAgent.find(uap)
if (ua == null)
Log.w(LOG_TAG, "onStartCommand did not find UA $uap")
else
ChatsActivity.saveUaMessage(ua.account.aor,
intent.getStringExtra("time").toLong(),
applicationContext.filesDir.absolutePath)
nm.cancel(BaresipService.MESSAGE_NOTIFICATION_ID)
}
"Message Delete" -> {
val uap = intent!!.getStringExtra("uap")
val ua = UserAgent.find(uap)
if (ua == null)
Log.w(LOG_TAG, "onStartCommand did not find UA $uap")
else
ChatsActivity.deleteUaMessage(ua.account.aor,
intent.getStringExtra("time").toLong(),
applicationContext.filesDir.absolutePath)
nm.cancel(BaresipService.MESSAGE_NOTIFICATION_ID)
}
"UpdateNotification" -> {
updateStatusNotification()
}
@ -243,14 +330,20 @@ class BaresipService: Service() {
else
status[account_index] = R.drawable.dot_green
updateStatusNotification()
if (!Utils.isVisible())
return
}
"registering failed" -> {
status[account_index] = R.drawable.dot_red
updateStatusNotification()
if (!Utils.isVisible())
return
}
"unregistering" -> {
status[account_index] = R.drawable.dot_yellow
updateStatusNotification()
if (!Utils.isVisible())
return
}
"call incoming" -> {
val peerUri = Api.call_peeruri(callp)
@ -260,6 +353,8 @@ class BaresipService: Service() {
CallHistory.add(CallHistory(aor, peerUri, "in", false))
CallHistory.save(filesPath)
ua.account.missedCalls = true
if (!Utils.isVisible())
return
newEvent = "call rejected"
} else {
Log.d(LOG_TAG, "Incoming call $uap/$callp/$peerUri")
@ -267,44 +362,41 @@ class BaresipService: Service() {
Utils.dtmfWatcher(callp)))
startRinging()
}
if ((newEvent == null) && !Utils.isVisible()) {
val intent = Intent(this, MainActivity::class.java)
.setAction(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER)
val pi = PendingIntent.getActivity(this, CALL_REQ_CODE, intent,
0)
if (!Utils.isVisible()) {
val intent = Intent(this, BaresipService::class.java)
intent.action = "Call Show"
intent.putExtra("callp", callp)
val pi = PendingIntent.getService(this, CALL_REQ_CODE, intent,
PendingIntent.FLAG_UPDATE_CURRENT)
val nb = NotificationCompat.Builder(this, HIGH_CHANNEL_ID)
val caller = Utils.friendlyUri(ContactsActivity.contactName(peerUri),
Utils.aorDomain(aor))
val title = "Incoming call from $caller"
nb.setSmallIcon(R.drawable.ic_stat)
.setColor(ContextCompat.getColor(this,
R.color.colorBaresip))
.setContentIntent(pi)
.setAutoCancel(true)
.setContentTitle(title)
.setContentTitle("Incoming call from")
.setContentText(caller)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
nb.setVibrate(LongArray(0))
.setVisibility(VISIBILITY_PRIVATE)
.setPriority(Notification.PRIORITY_HIGH)
}
val answerIntent = Intent(this, MainActivity::class.java)
answerIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
answerIntent.putExtra("action", "answer")
val answerIntent = Intent(this, BaresipService::class.java)
answerIntent.action = "Call Answer"
answerIntent.putExtra("callp", callp)
val answerPendingIntent = PendingIntent.getActivity(this,
val answerPendingIntent = PendingIntent.getService(this,
ANSWER_REQ_CODE, answerIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val rejectIntent = Intent(this, MainActivity::class.java)
rejectIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_SINGLE_TOP)
rejectIntent.putExtra("action", "reject")
val rejectIntent = Intent(this, BaresipService::class.java)
rejectIntent.action = "Call Reject"
rejectIntent.putExtra("callp", callp)
val rejectPendingIntent = PendingIntent.getActivity(this,
val rejectPendingIntent = PendingIntent.getService(this,
REJECT_REQ_CODE, rejectIntent, PendingIntent.FLAG_UPDATE_CURRENT)
nb.addAction(R.drawable.ic_stat, "Answer", answerPendingIntent)
nb.addAction(R.drawable.ic_stat, "Reject", rejectPendingIntent)
nm.notify(CALL_NOTIFICATION_ID, nb.build())
return
}
}
"call established" -> {
@ -324,54 +416,68 @@ class BaresipService: Service() {
am.mode = AudioManager.MODE_IN_COMMUNICATION
requestAudioFocus(AudioManager.STREAM_VOICE_CALL)
am.isSpeakerphoneOn = false
if (!Utils.isVisible())
return
}
"call verified", "call secure" -> {
val call = Call.find(callp)
if (call == null) {
Log.e("Baresip", "Call $callp that is verified is not found")
return
}
if (ev[0] == "call secure") {
call.security = R.drawable.box_yellow
} else {
call.security = R.drawable.box_green
call.zid = ev[1]
}
if (!Utils.isVisible())
return
}
"call transfer" -> {
val call = Call.find(callp)
if (call == null) {
Log.d(LOG_TAG, "AoR $aor call $callp to be transferred is not found")
Log.w(LOG_TAG, "Call $callp to be transferred is not found")
return
}
if (!Utils.isVisible()) {
val intent = Intent(this, MainActivity::class.java)
.setAction(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER)
val pi = PendingIntent.getActivity(this, TRANSFER_REQ_CODE,
intent, 0)
val intent = Intent(this, BaresipService::class.java)
intent.action = "Transfer Show"
intent.putExtra("uap", uap)
.putExtra("callp", callp)
.putExtra("uri", ev[1])
val pi = PendingIntent.getService(this, TRANSFER_REQ_CODE,
intent, PendingIntent.FLAG_UPDATE_CURRENT)
val nb = NotificationCompat.Builder(this, HIGH_CHANNEL_ID)
val target = Utils.friendlyUri(ContactsActivity.contactName(ev[1]),
Utils.aorDomain(aor))
val title = "Call transfer request to $target"
nb.setSmallIcon(R.drawable.ic_stat)
.setColor(ContextCompat.getColor(this,
R.color.colorBaresip))
.setColor(ContextCompat.getColor(this, R.color.colorBaresip))
.setContentIntent(pi)
.setDefaults(Notification.DEFAULT_SOUND)
.setAutoCancel(true)
.setContentTitle(title)
.setContentTitle("Call transfer request to")
.setContentText(target)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
nb.setVibrate(LongArray(0))
.setVisibility(VISIBILITY_PRIVATE)
.setPriority(Notification.PRIORITY_HIGH)
}
val acceptIntent = Intent(this, MainActivity::class.java)
acceptIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
acceptIntent.putExtra("action", "transfer")
val acceptIntent = Intent(this, BaresipService::class.java)
acceptIntent.action = "Transfer Accept"
acceptIntent.putExtra("uap", uap)
acceptIntent.putExtra("callp", callp)
acceptIntent.putExtra("uri", ev[1])
val acceptPendingIntent = PendingIntent.getActivity(this,
.putExtra("callp", callp)
.putExtra("uri", ev[1])
val acceptPendingIntent = PendingIntent.getService(this,
ACCEPT_REQ_CODE, acceptIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val denyIntent = Intent(this, MainActivity::class.java)
denyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_SINGLE_TOP)
denyIntent.putExtra("action", "deny")
val denyIntent = Intent(this, BaresipService::class.java)
denyIntent.action = "Transfer Deny"
denyIntent.putExtra("callp", callp)
val denyPendingIntent = PendingIntent.getActivity(this,
val denyPendingIntent = PendingIntent.getService(this,
DENY_REQ_CODE, denyIntent, PendingIntent.FLAG_UPDATE_CURRENT)
nb.addAction(R.drawable.ic_stat, "Accept", acceptPendingIntent)
nb.addAction(R.drawable.ic_stat, "Deny", denyPendingIntent)
nm.notify(CALL_NOTIFICATION_ID, nb.build())
nm.notify(TRANSFER_NOTIFICATION_ID, nb.build())
return
}
}
@ -395,6 +501,12 @@ class BaresipService: Service() {
if (am.isSpeakerphoneOn) am.isSpeakerphoneOn = false
if (audioFocused) abandonAudioFocus()
}
if (speakerPhone) {
am.isSpeakerphoneOn = !am.isSpeakerphoneOn
speakerPhone = am.isSpeakerphoneOn
}
if (!Utils.isVisible())
return
}
"transfer failed" -> {
Log.d(LOG_TAG, "AoR $aor hanging up call $callp with ${ev[1]}")
@ -406,6 +518,8 @@ class BaresipService: Service() {
}
if (newEvent == null) newEvent = event
val intent = Intent("service event")
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
intent.putExtra("event", newEvent)
intent.putExtra("params", arrayListOf(uap, callp))
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
@ -413,9 +527,9 @@ class BaresipService: Service() {
@Keep
fun messageEvent(uap: String, peer: String, msg: ByteArray) {
var s = "Decoding of message failed!"
var text = "Decoding of message failed!"
try {
s = String(msg, StandardCharsets.UTF_8)
text = String(msg, StandardCharsets.UTF_8)
} catch (e: Exception) {
Log.e(LOG_TAG, "UTF-8 decode failed")
}
@ -426,14 +540,15 @@ class BaresipService: Service() {
return
}
val timeStamp = System.currentTimeMillis().toString()
Message.add(Message(ua.account.aor, peer, text, timeStamp.toLong(),
R.drawable.arrow_down_green, 0, "", true))
if (!Utils.isVisible()) {
val intent = Intent(this, MainActivity::class.java)
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
.putExtra("action", "show")
.putExtra("uap", uap)
.putExtra("peer", peer)
val pi = PendingIntent.getActivity(this, MESSAGE_REQ_CODE, intent, 0)
val intent = Intent(this, BaresipService::class.java)
intent.action = "Message Show"
intent.putExtra("uap", uap)
.putExtra("time", timeStamp)
val pi = PendingIntent.getService(this, MESSAGE_REQ_CODE, intent,
PendingIntent.FLAG_UPDATE_CURRENT)
val nb = NotificationCompat.Builder(this, HIGH_CHANNEL_ID)
val sender = Utils.friendlyUri(ContactsActivity.contactName(peer),
Utils.aorDomain(ua.account.aor))
@ -443,44 +558,41 @@ class BaresipService: Service() {
.setDefaults(Notification.DEFAULT_SOUND)
.setAutoCancel(true)
.setContentTitle("Message from $sender")
.setContentText(s)
.setContentText(text)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
nb.setVibrate(LongArray(0))
.setVisibility(VISIBILITY_PRIVATE)
.setPriority(Notification.PRIORITY_HIGH)
}
val replyIntent = Intent(this, MainActivity::class.java)
replyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
replyIntent.putExtra("action", "reply")
val replyIntent = Intent(this, BaresipService::class.java)
replyIntent.action = "Message Reply"
replyIntent.putExtra("uap", uap)
replyIntent.putExtra("peer", peer)
val replyPendingIntent = PendingIntent.getActivity(this,
.putExtra("time", timeStamp)
val replyPendingIntent = PendingIntent.getService(this,
REPLY_REQ_CODE, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val saveIntent = Intent(this, MainActivity::class.java)
saveIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_SINGLE_TOP)
saveIntent.putExtra("action", "save")
val saveIntent = Intent(this, BaresipService::class.java)
saveIntent.action = "Message Save"
saveIntent.putExtra("uap", uap)
saveIntent.putExtra("time", timeStamp)
val savePendingIntent = PendingIntent.getActivity(this,
.putExtra("time", timeStamp)
val savePendingIntent = PendingIntent.getService(this,
SAVE_REQ_CODE, saveIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val deleteIntent = Intent(this, MainActivity::class.java)
deleteIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_SINGLE_TOP)
deleteIntent.putExtra("action", "delete")
val deleteIntent = Intent(this, BaresipService::class.java)
deleteIntent.action = "Message Delete"
deleteIntent.putExtra("uap", uap)
deleteIntent.putExtra("time", timeStamp)
val deletePendingIntent = PendingIntent.getActivity(this,
.putExtra("time", timeStamp)
val deletePendingIntent = PendingIntent.getService(this,
DELETE_REQ_CODE, deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT)
nb.addAction(R.drawable.ic_stat, "Reply", replyPendingIntent)
nb.addAction(R.drawable.ic_stat, "Save", savePendingIntent)
nb.addAction(R.drawable.ic_stat, "Delete", deletePendingIntent)
nm.notify(MESSAGE_NOTIFICATION_ID, nb.build())
return
}
val intent = Intent("service event")
intent.putExtra("event", "message")
intent.putExtra("params", arrayListOf(uap, peer, s, timeStamp))
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
intent.putExtra("event", "message show")
intent.putExtra("params", arrayListOf(uap, timeStamp))
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
}
@ -645,7 +757,8 @@ class BaresipService: Service() {
val STATUS_NOTIFICATION_ID = 101
val CALL_NOTIFICATION_ID = 102
val MESSAGE_NOTIFICATION_ID = 103
val TRANSFER_NOTIFICATION_ID = 103
val MESSAGE_NOTIFICATION_ID = 104
val STATUS_REQ_CODE = 1
val CALL_REQ_CODE = 2

View File

@ -1,6 +1,7 @@
package com.tutpro.baresip
import android.text.TextWatcher
import android.util.Log
import java.util.ArrayList
class Call(val callp: String, val ua: UserAgent, val peerURI: String, val dir: String,
@ -49,6 +50,5 @@ class Call(val callp: String, val ua: UserAgent, val peerURI: String, val dir: S
if (c.callp == callp) return c
return null
}
}
}

View File

@ -219,12 +219,6 @@ class ChatActivity : AppCompatActivity() {
return true
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
if ((requestCode == MainActivity.CONTACT_CODE) && (resultCode == Activity.RESULT_OK)) {
setTitle("Chat with ${data.getStringExtra("name")}")
}
}
private fun uaPeerMessages(aor: String, peerUri: String): ArrayList<Message> {
val res = ArrayList<Message>()
for (m in Message.messages())

View File

@ -65,10 +65,8 @@ class ChatListAdapter(private val cxt: Context, private var rows: ArrayList<Mess
}
val textView = chatView.findViewById(R.id.text) as TextView
textView.text = message.message
if (message.new) {
if (message.new)
textView.setTypeface(null, Typeface.BOLD)
message.new = false
}
return chatView
}

View File

@ -39,7 +39,7 @@ class ChatsActivity: AppCompatActivity() {
listView = findViewById(R.id.chats) as ListView
plusButton = findViewById(R.id.plusButton) as ImageButton
aor = intent.extras.getString("aor")
aor = intent.extras!!.getString("aor")!!
val headerView = findViewById(R.id.account) as TextView
val headerText = "Account ${aor.substringAfter(":")}"
@ -207,6 +207,14 @@ class ChatsActivity: AppCompatActivity() {
var filesPath = ""
fun findUaMessage(aor: String, timeStamp: Long): Message? {
for (i in Message.messages().indices.reversed())
if ((Message.messages()[i].aor == aor) &&
(Message.messages()[i].timeStamp == timeStamp))
return Message.messages()[i]
return null
}
fun saveUaMessage(aor: String, time: Long, path: String) {
for (i in Message.messages().indices.reversed())
if ((Message.messages()[i].aor == aor) &&

View File

@ -240,7 +240,7 @@ class MainActivity : AppCompatActivity() {
if (!Utils.checkSipUri(uri))
Utils.alertView(this,"Notice","Invalid SIP URI '$uri'")
else
call(ua, uri)
call(ua, uri, "outgoing")
} else {
val latest = CallHistory.aorLatestHistory(aor)
if (latest != null)
@ -409,18 +409,126 @@ class MainActivity : AppCompatActivity() {
if (intent.hasExtra("onStartup"))
moveTaskToBack(true)
if (intent.hasExtra("action")) {
if (intent.hasExtra("action"))
// MainActivity was not visible when call, message, or transfer request came in
handleIntent(intent)
}
override fun onNewIntent(intent: Intent) {
// Called when MainActivity already exists at the top of current task
super.onNewIntent(intent)
val action = intent.getStringExtra("action")
Log.d("Baresip", "onNewIntent action '$action'")
if (action != null) handleIntent(intent)
}
private fun handleIntent(intent: Intent) {
val action = intent.getStringExtra("action")
Log.d("Baresip", "Handling intent '$action'")
when (action) {
"call" -> {
if (!Call.calls().isEmpty()) {
Toast.makeText(applicationContext, "You already have an active call!",
Toast.LENGTH_SHORT).show()
return
}
val uap = intent.getStringExtra("uap")
val ua = UserAgent.find(uap)
if (ua == null) {
Log.e("Baresip", "handleIntent 'call' did not find ua $uap")
return
}
if (ua != UserAgent.uas()[aorSpinner.selectedItemPosition])
spinToAor(ua.account.aor)
resumeAction = action
resumeUri = intent.getStringExtra("peer")
}
"call show", "call answer" -> {
val callp = intent.getStringExtra("callp")
val call = Call.find(callp)
if (call == null) {
Log.e("Baresip", "handleIntent '$action' did not find call $callp")
return
}
val ua = call.ua
if (ua != UserAgent.uas()[aorSpinner.selectedItemPosition])
spinToAor(ua.account.aor)
resumeAction = action
resumeCall = call
}
"transfer show", "transfer accept" -> {
val callp = intent.getStringExtra("callp")
val call = Call.find(callp)
if (call == null) {
Log.e("Baresip", "handleIntent '$action' did not find call $callp")
moveTaskToBack(true)
return
}
resumeAction = action
resumeCall = call
resumeUri = intent.getStringExtra("uri")
}
"message show", "message reply" -> {
val uap = intent.getStringExtra("uap")
val ua = UserAgent.find(uap)
if (ua == null) {
Log.e("Baresip", "onNewIntent did not find ua $uap")
return
}
if (ua != UserAgent.uas()[aorSpinner.selectedItemPosition])
spinToAor(ua.account.aor)
resumeAction = action
resumeUap = uap
resumeTime = intent.getStringExtra("time")
}
}
}
override fun onResume() {
super.onResume()
Log.d("Baresip", "Main resumed with action '$resumeAction'")
// imm.hideSoftInputFromWindow(callUri.windowToken, 0)
visible = true
when (resumeAction) {
"call show" ->
handleServiceEvent("call incoming",
arrayListOf(resumeCall!!.ua.uap, resumeCall!!.callp))
"call answer" ->
answerButton.performClick()
"call reject" ->
rejectButton.performClick()
"call" ->
callButton.performClick()
"transfer show", "transfer accept" ->
handleServiceEvent("$resumeAction,$resumeUri",
arrayListOf(resumeCall!!.ua.uap, resumeCall!!.callp))
"message show", "message reply" ->
handleServiceEvent(resumeAction, arrayListOf(resumeUap, resumeTime))
else -> {
uaAdapter.notifyDataSetChanged()
if (aorSpinner.selectedItemPosition != -1)
showCall(UserAgent.uas()[aorSpinner.selectedItemPosition])
}
}
resumeAction = ""
}
override fun onPause() {
super.onPause()
// Log.d("Baresip", "Main paused")
visible = false
}
private fun handleServiceEvent(event: String, params: ArrayList<String>) {
if (taskId == -1) {
Log.d("Baresip", "Omit service event '$event' for task -1")
return
}
if (event == "stopped") {
Log.d("Baresip", "Handling service event 'stopped'")
quitTimer.cancel()
finishAndRemoveTask()
System.exit(0)
// System.exit(0)
return
}
val uap = params[0]
@ -491,11 +599,10 @@ class MainActivity : AppCompatActivity() {
dtmf.visibility = View.INVISIBLE
infoButton.visibility = View.INVISIBLE
}
if (Utils.isVisible()) {
Log.d("Baresip", "Baresip is visible")
val i = Intent(applicationContext, MainActivity::class.java)
i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
startActivity(i)
if (!visible) {
val i = Intent(applicationContext, MainActivity::class.java)
i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
startActivity(i)
}
}
"call established" -> {
@ -528,10 +635,10 @@ class MainActivity : AppCompatActivity() {
dtmf.hint = "DTMF"
dtmf.visibility = View.VISIBLE
dtmf.requestFocus()
(dtmf.tag as ArrayList<TextWatcher>).add(call.dtmfWatcher!!)
dtmf.addTextChangedListener(call.dtmfWatcher)
infoButton.visibility = View.VISIBLE
}
(dtmf.tag as ArrayList<TextWatcher>).add(call.dtmfWatcher!!)
dtmf.addTextChangedListener(call.dtmfWatcher)
}
"call verify" -> {
val callp = params[1]
@ -570,7 +677,7 @@ class MainActivity : AppCompatActivity() {
}
dialog.dismiss()
}
verifyDialog.create().show()
if (!isFinishing()) verifyDialog.create().show()
}
"call verified", "call secure" -> {
val callp = params[1]
@ -580,20 +687,16 @@ class MainActivity : AppCompatActivity() {
return
}
val tag: String
if (ev[0] == "call secure") {
call.security = R.drawable.box_yellow
if (call.security == R.drawable.box_yellow)
tag = "yellow"
} else {
call.security = R.drawable.box_green
else
tag = "green"
call.zid = ev[1]
}
if (ua == UserAgent.uas()[aorSpinner.selectedItemPosition]) {
securityButton.setImageResource(call.security)
securityButton.tag = tag
}
}
"call transfer" -> {
"call transfer", "transfer show" -> {
val callp = params[1]
val call = Call.find(callp)
if (call == null) {
@ -606,9 +709,9 @@ class MainActivity : AppCompatActivity() {
transferDialog.setMessage("Do you accept to transfer call to $target?")
transferDialog.setPositiveButton("Yes") { dialog, _ ->
if (call in Call.calls())
transfer(ua, call, ev[1])
else
call(ua, ev[1])
Api.ua_hangup(uap, callp, 0, "")
call(ua, ev[1], "transferring")
showCall(ua)
dialog.dismiss()
}
transferDialog.setNegativeButton("No") { dialog, _ ->
@ -618,6 +721,18 @@ class MainActivity : AppCompatActivity() {
}
transferDialog.create().show()
}
"transfer accept" -> {
val callp = params[1]
val call = Call.find(callp)
if (call == null) {
Log.e("Baresip", "Call $callp to be transferred is not found")
return
}
if (call in Call.calls())
Api.ua_hangup(uap, callp, 0, "")
call(ua, ev[1], "transferring")
showCall(ua)
}
"call closed" -> {
val watchers = dtmf.tag as ArrayList<TextWatcher>
if (watchers.size > 0) {
@ -630,10 +745,6 @@ class MainActivity : AppCompatActivity() {
callsButton.setImageResource(R.drawable.calls_missed)
}
speakerIcon.setIcon(R.drawable.speaker_off)
if (BaresipService.speakerPhone) {
baresipService.setAction("ToggleSpeaker")
startService(baresipService)
}
val param = ev[1].trim()
if ((param != "") && (Call.uaCalls(ua, "").size == 0)) {
if (param.get(0).isDigit())
@ -644,27 +755,25 @@ class MainActivity : AppCompatActivity() {
Toast.LENGTH_LONG).show()
}
}
"message" -> {
val peerUri = params[1]
val msgText = params[2]
val time = params[3]
Log.d("Baresip", "Incoming message $aor/$peerUri/$msgText")
Message.add(Message(aor, peerUri, msgText, time.toLong(),
R.drawable.arrow_down_green, 0, "",
true))
if (Utils.isVisible()) {
if ((aorSpinner.selectedItemPosition == -1) ||
(ua != UserAgent.uas()[aorSpinner.selectedItemPosition]))
aorSpinner.setSelection(account_index)
val i = Intent(applicationContext, ChatsActivity::class.java)
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val b = Bundle()
b.putString("aor", ua.account.aor)
b.putString("peer", peerUri)
b.putBoolean("focus", false)
i.putExtras(b)
startActivity(i)
"message show", "message reply" -> {
val timeStamp = params[1].toLong()
val msg = ChatsActivity.findUaMessage(ua.account.aor, timeStamp)
if (msg == null) {
Log.e("Baresip", "Message $aor/$timeStamp is not found")
return
}
Log.d("Baresip", "Message for $aor from ${msg.peerUri}")
if ((aorSpinner.selectedItemPosition == -1) ||
(ua != UserAgent.uas()[aorSpinner.selectedItemPosition]))
aorSpinner.setSelection(account_index)
val i = Intent(applicationContext, ChatsActivity::class.java)
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val b = Bundle()
b.putString("aor", aor)
b.putString("peer", msg.peerUri)
b.putBoolean("focus", ev[0] == "message reply")
i.putExtras(b)
startActivity(i)
}
"mwi notify" -> {
val lines = ev[1].split("\n")
@ -691,143 +800,11 @@ class MainActivity : AppCompatActivity() {
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
val action = intent.getStringExtra("action")
Log.d("Baresip", "onNewIntent action '$action'")
if (action != null) handleIntent(intent)
}
private fun handleIntent(intent: Intent) {
val action = intent.getStringExtra("action")
Log.d("Baresip", "Handling intent '$action'")
when (action) {
"call" -> {
if (!Call.calls().isEmpty()) {
Toast.makeText(applicationContext, "You already have an active call!",
Toast.LENGTH_SHORT).show()
return
}
val uap = intent.getStringExtra("uap")
val ua = UserAgent.find(uap)
if (ua == null) {
Log.e("Baresip", "handleIntent 'call' did not find ua $uap")
return
}
if (ua != UserAgent.uas()[aorSpinner.selectedItemPosition])
spinToAor(ua.account.aor)
makeCall = intent.getStringExtra("peer")
}
"answer" -> {
answerCall = intent.getStringExtra("callp")
}
"reject" -> {
rejectCall = intent.getStringExtra("callp")
moveTaskToBack(true)
}
"transfer" -> {
val callp = intent.getStringExtra("callp")
val call = Call.find(callp)
val uap = intent.getStringExtra("uap")
val ua = UserAgent.find(uap)
if (ua == null) {
Log.e("Baresip", "Ua $uap of call transfer target does not exist")
moveTaskToBack(true)
return
}
if (call == null)
call(ua, intent.getStringExtra("uri"))
else
transfer(ua, call, intent.getStringExtra("uri"))
}
"deny" -> {
val callp = intent.getStringExtra("callp")
val call = Call.find(callp)
if (call == null)
Log.d("Baresip", "Call $callp denied transfer does not exist anymore")
else
Api.call_notify_sipfrag(callp, 603, "Decline")
moveTaskToBack(true)
}
"show", "reply", "save", "delete" -> {
val uap = intent.getStringExtra("uap")
val ua = UserAgent.find(uap)
if (ua == null) {
Log.e("Baresip", "onNewIntent did not find ua $uap")
return
}
val aor = ua.account.aor
when (action) {
"show", "reply" -> {
val i = Intent(this@MainActivity, ChatsActivity::class.java)
val b = Bundle()
if (ua != UserAgent.uas()[aorSpinner.selectedItemPosition])
spinToAor(aor)
b.putString("aor", aor)
b.putString("peer", intent.getStringExtra("peer"))
b.putBoolean("focus", action == "reply")
i.putExtras(b)
startActivityForResult(i, MESSAGES_CODE)
}
"save" -> {
ChatsActivity.saveUaMessage(ua.account.aor,
intent.getStringExtra("time").toLong(),
applicationContext.filesDir.absolutePath)
moveTaskToBack(true)
}
"delete" -> {
ChatsActivity.deleteUaMessage(ua.account.aor,
intent.getStringExtra("time").toLong(),
applicationContext.filesDir.absolutePath)
moveTaskToBack(true)
}
}
nm.cancel(BaresipService.MESSAGE_NOTIFICATION_ID)
}
"message" -> {
val ua = UserAgent.find(intent.getStringExtra("uap"))!!
val i = Intent(applicationContext, ChatsActivity::class.java)
val b = Bundle()
b.putString("aor", ua.account.aor)
b.putString("peer", intent.getStringExtra("peer"))
b.putBoolean("focus", true)
i.putExtras(b)
startActivity(i)
}
}
}
override fun onPause() {
super.onPause()
// Log.d("Baresip", "Main paused")
visible = false
}
/*override fun onStop() {
super.onStop()
Log.d("Baresip", "Main stopped")
}*/
override fun onResume() {
super.onResume()
Log.d("Baresip", "Main resumed")
imm.hideSoftInputFromWindow(callUri.windowToken, 0)
visible = true
if (answerCall != "") {
answerCall = ""
answerButton.performClick()
}
if (rejectCall != "") {
rejectCall = ""
rejectButton.performClick()
}
if (makeCall != "") {
callUri.setText(makeCall)
makeCall = ""
callButton.performClick()
}
}
override fun onBackPressed() {
moveTaskToBack(true)
}
@ -976,7 +953,7 @@ class MainActivity : AppCompatActivity() {
}
}
private fun call(ua: UserAgent, uri: String) {
private fun call(ua: UserAgent, uri: String, status: String) {
if (ContextCompat.checkSelfPermission(applicationContext, Manifest.permission.RECORD_AUDIO)
== PackageManager.PERMISSION_DENIED) {
Toast.makeText(applicationContext,
@ -991,8 +968,7 @@ class MainActivity : AppCompatActivity() {
val callp = Api.ua_connect(ua.uap, uri)
if (callp != "") {
Log.d("Baresip", "Adding outgoing call ${ua.uap}/$callp/$uri")
Call.calls().add(Call(callp, ua, uri, "out", "outgoing",
Utils.dtmfWatcher(callp)))
Call.calls().add(Call(callp, ua, uri, "out", status, Utils.dtmfWatcher(callp)))
imm.hideSoftInputFromWindow(callUri.windowToken, 0)
securityButton.visibility = View.INVISIBLE
callButton.visibility = View.INVISIBLE
@ -1010,6 +986,7 @@ class MainActivity : AppCompatActivity() {
}
}
// Currently transfer is implemented by first closing existing call and the making the new one
private fun transfer(ua: UserAgent, call: Call, uri: String) {
val newCallp = Api.ua_call_alloc(ua.uap, call.callp)
if (newCallp != "") {
@ -1017,7 +994,8 @@ class MainActivity : AppCompatActivity() {
val newCall = Call(newCallp, ua, uri, "out", "transferring",
Utils.dtmfWatcher(newCallp))
Call.calls().add(newCall)
Api.call_stop_audio(call.callp)
Api.ua_hangup(ua.uap, call.callp, 0, "")
// Api.call_stop_audio(call.callp)
val err = Api.call_connect(newCallp, uri)
if (err == 0) {
Api.call_start_audio(newCallp)
@ -1103,15 +1081,6 @@ class MainActivity : AppCompatActivity() {
holdButton.visibility = View.INVISIBLE
dtmf.visibility = View.INVISIBLE
infoButton.visibility = View.INVISIBLE
if (answerCall == call.callp) {
answerCall = ""
answerButton.performClick()
}
if (rejectCall == call.callp) {
rejectCall = ""
rejectButton.performClick()
moveTaskToBack(true)
}
}
"connected" -> {
securityButton.setImageResource(call.security)
@ -1141,10 +1110,13 @@ class MainActivity : AppCompatActivity() {
companion object {
var visible = true
var makeCall = ""
var answerCall = ""
var rejectCall = ""
var visible = false
var resumeAction = ""
var resumeUap = ""
var resumeCall: Call? = null
var resumeUri = ""
var resumeTime = ""
const val ACCOUNTS_CODE = 1
const val CONTACTS_CODE = 2

View File

@ -63,7 +63,10 @@ class MessageListAdapter(private val cxt: Context, private val rows: ArrayList<M
}
val textView = messageView.findViewById(R.id.text) as TextView
textView.text = message.message
if (message.new) textView.setTypeface(null, Typeface.BOLD)
if (message.new) {
textView.setTypeface(null, Typeface.BOLD)
message.new = false
}
return messageView
}

View File

@ -6,6 +6,8 @@ import android.support.v7.app.AlertDialog
import android.util.Log
import android.os.PowerManager
import android.app.KeyguardManager
import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
@ -115,10 +117,13 @@ object Utils {
}
fun friendlyUri(uri: String, domain: String): String {
if (uri.contains("@") && !uri.substring(4).contains(":") &&
!uri.contains(";")) {
val user = uriUserPart(uri)
val host = uriHostPart(uri)
var u = uri
if (uri.startsWith("<") && (uri.endsWith(">")))
u = uri.substring(1).substringBeforeLast(">")
if (u.contains("@") && !u.substring(4).contains(":") &&
!u.contains(";")) {
val user = uriUserPart(u)
val host = uriHostPart(u)
if (host == domain) return user else return "$user@$host"
} else {
return uri
@ -281,4 +286,22 @@ object Utils {
}
}
fun dumpIntent(intent: Intent) {
val bundle: Bundle = intent.extras ?: return
val keys = bundle.keySet()
val it = keys.iterator()
Log.d("Baresip", "Dumping intent start")
while (it.hasNext()) {
val key = it.next()
Log.d("Baresip","[" + key + "=" + bundle.get(key)+"]");
}
Log.d("Baresip", "Dumping intent finish")
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 738 B

After

Width:  |  Height:  |  Size: 469 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.3.0'
ext.kotlin_version = '1.3.21'
repositories {
google()
jcenter()
@ -9,7 +9,6 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.3.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}