Replaced Show Android Contacts setting with Contacts setting with possible
values 'baresip', 'Android', and Both
This commit is contained in:
@ -85,7 +85,7 @@
|
||||
<activity
|
||||
android:name=".ContactsActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:label="@string/baresip_contacts"
|
||||
android:label="@string/contacts"
|
||||
android:parentActivityName=".MainActivity"
|
||||
android:windowSoftInputMode="adjustPan" >
|
||||
</activity>
|
||||
@ -95,18 +95,11 @@
|
||||
android:label="@string/contact"
|
||||
android:parentActivityName=".ContactsActivity" >
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".AndroidContactsActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:label="@string/android_contacts"
|
||||
android:parentActivityName=".MainActivity"
|
||||
android:windowSoftInputMode="adjustPan" >
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".AndroidContactActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:label="@string/contact"
|
||||
android:parentActivityName=".AndroidContactsActivity" >
|
||||
android:parentActivityName=".ContactsActivity" >
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ConfigActivity"
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.net.Uri
|
||||
import java.util.ArrayList
|
||||
|
||||
class AndroidContact(val id: Long, var name: String, var color: Int, var thumbnailUri: Uri?) {
|
||||
|
||||
val uris = ArrayList<String>()
|
||||
|
||||
companion object {
|
||||
|
||||
fun contacts(): ArrayList<AndroidContact> {
|
||||
return BaresipService.androidContacts
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -26,7 +26,6 @@ class AndroidContactActivity : AppCompatActivity() {
|
||||
|
||||
private var index = 0
|
||||
private var color = 0
|
||||
private var id: Long = 0
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
@ -43,10 +42,9 @@ class AndroidContactActivity : AppCompatActivity() {
|
||||
cardImageAvatarView = binding.ImageAvatar
|
||||
nameView = binding.Name
|
||||
|
||||
val contact = BaresipService.androidContacts[index]
|
||||
val contact = Contact.contacts()[index] as Contact.AndroidContact
|
||||
val name = contact.name
|
||||
color = contact.color
|
||||
id = contact.id
|
||||
val thumbnailUri = contact.thumbnailUri
|
||||
if (thumbnailUri != null)
|
||||
showImageAvatar(thumbnailUri)
|
||||
@ -105,5 +103,3 @@ class AndroidContactActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,75 +0,0 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.SystemClock
|
||||
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 androidx.core.content.ContextCompat.startActivity
|
||||
|
||||
class AndroidContactListAdapter(private val ctx: Context,
|
||||
private val rows: ArrayList<AndroidContact>,
|
||||
private val aor: String) :
|
||||
ArrayAdapter<AndroidContact>(ctx, R.layout.android_contact_row, rows) {
|
||||
|
||||
private val layoutInflater = LayoutInflater.from(context)
|
||||
private var lastClick: Long = 0
|
||||
|
||||
private class ViewHolder(view: View?) {
|
||||
val textAvatarView = view?.findViewById(R.id.TextAvatar) as TextView
|
||||
val imageAvatarView = view?.findViewById(R.id.ImageAvatar) as ImageView
|
||||
val nameView = view?.findViewById(R.id.contactName) as TextView
|
||||
}
|
||||
|
||||
override fun getView(position: Int, view: View?, parent: ViewGroup): View {
|
||||
|
||||
val viewHolder: ViewHolder
|
||||
val rowView: View
|
||||
|
||||
if (view == null) {
|
||||
rowView = layoutInflater.inflate(R.layout.android_contact_row, parent, false)
|
||||
viewHolder = ViewHolder(rowView)
|
||||
rowView.tag = viewHolder
|
||||
} else {
|
||||
rowView = view
|
||||
viewHolder = rowView.tag as ViewHolder
|
||||
}
|
||||
|
||||
val contact = rows[position]
|
||||
|
||||
val thumbNailUri = contact.thumbnailUri
|
||||
if (thumbNailUri != null) {
|
||||
viewHolder.imageAvatarView.setImageURI(thumbNailUri)
|
||||
} else {
|
||||
viewHolder.textAvatarView.background.setTint(contact.color)
|
||||
if (contact.name.isNotEmpty())
|
||||
viewHolder.textAvatarView.text = "${contact.name[0]}"
|
||||
else
|
||||
viewHolder.textAvatarView.text = ""
|
||||
viewHolder.imageAvatarView.setImageBitmap(Utils.bitmapFromView(viewHolder.textAvatarView))
|
||||
}
|
||||
|
||||
viewHolder.nameView.text = contact.name
|
||||
viewHolder.nameView.textSize = 20f
|
||||
viewHolder.nameView.setPadding(6, 6, 0, 6)
|
||||
|
||||
viewHolder.nameView.setOnClickListener {
|
||||
if (SystemClock.elapsedRealtime() - lastClick > 1000) {
|
||||
lastClick = SystemClock.elapsedRealtime()
|
||||
val i = Intent(ctx, AndroidContactActivity::class.java)
|
||||
val b = Bundle()
|
||||
b.putString("aor", aor)
|
||||
b.putInt("index", position)
|
||||
i.putExtras(b)
|
||||
startActivity(ctx, i, null)
|
||||
}
|
||||
}
|
||||
|
||||
return rowView
|
||||
}
|
||||
}
|
||||
@ -1,228 +0,0 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.*
|
||||
import android.content.pm.PackageManager
|
||||
import android.database.Cursor
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.SystemClock
|
||||
import android.provider.ContactsContract
|
||||
import android.view.Menu
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import android.view.MenuItem
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.net.toUri
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tutpro.baresip.Utils.showSnackBar
|
||||
import com.tutpro.baresip.databinding.ActivityAndroidContactsBinding
|
||||
|
||||
class AndroidContactsActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: ActivityAndroidContactsBinding
|
||||
private lateinit var layout: RelativeLayout
|
||||
private lateinit var clAdapter: AndroidContactListAdapter
|
||||
private lateinit var aor: String
|
||||
private var lastSwap: Long = 0
|
||||
private lateinit var permissionsLauncher: ActivityResultLauncher<Array<String>>
|
||||
private val permissions = arrayOf(Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS)
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityAndroidContactsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
layout = binding.AndroidContactsView
|
||||
|
||||
aor = intent.getStringExtra("aor")!!
|
||||
|
||||
val listView = binding.androidContacts
|
||||
|
||||
permissionsLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
|
||||
var allowed = true
|
||||
permissions.entries.forEach {
|
||||
allowed = allowed && it.value
|
||||
}
|
||||
if (allowed) {
|
||||
fetchAndroidContacts(this)
|
||||
clAdapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 23 && !Utils.checkPermissions(this, permissions))
|
||||
requestPermissions(permissions, CONTACT_PERMISSION_REQUEST_CODE)
|
||||
|
||||
clAdapter = AndroidContactListAdapter(this, BaresipService.androidContacts, aor)
|
||||
listView.adapter = clAdapter
|
||||
|
||||
Utils.addActivity("android contacts,$aor")
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.swap_contacts_icon, menu)
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
||||
when (item.itemId) {
|
||||
|
||||
R.id.swapIcon -> {
|
||||
if (SystemClock.elapsedRealtime() - lastSwap > 1000) {
|
||||
lastSwap = SystemClock.elapsedRealtime()
|
||||
BaresipService.activities.remove("android contacts,$aor")
|
||||
val intent = Intent(this, ContactsActivity::class.java)
|
||||
intent.putExtra("aor", aor)
|
||||
startActivity(intent)
|
||||
finish()
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
android.R.id.home -> {
|
||||
BaresipService.activities.remove("android contacts,$aor")
|
||||
setResult(Activity.RESULT_OK, Intent())
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
|
||||
BaresipService.activities.remove("android contacts,$aor")
|
||||
setResult(Activity.RESULT_OK, Intent())
|
||||
finish()
|
||||
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>,
|
||||
grandResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grandResults)
|
||||
when (requestCode) {
|
||||
CONTACT_PERMISSION_REQUEST_CODE -> {
|
||||
var allowed = true
|
||||
for (res in grandResults)
|
||||
allowed = allowed && res == PackageManager.PERMISSION_GRANTED
|
||||
if (allowed) {
|
||||
fetchAndroidContacts(this)
|
||||
clAdapter.notifyDataSetChanged()
|
||||
} else {
|
||||
when {
|
||||
ActivityCompat.shouldShowRequestPermissionRationale(this,
|
||||
Manifest.permission.READ_CONTACTS) -> {
|
||||
layout.showSnackBar(
|
||||
binding.root,
|
||||
getString(R.string.no_android_contacts),
|
||||
Snackbar.LENGTH_INDEFINITE,
|
||||
getString(R.string.ok)
|
||||
) {
|
||||
permissionsLauncher.launch(permissions)
|
||||
}
|
||||
}
|
||||
ActivityCompat.shouldShowRequestPermissionRationale(this,
|
||||
Manifest.permission.WRITE_CONTACTS) -> {
|
||||
layout.showSnackBar(
|
||||
binding.root,
|
||||
getString(R.string.no_android_contacts),
|
||||
Snackbar.LENGTH_INDEFINITE,
|
||||
getString(R.string.ok)
|
||||
) {
|
||||
permissionsLauncher.launch(permissions)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
permissionsLauncher.launch(permissions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun fetchAndroidContacts(ctx: Context) {
|
||||
val projection = arrayOf(ContactsContract.Data.CONTACT_ID, ContactsContract.Data.DISPLAY_NAME,
|
||||
ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1,
|
||||
ContactsContract.Data.PHOTO_THUMBNAIL_URI)
|
||||
val selection =
|
||||
ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE + "' OR " +
|
||||
ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE + "'"
|
||||
val cur: Cursor? = ctx.contentResolver.query(ContactsContract.Data.CONTENT_URI, projection,
|
||||
selection, null, null)
|
||||
val contacts = HashMap<Long, AndroidContact>()
|
||||
while (cur != null && cur.moveToNext()) {
|
||||
val id = cur.getLong(0)
|
||||
val name = cur.getString(1) ?: ""
|
||||
val mime = cur.getString(2)
|
||||
val data = cur.getString(3)
|
||||
val thumb = cur.getString(4)?.toUri()
|
||||
val contact = if (contacts.containsKey(id))
|
||||
contacts[id]!!
|
||||
else
|
||||
AndroidContact(id, name, Utils.randomColor(), thumb)
|
||||
if (contact.name == "" && name != "")
|
||||
contact.name = name
|
||||
if (contact.thumbnailUri == null && thumb != null)
|
||||
contact.thumbnailUri = thumb
|
||||
if (mime == ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
|
||||
contact.uris.add("tel:${data.filterNot{setOf('-', ' ').contains(it)}}")
|
||||
else if (mime == ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
|
||||
contact.uris.add("sip:$data")
|
||||
else
|
||||
continue
|
||||
if (!contacts.containsKey(id))
|
||||
contacts[id] = contact
|
||||
}
|
||||
cur?.close()
|
||||
BaresipService.androidContacts.clear()
|
||||
for ((_, value) in contacts)
|
||||
if (value.name != "")
|
||||
BaresipService.androidContacts.add(value)
|
||||
Utils.reloadContactNames()
|
||||
return
|
||||
}
|
||||
|
||||
fun findContact(uri: String): AndroidContact? {
|
||||
for (c in BaresipService.androidContacts)
|
||||
for (u in c.uris)
|
||||
if (Utils.uriMatch(u, uri))
|
||||
return c
|
||||
return null
|
||||
}
|
||||
|
||||
// Return contact name of uri or uri itself if contact with uri is not found
|
||||
fun contactName(uri: String): String {
|
||||
val userPart = Utils.uriUserPart(uri)
|
||||
return if (Utils.isTelNumber(userPart))
|
||||
findContact("tel:$userPart")?.name ?: uri
|
||||
else
|
||||
findContact(uri)?.name ?: uri
|
||||
}
|
||||
|
||||
// Return first sip (preferred) or tel uri of contact name or
|
||||
// null if contact is not found or if it has no uris
|
||||
fun contactUri(name: String): String? {
|
||||
for (c in BaresipService.androidContacts)
|
||||
if (c.name == name) {
|
||||
if (c.uris.isNotEmpty()) {
|
||||
for (u in c.uris)
|
||||
if (u.startsWith("sip:"))
|
||||
return u
|
||||
return c.uris.first()
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -41,6 +41,7 @@ import java.io.File
|
||||
import java.net.InetAddress
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.concurrent.schedule
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@ -74,6 +75,7 @@ class BaresipService: Service() {
|
||||
private var hotSpotIsEnabled = false
|
||||
private var hotSpotAddresses = mapOf<String, String>()
|
||||
private var mediaPlayer: MediaPlayer? = null
|
||||
private var contentObserverRegistered = false
|
||||
|
||||
@SuppressLint("WakelockTimeout")
|
||||
override fun onCreate() {
|
||||
@ -299,33 +301,28 @@ class BaresipService: Service() {
|
||||
this.registerReceiver(bluetoothReceiver, filter)
|
||||
}
|
||||
|
||||
val contentObserver: ContentObserver = object : ContentObserver(null) {
|
||||
contentObserver = object : ContentObserver(null) {
|
||||
override fun onChange(self: Boolean) {
|
||||
Log.d(TAG, "Contacts change")
|
||||
AndroidContactsActivity.fetchAndroidContacts(this@BaresipService.applicationContext)
|
||||
if (contactsMode != "baresip") {
|
||||
Contact.loadAndroidContacts(this@BaresipService.applicationContext)
|
||||
Contact.contactsUpdate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
AndroidContactsActivity.fetchAndroidContacts(this)
|
||||
contentResolver.registerContentObserver(
|
||||
ContactsContract.Contacts.CONTENT_URI, true, contentObserver)
|
||||
} catch(e: SecurityException) {
|
||||
Log.i(TAG, "No Contacts permission")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
|
||||
val action: String
|
||||
val action: String?
|
||||
|
||||
if (intent == null) {
|
||||
action = "Start"
|
||||
Log.d(TAG, "Received onStartCommand with null intent")
|
||||
} else {
|
||||
// Utils.dumpIntent(intent)
|
||||
action = intent.action!!
|
||||
action = intent.action
|
||||
Log.d(TAG, "Received onStartCommand action $action")
|
||||
}
|
||||
|
||||
@ -359,13 +356,21 @@ class BaresipService: Service() {
|
||||
Log.i(TAG, "Asset '$a' already copied")
|
||||
}
|
||||
if (a == "config")
|
||||
Config.initialize()
|
||||
Config.initialize(applicationContext)
|
||||
}
|
||||
|
||||
if (File(filesDir, "history").exists())
|
||||
File(filesDir, "history").renameTo(File(filesDir, "calls"))
|
||||
|
||||
Contact.restore()
|
||||
|
||||
if (contactsMode != "Android")
|
||||
Contact.restoreBaresipContacts()
|
||||
if (contactsMode != "baresip") {
|
||||
Contact.loadAndroidContacts(applicationContext)
|
||||
registerContentObserver()
|
||||
}
|
||||
Contact.contactsUpdate()
|
||||
|
||||
val history = CallHistory.get()
|
||||
if (history.isEmpty()) {
|
||||
NewCallHistory.restore()
|
||||
@ -417,6 +422,14 @@ class BaresipService: Service() {
|
||||
|
||||
}
|
||||
|
||||
"Start Content Observer" -> {
|
||||
registerContentObserver()
|
||||
}
|
||||
|
||||
"Stop Content Observer" -> {
|
||||
unRegisterContentObserver()
|
||||
}
|
||||
|
||||
"Call Answer" -> {
|
||||
val uap = intent!!.getStringExtra("uap")!!
|
||||
val callp = intent.getStringExtra("callp")!!
|
||||
@ -666,7 +679,7 @@ class BaresipService: Service() {
|
||||
PendingIntent.getActivity(applicationContext, CALL_REQ_CODE, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
val nb = NotificationCompat.Builder(this, HIGH_CHANNEL_ID)
|
||||
val caller = Utils.friendlyUri(Utils.contactName(peerUri), Utils.aorDomain(aor))
|
||||
val caller = Utils.friendlyUri(Contact.contactName(peerUri), Utils.aorDomain(aor))
|
||||
nb.setSmallIcon(R.drawable.ic_stat_call)
|
||||
.setColor(ContextCompat.getColor(this, R.color.colorBaresip))
|
||||
.setContentIntent(pi)
|
||||
@ -760,7 +773,7 @@ class BaresipService: Service() {
|
||||
PendingIntent.getActivity(applicationContext, TRANSFER_REQ_CODE,
|
||||
intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
val nb = NotificationCompat.Builder(this, HIGH_CHANNEL_ID)
|
||||
val target = Utils.friendlyUri(Utils.contactName(ev[1]), Utils.aorDomain(aor))
|
||||
val target = Utils.friendlyUri(Contact.contactName(ev[1]), Utils.aorDomain(aor))
|
||||
nb.setSmallIcon(R.drawable.ic_stat_call)
|
||||
.setColor(ContextCompat.getColor(this, R.color.colorBaresip))
|
||||
.setContentIntent(pi)
|
||||
@ -836,7 +849,7 @@ class BaresipService: Service() {
|
||||
}
|
||||
if (!Utils.isVisible()) {
|
||||
if (missed) {
|
||||
val caller = Utils.friendlyUri(Utils.contactName(call.peerUri), Utils.aorDomain(aor))
|
||||
val caller = Utils.friendlyUri(Contact.contactName(call.peerUri), Utils.aorDomain(aor))
|
||||
val intent = Intent(applicationContext, MainActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or
|
||||
Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
@ -942,7 +955,7 @@ class BaresipService: Service() {
|
||||
PendingIntent.getActivity(applicationContext, MESSAGE_REQ_CODE, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
val nb = NotificationCompat.Builder(this, HIGH_CHANNEL_ID)
|
||||
val sender = Utils.friendlyUri(Utils.contactName(peer), Utils.aorDomain(ua.account.aor))
|
||||
val sender = Utils.friendlyUri(Contact.contactName(peer), Utils.aorDomain(ua.account.aor))
|
||||
nb.setSmallIcon(R.drawable.ic_stat_message)
|
||||
.setColor(ContextCompat.getColor(this, R.color.colorBaresip))
|
||||
.setContentIntent(pi)
|
||||
@ -1389,6 +1402,24 @@ class BaresipService: Service() {
|
||||
return false
|
||||
}
|
||||
|
||||
private fun registerContentObserver() {
|
||||
if (!contentObserverRegistered)
|
||||
try {
|
||||
contentResolver.registerContentObserver(ContactsContract.Contacts.CONTENT_URI,
|
||||
true, contentObserver)
|
||||
contentObserverRegistered = true
|
||||
} catch (e: SecurityException) {
|
||||
Log.i(TAG, "No Contacts permission")
|
||||
}
|
||||
}
|
||||
|
||||
private fun unRegisterContentObserver() {
|
||||
if (contentObserverRegistered) {
|
||||
contentResolver.unregisterContentObserver(contentObserver)
|
||||
contentObserverRegistered = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun cleanService() {
|
||||
am.mode = AudioManager.MODE_NORMAL
|
||||
abandonAudioFocus()
|
||||
@ -1429,7 +1460,6 @@ class BaresipService: Service() {
|
||||
var callActionUri = ""
|
||||
var isMainVisible = false
|
||||
var isMicMuted = false
|
||||
var preferAndroidContacts = false
|
||||
|
||||
val uas = ArrayList<UserAgent>()
|
||||
val status = ArrayList<Int>()
|
||||
@ -1437,10 +1467,13 @@ class BaresipService: Service() {
|
||||
var callHistory = ArrayList<NewCallHistory>()
|
||||
var messages = ArrayList<Message>()
|
||||
val messageUpdate = MutableLiveData<Long>()
|
||||
val contactUpdate = MutableLiveData<Long>()
|
||||
val registrationUpdate = MutableLiveData<Long>()
|
||||
val baresipContacts = ArrayList<Contact.BaresipContact>()
|
||||
val androidContacts = ArrayList<Contact.AndroidContact>()
|
||||
val contacts = ArrayList<Contact>()
|
||||
val androidContacts = ArrayList<AndroidContact>()
|
||||
val contactNames = mutableListOf<String>()
|
||||
val contactNames = ArrayList<String>()
|
||||
var contactsMode = "baresip"
|
||||
val chatTexts: MutableMap<String, String> = mutableMapOf()
|
||||
val activities = mutableListOf<String>()
|
||||
var dnsServers = listOf<InetAddress>()
|
||||
|
||||
@ -62,7 +62,7 @@ class CallListAdapter(private val ctx: Context, private val aor: String, private
|
||||
if (count <= 3)
|
||||
viewHolder.etcView.text = ""
|
||||
|
||||
val contactName = Utils.contactName(callRow.peerUri)
|
||||
val contactName = Contact.contactName(callRow.peerUri)
|
||||
if (contactName.startsWith("sip:"))
|
||||
viewHolder.peerURIView.text = Utils.friendlyUri(contactName, Utils.aorDomain(callRow.aor))
|
||||
else
|
||||
|
||||
@ -50,7 +50,7 @@ class CallsActivity : AppCompatActivity() {
|
||||
|
||||
listView.onItemClickListener = AdapterView.OnItemClickListener { _, _, pos, _ ->
|
||||
val peerUri = uaHistory[pos].peerUri
|
||||
var peerName = Utils.contactName(peerUri)
|
||||
var peerName = Contact.contactName(peerUri)
|
||||
if (peerName.startsWith("sip:"))
|
||||
peerName = Utils.friendlyUri(peerName, Utils.aorDomain(aor))
|
||||
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
|
||||
@ -95,7 +95,7 @@ class CallsActivity : AppCompatActivity() {
|
||||
|
||||
listView.onItemLongClickListener = AdapterView.OnItemLongClickListener { _, _, pos, _ ->
|
||||
val peerUri = uaHistory[pos].peerUri
|
||||
val peerName = Utils.contactName(peerUri)
|
||||
val peerName = Contact.contactName(peerUri)
|
||||
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
|
||||
when (which) {
|
||||
DialogInterface.BUTTON_NEGATIVE -> {
|
||||
|
||||
@ -63,7 +63,7 @@ class ChatActivity : AppCompatActivity() {
|
||||
imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
this@ChatActivity.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN)
|
||||
|
||||
var chatPeer = Utils.contactName(peerUri)
|
||||
var chatPeer = Contact.contactName(peerUri)
|
||||
if (chatPeer.startsWith("sip:"))
|
||||
chatPeer = Utils.friendlyUri(chatPeer, Utils.aorDomain(aor))
|
||||
|
||||
@ -112,7 +112,7 @@ class ChatActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
val builder = AlertDialog.Builder(this@ChatActivity, R.style.Theme_AppCompat)
|
||||
if (Utils.contactName(peerUri) == peerUri)
|
||||
if (Contact.contactName(peerUri) == peerUri)
|
||||
with (builder) {
|
||||
setMessage(String.format(getString(R.string.long_message_question),
|
||||
chatPeer))
|
||||
|
||||
@ -52,7 +52,7 @@ class ChatListAdapter(private val ctx: Context, private val rows: ArrayList<Mess
|
||||
else
|
||||
viewHolder.layoutView.setBackgroundResource(R.drawable.message_out_bg)
|
||||
|
||||
val peerName = Utils.contactName(message.peerUri)
|
||||
val peerName = Contact.contactName(message.peerUri)
|
||||
viewHolder.peerView.text = if (peerName !=message.peerUri )
|
||||
peerName
|
||||
else
|
||||
|
||||
@ -78,14 +78,14 @@ class ChatsActivity: AppCompatActivity() {
|
||||
}
|
||||
DialogInterface.BUTTON_NEGATIVE -> {
|
||||
val peerUri = uaMessages[pos].peerUri
|
||||
val msgs = ArrayList<Message>()
|
||||
val messages = ArrayList<Message>()
|
||||
for (m in Message.messages())
|
||||
if ((m.aor != aor) || (m.peerUri != peerUri))
|
||||
msgs.add(m)
|
||||
messages.add(m)
|
||||
else
|
||||
clAdapter.remove(m)
|
||||
clAdapter.notifyDataSetChanged()
|
||||
BaresipService.messages = msgs
|
||||
BaresipService.messages = messages
|
||||
Message.save()
|
||||
uaMessages = uaMessages(aor)
|
||||
}
|
||||
@ -95,7 +95,7 @@ class ChatsActivity: AppCompatActivity() {
|
||||
}
|
||||
|
||||
val builder = AlertDialog.Builder(this@ChatsActivity, R.style.Theme_AppCompat)
|
||||
val peer = Utils.contactName(uaMessages[pos].peerUri)
|
||||
val peer = Contact.contactName(uaMessages[pos].peerUri)
|
||||
if (peer.startsWith("sip:"))
|
||||
with (builder) {
|
||||
setMessage(String.format(getString(R.string.long_chat_question),
|
||||
@ -118,12 +118,12 @@ class ChatsActivity: AppCompatActivity() {
|
||||
peerUri = binding.peer
|
||||
peerUri.threshold = 2
|
||||
peerUri.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item,
|
||||
Utils.contactNames()))
|
||||
Contact.contactNames()))
|
||||
|
||||
plusButton.setOnClickListener {
|
||||
val uriText = peerUri.text.toString().trim()
|
||||
if (uriText.isNotEmpty()) {
|
||||
var uri = Utils.contactUri(uriText)
|
||||
var uri = Contact.contactUri(uriText)
|
||||
if (uri == null)
|
||||
uri = if (Utils.isTelNumber(uriText))
|
||||
"tel:$uriText"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import java.net.InetAddress
|
||||
import java.nio.charset.StandardCharsets
|
||||
@ -9,7 +10,7 @@ object Config {
|
||||
private val configPath = BaresipService.filesPath + "/config"
|
||||
private var config = String(Utils.getFileContents(configPath)!!, StandardCharsets.ISO_8859_1)
|
||||
|
||||
fun initialize() {
|
||||
fun initialize(ctx: Context) {
|
||||
|
||||
config = config.replace("module_tmp uuid.so", "module uuid.so")
|
||||
|
||||
@ -85,7 +86,19 @@ object Config {
|
||||
config = "${config}jitter_buffer_wish 6\n"
|
||||
}
|
||||
|
||||
BaresipService.preferAndroidContacts = config.contains("prefer_android_contacts yes")
|
||||
removeVariable("prefer_android_contacts")
|
||||
|
||||
if (config.contains("contacts_mode")) {
|
||||
BaresipService.contactsMode = variable("contacts_mode")[0]
|
||||
if (BaresipService.contactsMode != "baresip" &&
|
||||
!Utils.checkPermissions(ctx, arrayOf(Manifest.permission.READ_CONTACTS,
|
||||
Manifest.permission.WRITE_CONTACTS))) {
|
||||
BaresipService.contactsMode = "baresip"
|
||||
replaceVariable("contacts_mode", "baresip")
|
||||
}
|
||||
} else {
|
||||
BaresipService.contactsMode = "baresip"
|
||||
}
|
||||
|
||||
Utils.putFileContents(configPath, config.toByteArray())
|
||||
BaresipService.isConfigInitialized = true
|
||||
|
||||
@ -32,6 +32,7 @@ class ConfigActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: ActivityConfigBinding
|
||||
private lateinit var layout: ScrollView
|
||||
private lateinit var baresipService: Intent
|
||||
private lateinit var autoStart: CheckBox
|
||||
private lateinit var batteryOptimizations: CheckBox
|
||||
private lateinit var listenAddr: EditText
|
||||
@ -40,11 +41,14 @@ class ConfigActivity : AppCompatActivity() {
|
||||
private lateinit var verifyServer: CheckBox
|
||||
private lateinit var caFile: CheckBox
|
||||
private lateinit var darkTheme: CheckBox
|
||||
private lateinit var androidContacts: CheckBox
|
||||
private lateinit var contactsSpinner: Spinner
|
||||
private lateinit var contactsMode: String
|
||||
private lateinit var contactsModes: ArrayList<String>
|
||||
private lateinit var debug: CheckBox
|
||||
private lateinit var sipTrace: CheckBox
|
||||
private lateinit var reset: CheckBox
|
||||
private lateinit var requestPermissionLauncher: ActivityResultLauncher<String>
|
||||
private lateinit var requestPermissionsLauncher: ActivityResultLauncher<Array<String>>
|
||||
|
||||
private var oldAutoStart = ""
|
||||
private var oldListenAddr = ""
|
||||
@ -54,7 +58,7 @@ class ConfigActivity : AppCompatActivity() {
|
||||
private var oldCAFile = false
|
||||
private var oldLogLevel = ""
|
||||
private var oldDisplayTheme = -1
|
||||
private var oldAndroidContacts = ""
|
||||
private var oldContactsMode = ""
|
||||
private var save = false
|
||||
private var restart = false
|
||||
private var menu: Menu? = null
|
||||
@ -63,12 +67,16 @@ class ConfigActivity : AppCompatActivity() {
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val contactsPermissions = arrayOf(Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS)
|
||||
|
||||
binding = ActivityConfigBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
layout = binding.ConfigView
|
||||
|
||||
Utils.addActivity("config")
|
||||
|
||||
baresipService = Intent(this@ConfigActivity, BaresipService::class.java)
|
||||
|
||||
autoStart = binding.AutoStart
|
||||
val asCv = Config.variable("auto_start")
|
||||
oldAutoStart = if (asCv.size == 0) "no" else asCv[0]
|
||||
@ -291,10 +299,27 @@ class ConfigActivity : AppCompatActivity() {
|
||||
oldDisplayTheme = Preferences(applicationContext).displayTheme
|
||||
darkTheme.isChecked = oldDisplayTheme == AppCompatDelegate.MODE_NIGHT_YES
|
||||
|
||||
androidContacts = binding.AndroidContacts
|
||||
val acCv = Config.variable("prefer_android_contacts")
|
||||
oldAndroidContacts = if (acCv.size == 0) "no" else acCv[0]
|
||||
androidContacts.isChecked = oldAndroidContacts == "yes"
|
||||
contactsModes = arrayListOf(
|
||||
getString(R.string.baresip), getString(R.string.android), getString(R.string.both))
|
||||
contactsSpinner = binding.contactsSpinner
|
||||
val ctCv = Config.variable("contacts_mode")
|
||||
oldContactsMode = if (ctCv.size == 0) "baresip" else ctCv[0]
|
||||
contactsMode = oldContactsMode
|
||||
contactsModes.removeAt(contactsModes.indexOf(oldContactsMode))
|
||||
contactsModes.add(0, oldContactsMode)
|
||||
val contactsAdapter = ArrayAdapter(this,android.R.layout.simple_spinner_item,
|
||||
contactsModes)
|
||||
contactsAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
contactsSpinner.adapter = contactsAdapter
|
||||
contactsSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
|
||||
contactsMode = contactsModes[position]
|
||||
if (contactsMode != "baresip" && Build.VERSION.SDK_INT >= 23 &&
|
||||
!Utils.checkPermissions(applicationContext, contactsPermissions))
|
||||
requestPermissions(contactsPermissions, CONTACTS_PERMISSION_REQUEST_CODE)
|
||||
}
|
||||
override fun onNothingSelected(parent: AdapterView<*>) {}
|
||||
}
|
||||
|
||||
debug = binding.Debug
|
||||
val dbCv = Config.variable("log_level")
|
||||
@ -340,7 +365,14 @@ class ConfigActivity : AppCompatActivity() {
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
requestPermissionLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.RequestPermission()) {}
|
||||
registerForActivityResult(ActivityResultContracts.RequestPermission()) {}
|
||||
requestPermissionsLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
|
||||
if (it.containsValue(false)) {
|
||||
contactsMode = oldContactsMode
|
||||
contactsSpinner.setSelection(contactsModes.indexOf(oldContactsMode))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
@ -356,6 +388,44 @@ class ConfigActivity : AppCompatActivity() {
|
||||
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>,
|
||||
grandResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grandResults)
|
||||
when (requestCode) {
|
||||
CONTACTS_PERMISSION_REQUEST_CODE -> {
|
||||
if (grandResults.contains(PackageManager.PERMISSION_DENIED)) {
|
||||
when {
|
||||
ActivityCompat.shouldShowRequestPermissionRationale(this,
|
||||
Manifest.permission.READ_CONTACTS) -> {
|
||||
layout.showSnackBar(
|
||||
binding.root,
|
||||
getString(R.string.no_android_contacts),
|
||||
Snackbar.LENGTH_INDEFINITE,
|
||||
getString(R.string.ok)
|
||||
) {
|
||||
requestPermissionsLauncher.launch(permissions)
|
||||
}
|
||||
}
|
||||
ActivityCompat.shouldShowRequestPermissionRationale(this,
|
||||
Manifest.permission.WRITE_CONTACTS) -> {
|
||||
layout.showSnackBar(
|
||||
binding.root,
|
||||
getString(R.string.no_android_contacts),
|
||||
Snackbar.LENGTH_INDEFINITE,
|
||||
getString(R.string.ok)
|
||||
) {
|
||||
requestPermissionsLauncher.launch(permissions)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
requestPermissionsLauncher.launch(permissions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
||||
if (BaresipService.activities.indexOf("config") == -1) return true
|
||||
@ -433,13 +503,28 @@ class ConfigActivity : AppCompatActivity() {
|
||||
if (oldDisplayTheme != newDisplayTheme)
|
||||
Preferences(applicationContext).displayTheme = newDisplayTheme
|
||||
|
||||
val androidContactsString = if (androidContacts.isChecked)
|
||||
"yes"
|
||||
else
|
||||
"no"
|
||||
if (oldAndroidContacts != androidContactsString) {
|
||||
Config.replaceVariable("prefer_android_contacts", androidContactsString)
|
||||
BaresipService.preferAndroidContacts = androidContacts.isChecked
|
||||
if (oldContactsMode != contactsMode) {
|
||||
Config.replaceVariable("contacts_mode", contactsMode)
|
||||
BaresipService.contactsMode = contactsMode
|
||||
when (contactsMode) {
|
||||
"baresip" -> {
|
||||
BaresipService.androidContacts.clear()
|
||||
Contact.restoreBaresipContacts()
|
||||
baresipService.action = "Stop Content Observer"
|
||||
}
|
||||
"Android" -> {
|
||||
BaresipService.baresipContacts.clear()
|
||||
Contact.loadAndroidContacts(this)
|
||||
baresipService.action = "Start Content Observer"
|
||||
}
|
||||
"Both" -> {
|
||||
Contact.restoreBaresipContacts()
|
||||
Contact.loadAndroidContacts(this)
|
||||
baresipService.action = "Start Content Observer"
|
||||
}
|
||||
}
|
||||
Contact.contactsUpdate()
|
||||
startService(baresipService)
|
||||
save = true
|
||||
}
|
||||
|
||||
@ -530,9 +615,9 @@ class ConfigActivity : AppCompatActivity() {
|
||||
Utils.alertView(this, getString(R.string.dark_theme),
|
||||
getString(R.string.dark_theme_help))
|
||||
}
|
||||
binding.AndroidContactsTitle.setOnClickListener {
|
||||
Utils.alertView(this, getString(R.string.show_android_contacts),
|
||||
getString(R.string.show_android_contacts_help))
|
||||
binding.ContactsTitle.setOnClickListener {
|
||||
Utils.alertView(this, getString(R.string.contacts),
|
||||
getString(R.string.contacts_help))
|
||||
}
|
||||
binding.DebugTitle.setOnClickListener {
|
||||
Utils.alertView(this, getString(R.string.debug), getString(R.string.debug_help))
|
||||
|
||||
@ -6,7 +6,7 @@ const val DEFAULT_CHANNEL_ID = "com.tutpro.baresip.default"
|
||||
const val HIGH_CHANNEL_ID = "com.tutpro.baresip.high"
|
||||
|
||||
const val MIC_PERMISSION_REQUEST_CODE = 1
|
||||
const val CONTACT_PERMISSION_REQUEST_CODE = 2
|
||||
const val CONTACTS_PERMISSION_REQUEST_CODE = 2
|
||||
|
||||
const val STATUS_NOTIFICATION_ID = 101
|
||||
const val CALL_NOTIFICATION_ID = 102
|
||||
|
||||
@ -1,39 +1,165 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
|
||||
import android.net.Uri
|
||||
import android.provider.ContactsContract
|
||||
import androidx.core.net.toUri
|
||||
import java.io.File
|
||||
import java.util.ArrayList
|
||||
|
||||
class Contact(var name: String, var uri: String, var color: Int, val id: Long) {
|
||||
sealed class Contact {
|
||||
|
||||
var avatarImage: Bitmap? = null
|
||||
var androidContact = false
|
||||
class BaresipContact(var name: String, var uri: String, var color: Int, val id: Long): Contact() {
|
||||
var avatarImage: Bitmap? = null
|
||||
}
|
||||
|
||||
class AndroidContact(var name: String, var color: Int, var thumbnailUri: Uri?): Contact() {
|
||||
val uris = ArrayList<String>()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val CONTACTS_SIZE = 100
|
||||
const val CONTACTS_SIZE = 256
|
||||
|
||||
fun contacts(): ArrayList<Contact> {
|
||||
return BaresipService.contacts
|
||||
}
|
||||
|
||||
fun save(): Boolean {
|
||||
fun contactNames(): ArrayList<String> {
|
||||
return BaresipService.contactNames
|
||||
}
|
||||
|
||||
// Return contact name of uri or uri itself if contact with uri is not found
|
||||
fun contactName(uri: String): String {
|
||||
val userPart = Utils.uriUserPart(uri)
|
||||
val contact = if (Utils.isTelNumber(userPart))
|
||||
findContact("tel:$userPart")
|
||||
else
|
||||
findContact(uri)
|
||||
if (contact != null) {
|
||||
return when (contact) {
|
||||
is BaresipContact ->
|
||||
contact.name
|
||||
is AndroidContact ->
|
||||
contact.name
|
||||
}
|
||||
}
|
||||
return uri
|
||||
}
|
||||
|
||||
// Return uri of contact name or null if contact is not found
|
||||
fun contactUri(name: String): String? {
|
||||
for (c in contacts())
|
||||
when (c) {
|
||||
is BaresipContact -> {
|
||||
if (c.name.equals(name, ignoreCase = true))
|
||||
return c.uri.removePrefix("<")
|
||||
.replaceAfter(">", "")
|
||||
.replace(">", "")
|
||||
}
|
||||
is AndroidContact -> {
|
||||
if (c.name == name) {
|
||||
if (c.uris.isNotEmpty()) {
|
||||
for (u in c.uris)
|
||||
if (u.startsWith("sip:"))
|
||||
return u
|
||||
return c.uris.first()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun findContact(uri: String): Contact? {
|
||||
for (c in contacts())
|
||||
when (c) {
|
||||
is BaresipContact -> {
|
||||
if (Utils.uriMatch(c.uri, uri))
|
||||
return c
|
||||
}
|
||||
is AndroidContact -> {
|
||||
for (u in c.uris)
|
||||
if (Utils.uriMatch(u, uri))
|
||||
return c
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun nameExists(name: String, ignoreCase: Boolean): Boolean {
|
||||
for (c in BaresipService.baresipContacts)
|
||||
if (c.name.equals(name, ignoreCase = ignoreCase))
|
||||
return true
|
||||
for (c in BaresipService.androidContacts)
|
||||
if (c.name.equals(name, ignoreCase = ignoreCase))
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
fun saveBaresipContacts() {
|
||||
var contents = ""
|
||||
for (c in BaresipService.contacts) contents +=
|
||||
"\"${c.name}\" <${c.uri}>;id=${c.id};color=${c.color};android=${c.androidContact}\n"
|
||||
return Utils.putFileContents(BaresipService.filesPath + "/contacts",
|
||||
for (c in BaresipService.contacts)
|
||||
if (c is BaresipContact)
|
||||
contents += "\"${c.name}\" <${c.uri}>;id=${c.id};color=${c.color}\n"
|
||||
Utils.putFileContents(BaresipService.filesPath + "/contacts",
|
||||
contents.toByteArray())
|
||||
}
|
||||
|
||||
fun restore(): Boolean {
|
||||
fun loadAndroidContacts(ctx: Context) {
|
||||
val projection = arrayOf(ContactsContract.Data.CONTACT_ID, ContactsContract.Data.DISPLAY_NAME,
|
||||
ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1,
|
||||
ContactsContract.Data.PHOTO_THUMBNAIL_URI)
|
||||
val selection =
|
||||
ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE + "' OR " +
|
||||
ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE + "'"
|
||||
val cur: Cursor? = ctx.contentResolver.query(ContactsContract.Data.CONTENT_URI, projection,
|
||||
selection, null, null)
|
||||
BaresipService.androidContacts.clear()
|
||||
val contacts = HashMap<Long, AndroidContact>()
|
||||
while (cur != null && cur.moveToNext()) {
|
||||
val id = cur.getLong(0)
|
||||
val name = cur.getString(1) ?: ""
|
||||
val mime = cur.getString(2)
|
||||
val data = cur.getString(3)
|
||||
val thumb = cur.getString(4)?.toUri()
|
||||
if (nameExists(name, true)) {
|
||||
Log.d(TAG, "Skipping Android contact with existing name '$name'")
|
||||
continue
|
||||
}
|
||||
val contact = if (contacts.containsKey(id))
|
||||
contacts[id]!!
|
||||
else
|
||||
AndroidContact(name, Utils.randomColor(), thumb)
|
||||
if (contact.name == "" && name != "")
|
||||
contact.name = name
|
||||
if (contact.thumbnailUri == null && thumb != null)
|
||||
contact.thumbnailUri = thumb
|
||||
if (mime == ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
|
||||
contact.uris.add("tel:${data.filterNot{setOf('-', ' ').contains(it)}}")
|
||||
else if (mime == ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE)
|
||||
contact.uris.add("sip:$data")
|
||||
else
|
||||
continue
|
||||
if (!contacts.containsKey(id))
|
||||
contacts[id] = contact
|
||||
}
|
||||
cur?.close()
|
||||
for ((_, value) in contacts)
|
||||
if (value.name != "")
|
||||
BaresipService.androidContacts.add(value)
|
||||
}
|
||||
|
||||
fun restoreBaresipContacts(): Boolean {
|
||||
val content = Utils.getFileContents(BaresipService.filesPath + "/contacts")
|
||||
?: return false
|
||||
val contacts = String(content)
|
||||
BaresipService.contacts.clear()
|
||||
var contactNo = 0
|
||||
val baseId = System.currentTimeMillis()
|
||||
BaresipService.baresipContacts.clear()
|
||||
contacts.lines().forEach {
|
||||
val parts = it.split("\"")
|
||||
if (parts.size == 3) {
|
||||
@ -47,15 +173,13 @@ class Contact(var name: String, var uri: String, var color: Int, val id: Long) {
|
||||
colorValue.toInt()
|
||||
else
|
||||
Utils.randomColor()
|
||||
val androidContact = Utils.paramValue(params, "android" ) == "true"
|
||||
val idValue = Utils.paramValue(params, "id" )
|
||||
val id: Long = if (idValue != "")
|
||||
idValue.toLong()
|
||||
else
|
||||
baseId + contactNo
|
||||
Log.d(TAG, "Restoring contact $name, $uri, $color, $id, $androidContact")
|
||||
val contact = Contact(name, uri, color, id)
|
||||
contact.androidContact = androidContact
|
||||
Log.d(TAG, "Restoring contact $name, $uri, $color, $id")
|
||||
val contact = BaresipContact(name, uri, color, id)
|
||||
val avatarFilePath = BaresipService.filesPath + "/$id.png"
|
||||
if (File(avatarFilePath).exists()) {
|
||||
try {
|
||||
@ -67,12 +191,38 @@ class Contact(var name: String, var uri: String, var color: Int, val id: Long) {
|
||||
Log.e(TAG, "Could not read avatar image from '$id.img")
|
||||
}
|
||||
}
|
||||
BaresipService.contacts.add(contact)
|
||||
BaresipService.baresipContacts.add(contact)
|
||||
}
|
||||
}
|
||||
Utils.reloadContactNames()
|
||||
return true
|
||||
}
|
||||
|
||||
fun contactsUpdate() {
|
||||
BaresipService.contacts.clear()
|
||||
if (BaresipService.contactsMode != "Android")
|
||||
BaresipService.contacts.addAll(BaresipService.baresipContacts)
|
||||
if (BaresipService.contactsMode != "baresip")
|
||||
BaresipService.contacts.addAll(BaresipService.androidContacts)
|
||||
sortContacts()
|
||||
generateContactNames()
|
||||
BaresipService.contactUpdate.postValue(System.nanoTime())
|
||||
}
|
||||
|
||||
fun sortContacts() {
|
||||
BaresipService.contacts.sortBy{ when (it) {
|
||||
is BaresipContact -> it.name
|
||||
is AndroidContact -> it.name
|
||||
}}
|
||||
}
|
||||
|
||||
fun generateContactNames () {
|
||||
BaresipService.contactNames.clear()
|
||||
BaresipService.contactNames.addAll(
|
||||
BaresipService.contacts.map {
|
||||
when (it) {
|
||||
is BaresipContact -> it.name
|
||||
is AndroidContact -> it.name
|
||||
}})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,18 +1,15 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.ContentProviderOperation
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.database.Cursor
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.ContactsContract
|
||||
import android.provider.ContactsContract.CommonDataKinds
|
||||
@ -21,14 +18,10 @@ import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.cardview.widget.CardView
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.exifinterface.media.ExifInterface
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tutpro.baresip.Utils.showSnackBar
|
||||
import com.tutpro.baresip.databinding.ActivityContactBinding
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
@ -44,7 +37,6 @@ class ContactActivity : AppCompatActivity() {
|
||||
private lateinit var uriView: EditText
|
||||
private lateinit var androidCheck: CheckBox
|
||||
private lateinit var menu: Menu
|
||||
private lateinit var requestPermissionsLauncher: ActivityResultLauncher<Array<String>>
|
||||
|
||||
private var newContact = false
|
||||
private var newAvatar = ""
|
||||
@ -53,10 +45,6 @@ class ContactActivity : AppCompatActivity() {
|
||||
private var index = 0
|
||||
private var color = 0
|
||||
private var id: Long = 0
|
||||
private var oldAndroid = false
|
||||
|
||||
private val permissions =
|
||||
arrayOf(Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
@ -75,6 +63,10 @@ class ContactActivity : AppCompatActivity() {
|
||||
newContact = intent.getBooleanExtra("new", false)
|
||||
|
||||
if (newContact) {
|
||||
if (BaresipService.contactsMode == "baresip") {
|
||||
binding.AndroidTitle.visibility = View.GONE
|
||||
androidCheck.visibility = View.GONE
|
||||
}
|
||||
title = getString(R.string.new_contact)
|
||||
color = Utils.randomColor()
|
||||
id = System.currentTimeMillis()
|
||||
@ -88,27 +80,33 @@ class ContactActivity : AppCompatActivity() {
|
||||
else
|
||||
uriView.setText(uri)
|
||||
uOrI = uri
|
||||
androidCheck.isChecked = false
|
||||
if ((BaresipService.contactsMode == "Android")) {
|
||||
androidCheck.isChecked = true
|
||||
androidCheck.isClickable = false
|
||||
} else {
|
||||
androidCheck.isChecked = false
|
||||
}
|
||||
} else {
|
||||
binding.AndroidTitle.visibility = View.GONE
|
||||
androidCheck.visibility = View.GONE
|
||||
index = intent.getIntExtra("index", 0)
|
||||
val contact = Contact.contacts()[index]
|
||||
val name = contact.name
|
||||
color = contact.color
|
||||
id = contact.id
|
||||
val avatarImage = contact.avatarImage
|
||||
if (avatarImage != null)
|
||||
showImageAvatar(avatarImage)
|
||||
else
|
||||
showTextAvatar(name, color)
|
||||
title = name
|
||||
nameView.setText(name)
|
||||
uriView.setText(contact.uri)
|
||||
uOrI = index.toString()
|
||||
androidCheck.isChecked = contact.androidContact
|
||||
if (contact is Contact.BaresipContact) {
|
||||
val name = contact.name
|
||||
color = contact.color
|
||||
id = contact.id
|
||||
val avatarImage = contact.avatarImage
|
||||
if (avatarImage != null)
|
||||
showImageAvatar(avatarImage)
|
||||
else
|
||||
showTextAvatar(name, color)
|
||||
title = name
|
||||
nameView.setText(name)
|
||||
uriView.setText(contact.uri)
|
||||
uOrI = index.toString()
|
||||
}
|
||||
}
|
||||
|
||||
oldAndroid = androidCheck.isChecked
|
||||
|
||||
val avatarRequest =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
if (it.resultCode == Activity.RESULT_OK) {
|
||||
@ -175,12 +173,6 @@ class ContactActivity : AppCompatActivity() {
|
||||
getString(R.string.android_contact_help))
|
||||
}
|
||||
|
||||
androidCheck.setOnClickListener{
|
||||
if (Build.VERSION.SDK_INT >= 23)
|
||||
if (!Utils.checkPermissions(this, permissions))
|
||||
requestPermissions(permissions, CONTACT_PERMISSION_REQUEST_CODE)
|
||||
}
|
||||
|
||||
// Log.d(TAG, "Android sip contacts ${logAndroidContacts(this, "sip")}")
|
||||
// Log.d(TAG, "Android tel contacts ${logAndroidContacts(this, "tel")}")
|
||||
|
||||
@ -188,12 +180,6 @@ class ContactActivity : AppCompatActivity() {
|
||||
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
requestPermissionsLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(optionsMenu: Menu): Boolean {
|
||||
|
||||
super.onCreateOptionsMenu(optionsMenu)
|
||||
@ -205,48 +191,6 @@ class ContactActivity : AppCompatActivity() {
|
||||
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>,
|
||||
grandResults: IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grandResults)
|
||||
when (requestCode) {
|
||||
CONTACT_PERMISSION_REQUEST_CODE -> {
|
||||
var allowed = true
|
||||
for (res in grandResults)
|
||||
allowed = allowed && res == PackageManager.PERMISSION_GRANTED
|
||||
if (!allowed) {
|
||||
androidCheck.isChecked = oldAndroid
|
||||
when {
|
||||
ActivityCompat.shouldShowRequestPermissionRationale(this,
|
||||
Manifest.permission.READ_CONTACTS) -> {
|
||||
layout.showSnackBar(
|
||||
binding.root,
|
||||
getString(R.string.no_android_contacts),
|
||||
Snackbar.LENGTH_INDEFINITE,
|
||||
getString(R.string.ok)
|
||||
) {
|
||||
requestPermissionsLauncher.launch(permissions)
|
||||
}
|
||||
}
|
||||
ActivityCompat.shouldShowRequestPermissionRationale(this,
|
||||
Manifest.permission.WRITE_CONTACTS) -> {
|
||||
layout.showSnackBar(
|
||||
binding.root,
|
||||
getString(R.string.no_android_contacts),
|
||||
Snackbar.LENGTH_INDEFINITE,
|
||||
getString(R.string.ok)
|
||||
) {
|
||||
requestPermissionsLauncher.launch(permissions)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
requestPermissionsLauncher.launch(permissions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
||||
if (BaresipService.activities.indexOf("contact,$newContact,$uOrI") == -1) return true
|
||||
@ -265,11 +209,13 @@ class ContactActivity : AppCompatActivity() {
|
||||
String.format(getString(R.string.invalid_contact), newName))
|
||||
return false
|
||||
}
|
||||
|
||||
val alert: Boolean = if (newContact)
|
||||
ContactsActivity.nameExists(newName, true)
|
||||
else
|
||||
(Contact.contacts()[index].name != newName) &&
|
||||
ContactsActivity.nameExists(newName, false)
|
||||
Contact.nameExists(newName, true)
|
||||
else {
|
||||
val c = Contact.contacts()[index] as Contact.BaresipContact
|
||||
(c.name != newName) && Contact.nameExists(newName, false)
|
||||
}
|
||||
if (alert) {
|
||||
Utils.alertView(this, getString(R.string.notice),
|
||||
String.format(getString(R.string.contact_already_exists), newName))
|
||||
@ -287,7 +233,8 @@ class ContactActivity : AppCompatActivity() {
|
||||
return false
|
||||
}
|
||||
|
||||
val contact: Contact
|
||||
val contact: Contact.BaresipContact
|
||||
|
||||
if (newContact) {
|
||||
if (Contact.contacts().size >= Contact.CONTACTS_SIZE) {
|
||||
Utils.alertView(this, getString(R.string.notice),
|
||||
@ -296,16 +243,13 @@ class ContactActivity : AppCompatActivity() {
|
||||
BaresipService.activities.removeAt(0)
|
||||
return true
|
||||
} else {
|
||||
contact = Contact(newName, newUri, color, id)
|
||||
contact.androidContact = androidCheck.isChecked
|
||||
Contact.contacts().add(contact)
|
||||
contact = Contact.BaresipContact(newName, newUri, color, id)
|
||||
}
|
||||
} else {
|
||||
contact = Contact.contacts()[index]
|
||||
contact = Contact.contacts()[index] as Contact.BaresipContact
|
||||
contact.uri = newUri
|
||||
contact.name = newName
|
||||
contact.color = color
|
||||
contact.androidContact = androidCheck.isChecked
|
||||
}
|
||||
|
||||
when (newAvatar) {
|
||||
@ -323,21 +267,18 @@ class ContactActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
Contact.contacts().sortBy { Contact -> Contact.name }
|
||||
|
||||
if (Utils.checkPermissions(this, permissions)) {
|
||||
if (contact.androidContact)
|
||||
addOrUpdateAndroidContact(this, contact)
|
||||
else if (oldAndroid)
|
||||
deleteAndroidContact(this, contact)
|
||||
if (androidCheck.isChecked) {
|
||||
addOrUpdateAndroidContact(this, contact)
|
||||
} else {
|
||||
contact.androidContact = oldAndroid
|
||||
if (newContact)
|
||||
Contact.contacts().add(contact)
|
||||
Contact.sortContacts()
|
||||
Contact.generateContactNames()
|
||||
Contact.saveBaresipContacts()
|
||||
}
|
||||
|
||||
Contact.save()
|
||||
Utils.reloadContactNames()
|
||||
|
||||
BaresipService.activities.remove("contact,$newContact,$uOrI")
|
||||
|
||||
val i = Intent(this, MainActivity::class.java)
|
||||
i.putExtra("name", newName)
|
||||
setResult(Activity.RESULT_OK, i)
|
||||
@ -407,7 +348,7 @@ class ContactActivity : AppCompatActivity() {
|
||||
return rotatedBitmap
|
||||
}
|
||||
|
||||
private fun addOrUpdateAndroidContact(ctx: Context, contact: Contact) {
|
||||
private fun addOrUpdateAndroidContact(ctx: Context, contact: Contact.BaresipContact) {
|
||||
val projection = arrayOf(ContactsContract.Data.RAW_CONTACT_ID)
|
||||
val selection = ContactsContract.Data.MIMETYPE + "='" +
|
||||
CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "' AND " +
|
||||
@ -420,10 +361,9 @@ class ContactActivity : AppCompatActivity() {
|
||||
addAndroidContact(ctx, contact)
|
||||
}
|
||||
c?.close()
|
||||
contact.androidContact = true
|
||||
}
|
||||
|
||||
private fun addAndroidContact(ctx: Context, contact: Contact): Boolean {
|
||||
private fun addAndroidContact(ctx: Context, contact: Contact.BaresipContact): Boolean {
|
||||
val ops = ArrayList<ContentProviderOperation>()
|
||||
ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
|
||||
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
|
||||
@ -464,7 +404,7 @@ class ContactActivity : AppCompatActivity() {
|
||||
return true
|
||||
}
|
||||
|
||||
private fun updateAndroidContact(rawContactId: Long, contact: Contact) {
|
||||
private fun updateAndroidContact(rawContactId: Long, contact: Contact.BaresipContact) {
|
||||
if (updateAndroidUri(rawContactId, contact.uri) == 0)
|
||||
addAndroidUri(rawContactId, contact.uri)
|
||||
if (updateAndroidPhoto(rawContactId, contact.avatarImage) == 0)
|
||||
@ -561,9 +501,9 @@ class ContactActivity : AppCompatActivity() {
|
||||
|
||||
var contact: Contact? = null
|
||||
|
||||
fun deleteAndroidContact(ctx: Context, contact: Contact): Int {
|
||||
fun deleteAndroidContact(ctx: Context, name: String): Int {
|
||||
return ctx.contentResolver.delete(ContactsContract.RawContacts.CONTENT_URI,
|
||||
ContactsContract.Contacts.DISPLAY_NAME + "='" + contact.name + "'",
|
||||
ContactsContract.Contacts.DISPLAY_NAME + "='" + name + "'",
|
||||
null)
|
||||
}
|
||||
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
package com.tutpro.baresip
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.SystemClock
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.*
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.ImageButton
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat.startActivity
|
||||
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
||||
class ContactListAdapter(private val ctx: Context, private val rows: ArrayList<Contact>,
|
||||
private val aor: String) :
|
||||
@ -48,82 +48,137 @@ class ContactListAdapter(private val ctx: Context, private val rows: ArrayList<C
|
||||
|
||||
val contact = rows[position]
|
||||
|
||||
val avatarImage = contact.avatarImage
|
||||
if (avatarImage != null) {
|
||||
viewHolder.imageAvatarView.setImageBitmap(avatarImage)
|
||||
} else {
|
||||
viewHolder.textAvatarView.background.setTint(contact.color)
|
||||
if (contact.name.isNotEmpty())
|
||||
viewHolder.textAvatarView.text = "${contact.name[0]}"
|
||||
else
|
||||
viewHolder.textAvatarView.text = ""
|
||||
viewHolder.imageAvatarView.setImageBitmap(Utils.bitmapFromView(viewHolder.textAvatarView))
|
||||
}
|
||||
if (contact is Contact.BaresipContact) {
|
||||
|
||||
viewHolder.nameView.text = contact.name
|
||||
viewHolder.nameView.textSize = 20f
|
||||
viewHolder.nameView.setPadding(6, 6, 0, 6)
|
||||
val avatarImage = contact.avatarImage
|
||||
if (avatarImage != null) {
|
||||
viewHolder.imageAvatarView.setImageBitmap(avatarImage)
|
||||
} else {
|
||||
viewHolder.textAvatarView.background.setTint(contact.color)
|
||||
if (contact.name.isNotEmpty())
|
||||
viewHolder.textAvatarView.text = "${contact.name[0]}"
|
||||
else
|
||||
viewHolder.textAvatarView.text = ""
|
||||
viewHolder.imageAvatarView.setImageBitmap(Utils.bitmapFromView(viewHolder.textAvatarView))
|
||||
}
|
||||
|
||||
if (aor != "") {
|
||||
viewHolder.nameView.setOnClickListener {
|
||||
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
|
||||
when (which) {
|
||||
DialogInterface.BUTTON_POSITIVE, DialogInterface.BUTTON_NEGATIVE -> {
|
||||
val i = Intent(ctx, MainActivity::class.java)
|
||||
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK or
|
||||
Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
if (which == DialogInterface.BUTTON_NEGATIVE)
|
||||
i.putExtra("action", "call")
|
||||
else
|
||||
i.putExtra("action", "message")
|
||||
val ua = UserAgent.ofAor(aor)
|
||||
if (ua == null) {
|
||||
Log.w(TAG, "onClickListener did not find AoR $aor")
|
||||
} else {
|
||||
BaresipService.activities.clear()
|
||||
i.putExtra("uap", ua.uap)
|
||||
i.putExtra("peer", contact.uri)
|
||||
(ctx as Activity).startActivity(i)
|
||||
viewHolder.nameView.text = contact.name
|
||||
viewHolder.nameView.textSize = 20f
|
||||
viewHolder.nameView.setPadding(6, 6, 0, 6)
|
||||
|
||||
if (aor != "") {
|
||||
viewHolder.nameView.setOnClickListener {
|
||||
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
|
||||
when (which) {
|
||||
DialogInterface.BUTTON_POSITIVE, DialogInterface.BUTTON_NEGATIVE -> {
|
||||
val i = Intent(ctx, MainActivity::class.java)
|
||||
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK or
|
||||
Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
if (which == DialogInterface.BUTTON_NEGATIVE)
|
||||
i.putExtra("action", "call")
|
||||
else
|
||||
i.putExtra("action", "message")
|
||||
val ua = UserAgent.ofAor(aor)
|
||||
if (ua == null) {
|
||||
Log.w(TAG, "onClickListener did not find AoR $aor")
|
||||
} else {
|
||||
BaresipService.activities.clear()
|
||||
i.putExtra("uap", ua.uap)
|
||||
i.putExtra("peer", contact.uri)
|
||||
(ctx as Activity).startActivity(i)
|
||||
}
|
||||
}
|
||||
DialogInterface.BUTTON_NEUTRAL -> {
|
||||
}
|
||||
}
|
||||
DialogInterface.BUTTON_NEUTRAL -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SystemClock.elapsedRealtime() - lastClick > 1000) {
|
||||
lastClick = SystemClock.elapsedRealtime()
|
||||
with (AlertDialog.Builder(ctx, R.style.Theme_AppCompat)) {
|
||||
setMessage(String.format(ctx.getString(R.string.contact_action_question),
|
||||
Contact.contacts()[position].name))
|
||||
setNeutralButton(ctx.getText(R.string.cancel), dialogClickListener)
|
||||
setNegativeButton(ctx.getText(R.string.call), dialogClickListener)
|
||||
setPositiveButton(ctx.getText(R.string.send_message), dialogClickListener)
|
||||
show()
|
||||
if (SystemClock.elapsedRealtime() - lastClick > 1000) {
|
||||
lastClick = SystemClock.elapsedRealtime()
|
||||
with(AlertDialog.Builder(ctx, R.style.Theme_AppCompat)) {
|
||||
setMessage(String.format(ctx.getString(R.string.contact_action_question),
|
||||
contact.name))
|
||||
setNeutralButton(ctx.getText(R.string.cancel), dialogClickListener)
|
||||
setNegativeButton(ctx.getText(R.string.call), dialogClickListener)
|
||||
setPositiveButton(ctx.getText(R.string.send_message), dialogClickListener)
|
||||
show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewHolder.actionView.visibility = View.VISIBLE
|
||||
viewHolder.actionView.setOnClickListener {
|
||||
if (SystemClock.elapsedRealtime() - lastClick > 1000) {
|
||||
lastClick = SystemClock.elapsedRealtime()
|
||||
val i = Intent(ctx, ContactActivity::class.java)
|
||||
val b = Bundle()
|
||||
b.putBoolean("new", false)
|
||||
b.putInt("index", position)
|
||||
i.putExtras(b)
|
||||
startActivity(ctx, i, null)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (contact is Contact.AndroidContact) {
|
||||
|
||||
val thumbNailUri = contact.thumbnailUri
|
||||
if (thumbNailUri != null) {
|
||||
viewHolder.imageAvatarView.setImageURI(thumbNailUri)
|
||||
} else {
|
||||
viewHolder.textAvatarView.background.setTint(contact.color)
|
||||
if (contact.name.isNotEmpty())
|
||||
viewHolder.textAvatarView.text = "${contact.name[0]}"
|
||||
else
|
||||
viewHolder.textAvatarView.text = ""
|
||||
viewHolder.imageAvatarView.setImageBitmap(Utils.bitmapFromView(viewHolder.textAvatarView))
|
||||
}
|
||||
|
||||
viewHolder.nameView.text = contact.name
|
||||
viewHolder.nameView.textSize = 20f
|
||||
viewHolder.nameView.setPadding(6, 6, 0, 6)
|
||||
|
||||
viewHolder.nameView.setOnClickListener {
|
||||
if (SystemClock.elapsedRealtime() - lastClick > 1000) {
|
||||
lastClick = SystemClock.elapsedRealtime()
|
||||
val i = Intent(ctx, AndroidContactActivity::class.java)
|
||||
val b = Bundle()
|
||||
b.putString("aor", aor)
|
||||
b.putInt("index", position)
|
||||
i.putExtras(b)
|
||||
startActivity(ctx, i, null)
|
||||
}
|
||||
}
|
||||
|
||||
viewHolder.actionView.visibility = View.GONE
|
||||
|
||||
}
|
||||
|
||||
viewHolder.nameView.setOnLongClickListener {
|
||||
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
|
||||
when (which) {
|
||||
DialogInterface.BUTTON_POSITIVE -> {
|
||||
val id = contact.id
|
||||
val avatarFile = File(BaresipService.filesPath, "$id.img")
|
||||
if (avatarFile.exists()) {
|
||||
try {
|
||||
avatarFile.delete()
|
||||
} catch (e: IOException) {
|
||||
Log.e(TAG, "Could not delete file '$id.img")
|
||||
when (contact) {
|
||||
is Contact.BaresipContact -> {
|
||||
val id = contact.id
|
||||
val avatarFile = File(BaresipService.filesPath, "$id.img")
|
||||
if (avatarFile.exists()) {
|
||||
try {
|
||||
avatarFile.delete()
|
||||
} catch (e: IOException) {
|
||||
Log.e(TAG, "Could not delete file '$id.img")
|
||||
}
|
||||
}
|
||||
Contact.contacts().removeAt(position)
|
||||
Contact.contactNames().removeAt(position)
|
||||
Contact.saveBaresipContacts()
|
||||
this.notifyDataSetChanged()
|
||||
}
|
||||
is Contact.AndroidContact -> {
|
||||
ContactActivity.deleteAndroidContact(ctx, contact.name)
|
||||
}
|
||||
}
|
||||
if (contact.androidContact &&
|
||||
Utils.checkPermissions(ctx, arrayOf(Manifest.permission.WRITE_CONTACTS)))
|
||||
ContactActivity.deleteAndroidContact(ctx, contact)
|
||||
Contact.contacts().removeAt(position)
|
||||
Contact.save()
|
||||
Utils.reloadContactNames()
|
||||
this.notifyDataSetChanged()
|
||||
}
|
||||
DialogInterface.BUTTON_NEGATIVE -> {
|
||||
}
|
||||
@ -131,10 +186,13 @@ class ContactListAdapter(private val ctx: Context, private val rows: ArrayList<C
|
||||
}
|
||||
val titleView = View.inflate(ctx, R.layout.alert_title, null) as TextView
|
||||
titleView.text = ctx.getString(R.string.confirmation)
|
||||
with (AlertDialog.Builder(ctx)) {
|
||||
with(AlertDialog.Builder(ctx)) {
|
||||
setCustomTitle(titleView)
|
||||
setMessage(String.format(ctx.getString(R.string.contact_delete_question),
|
||||
Contact.contacts()[position].name))
|
||||
when (contact) {
|
||||
is Contact.BaresipContact -> contact.name
|
||||
is Contact.AndroidContact -> contact.name
|
||||
}))
|
||||
setNegativeButton(ctx.getText(R.string.cancel), dialogClickListener)
|
||||
setPositiveButton(ctx.getText(R.string.delete), dialogClickListener)
|
||||
show()
|
||||
@ -142,18 +200,6 @@ class ContactListAdapter(private val ctx: Context, private val rows: ArrayList<C
|
||||
true
|
||||
}
|
||||
|
||||
viewHolder.actionView.setOnClickListener {
|
||||
if (SystemClock.elapsedRealtime() - lastClick > 1000) {
|
||||
lastClick = SystemClock.elapsedRealtime()
|
||||
val i = Intent(ctx, ContactActivity::class.java)
|
||||
val b = Bundle()
|
||||
b.putBoolean("new", false)
|
||||
b.putInt("index", position)
|
||||
i.putExtras(b)
|
||||
startActivity(ctx, i, null)
|
||||
}
|
||||
}
|
||||
|
||||
return rowView
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,10 +4,10 @@ import android.app.Activity
|
||||
import android.content.*
|
||||
import android.os.Bundle
|
||||
import android.os.SystemClock
|
||||
import android.view.Menu
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import android.view.MenuItem
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.lifecycle.Observer
|
||||
import com.tutpro.baresip.databinding.ActivityContactsBinding
|
||||
|
||||
class ContactsActivity : AppCompatActivity() {
|
||||
@ -27,10 +27,15 @@ class ContactsActivity : AppCompatActivity() {
|
||||
Utils.addActivity("contacts,$aor")
|
||||
|
||||
val listView = binding.contacts
|
||||
clAdapter = ContactListAdapter(this, Contact.contacts(), aor)
|
||||
clAdapter = ContactListAdapter(this, BaresipService.contacts, aor)
|
||||
listView.adapter = clAdapter
|
||||
listView.isLongClickable = true
|
||||
|
||||
val contactObserver = Observer<Long> {
|
||||
clAdapter.notifyDataSetChanged()
|
||||
}
|
||||
BaresipService.contactUpdate.observe(this, contactObserver)
|
||||
|
||||
val contactRequest =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
if (it.resultCode == RESULT_OK)
|
||||
@ -58,34 +63,14 @@ class ContactsActivity : AppCompatActivity() {
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.swap_contacts_icon, menu)
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
||||
super.onResume()
|
||||
|
||||
clAdapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
||||
when (item.itemId) {
|
||||
|
||||
R.id.swapIcon -> {
|
||||
if (SystemClock.elapsedRealtime() - lastClick > 1000) {
|
||||
lastClick = SystemClock.elapsedRealtime()
|
||||
BaresipService.activities.remove("contacts,$aor")
|
||||
val intent = Intent(this, AndroidContactsActivity::class.java)
|
||||
intent.putExtra("aor", aor)
|
||||
startActivity(intent)
|
||||
finish()
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
android.R.id.home -> {
|
||||
BaresipService.activities.remove("contacts,$aor")
|
||||
setResult(Activity.RESULT_OK, Intent())
|
||||
@ -105,40 +90,4 @@ class ContactsActivity : AppCompatActivity() {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
// Return uri of contact name or null if contact is not found
|
||||
fun contactUri(name: String): String? {
|
||||
for (c in Contact.contacts())
|
||||
if (c.name.equals(name, ignoreCase = true))
|
||||
return c.uri.removePrefix("<")
|
||||
.replaceAfter(">", "")
|
||||
.replace(">", "")
|
||||
return null
|
||||
}
|
||||
|
||||
// Return contact name of uri or null if contact with uri is not found
|
||||
fun contactName(uri: String): String? {
|
||||
val userPart = Utils.uriUserPart(uri)
|
||||
return if (Utils.isTelNumber(userPart))
|
||||
findContact("tel:$userPart")?.name
|
||||
else
|
||||
findContact(uri)?.name
|
||||
}
|
||||
|
||||
fun findContact(uri: String): Contact? {
|
||||
for (c in Contact.contacts()) {
|
||||
if (Utils.uriMatch(c.uri, uri))
|
||||
return c
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun nameExists(name: String, ignoreCase: Boolean): Boolean {
|
||||
for (c in Contact.contacts())
|
||||
if (c.name.equals(name, ignoreCase = ignoreCase)) return true
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,11 +209,13 @@ class MainActivity : AppCompatActivity() {
|
||||
// Haven't found any explanation why this can happen.
|
||||
override fun onItemSelected(parent: AdapterView<*>, view: View?, position: Int, id: Long) {
|
||||
Log.d(TAG, "aorSpinner selecting $position")
|
||||
val acc = UserAgent.uas()[position].account
|
||||
aorSpinner.tag = acc.aor
|
||||
val ua = UserAgent.uas()[position]
|
||||
showCall(ua)
|
||||
updateIcons(acc)
|
||||
if (position < UserAgent.uas().size) {
|
||||
val acc = UserAgent.uas()[position].account
|
||||
aorSpinner.tag = acc.aor
|
||||
val ua = UserAgent.uas()[position]
|
||||
showCall(ua)
|
||||
updateIcons(acc)
|
||||
}
|
||||
}
|
||||
override fun onNothingSelected(parent: AdapterView<*>) {
|
||||
Log.d(TAG, "Nothing selected")
|
||||
@ -273,7 +275,7 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
callUri.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item,
|
||||
Utils.contactNames()))
|
||||
Contact.contactNames()))
|
||||
callUri.threshold = 2
|
||||
callUri.setOnFocusChangeListener { view, b ->
|
||||
if (b) {
|
||||
@ -456,27 +458,18 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
contactsRequest = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
callUri.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item,
|
||||
Utils.contactNames()))
|
||||
Contact.contactNames()))
|
||||
}
|
||||
|
||||
contactsButton.setOnClickListener {
|
||||
if (BaresipService.preferAndroidContacts) {
|
||||
val i = Intent(this@MainActivity, AndroidContactsActivity::class.java)
|
||||
if (aorSpinner.selectedItemPosition >= 0)
|
||||
i.putExtra("aor", aorSpinner.tag.toString())
|
||||
else
|
||||
i.putExtra("aor", "")
|
||||
startActivity(i)
|
||||
} else {
|
||||
val i = Intent(this@MainActivity, ContactsActivity::class.java)
|
||||
val b = Bundle()
|
||||
if (aorSpinner.selectedItemPosition >= 0)
|
||||
b.putString("aor", aorSpinner.tag.toString())
|
||||
else
|
||||
b.putString("aor", "")
|
||||
i.putExtras(b)
|
||||
contactsRequest.launch(i)
|
||||
}
|
||||
val i = Intent(this@MainActivity, ContactsActivity::class.java)
|
||||
val b = Bundle()
|
||||
if (aorSpinner.selectedItemPosition >= 0)
|
||||
b.putString("aor", aorSpinner.tag.toString())
|
||||
else
|
||||
b.putString("aor", "")
|
||||
i.putExtras(b)
|
||||
contactsRequest.launch(i)
|
||||
}
|
||||
|
||||
chatRequests = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
@ -932,6 +925,13 @@ class MainActivity : AppCompatActivity() {
|
||||
if (event == "started") {
|
||||
val callActionUri = params[0]
|
||||
Log.d(TAG, "Handling service event 'started' with '$callActionUri'")
|
||||
if (!this::uaAdapter.isInitialized) {
|
||||
// Android has restarted baresip when permission has been denied in app settings
|
||||
val i = Intent(this, MainActivity::class.java)
|
||||
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
startActivity(i)
|
||||
return
|
||||
}
|
||||
uaAdapter.notifyDataSetChanged()
|
||||
if (callActionUri != "") {
|
||||
var ua = UserAgent.ofDomain(Utils.uriHostPart(callActionUri))
|
||||
@ -1105,7 +1105,7 @@ class MainActivity : AppCompatActivity() {
|
||||
val call = Call.ofCallp(callp)!!
|
||||
val titleView = View.inflate(this, R.layout.alert_title, null) as TextView
|
||||
titleView.text = getString(R.string.transfer_request)
|
||||
val target = Utils.friendlyUri(Utils.contactName(ev[1]), Utils.aorDomain(aor))
|
||||
val target = Utils.friendlyUri(Contact.contactName(ev[1]), Utils.aorDomain(aor))
|
||||
with(AlertDialog.Builder(this)) {
|
||||
setCustomTitle(titleView)
|
||||
setMessage(String.format(getString(R.string.transfer_request_query),
|
||||
@ -1403,7 +1403,7 @@ class MainActivity : AppCompatActivity() {
|
||||
titleView.text = getString(R.string.call_transfer)
|
||||
val transferUri = layout.findViewById(R.id.transferUri) as AutoCompleteTextView
|
||||
transferUri.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item,
|
||||
Utils.contactNames()))
|
||||
Contact.contactNames()))
|
||||
transferUri.threshold = 2
|
||||
transferUri.requestFocus()
|
||||
val builder = AlertDialog.Builder(this)
|
||||
@ -1414,7 +1414,7 @@ class MainActivity : AppCompatActivity() {
|
||||
dialog.dismiss()
|
||||
var uriText = transferUri.text.toString().trim()
|
||||
if (uriText.isNotEmpty()) {
|
||||
uriText = Utils.contactUri(uriText) ?: uriText
|
||||
uriText = Contact.contactUri(uriText) ?: uriText
|
||||
if (Utils.isTelNumber(uriText))
|
||||
uriText = "tel:$uriText"
|
||||
val uri = if (Utils.isTelUri(uriText))
|
||||
@ -1702,7 +1702,7 @@ class MainActivity : AppCompatActivity() {
|
||||
if (Call.calls().isEmpty()) {
|
||||
var uriText = callUri.text.toString().trim()
|
||||
if (uriText.isNotEmpty()) {
|
||||
uriText = Utils.contactUri(uriText) ?: uriText
|
||||
uriText = Contact.contactUri(uriText) ?: uriText
|
||||
if (Utils.isTelNumber(uriText))
|
||||
uriText = "tel:$uriText"
|
||||
val uri = if (Utils.isTelUri(uriText)) {
|
||||
@ -1750,10 +1750,8 @@ class MainActivity : AppCompatActivity() {
|
||||
} else {
|
||||
val latest = NewCallHistory.aorLatestHistory(aor)
|
||||
if (latest != null)
|
||||
callUri.setText(
|
||||
Utils.friendlyUri(Utils.contactName(latest.peerUri), Utils.aorDomain(aor)
|
||||
)
|
||||
)
|
||||
callUri.setText(Utils.friendlyUri(Contact.contactName(latest.peerUri),
|
||||
Utils.aorDomain(aor)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1772,7 +1770,7 @@ class MainActivity : AppCompatActivity() {
|
||||
callUri.isFocusableInTouchMode = true
|
||||
imm.hideSoftInputFromWindow(callUri.windowToken, 0)
|
||||
callUri.setAdapter(ArrayAdapter(this, android.R.layout.select_dialog_item,
|
||||
Utils.contactNames()))
|
||||
Contact.contactNames()))
|
||||
securityButton.visibility = View.INVISIBLE
|
||||
callButton.visibility = View.VISIBLE
|
||||
callButton.isEnabled = true
|
||||
@ -1797,7 +1795,7 @@ class MainActivity : AppCompatActivity() {
|
||||
else
|
||||
getString(R.string.outgoing_call_to_dots)
|
||||
callTimer.visibility = View.INVISIBLE
|
||||
callUri.setText(Utils.friendlyUri(Utils.contactName(call.peerUri),
|
||||
callUri.setText(Utils.friendlyUri(Contact.contactName(call.peerUri),
|
||||
Utils.aorDomain(ua.account.aor)))
|
||||
securityButton.visibility = View.INVISIBLE
|
||||
callButton.visibility = View.INVISIBLE
|
||||
@ -1812,7 +1810,7 @@ class MainActivity : AppCompatActivity() {
|
||||
"incoming" -> {
|
||||
callTitle.text = getString(R.string.incoming_call_from_dots)
|
||||
callTimer.visibility = View.INVISIBLE
|
||||
callUri.setText(Utils.friendlyUri(Utils.contactName(call.peerUri),
|
||||
callUri.setText(Utils.friendlyUri(Contact.contactName(call.peerUri),
|
||||
Utils.aorDomain(ua.account.aor)))
|
||||
callUri.setAdapter(null)
|
||||
securityButton.visibility = View.INVISIBLE
|
||||
@ -1832,7 +1830,7 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
if (call.referTo != "") {
|
||||
callTitle.text = getString(R.string.transferring_call_to_dots)
|
||||
callUri.setText(Utils.friendlyUri(Utils.contactName(call.referTo),
|
||||
callUri.setText(Utils.friendlyUri(Contact.contactName(call.referTo),
|
||||
Utils.aorDomain(ua.account.aor)))
|
||||
transferButton.isEnabled = false
|
||||
} else {
|
||||
@ -1840,7 +1838,7 @@ class MainActivity : AppCompatActivity() {
|
||||
callTitle.text = getString(R.string.outgoing_call_to_dots)
|
||||
else
|
||||
callTitle.text = getString(R.string.incoming_call_from_dots)
|
||||
callUri.setText(Utils.friendlyUri(Utils.contactName(call.peerUri),
|
||||
callUri.setText(Utils.friendlyUri(Contact.contactName(call.peerUri),
|
||||
Utils.aorDomain(ua.account.aor)))
|
||||
transferButton.isEnabled = true
|
||||
}
|
||||
@ -1973,21 +1971,6 @@ class MainActivity : AppCompatActivity() {
|
||||
i.putExtras(b)
|
||||
startActivity(i)
|
||||
}
|
||||
"android contacts" -> {
|
||||
val i = Intent(this, AndroidContactsActivity::class.java)
|
||||
val b = Bundle()
|
||||
b.putString("aor", activity[1])
|
||||
i.putExtras(b)
|
||||
startActivity(i)
|
||||
}
|
||||
"android contact" -> {
|
||||
val i = Intent(this, AndroidContactActivity::class.java)
|
||||
val b = Bundle()
|
||||
b.putString("aor", activity[1])
|
||||
b.putInt("index", activity[2].toInt())
|
||||
i.putExtras(b)
|
||||
startActivity(i)
|
||||
}
|
||||
"chats" -> {
|
||||
val i = Intent(this, ChatsActivity::class.java)
|
||||
val b = Bundle()
|
||||
|
||||
@ -45,7 +45,7 @@ class MessageListAdapter(private val ctx: Context, private val rows: ArrayList<M
|
||||
val peer: String = if (down) {
|
||||
lp.setMargins(0, 10, 75, 10)
|
||||
viewHolder.layoutView.setBackgroundResource(R.drawable.message_in_bg)
|
||||
val contactName = Utils.contactName(message.peerUri)
|
||||
val contactName = Contact.contactName(message.peerUri)
|
||||
if (contactName.startsWith("sip:") &&
|
||||
(Utils.uriHostPart(message.peerUri) == Utils.uriHostPart(message.aor)))
|
||||
Utils.uriUserPart(message.peerUri)
|
||||
|
||||
@ -320,57 +320,43 @@ object Utils {
|
||||
name.lines().size == 1 && !name.contains('"')
|
||||
}
|
||||
|
||||
fun contactName(uri: String) : String {
|
||||
return ContactsActivity.contactName(uri) ?: AndroidContactsActivity.contactName(uri)
|
||||
}
|
||||
|
||||
fun contactUri(name: String) : String? {
|
||||
return ContactsActivity.contactUri(name) ?: AndroidContactsActivity.contactUri(name)
|
||||
}
|
||||
|
||||
fun reloadContactNames() {
|
||||
BaresipService.contactNames.clear()
|
||||
BaresipService.contactNames.addAll(Contact.contacts().map{Contact -> Contact.name})
|
||||
BaresipService.contactNames.addAll(AndroidContact.contacts().map{AndroidContact -> AndroidContact.name})
|
||||
BaresipService.contactNames.sort()
|
||||
}
|
||||
|
||||
fun contactNames() : List<String> {
|
||||
return BaresipService.contactNames
|
||||
}
|
||||
|
||||
fun setAvatar(ctx: Context, imageView: ImageView, textView: TextView, uri: String) {
|
||||
val contact = ContactsActivity.findContact(uri)
|
||||
if (contact != null) {
|
||||
val avatarImage = contact.avatarImage
|
||||
if (avatarImage != null) {
|
||||
imageView.setImageBitmap(avatarImage)
|
||||
} else {
|
||||
textView.background.setTint(contact.color)
|
||||
if (contact.name.isNotEmpty())
|
||||
textView.text = "${contact.name[0]}"
|
||||
else
|
||||
textView.text = ""
|
||||
imageView.setImageBitmap(bitmapFromView(textView))
|
||||
}
|
||||
} else {
|
||||
val androidContact = AndroidContactsActivity.findContact(uri)
|
||||
if (androidContact != null) {
|
||||
val thumbnailUri = androidContact.thumbnailUri
|
||||
if (thumbnailUri != null) {
|
||||
imageView.setImageURI(thumbnailUri)
|
||||
|
||||
when (val contact = Contact.findContact(uri)) {
|
||||
|
||||
is Contact.BaresipContact -> {
|
||||
val avatarImage = contact.avatarImage
|
||||
if (avatarImage != null) {
|
||||
imageView.setImageBitmap(avatarImage)
|
||||
} else {
|
||||
textView.background.setTint(androidContact.color)
|
||||
if (androidContact.name.isNotEmpty())
|
||||
textView.text = "${androidContact.name[0]}"
|
||||
textView.background.setTint(contact.color)
|
||||
if (contact.name.isNotEmpty())
|
||||
textView.text = "${contact.name[0]}"
|
||||
else
|
||||
textView.text = ""
|
||||
imageView.setImageBitmap(bitmapFromView(textView))
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
is Contact.AndroidContact -> {
|
||||
val thumbnailUri = contact.thumbnailUri
|
||||
if (thumbnailUri != null) {
|
||||
imageView.setImageURI(thumbnailUri)
|
||||
} else {
|
||||
textView.background.setTint(contact.color)
|
||||
if (contact.name.isNotEmpty())
|
||||
textView.text = "${contact.name[0]}"
|
||||
else
|
||||
textView.text = ""
|
||||
imageView.setImageBitmap(bitmapFromView(textView))
|
||||
}
|
||||
}
|
||||
|
||||
null -> {
|
||||
val bitmap = BitmapFactory.decodeResource(ctx.resources, R.drawable.person_image)
|
||||
imageView.setImageBitmap(bitmap)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -215,37 +215,27 @@
|
||||
android:id="@+id/AudioSettingsTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/audio_settings" >
|
||||
</TextView>
|
||||
|
||||
<RelativeLayout
|
||||
<TextView
|
||||
android:id="@+id/ContactsTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="18sp"
|
||||
android:text="@string/contacts" >
|
||||
</TextView>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/contactsSpinner"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:orientation="horizontal" >
|
||||
<TextView
|
||||
android:id="@+id/AndroidContactsTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toStartOf="@id/AndroidContacts"
|
||||
android:textSize="18sp"
|
||||
android:text="@string/show_android_contacts" >
|
||||
</TextView>
|
||||
<CheckBox
|
||||
android:id="@+id/AndroidContacts"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_gravity="end"
|
||||
android:checked="false" >
|
||||
</CheckBox>
|
||||
</RelativeLayout>
|
||||
android:paddingTop="8dp" >
|
||||
</Spinner>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@ -262,6 +262,7 @@
|
||||
android:src="@drawable/voicemail"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:visibility="invisible"
|
||||
android:contentDescription="@string/voicemail" >
|
||||
</ImageButton>
|
||||
|
||||
|
||||
@ -329,9 +329,7 @@
|
||||
<string name="video_size_help">Size of transmitted video frames (width x height).
|
||||
Factory default is 800x600.</string>
|
||||
<string name="android_settings">Android Settings</string>
|
||||
<string name="show_android_contacts">Show Android Contacts</string>
|
||||
<string name="show_android_contacts_help">If checked, Android contacts are shown when Contacts
|
||||
button is touched.</string>
|
||||
<string name="contacts_help">Chooses if baresip contacts, Android contacts, or both will be used.</string>
|
||||
<string name="debug">Debug</string>
|
||||
<string name="debug_help">If checked, provides debug and info level log messages to Logcat.</string>
|
||||
<string name="sip_trace">SIP Trace</string>
|
||||
@ -356,8 +354,7 @@
|
||||
<string name="invalid_contact">Invalid contact name \'%1$s\'</string>
|
||||
<string name="contact_already_exists">Contact \'%1$s\' already exists.</string>
|
||||
<string name="invalid_contact_uri">Invalid SIP URI</string>
|
||||
<string name="android" translatable="false">Android</string>
|
||||
<string name="android_contact_help">If checked, this contact is available also in Android contacts.</string>
|
||||
<string name="android_contact_help">If checked, this contact is added to Android contacts.</string>
|
||||
<string name="avatar_image">Profile image</string>
|
||||
<!-- Contacts Activity -->
|
||||
<string name="contacts">Contacts</string>
|
||||
@ -392,6 +389,9 @@
|
||||
<string name="dots" translatable="false">…</string>
|
||||
<string name="bullet_item" translatable="false">\u2022 %1$s</string>
|
||||
<string name="invalid_sip_or_tel_uri">Invalid SIP or tel URI \'%1$s\'</string>
|
||||
<string name="baresip" translatable="false">baresip</string>
|
||||
<string name="android" translatable="false">Android</string>
|
||||
<string name="both">Both</string>
|
||||
<!-- Main Activity -->
|
||||
<string name="backup">Backup</string>
|
||||
<string name="restore">Restore</string>
|
||||
|
||||
Reference in New Issue
Block a user