Added call details activity that can be accessed by touching time in call history list

This commit is contained in:
Juha Heinanen
2022-01-18 17:29:14 +02:00
parent 3a3198a403
commit 34fc9220f8
14 changed files with 329 additions and 50 deletions
+6
View File
@@ -109,6 +109,12 @@
android:label="@string/call_history" android:label="@string/call_history"
android:parentActivityName=".MainActivity" > android:parentActivityName=".MainActivity" >
</activity> </activity>
<activity
android:name=".CallDetailsActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/call_details"
android:parentActivityName=".CallsActivity" >
</activity>
<activity <activity
android:name=".ChatsActivity" android:name=".ChatsActivity"
android:configChanges="orientation|keyboardHidden|screenSize" android:configChanges="orientation|keyboardHidden|screenSize"
@@ -0,0 +1,64 @@
package com.tutpro.baresip
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.MenuItem
import com.tutpro.baresip.databinding.ActivityCallDetailsBinding
class CallDetailsActivity : AppCompatActivity() {
private lateinit var binding: ActivityCallDetailsBinding
private lateinit var aor: String
private lateinit var peer: String
private var position = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_call_details)
binding = ActivityCallDetailsBinding.inflate(layoutInflater)
setContentView(binding.root)
aor = intent.getStringExtra("aor")!!
peer = intent.getStringExtra("peer")!!
position = intent.getIntExtra("position", 0)
Utils.addActivity("call_details,$aor,$peer,$position")
val headerView = binding.peer
val headerText = "${getString(R.string.peer)} $peer"
headerView.text = headerText
val listView = binding.calls
listView.adapter = CallDetailsAdapter(this, CallsActivity.uaHistory[position].details)
}
override fun onPause() {
MainActivity.activityAor = aor
super.onPause()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (BaresipService.activities.indexOf("call_details,$aor,$peer,$position") == -1)
return true
when (item.itemId) {
android.R.id.home -> {
onBackPressed()
return true
}
}
return super.onOptionsItemSelected(item)
}
override fun onBackPressed() {
BaresipService.activities.remove("call_details,$aor,$peer,$position")
finish()
super.onBackPressed()
}
}
@@ -0,0 +1,77 @@
package com.tutpro.baresip
import android.content.Context
import android.text.format.DateUtils
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.text.DateFormat
import java.util.*
class CallDetailsAdapter(private val ctx: Context, private val rows: ArrayList<CallRow.Details>) :
ArrayAdapter<CallRow.Details>(ctx, R.layout.call_detail_row, rows) {
private val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
private class ViewHolder(view: View?) {
val directionView = view?.findViewById(R.id.direction) as ImageView
val timeView = view?.findViewById(R.id.time) as TextView
val durationView = view?.findViewById(R.id.duration) 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.call_detail_row, parent, false)
viewHolder = ViewHolder(rowView)
rowView.tag = viewHolder
} else {
rowView = view
viewHolder = rowView.tag as ViewHolder
}
val direction = rows[position].direction
viewHolder.directionView.setImageResource(direction)
val startTime = rows[position].startTime
val stopTime = rows[position].stopTime
val stopText = if (DateUtils.isToday(stopTime.timeInMillis)) {
val fmt = DateFormat.getTimeInstance(DateFormat.LONG)
ctx.getString(R.string.today) + " " + fmt.format(stopTime.time)
} else {
val fmt = DateFormat.getDateTimeInstance()
fmt.format(stopTime.time)
}
if (startTime == GregorianCalendar(0, 0, 0)) {
viewHolder.timeView.text = stopText
viewHolder.durationView.text = "?"
} else {
if (startTime == null) {
viewHolder.timeView.text = stopText
viewHolder.durationView.text = ""
} else {
val startText = if (DateUtils.isToday(startTime.timeInMillis)) {
val fmt = DateFormat.getTimeInstance(DateFormat.LONG)
ctx.getString(R.string.today) + " " + fmt.format(startTime.time)
} else {
val fmt = DateFormat.getDateTimeInstance()
fmt.format(startTime.time)
}
viewHolder.timeView.text = startText
val duration = (stopTime.time.time - startTime.time.time) / 1000
viewHolder.durationView.text = DateUtils.formatElapsedTime(duration)
}
}
return rowView
}
}
@@ -1,6 +1,8 @@
package com.tutpro.baresip package com.tutpro.baresip
import android.content.Context import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.cardview.widget.CardView import androidx.cardview.widget.CardView
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@@ -12,15 +14,15 @@ import android.widget.TextView
import java.util.* import java.util.*
class CallListAdapter(private val cxt: Context, private val rows: ArrayList<CallRow>) : class CallListAdapter(private val ctx: Context, private val aor: String, private val rows: ArrayList<CallRow>) :
ArrayAdapter<CallRow>(cxt, R.layout.call_row, rows) { ArrayAdapter<CallRow>(ctx, R.layout.call_row, rows) {
private val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater private val layoutInflater = LayoutInflater.from(context)
private class ViewHolder(view: View?) { private class ViewHolder(view: View?) {
val textAvatarView = view?.findViewById(R.id.TextAvatar) as TextView val textAvatarView = view?.findViewById(R.id.TextAvatar) as TextView
val cardAvatarView = view?.findViewById(R.id.CardAvatar) as CardView val cardAvatarView = view?.findViewById(R.id.CardAvatar) as CardView
val cardImageAvatarView = view?.findViewById(R.id.CardImageAvatar) as ImageView val imageAvatarView = view?.findViewById(R.id.ImageAvatar) as ImageView
val directionsView = view?.findViewById(R.id.directions) as LinearLayout val directionsView = view?.findViewById(R.id.directions) as LinearLayout
val etcView = view?.findViewById(R.id.etc) as TextView val etcView = view?.findViewById(R.id.etc) as TextView
val peerURIView = view?.findViewById(R.id.peer_uri) as TextView val peerURIView = view?.findViewById(R.id.peer_uri) as TextView
@@ -42,18 +44,22 @@ class CallListAdapter(private val cxt: Context, private val rows: ArrayList<Call
} }
val callRow = rows[position] val callRow = rows[position]
val contact = ContactsActivity.findContact(callRow.peerUri) val contact = ContactsActivity.findContact(callRow.peerUri)
if (contact != null) { if (contact != null) {
val avatarImage = contact.avatarImage val avatarImage = contact.avatarImage
if (avatarImage != null) { if (avatarImage != null) {
viewHolder.textAvatarView.visibility = View.GONE viewHolder.textAvatarView.visibility = View.GONE
viewHolder.cardAvatarView.visibility = View.VISIBLE viewHolder.cardAvatarView.visibility = View.VISIBLE
viewHolder.cardImageAvatarView.setImageBitmap(avatarImage) viewHolder.imageAvatarView.setImageBitmap(avatarImage)
} else { } else {
viewHolder.textAvatarView.visibility = View.VISIBLE viewHolder.textAvatarView.visibility = View.VISIBLE
viewHolder.cardAvatarView.visibility = View.GONE viewHolder.cardAvatarView.visibility = View.GONE
viewHolder.textAvatarView.background.setTint(contact.color) viewHolder.textAvatarView.background.setTint(contact.color)
viewHolder.textAvatarView.text = "${contact.name[0]}" if (contact.name.isNotEmpty())
viewHolder.textAvatarView.text = "${contact.name[0]}"
else
viewHolder.textAvatarView.text = ""
} }
} else { } else {
viewHolder.textAvatarView.visibility = View.VISIBLE viewHolder.textAvatarView.visibility = View.VISIBLE
@@ -63,17 +69,17 @@ class CallListAdapter(private val cxt: Context, private val rows: ArrayList<Call
viewHolder.directionsView.removeAllViews() viewHolder.directionsView.removeAllViews()
var count = 1 var count = 1
for (d in callRow.directions) { for (d in callRow.details) {
if (count > 3) { if (count > 3) {
viewHolder.etcView.text = "..." viewHolder.etcView.text = "..."
break break
} }
val dirView = ImageView(cxt) val dirView = ImageView(ctx)
val params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, val params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT) ViewGroup.LayoutParams.WRAP_CONTENT)
dirView.layoutParams = params dirView.layoutParams = params
dirView.setPadding(0, 5, 0, 0) dirView.setPadding(0, 5, 0, 0)
dirView.setImageResource(d) dirView.setImageResource(d.direction)
viewHolder.directionsView.addView(dirView) viewHolder.directionsView.addView(dirView)
count++ count++
} }
@@ -84,7 +90,17 @@ class CallListAdapter(private val cxt: Context, private val rows: ArrayList<Call
else else
viewHolder.peerURIView.text = contactName viewHolder.peerURIView.text = contactName
viewHolder.timeView.text = callRow.stopTime viewHolder.timeView.text = Utils.relativeTime(ctx, callRow.stopTime)
viewHolder.timeView.setOnClickListener {
val i = Intent(ctx, CallDetailsActivity::class.java)
val b = Bundle()
b.putString("aor", aor)
b.putString("peer", viewHolder.peerURIView.text!!.toString())
b.putInt("position", position)
i.putExtras(b)
ctx.startActivity(i)
}
return rowView return rowView
} }
@@ -1,13 +1,17 @@
package com.tutpro.baresip package com.tutpro.baresip
class CallRow(val aor: String, val peerUri: String, val direction: Int, val stopTime: String, val index: Int) { import java.util.*
import kotlin.collections.ArrayList
val directions = ArrayList<Int>() class CallRow(val aor: String, val peerUri: String, val direction: Int,
val indexes = ArrayList<Int>() startTime: GregorianCalendar?, val stopTime: GregorianCalendar) {
class Details(val direction: Int, val startTime: GregorianCalendar?, val stopTime: GregorianCalendar)
val details = ArrayList<Details>()
init { init {
directions.add(direction) details.add(Details(direction, startTime, stopTime))
indexes.add(index)
} }
} }
@@ -7,7 +7,6 @@ import android.os.Bundle
import android.os.SystemClock import android.os.SystemClock
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.text.format.DateUtils.isToday
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
@@ -16,7 +15,6 @@ import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import com.tutpro.baresip.databinding.ActivityCallsBinding import com.tutpro.baresip.databinding.ActivityCallsBinding
import java.text.DateFormat
import java.util.* import java.util.*
class CallsActivity : AppCompatActivity() { class CallsActivity : AppCompatActivity() {
@@ -46,7 +44,7 @@ class CallsActivity : AppCompatActivity() {
val listView = binding.calls val listView = binding.calls
aorGenerateHistory(aor) aorGenerateHistory(aor)
clAdapter = CallListAdapter(this, uaHistory) clAdapter = CallListAdapter(this, aor, uaHistory)
listView.adapter = clAdapter listView.adapter = clAdapter
listView.isLongClickable = true listView.isLongClickable = true
@@ -117,7 +115,7 @@ class CallsActivity : AppCompatActivity() {
} }
} }
} }
val callText: String = if (uaHistory[pos].directions.size > 1) val callText: String = if (uaHistory[pos].details.size > 1)
getString(R.string.calls_calls) getString(R.string.calls_calls)
else else
getString(R.string.calls_call) getString(R.string.calls_call)
@@ -236,33 +234,19 @@ class CallsActivity : AppCompatActivity() {
R.drawable.arrow_up_green R.drawable.arrow_up_green
else else
R.drawable.arrow_up_red R.drawable.arrow_up_red
if (uaHistory.isNotEmpty() && (uaHistory.last().peerUri == h.peerUri)) { if (uaHistory.isNotEmpty() && (uaHistory.last().peerUri == h.peerUri))
uaHistory.last().directions.add(direction) uaHistory.last().details.add(CallRow.Details(direction, h.startTime, h.stopTime))
uaHistory.last().indexes.add(i) else
} else { uaHistory.add(CallRow(h.aor, h.peerUri, direction, h.startTime, h.stopTime))
val time = if (isToday(h.stopTime.timeInMillis)) {
val fmt = DateFormat.getTimeInstance(DateFormat.SHORT)
getString(R.string.today) + "\n" + fmt.format(h.stopTime.time)
} else {
val month = h.stopTime.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault())
val day = h.stopTime.get(Calendar.DAY_OF_MONTH)
val currentYear = Calendar.getInstance().get(Calendar.YEAR)
if (h.stopTime.get(Calendar.YEAR) == currentYear) {
val fmt = DateFormat.getTimeInstance(DateFormat.SHORT)
"$month $day" + "\n" + fmt.format(h.stopTime.time)
} else {
"$month $day" + "\n" + h.stopTime.get(Calendar.YEAR)
}
}
uaHistory.add(CallRow(h.aor, h.peerUri, direction, time, i))
}
} }
} }
} }
private fun removeUaHistoryAt(i: Int) { private fun removeUaHistoryAt(i: Int) {
for (index in uaHistory[i].indexes) for (details in uaHistory[i].details)
BaresipService.callHistory.removeAt(index) BaresipService.callHistory.removeAll {
it.startTime == details.startTime && it.stopTime == details.stopTime
}
uaHistory.removeAt(i) uaHistory.removeAt(i)
} }
@@ -88,6 +88,7 @@ class MainActivity : AppCompatActivity() {
private lateinit var restoreRequest: ActivityResultLauncher<Intent> private lateinit var restoreRequest: ActivityResultLauncher<Intent>
private lateinit var contactsRequest: ActivityResultLauncher<Intent> private lateinit var contactsRequest: ActivityResultLauncher<Intent>
private lateinit var callsRequest: ActivityResultLauncher<Intent> private lateinit var callsRequest: ActivityResultLauncher<Intent>
private lateinit var callDetailsRequest: ActivityResultLauncher<Intent>
private var downloadsInputStream: FileInputStream? = null private var downloadsInputStream: FileInputStream? = null
private var downloadsOutputStream: FileOutputStream? = null private var downloadsOutputStream: FileOutputStream? = null
@@ -1920,6 +1921,15 @@ class MainActivity : AppCompatActivity() {
i.putExtras(b) i.putExtras(b)
callsRequest.launch(i) callsRequest.launch(i)
} }
"call_details" -> {
val i = Intent(this, CallDetailsActivity::class.java)
val b = Bundle()
b.putString("aor", activity[1])
b.putString("peer", activity[2])
b.putInt("position", activity[3].toInt())
i.putExtras(b)
callsRequest.launch(i)
}
} }
return return
} }
@@ -18,13 +18,13 @@ import android.provider.MediaStore
import android.provider.OpenableColumns import android.provider.OpenableColumns
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.text.format.DateUtils
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
import android.widget.TextView import android.widget.TextView
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ProcessLifecycleOwner import androidx.lifecycle.ProcessLifecycleOwner
@@ -39,6 +39,7 @@ import java.util.zip.ZipOutputStream
import java.net.InetAddress import java.net.InetAddress
import java.net.NetworkInterface import java.net.NetworkInterface
import java.net.SocketException import java.net.SocketException
import java.text.DateFormat
import javax.crypto.Cipher import javax.crypto.Cipher
import javax.crypto.SecretKeyFactory import javax.crypto.SecretKeyFactory
import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.IvParameterSpec
@@ -694,4 +695,20 @@ object Utils {
} }
} }
fun relativeTime(ctx: Context, time: GregorianCalendar): String {
return if (DateUtils.isToday(time.timeInMillis)) {
val fmt = DateFormat.getTimeInstance(DateFormat.SHORT)
ctx.getString(R.string.today) + "\n" + fmt.format(time.time)
} else {
val month = time.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault())
val day = time.get(Calendar.DAY_OF_MONTH)
val currentYear = Calendar.getInstance().get(Calendar.YEAR)
if (time.get(Calendar.YEAR) == currentYear) {
val fmt = DateFormat.getTimeInstance(DateFormat.SHORT)
"$month $day" + "\n" + fmt.format(time.time)
} else {
"$month $day" + "\n" + time.get(Calendar.YEAR)
}
}
}
} }
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".CallDetailsActivity">
<TextView
android:id="@+id/peer"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:textSize="16sp"
android:gravity="center_horizontal" >
</TextView>
<RelativeLayout
android:id="@+id/headings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/peer"
android:orientation="horizontal" >
<TextView android:id="@+id/direction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:textSize="16sp"
android:text="@string/direction" >
</TextView>
<TextView android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginStart="76dp"
android:textSize="16sp"
android:text="@string/time" >
</TextView>
<TextView android:id="@+id/duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:textSize="16sp"
android:text="@string/calls_duration">
</TextView>
</RelativeLayout>
<ListView
android:id="@+id/calls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/headings"
android:layout_marginTop="12dp"
android:divider="#00000000"
android:dividerHeight="10dp" >
</ListView>
</RelativeLayout>
@@ -14,6 +14,7 @@
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
android:textSize="16sp"
android:gravity="center_horizontal" > android:gravity="center_horizontal" >
</TextView> </TextView>
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<ImageView
android:id="@+id/direction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginStart="12dp"
android:contentDescription="@string/direction" />
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginStart="76dp"
android:text="" />
<TextView
android:id="@+id/duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:text="" />
</RelativeLayout>
+4 -8
View File
@@ -1,13 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_height="fill_parent" android:orientation="horizontal" >
android:layout_marginBottom="0dp"
android:layout_marginTop="0dp"
android:layout_gravity="center_vertical"
android:descendantFocusability="blocksDescendants" >
<TextView <TextView
android:id="@+id/TextAvatar" android:id="@+id/TextAvatar"
@@ -30,7 +26,7 @@
app:cardCornerRadius="18dp" > app:cardCornerRadius="18dp" >
<ImageView <ImageView
android:id="@+id/CardImageAvatar" android:id="@+id/ImageAvatar"
android:contentDescription="@string/avatar_image" android:contentDescription="@string/avatar_image"
android:layout_height="36dp" android:layout_height="36dp"
android:layout_width="36dp" android:layout_width="36dp"
+4
View File
@@ -242,6 +242,10 @@
<string name="call">Soita</string> <string name="call">Soita</string>
<string name="calls_calls">puhelut</string> <string name="calls_calls">puhelut</string>
<string name="calls_call">puhelun</string> <string name="calls_call">puhelun</string>
<string name="direction">Suunta</string>
<string name="peer">Pääri</string>
<string name="time">Aika</string>
<string name="calls_duration">Kesto</string>
<string name="calls_call_message_question">Haluatko soittaa tai lähettää viestin kohteeseen <string name="calls_call_message_question">Haluatko soittaa tai lähettää viestin kohteeseen
\'%1$s\'? \'%1$s\'?
</string> </string>
+5
View File
@@ -215,9 +215,14 @@
<string name="tap_to_start">Tap to start application</string> <string name="tap_to_start">Tap to start application</string>
<!-- Calls Activity --> <!-- Calls Activity -->
<string name="call_history">Call History</string> <string name="call_history">Call History</string>
<string name="call_details">Call Details</string>
<string name="call">Call</string> <string name="call">Call</string>
<string name="calls_calls">calls</string> <string name="calls_calls">calls</string>
<string name="calls_call">call</string> <string name="calls_call">call</string>
<string name="peer">Peer</string>
<string name="direction">Direction</string>
<string name="time">Time</string>
<string name="calls_duration">Duration</string>
<string name="calls_call_message_question">Do you want to call or send message to \'%1$s\'?</string> <string name="calls_call_message_question">Do you want to call or send message to \'%1$s\'?</string>
<string name="calls_add_delete_question">Do you want to add \'%1$s\' to contacts or delete <string name="calls_add_delete_question">Do you want to add \'%1$s\' to contacts or delete
%2$s from call history? %2$s from call history?