since this is a fun learning project, moved from java to kotlin for
more fun (or desperation)
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.view.MenuItem
|
||||
import android.widget.TextView
|
||||
|
||||
class AboutActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_about)
|
||||
val aboutView = findViewById(R.id.aboutText) as TextView
|
||||
aboutView.isEnabled = false
|
||||
aboutView.text = getString(R.string.aboutText)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
val i = Intent()
|
||||
setResult(Activity.RESULT_CANCELED, i)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
class Account(val ua: String, val aoR: String, var status: String) {
|
||||
private var statusImage: Int = 0
|
||||
|
||||
init {
|
||||
this.statusImage = 0
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
class AccountSpinnerAdapter(private val cxt: Context, private val aors: ArrayList<String>,
|
||||
private val images: ArrayList<Int>) :
|
||||
ArrayAdapter<Int>(cxt, android.R.layout.simple_spinner_item, images) {
|
||||
|
||||
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||
return getImageForPosition(position, parent)
|
||||
}
|
||||
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||
return getImageForPosition(position, parent)
|
||||
}
|
||||
|
||||
private fun getImageForPosition(position: Int, parent: ViewGroup): View {
|
||||
val inflater = cxt.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||
val row = inflater.inflate(R.layout.account_spinner, parent, false)
|
||||
val textView = row.findViewById(R.id.spinnerText) as TextView
|
||||
textView.text = aors[position]
|
||||
textView.textSize = 17f
|
||||
val imageView = row.findViewById(R.id.spinnerImage) as ImageView
|
||||
imageView.setImageResource(images[position])
|
||||
return row
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
class Call(val ua: String, val call: String, val peerURI: String, var status: String) {
|
||||
var hold: Boolean = false
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
class Contact(val name: String, val uri: String)
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.io.OutputStreamWriter
|
||||
|
||||
class EditAccountsActivity : AppCompatActivity() {
|
||||
|
||||
private var editText: EditText? = null
|
||||
private var path: String? = null
|
||||
private var file: File? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_edit_accounts)
|
||||
|
||||
editText = findViewById(R.id.editAccounts) as EditText
|
||||
path = applicationContext.filesDir.absolutePath + "/accounts"
|
||||
file = File(path!!)
|
||||
var content: String
|
||||
|
||||
if (!file!!.exists()) {
|
||||
Log.e("Baresip", "Failed to find accounts file")
|
||||
content = "No accounts"
|
||||
} else {
|
||||
Log.e("Baresip", "Found accounts file")
|
||||
val length = file!!.length().toInt()
|
||||
val bytes = ByteArray(length)
|
||||
try {
|
||||
val `in` = FileInputStream(file!!)
|
||||
try {
|
||||
`in`.read(bytes)
|
||||
} finally {
|
||||
`in`.close()
|
||||
}
|
||||
content = String(bytes)
|
||||
} catch (e: java.io.IOException) {
|
||||
Log.e("Baresip", "Failed to read accounts file: " + e.toString())
|
||||
content = "Failed to read account file"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Log.d("Baresip", "Content length is: " + content.length)
|
||||
|
||||
editText!!.setTextSize(TypedValue.COMPLEX_UNIT_PX,
|
||||
resources.getDimension(R.dimen.textsize))
|
||||
editText!!.setText(content, TextView.BufferType.EDITABLE)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
super.onCreateOptionsMenu(menu)
|
||||
val inflater = menuInflater
|
||||
inflater.inflate(R.menu.edit_menu, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
val i = Intent()
|
||||
when (item.itemId) {
|
||||
R.id.save -> {
|
||||
try {
|
||||
val fOut = FileOutputStream(file!!.absoluteFile, false)
|
||||
val fWriter = OutputStreamWriter(fOut)
|
||||
val res = editText!!.text.toString()
|
||||
try {
|
||||
fWriter.write(res)
|
||||
fWriter.close()
|
||||
fOut.close()
|
||||
} catch (e: java.io.IOException) {
|
||||
Log.e("Baresip", "Failed to write accounts file: " + e.toString())
|
||||
}
|
||||
|
||||
} catch (e: java.io.FileNotFoundException) {
|
||||
Log.e("Baresip", "Failed to find accounts file: " + e.toString())
|
||||
}
|
||||
|
||||
Log.d("Baresip", "Updated accounts file")
|
||||
setResult(RESULT_OK, i)
|
||||
finish()
|
||||
return true
|
||||
}
|
||||
R.id.cancel, android.R.id.home -> {
|
||||
setResult(RESULT_CANCELED, i)
|
||||
finish()
|
||||
return true
|
||||
}
|
||||
else -> return super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.io.OutputStreamWriter
|
||||
|
||||
class EditConfigActivity : AppCompatActivity() {
|
||||
|
||||
private var editText: EditText? = null
|
||||
private var path: String? = null
|
||||
private var file: File? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_edit_config)
|
||||
|
||||
editText = findViewById(R.id.editConfig) as EditText
|
||||
path = applicationContext.filesDir.absolutePath + "/config"
|
||||
// path = "/sdcard/baresip/config";
|
||||
file = File(path!!)
|
||||
var content: String
|
||||
|
||||
if (!file!!.exists()) {
|
||||
Log.e("Baresip", "Failed to find config file")
|
||||
content = "No config"
|
||||
} else {
|
||||
Log.e("Baresip", "Found config file")
|
||||
val length = file!!.length().toInt()
|
||||
val bytes = ByteArray(length)
|
||||
try {
|
||||
val `in` = FileInputStream(file!!)
|
||||
try {
|
||||
`in`.read(bytes)
|
||||
} finally {
|
||||
`in`.close()
|
||||
}
|
||||
content = String(bytes)
|
||||
} catch (e: java.io.IOException) {
|
||||
Log.e("Baresip", "Failed to read config file: " + e.toString())
|
||||
content = "Failed to read account file"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Log.d("Baresip", "Content length is: " + content.length)
|
||||
|
||||
editText!!.setTextSize(TypedValue.COMPLEX_UNIT_PX,
|
||||
resources.getDimension(R.dimen.textsize))
|
||||
editText!!.setText(content, TextView.BufferType.EDITABLE)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
super.onCreateOptionsMenu(menu)
|
||||
val inflater = menuInflater
|
||||
inflater.inflate(R.menu.edit_menu, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
val i = Intent(this, MainActivity::class.java)
|
||||
when (item.itemId) {
|
||||
R.id.save -> {
|
||||
try {
|
||||
val fOut = FileOutputStream(file!!.absoluteFile, false)
|
||||
val fWriter = OutputStreamWriter(fOut)
|
||||
val res = editText!!.text.toString()
|
||||
try {
|
||||
fWriter.write(res)
|
||||
fWriter.close()
|
||||
fOut.close()
|
||||
} catch (e: java.io.IOException) {
|
||||
Log.e("Baresip", "Failed to write config file: " + e.toString())
|
||||
}
|
||||
|
||||
} catch (e: java.io.FileNotFoundException) {
|
||||
Log.e("Baresip", "Failed to find config file: " + e.toString())
|
||||
}
|
||||
|
||||
Log.d("Baresip", "Updated config file")
|
||||
setResult(RESULT_OK, i)
|
||||
finish()
|
||||
return true
|
||||
}
|
||||
R.id.cancel, android.R.id.home -> {
|
||||
setResult(RESULT_CANCELED, i)
|
||||
finish()
|
||||
return true
|
||||
}
|
||||
else -> return super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
|
||||
import java.io.File
|
||||
import java.util.ArrayList
|
||||
|
||||
class EditContactsActivity : AppCompatActivity() {
|
||||
|
||||
private var editText: EditText? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_edit_contacts)
|
||||
editText = findViewById(R.id.editText) as EditText
|
||||
val path = applicationContext.filesDir.absolutePath + "/contacts"
|
||||
val file = File(path)
|
||||
val content = Utils.getFileContents(file)
|
||||
Log.d("Baresip", "Contacts length is: " + content.length)
|
||||
editText!!.setTextSize(TypedValue.COMPLEX_UNIT_PX,
|
||||
resources.getDimension(R.dimen.textsize))
|
||||
editText!!.setText(content, TextView.BufferType.EDITABLE)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
super.onCreateOptionsMenu(menu)
|
||||
val inflater = menuInflater
|
||||
inflater.inflate(R.menu.edit_menu, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
val i = Intent(this, MainActivity::class.java)
|
||||
when (item.itemId) {
|
||||
R.id.save -> {
|
||||
val path = applicationContext.filesDir.absolutePath + "/contacts"
|
||||
val file = File(path)
|
||||
Utils.putFileContents(file, editText!!.text.toString())
|
||||
Log.d("Baresip", "Updated contacts file")
|
||||
MainActivity.contacts_remove()
|
||||
updateContactsAndNames(path)
|
||||
// MainActivity.CalleeAdapter.notifyDataSetChanged(); does not work
|
||||
setResult(RESULT_OK, i)
|
||||
finish()
|
||||
return true
|
||||
}
|
||||
R.id.cancel, android.R.id.home -> {
|
||||
i.putExtra("action", "cancel")
|
||||
setResult(RESULT_OK, i)
|
||||
finish()
|
||||
return true
|
||||
}
|
||||
else -> return super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
var Contacts: ArrayList<Contact> = java.util.ArrayList()
|
||||
var Names: ArrayList<String> = java.util.ArrayList()
|
||||
|
||||
fun updateContactsAndNames(path: String) {
|
||||
val file = File(path)
|
||||
val lines = Utils.getFileContents(file).split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
var name: String
|
||||
var uri: String
|
||||
Contacts.clear()
|
||||
Names.clear()
|
||||
for (line in lines) {
|
||||
line.trim { it <= ' ' }
|
||||
if (line.startsWith("#") || line.length == 0) continue
|
||||
val parts = line.split("\"".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
if (parts.size != 3) {
|
||||
Log.e("Baresip", "Invalid contacts line: $line")
|
||||
continue
|
||||
}
|
||||
name = parts[1]
|
||||
if (name.length < 2) {
|
||||
Log.e("Baresip", "Too short contact display name: $name")
|
||||
continue
|
||||
}
|
||||
uri = parts[2].trim { it <= ' ' }
|
||||
if (!uri.startsWith("<") || !uri.contains(">")) {
|
||||
Log.e("Baresip", "Invalid contact uri: $uri")
|
||||
continue
|
||||
}
|
||||
MainActivity.contact_add("\"$name\" $uri")
|
||||
if (uri.indexOf(";access") > 0) continue
|
||||
uri = uri.substring(1, uri.indexOf(">"))
|
||||
Log.d("Baresip", "Adding contact name/uri: $name/$uri")
|
||||
Contacts.add(Contact(name, uri))
|
||||
Names.add(name)
|
||||
}
|
||||
}
|
||||
|
||||
fun findContactURI(name: String): String {
|
||||
for (c in Contacts) {
|
||||
if (c.name == name) return c.uri
|
||||
}
|
||||
return name
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import java.io.Serializable
|
||||
import java.util.GregorianCalendar
|
||||
|
||||
class History(val ua: String, val call: String, val aor: String, val peerURI: String,
|
||||
val direction: String, val connected: Boolean) : Serializable {
|
||||
|
||||
val time: GregorianCalendar = GregorianCalendar()
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.util.Log
|
||||
import android.view.MenuItem
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ListView
|
||||
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.ArrayList
|
||||
import java.util.Calendar
|
||||
import java.util.GregorianCalendar
|
||||
|
||||
class HistoryActivity : AppCompatActivity() {
|
||||
|
||||
internal var uaHistory = ArrayList<HistoryRow>()
|
||||
internal var posAtHistory = ArrayList<Int>()
|
||||
internal var aor: String = ""
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_history)
|
||||
|
||||
val listview = findViewById(R.id.history) as ListView
|
||||
|
||||
val b = intent.extras
|
||||
aor = b.getString("aor")
|
||||
generate_ua_history(aor)
|
||||
|
||||
val adapter = HistoryListAdapter(this, uaHistory)
|
||||
listview.adapter = adapter
|
||||
listview.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ ->
|
||||
val row = uaHistory[position]
|
||||
val i = Intent()
|
||||
i.putExtra("peer_uri", row.peerURI)
|
||||
setResult(Activity.RESULT_OK, i)
|
||||
finish()
|
||||
}
|
||||
|
||||
listview.onItemLongClickListener = AdapterView.OnItemLongClickListener { _, _, pos, _ ->
|
||||
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
|
||||
when (which) {
|
||||
DialogInterface.BUTTON_POSITIVE -> {
|
||||
History.removeAt(posAtHistory[pos])
|
||||
generate_ua_history(aor)
|
||||
if (uaHistory.size == 0) {
|
||||
val i = Intent()
|
||||
setResult(Activity.RESULT_CANCELED, i)
|
||||
finish()
|
||||
}
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
DialogInterface.BUTTON_NEGATIVE -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
val builder = AlertDialog.Builder(this@HistoryActivity,
|
||||
R.style.Theme_AppCompat)
|
||||
builder.setMessage("Do you want to delete " +
|
||||
History[pos].peerURI + "?")
|
||||
.setPositiveButton("Yes", dialogClickListener)
|
||||
.setNegativeButton("No", dialogClickListener).show()
|
||||
true
|
||||
}
|
||||
|
||||
listview.isLongClickable = true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
Log.d("Baresip", "Back array was pressed")
|
||||
val i = Intent()
|
||||
setResult(Activity.RESULT_CANCELED, i)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun generate_ua_history(aor: String) {
|
||||
uaHistory.clear()
|
||||
posAtHistory.clear()
|
||||
for (i in History.indices.reversed()) {
|
||||
val h = History[i]
|
||||
if (h.aor == aor) {
|
||||
val time: String
|
||||
if (isToday(h.time)) {
|
||||
val fmt = SimpleDateFormat("HH:mm")
|
||||
time = fmt.format(h.time.time)
|
||||
} else {
|
||||
val fmt = SimpleDateFormat("MMM dd")
|
||||
time = fmt.format(h.time.time)
|
||||
}
|
||||
if (h.direction == "in") {
|
||||
if (h.connected) {
|
||||
uaHistory.add(HistoryRow(h.peerURI, R.drawable.arrow_down_green, time))
|
||||
} else {
|
||||
uaHistory.add(HistoryRow(h.peerURI, R.drawable.arrow_down_red, time))
|
||||
}
|
||||
} else {
|
||||
if (h.connected) {
|
||||
uaHistory.add(HistoryRow(h.peerURI, R.drawable.arrow_up_green, time))
|
||||
} else {
|
||||
uaHistory.add(HistoryRow(h.peerURI, R.drawable.arrow_up_red, time))
|
||||
}
|
||||
}
|
||||
posAtHistory.add(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isToday(time: GregorianCalendar): Boolean {
|
||||
val now = GregorianCalendar()
|
||||
return now.get(Calendar.YEAR) == time.get(Calendar.YEAR) &&
|
||||
now.get(Calendar.MONTH) == time.get(Calendar.MONTH) &&
|
||||
now.get(Calendar.DAY_OF_MONTH) == time.get(Calendar.DAY_OF_MONTH)
|
||||
}
|
||||
|
||||
companion object {
|
||||
var History: ArrayList<History> = ArrayList<History>()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
class HistoryListAdapter(private val cxt: Context, private val rows: ArrayList<HistoryRow>) :
|
||||
ArrayAdapter<HistoryRow>(cxt, R.layout.history_row, rows) {
|
||||
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||
val row = rows[position]
|
||||
val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||
val rowView = inflater.inflate(R.layout.history_row, parent, false)
|
||||
val directionView = rowView.findViewById(R.id.direction) as ImageView
|
||||
directionView.setImageResource(row.direction)
|
||||
val peerURIView = rowView.findViewById(R.id.peer_uri) as TextView
|
||||
peerURIView.text = row.peerURI
|
||||
val timeView = rowView.findViewById(R.id.time) as TextView
|
||||
timeView.text = row.time
|
||||
return rowView
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
class HistoryRow(val peerURI: String, val direction: Int, val time: String)
|
||||
@@ -0,0 +1,668 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Color
|
||||
import android.support.v4.app.ActivityCompat
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.os.Bundle
|
||||
import android.widget.*
|
||||
import android.widget.RelativeLayout.LayoutParams
|
||||
import android.widget.AutoCompleteTextView
|
||||
import android.view.*
|
||||
import android.util.Log
|
||||
|
||||
import java.util.*
|
||||
import java.io.*
|
||||
import android.widget.RelativeLayout
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
|
||||
mainActivityContext = applicationContext
|
||||
layout = findViewById(R.id.mainActivityLayout) as RelativeLayout
|
||||
callee = findViewById(R.id.callee) as AutoCompleteTextView
|
||||
callButton = findViewById(R.id.callButton) as Button
|
||||
holdButton = findViewById(R.id.holdButton) as Button
|
||||
|
||||
AoRSpinner = findViewById(R.id.AoRList) as Spinner
|
||||
|
||||
Log.i("Baresip", "Setting AccountAdapter")
|
||||
AccountAdapter = AccountSpinnerAdapter(applicationContext, AoRs, Images)
|
||||
AoRSpinner.adapter = AccountAdapter
|
||||
AoRSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
|
||||
val aor = AoRs[position]
|
||||
val callee = findViewById(R.id.callee) as AutoCompleteTextView
|
||||
val callButton = findViewById(R.id.callButton) as Button
|
||||
val holdButton = findViewById(R.id.holdButton) as Button
|
||||
Log.i("Baresip", "Setting $aor current")
|
||||
val out = uaCalls(Out, aor_ua(aor))
|
||||
if (out.size == 0) {
|
||||
callee.text.clear()
|
||||
callee.hint = "Callee"
|
||||
callButton.text = "Call"
|
||||
if (aorHasHistory(aor)) {
|
||||
holdButton.text = "History"
|
||||
holdButton.visibility = View.VISIBLE
|
||||
} else {
|
||||
holdButton.visibility = View.INVISIBLE
|
||||
}
|
||||
} else {
|
||||
callee.setText(out[0].peerURI)
|
||||
callButton.text = out[0].status
|
||||
if (out[0].status == "Hangup") {
|
||||
if (out[0].hold) {
|
||||
holdButton.text = "Unhold"
|
||||
} else {
|
||||
holdButton.text = "Hold"
|
||||
}
|
||||
holdButton.visibility = View.VISIBLE
|
||||
} else {
|
||||
holdButton.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
val `in` = uaCalls(In, aor_ua(aor))
|
||||
val view_count = layout.childCount
|
||||
Log.d("Baresip", "View count is $view_count")
|
||||
if (view_count > 5) {
|
||||
layout.removeViews(5, view_count - 5)
|
||||
}
|
||||
for (c in `in`) {
|
||||
for (call_index in In.indices) {
|
||||
addCallViews(c, (call_index + 1) * 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNothingSelected(parent: AdapterView<*>) {
|
||||
Log.i("Baresip", "Nothing selected")
|
||||
}
|
||||
}
|
||||
|
||||
val assets = arrayOf("accounts", "contacts", "config", "busy.wav", "callwaiting.wav", "error.wav", "message.wav", "notfound.wav", "ring.wav", "ringback.wav")
|
||||
val path = applicationContext.filesDir.path
|
||||
Log.d("Baresip", "path is: $path")
|
||||
var file = File(path)
|
||||
if (!file.exists()) {
|
||||
Log.d("Baresip", "Creating baresip directory")
|
||||
try {
|
||||
File(path).mkdirs()
|
||||
} catch (e: Error) {
|
||||
Log.e("Baresip", "Failed to create directory: " + e.toString())
|
||||
}
|
||||
|
||||
}
|
||||
for (a in assets) {
|
||||
file = File("$path/$a")
|
||||
if (!file.exists()) {
|
||||
Log.d("Baresip", "Copying asset $a")
|
||||
copyAssetToFile(a, "$path/$a")
|
||||
} else {
|
||||
Log.d("Baresip", "Asset $a already copied")
|
||||
}
|
||||
}
|
||||
|
||||
file = File(path, "history")
|
||||
try {
|
||||
val fis = FileInputStream(file)
|
||||
val ois = ObjectInputStream(fis)
|
||||
@SuppressWarnings("unchecked")
|
||||
HistoryActivity.History = ois.readObject() as ArrayList<History>
|
||||
Log.d("Baresip", "Restored History of " + HistoryActivity.History.size + " entries")
|
||||
ois.close()
|
||||
fis.close()
|
||||
} catch (e: Exception) {
|
||||
Log.w("Baresip", "InputStream exception: - " + e.toString())
|
||||
}
|
||||
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
|
||||
Log.d("Baresip", "Baresip does not have RECORD_AUDIO permission")
|
||||
ActivityCompat.requestPermissions(this,
|
||||
arrayOf(Manifest.permission.RECORD_AUDIO), RECORD_AUDIO_PERMISSION)
|
||||
}
|
||||
|
||||
if (!running) {
|
||||
Log.i("Baresip", "Starting Baresip with path $path")
|
||||
Thread(Runnable { baresipStart(path) }).start()
|
||||
running = true
|
||||
}
|
||||
|
||||
EditContactsActivity.updateContactsAndNames(applicationContext.filesDir.absolutePath + "/contacts")
|
||||
CalleeAdapter = ArrayAdapter(this, android.R.layout.select_dialog_item, EditContactsActivity.Names)
|
||||
callee.threshold = 2
|
||||
callee.setAdapter<ArrayAdapter<String>>(CalleeAdapter)
|
||||
|
||||
callButton.text = "Call"
|
||||
callButton.setOnClickListener {
|
||||
Log.d("Baresip", "AoR at position is " + AoRs[AoRSpinner.selectedItemPosition])
|
||||
val aor = AoRs[AoRSpinner.selectedItemPosition]
|
||||
if (callButton.text.toString() == "Call") {
|
||||
call(aor, (findViewById(R.id.callee) as EditText).text.toString())
|
||||
} else {
|
||||
Log.i("Baresip", "Canceling UA " + aor_ua(aor) + " call " +
|
||||
Out[0].call + " to " +
|
||||
(findViewById(R.id.callee) as EditText).text)
|
||||
ua_hangup(aor_ua(aor), Out[0].call, 486, "Rejected")
|
||||
}
|
||||
}
|
||||
|
||||
val holdButton = findViewById(R.id.holdButton) as Button
|
||||
holdButton.setOnClickListener {
|
||||
when (holdButton.text.toString()) {
|
||||
"Hold" -> {
|
||||
Log.i("Baresip", "Holding up " + (findViewById(R.id.callee) as EditText).text)
|
||||
call_hold(Out[0].call)
|
||||
Out[0].hold = true
|
||||
holdButton.text = "Unhold"
|
||||
}
|
||||
"Unhold" -> {
|
||||
Log.i("Baresip", "Unholding " + (findViewById(R.id.callee) as EditText).text)
|
||||
call_unhold(Out[0].call)
|
||||
Out[0].hold = false
|
||||
holdButton.text = "Hold"
|
||||
}
|
||||
"History" -> {
|
||||
val i = Intent(this@MainActivity, HistoryActivity::class.java)
|
||||
val b = Bundle()
|
||||
b.putString("aor", AoRs[AoRSpinner.selectedItemPosition])
|
||||
i.putExtras(b)
|
||||
startActivityForResult(i, HISTORY_CODE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
Log.d("Baresip", "Screen orientation change to landscape")
|
||||
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
Log.d("Baresip", "Screen orientation change to portrait")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int,
|
||||
permissions: Array<String>, grantResults: IntArray) {
|
||||
when (requestCode) {
|
||||
RECORD_AUDIO_PERMISSION -> {
|
||||
if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
Log.d("Baresip", "RECORD_AUDIO permission granted")
|
||||
} else {
|
||||
Log.d("Baresip", "RECORD_AUDIO permission NOT granted")
|
||||
}
|
||||
return
|
||||
}
|
||||
else -> Log.e("Baresip", "Unknown permissions request code: $requestCode")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
super.onCreateOptionsMenu(menu)
|
||||
val inflater = menuInflater
|
||||
inflater.inflate(R.menu.main_menu, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
val i: Intent
|
||||
when (item.itemId) {
|
||||
R.id.accounts -> {
|
||||
i = Intent(this, EditAccountsActivity::class.java)
|
||||
startActivityForResult(i, EDIT_ACCOUNTS_CODE)
|
||||
return true
|
||||
}
|
||||
R.id.contacts -> {
|
||||
i = Intent(this, EditContactsActivity::class.java)
|
||||
startActivityForResult(i, EDIT_CONTACTS_CODE)
|
||||
return true
|
||||
}
|
||||
R.id.config -> {
|
||||
i = Intent(this, EditConfigActivity::class.java)
|
||||
startActivityForResult(i, EDIT_CONFIG_CODE)
|
||||
return true
|
||||
}
|
||||
R.id.about -> {
|
||||
i = Intent(this, AboutActivity::class.java)
|
||||
startActivityForResult(i, ABOUT_CODE)
|
||||
return true
|
||||
}
|
||||
R.id.quit -> {
|
||||
if (running) {
|
||||
Log.d("Baresip", "Stopping")
|
||||
val path = applicationContext.filesDir.path
|
||||
Log.d("Baresip", "Saving history to $path")
|
||||
val file = File(path, "history")
|
||||
try {
|
||||
val fos = FileOutputStream(file)
|
||||
val oos = ObjectOutputStream(fos)
|
||||
oos.writeObject(HistoryActivity.History)
|
||||
oos.close()
|
||||
fos.close()
|
||||
} catch (e: IOException) {
|
||||
Log.w("Baresip", "OutputStream exception: " + e.toString())
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
baresipStop()
|
||||
running = false
|
||||
}
|
||||
finish()
|
||||
System.exit(0)
|
||||
return true
|
||||
}
|
||||
else -> return super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == EDIT_ACCOUNTS_CODE) {
|
||||
if (resultCode == RESULT_OK) {
|
||||
val alertDialog = AlertDialog.Builder(this).create()
|
||||
alertDialog.setTitle("Alert")
|
||||
alertDialog.setMessage("You need to restart baresip in order to activate saved accounts!")
|
||||
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK"
|
||||
) { dialog, _ -> dialog.dismiss() }
|
||||
alertDialog.show()
|
||||
}
|
||||
if (resultCode == RESULT_CANCELED) {
|
||||
Log.d("Baresip", "Edit accounts canceled")
|
||||
}
|
||||
}
|
||||
if (requestCode == EDIT_CONFIG_CODE) {
|
||||
if (resultCode == RESULT_OK) {
|
||||
Utils.alertView(this,
|
||||
"You need to restart baresip in order to activate saved config!")
|
||||
reload_config()
|
||||
}
|
||||
if (resultCode == RESULT_CANCELED) {
|
||||
Log.d("Baresip", "Edit config canceled")
|
||||
}
|
||||
}
|
||||
if (requestCode == HISTORY_CODE) {
|
||||
if (resultCode == RESULT_OK) {
|
||||
if (data != null) {
|
||||
(findViewById(R.id.callee) as EditText).setText(data.getStringExtra("peer_uri"))
|
||||
}
|
||||
}
|
||||
if (resultCode == RESULT_CANCELED) {
|
||||
Log.d("Baresip", "History canceled")
|
||||
if (!aorHasHistory(AoRs[AoRSpinner.selectedItemPosition])) {
|
||||
(findViewById(R.id.holdButton) as Button).visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
if (requestCode == EDIT_CONTACTS_CODE || requestCode == ABOUT_CODE) {
|
||||
Log.d("Baresip", "Back arrow or Cancel pressed at request: $requestCode")
|
||||
}
|
||||
}
|
||||
|
||||
fun addAccount(ua: String) {
|
||||
val aor = ua_aor(ua)
|
||||
Log.d("Baresip", "Adding account $ua with AoR $aor")
|
||||
Accounts.add(Account(ua, aor, ""))
|
||||
AoRs.add(aor)
|
||||
Images.add(R.drawable.yellow)
|
||||
runOnUiThread { AccountAdapter.notifyDataSetChanged() }
|
||||
}
|
||||
|
||||
private fun call(aor: String, callee: String) {
|
||||
if (callee.length == 0) return
|
||||
var uri = EditContactsActivity.findContactURI(callee)
|
||||
if (!uri.startsWith("sip:")) uri = "sip:$uri"
|
||||
if (!uri.contains("@")) {
|
||||
val host = aor.substring(aor.indexOf("@") + 1)
|
||||
uri = "$uri@$host"
|
||||
}
|
||||
(findViewById(R.id.callee) as EditText).setText(uri)
|
||||
val ua = aor_ua(aor)
|
||||
Log.i("Baresip", "Calling $ua / $uri")
|
||||
val call = ua_connect(ua, uri)
|
||||
if (call != "") {
|
||||
Log.i("Baresip", "Adding outgoing call $ua / $call / $uri")
|
||||
Out.add(Call(ua, call, uri, "Cancel"))
|
||||
(findViewById(R.id.callButton) as Button).text = "Cancel"
|
||||
(findViewById(R.id.holdButton) as Button).visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyAssetToFile(asset: String, path: String) {
|
||||
try {
|
||||
val assetManager = assets
|
||||
val `is` = assetManager.open(asset)
|
||||
val os = FileOutputStream(path)
|
||||
val buffer = ByteArray(512)
|
||||
var byteRead: Int = `is`.read(buffer)
|
||||
while (byteRead != -1) {
|
||||
os.write(buffer, 0, byteRead)
|
||||
byteRead = `is`.read(buffer)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.e("Baresip", "Failed to read asset " + asset + ": " +
|
||||
e.toString())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun addCallViews(call: Call, id: Int) {
|
||||
Log.d("Baresip", "Creating new Incoming textview at $id")
|
||||
|
||||
val caller_heading = TextView(mainActivityContext)
|
||||
|
||||
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 + 3)
|
||||
caller_heading.layoutParams = heading_params
|
||||
layout.addView(caller_heading)
|
||||
|
||||
val caller_uri = TextView(mainActivityContext)
|
||||
caller_uri.text = In[In.size - 1].peerURI
|
||||
caller_uri.setTextColor(Color.GREEN)
|
||||
caller_uri.textSize = 20f
|
||||
caller_uri.setPadding(10, 10, 0, 10)
|
||||
Log.d("Baresip", "Creating new caller textview at " + (id + 1))
|
||||
caller_uri.id = id + 1
|
||||
val caller_uri_params = LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.WRAP_CONTENT)
|
||||
caller_uri_params.addRule(RelativeLayout.BELOW, id)
|
||||
caller_uri.layoutParams = caller_uri_params
|
||||
layout.addView(caller_uri)
|
||||
|
||||
val answer_button = Button(mainActivityContext)
|
||||
answer_button.text = call.status
|
||||
answer_button.setBackgroundResource(android.R.drawable.btn_default)
|
||||
answer_button.setTextColor(Color.BLACK)
|
||||
Log.d("Baresip", "Creating new answer button at " + (id + 2))
|
||||
answer_button.id = id + 2
|
||||
answer_button.setOnClickListener { v ->
|
||||
val call_ua = call.ua
|
||||
val call_call = call.call
|
||||
when ((v as Button).text.toString()) {
|
||||
"Answer" -> {
|
||||
Log.i("Baresip", "UA " + call_ua + " accepting incoming call " +
|
||||
call_call)
|
||||
ua_answer(call_ua, call_call)
|
||||
val final_in_index = callIndex(In, call_ua, call_call)
|
||||
if (final_in_index >= 0) {
|
||||
Log.d("Baresip", "Updating Hangup and Hold")
|
||||
In[final_in_index].status = "Hangup"
|
||||
In[final_in_index].hold = false
|
||||
runOnUiThread {
|
||||
val answer_id = (final_in_index + 1) * 10 + 2
|
||||
val answer_but = layout.findViewById(answer_id) as Button
|
||||
answer_but.text = "Hangup"
|
||||
val reject_button = layout.findViewById(answer_id + 1) as Button
|
||||
reject_button.text = "Hold"
|
||||
}
|
||||
}
|
||||
}
|
||||
"Hangup" -> {
|
||||
Log.i("Baresip", "UA " + call_ua + " hanging up call " +
|
||||
call_call)
|
||||
ua_hangup(call_ua, call_call, 200, "OK")
|
||||
}
|
||||
else -> Log.e("Baresip", "Invalid answer button text: " + v.text.toString())
|
||||
}
|
||||
}
|
||||
val answer_button_params = LayoutParams(200,
|
||||
LayoutParams.WRAP_CONTENT)
|
||||
answer_button_params.addRule(RelativeLayout.BELOW, id + 1)
|
||||
answer_button_params.setMargins(3, 10, 0, 0)
|
||||
answer_button.layoutParams = answer_button_params
|
||||
layout.addView(answer_button)
|
||||
|
||||
val reject_button = Button(mainActivityContext)
|
||||
if (call.status == "Answer") {
|
||||
reject_button.text = "Reject"
|
||||
} else {
|
||||
if (call.hold) {
|
||||
reject_button.text = "Unhold"
|
||||
} else {
|
||||
reject_button.text = "Hold"
|
||||
}
|
||||
}
|
||||
reject_button.setBackgroundResource(android.R.drawable.btn_default)
|
||||
reject_button.setTextColor(Color.BLACK)
|
||||
Log.d("Baresip", "Creating new reject button at " + (id + 3))
|
||||
reject_button.id = id + 3
|
||||
reject_button.setOnClickListener { v ->
|
||||
when ((v as Button).text.toString()) {
|
||||
"Reject" -> {
|
||||
Log.i("Baresip", "UA " + call.ua +
|
||||
" rejecting incoming call " + call.call)
|
||||
ua_hangup(call.ua, call.call, 486, "Rejected")
|
||||
}
|
||||
"Hold" -> {
|
||||
call_hold(call.call)
|
||||
v.text = "Unhold"
|
||||
call.hold = true
|
||||
}
|
||||
"Unhold" -> {
|
||||
call_unhold(call.call)
|
||||
v.text = "Hold"
|
||||
call.hold = false
|
||||
}
|
||||
}
|
||||
}
|
||||
val reject_button_params = LayoutParams(200,
|
||||
LayoutParams.WRAP_CONTENT)
|
||||
reject_button_params.addRule(RelativeLayout.BELOW, id + 1)
|
||||
reject_button_params.setMargins(225, 10, 0, 0)
|
||||
reject_button.layoutParams = reject_button_params
|
||||
layout.addView(reject_button)
|
||||
}
|
||||
|
||||
private fun callIndex(calls: ArrayList<Call>, ua: String, call: String): Int {
|
||||
for (i in calls.indices) {
|
||||
if (calls[i].ua.equals(ua) && calls[i].call == call)
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
private fun uaCalls(calls: ArrayList<Call>, ua: String): ArrayList<Call> {
|
||||
val result = ArrayList<Call>()
|
||||
for (i in calls.indices) {
|
||||
if (calls[i].ua == ua) result.add(calls[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun aorHasHistory(aor: String): Boolean {
|
||||
for (h in HistoryActivity.History) {
|
||||
if (h.aor == aor) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun callHasHistory(ua: String, call: String): Boolean {
|
||||
for (h in HistoryActivity.History) {
|
||||
if (h.ua == ua && h.call == call) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun updateStatus(event: String, ua: String, call: String) {
|
||||
val aor = ua_aor(ua)
|
||||
var call_index: Int
|
||||
|
||||
Log.d("Baresip", "Handling event " + event + " for " + ua + "/" + call + "/" +
|
||||
aor)
|
||||
|
||||
for (account_index in Accounts.indices) {
|
||||
if (Accounts[account_index].aoR == aor) {
|
||||
Log.d("Baresip", "Found AoR at index $account_index")
|
||||
when (event) {
|
||||
"registering", "unregistering" -> {
|
||||
}
|
||||
"registered" -> {
|
||||
Log.d("Baresip", "Setting status to green")
|
||||
Accounts[account_index].status = "OK"
|
||||
AoRs[account_index] = aor
|
||||
Images[account_index] = R.drawable.green
|
||||
runOnUiThread { AccountAdapter.notifyDataSetChanged() }
|
||||
}
|
||||
"registering failed" -> {
|
||||
Log.d("Baresip", "Setting status to red")
|
||||
Accounts[account_index].status = "FAIL"
|
||||
AoRs[account_index] = aor
|
||||
Images[account_index] = R.drawable.red
|
||||
runOnUiThread { AccountAdapter.notifyDataSetChanged() }
|
||||
}
|
||||
"call ringing" -> {
|
||||
}
|
||||
"call established" -> {
|
||||
val out_index = callIndex(Out, ua, call)
|
||||
if (out_index >= 0) {
|
||||
Log.d("Baresip", "Outbound call " + call + " established")
|
||||
Out[out_index].status = "Hangup"
|
||||
Out[out_index].hold = false
|
||||
runOnUiThread {
|
||||
if (ua == aor_ua(AoRs[AoRSpinner.selectedItemPosition])) {
|
||||
callButton.text = "Hangup"
|
||||
holdButton.text = "Hold"
|
||||
holdButton.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
HistoryActivity.History.add(History(ua, call, aor, call_peeruri(call),
|
||||
"out", true))
|
||||
} else {
|
||||
Log.d("Baresip", "Inbound call " + call + " established")
|
||||
HistoryActivity.History.add(History(ua, call, aor, call_peeruri(call),
|
||||
"in", true))
|
||||
}
|
||||
}
|
||||
"call incoming" -> {
|
||||
val peer_uri = call_peeruri(call)
|
||||
Log.d("Baresip", "Incoming call " + ua + "/" + call + "/" +
|
||||
peer_uri)
|
||||
val new_call = Call(ua, call, peer_uri, "Answer")
|
||||
In.add(new_call)
|
||||
this@MainActivity.runOnUiThread {
|
||||
if (ua == aor_ua(AoRs[AoRSpinner.selectedItemPosition])) {
|
||||
addCallViews(new_call, In.size * 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
"call closed" -> {
|
||||
call_index = callIndex(In, ua, call)
|
||||
if (call_index != -1) {
|
||||
Log.d("Baresip", "Removing inbound call " + ua + "/" +
|
||||
call + "/" + In[call_index].peerURI)
|
||||
val view_id = (call_index + 1) * 10
|
||||
val remove_count = In.size - call_index
|
||||
In.removeAt(call_index)
|
||||
this@MainActivity.runOnUiThread {
|
||||
if (ua == aor_ua(AoRs[AoRSpinner.selectedItemPosition])) {
|
||||
if (callButton.text == "Call") {
|
||||
holdButton.text = "History"
|
||||
holdButton.visibility = View.VISIBLE
|
||||
}
|
||||
val caller_heading = layout.findViewById(view_id)
|
||||
val view_index = layout.indexOfChild(caller_heading)
|
||||
Log.d("Baresip", "Index of caller heading is $view_index")
|
||||
layout.removeViews(view_index, 4 * remove_count)
|
||||
for (i in call_index until In.size) {
|
||||
this@MainActivity.addCallViews(In[i], (i + 1) * 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!callHasHistory(ua, call)) {
|
||||
HistoryActivity.History.add(History(ua, call, aor, call_peeruri(call),
|
||||
"in", false))
|
||||
}
|
||||
} else {
|
||||
call_index = callIndex(Out, ua, call)
|
||||
if (call_index != -1) {
|
||||
Log.d("Baresip", "Removing outgoing call " + ua + "/" +
|
||||
call + "/" + Out[call_index].peerURI)
|
||||
Out.removeAt(call_index)
|
||||
runOnUiThread {
|
||||
if (ua == aor_ua(AoRs[AoRSpinner.selectedItemPosition])) {
|
||||
callButton.text = "Call"
|
||||
callButton.isEnabled = true
|
||||
callee.setText("")
|
||||
callee.hint = "Callee"
|
||||
holdButton.text = "History"
|
||||
holdButton.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
if (!callHasHistory(ua, call)) {
|
||||
HistoryActivity.History.add(History(ua, call, aor, call_peeruri(call),
|
||||
"out", false))
|
||||
}
|
||||
} else {
|
||||
Log.e("Baresip", "Unknown call " + ua + "/" + call +
|
||||
" closed")
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> Log.d("Baresip", "Unknown event '$event'")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
external fun baresipStart(path: String)
|
||||
external fun baresipStop()
|
||||
external fun call_peeruri(call: String): String
|
||||
external fun ua_aor(ua: String): String
|
||||
external fun aor_ua(aor: String): String
|
||||
external fun ua_connect(ua: String, peer_uri: String): String
|
||||
external fun ua_answer(ua: String, call: String)
|
||||
external fun call_hold(call: String): Int?
|
||||
external fun call_unhold(call: String): Int?
|
||||
external fun ua_hangup(ua: String, call: String, code: Int, reason: String)
|
||||
external fun reload_config(): Int
|
||||
|
||||
companion object {
|
||||
|
||||
internal lateinit var mainActivityContext: Context
|
||||
internal lateinit var layout: RelativeLayout
|
||||
internal lateinit var callee: AutoCompleteTextView
|
||||
internal lateinit var callButton: Button
|
||||
internal lateinit var holdButton: Button
|
||||
internal lateinit var AccountAdapter: AccountSpinnerAdapter
|
||||
internal lateinit var AoRSpinner: Spinner
|
||||
|
||||
internal var running: Boolean = false
|
||||
internal var Accounts = ArrayList<Account>()
|
||||
internal var AoRs = ArrayList<String>()
|
||||
internal var Images = ArrayList<Int>()
|
||||
internal var CalleeAdapter: ArrayAdapter<String>? = null
|
||||
internal var In = ArrayList<Call>()
|
||||
internal var Out = ArrayList<Call>()
|
||||
|
||||
private val RECORD_AUDIO_PERMISSION = 1
|
||||
private val EDIT_ACCOUNTS_CODE = 1
|
||||
private val EDIT_CONTACTS_CODE = 2
|
||||
private val EDIT_CONFIG_CODE = 3
|
||||
private val HISTORY_CODE = 4
|
||||
private val ABOUT_CODE = 5
|
||||
|
||||
external fun contacts_remove()
|
||||
external fun contact_add(contact: String)
|
||||
|
||||
init {
|
||||
System.loadLibrary("baresip")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.util.Log
|
||||
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.io.OutputStreamWriter
|
||||
|
||||
object Utils {
|
||||
|
||||
fun getFileContents(file: File): String {
|
||||
if (!file.exists()) {
|
||||
Log.e("Baresip", "Failed to find file: " + file.path)
|
||||
return ""
|
||||
} else {
|
||||
Log.e("Baresip", "Found file: " + file.path)
|
||||
val length = file.length().toInt()
|
||||
val bytes = ByteArray(length)
|
||||
try {
|
||||
val `in` = FileInputStream(file)
|
||||
try {
|
||||
`in`.read(bytes)
|
||||
} finally {
|
||||
`in`.close()
|
||||
}
|
||||
return String(bytes)
|
||||
} catch (e: java.io.IOException) {
|
||||
Log.e("Baresip", "Failed to read file: " + file.path + ": " +
|
||||
e.toString())
|
||||
return ""
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun putFileContents(file: File, contents: String) {
|
||||
try {
|
||||
val fOut = FileOutputStream(file.absoluteFile, false)
|
||||
val fWriter = OutputStreamWriter(fOut)
|
||||
try {
|
||||
fWriter.write(contents)
|
||||
fWriter.close()
|
||||
fOut.close()
|
||||
} catch (e: java.io.IOException) {
|
||||
Log.e("Baresip", "Failed to put contents to file: " + e.toString())
|
||||
}
|
||||
|
||||
} catch (e: java.io.FileNotFoundException) {
|
||||
Log.e("Baresip", "Failed to find contents file: " + e.toString())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun alertView(context: Context, message: String) {
|
||||
val alertDialog = AlertDialog.Builder(context).create()
|
||||
alertDialog.setTitle("Alert")
|
||||
alertDialog.setMessage(message)
|
||||
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK"
|
||||
) { dialog, _ -> dialog.dismiss() }
|
||||
alertDialog.show()
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user