diff --git a/app/build.gradle b/app/build.gradle index 44b155d0..ea456f60 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 890c62dd..c1da457c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,7 @@ + @@ -95,6 +96,7 @@ @@ -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" > diff --git a/app/src/main/cpp/baresip.c b/app/src/main/cpp/baresip.c index 669fd592..a03aee1d 100644 --- a/app/src/main/cpp/baresip.c +++ b/app/src/main/cpp/baresip.c @@ -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 diff --git a/app/src/main/kotlin/com/tutpro/baresip/AccountListAdapter.kt b/app/src/main/kotlin/com/tutpro/baresip/AccountListAdapter.kt index 0187e265..44916fa9 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/AccountListAdapter.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/AccountListAdapter.kt @@ -41,8 +41,9 @@ class AccountListAdapter(private val cxt: Context, private val rows: ArrayList - 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() diff --git a/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt b/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt index 5bac460e..85cdd634 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/BaresipService.kt @@ -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 diff --git a/app/src/main/kotlin/com/tutpro/baresip/Call.kt b/app/src/main/kotlin/com/tutpro/baresip/Call.kt index 54a7e26f..27ea79be 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/Call.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/Call.kt @@ -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 } - } } diff --git a/app/src/main/kotlin/com/tutpro/baresip/ChatActivity.kt b/app/src/main/kotlin/com/tutpro/baresip/ChatActivity.kt index 60e6d2d2..458d5baa 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/ChatActivity.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/ChatActivity.kt @@ -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 { val res = ArrayList() for (m in Message.messages()) diff --git a/app/src/main/kotlin/com/tutpro/baresip/ChatListAdapter.kt b/app/src/main/kotlin/com/tutpro/baresip/ChatListAdapter.kt index 0fcbb818..75d043c8 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/ChatListAdapter.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/ChatListAdapter.kt @@ -65,10 +65,8 @@ class ChatListAdapter(private val cxt: Context, private var rows: ArrayList { + 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) { + 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).add(call.dtmfWatcher!!) + dtmf.addTextChangedListener(call.dtmfWatcher) infoButton.visibility = View.VISIBLE } - (dtmf.tag as ArrayList).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 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 diff --git a/app/src/main/kotlin/com/tutpro/baresip/MessageListAdapter.kt b/app/src/main/kotlin/com/tutpro/baresip/MessageListAdapter.kt index e7cde52a..74d94cb2 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/MessageListAdapter.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/MessageListAdapter.kt @@ -63,7 +63,10 @@ class MessageListAdapter(private val cxt: Context, private val rows: ArrayList"))) + 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") + + } + } diff --git a/app/src/main/res/drawable/baresip.png b/app/src/main/res/drawable/baresip.png index 2d3723e8..984ca1a2 100644 Binary files a/app/src/main/res/drawable/baresip.png and b/app/src/main/res/drawable/baresip.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png index 4a292e73..99533c81 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png index c917693c..c30a1e02 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 3025631a..dc86f2e2 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 7ad22e20..87bb9724 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index cd8a3032..341cd417 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/build.gradle b/build.gradle index 63e7f9ed..fbbb51ab 100644 --- a/build.gradle +++ b/build.gradle @@ -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 }