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

View File

@ -109,6 +109,12 @@
android:label="@string/call_history"
android:parentActivityName=".MainActivity" >
</activity>
<activity
android:name=".CallDetailsActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/call_details"
android:parentActivityName=".CallsActivity" >
</activity>
<activity
android:name=".ChatsActivity"
android:configChanges="orientation|keyboardHidden|screenSize"

View File

@ -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()
}
}

View File

@ -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
}
}

View File

@ -1,6 +1,8 @@
package com.tutpro.baresip
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.cardview.widget.CardView
import android.view.LayoutInflater
import android.view.View
@ -12,15 +14,15 @@ import android.widget.TextView
import java.util.*
class CallListAdapter(private val cxt: Context, private val rows: ArrayList<CallRow>) :
ArrayAdapter<CallRow>(cxt, R.layout.call_row, rows) {
class CallListAdapter(private val ctx: Context, private val aor: String, private val rows: ArrayList<CallRow>) :
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?) {
val textAvatarView = view?.findViewById(R.id.TextAvatar) as TextView
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 etcView = view?.findViewById(R.id.etc) 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 contact = ContactsActivity.findContact(callRow.peerUri)
if (contact != null) {
val avatarImage = contact.avatarImage
if (avatarImage != null) {
viewHolder.textAvatarView.visibility = View.GONE
viewHolder.cardAvatarView.visibility = View.VISIBLE
viewHolder.cardImageAvatarView.setImageBitmap(avatarImage)
viewHolder.imageAvatarView.setImageBitmap(avatarImage)
} else {
viewHolder.textAvatarView.visibility = View.VISIBLE
viewHolder.cardAvatarView.visibility = View.GONE
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 {
viewHolder.textAvatarView.visibility = View.VISIBLE
@ -63,17 +69,17 @@ class CallListAdapter(private val cxt: Context, private val rows: ArrayList<Call
viewHolder.directionsView.removeAllViews()
var count = 1
for (d in callRow.directions) {
for (d in callRow.details) {
if (count > 3) {
viewHolder.etcView.text = "..."
break
}
val dirView = ImageView(cxt)
val dirView = ImageView(ctx)
val params = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT)
dirView.layoutParams = params
dirView.setPadding(0, 5, 0, 0)
dirView.setImageResource(d)
dirView.setImageResource(d.direction)
viewHolder.directionsView.addView(dirView)
count++
}
@ -84,7 +90,17 @@ class CallListAdapter(private val cxt: Context, private val rows: ArrayList<Call
else
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
}

View File

@ -1,13 +1,17 @@
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>()
val indexes = ArrayList<Int>()
class CallRow(val aor: String, val peerUri: String, val direction: Int,
startTime: GregorianCalendar?, val stopTime: GregorianCalendar) {
class Details(val direction: Int, val startTime: GregorianCalendar?, val stopTime: GregorianCalendar)
val details = ArrayList<Details>()
init {
directions.add(direction)
indexes.add(index)
details.add(Details(direction, startTime, stopTime))
}
}

View File

@ -7,7 +7,6 @@ import android.os.Bundle
import android.os.SystemClock
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import android.text.format.DateUtils.isToday
import android.view.Menu
import android.view.MenuItem
import android.view.View
@ -16,7 +15,6 @@ import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import com.tutpro.baresip.databinding.ActivityCallsBinding
import java.text.DateFormat
import java.util.*
class CallsActivity : AppCompatActivity() {
@ -46,7 +44,7 @@ class CallsActivity : AppCompatActivity() {
val listView = binding.calls
aorGenerateHistory(aor)
clAdapter = CallListAdapter(this, uaHistory)
clAdapter = CallListAdapter(this, aor, uaHistory)
listView.adapter = clAdapter
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)
else
getString(R.string.calls_call)
@ -236,33 +234,19 @@ class CallsActivity : AppCompatActivity() {
R.drawable.arrow_up_green
else
R.drawable.arrow_up_red
if (uaHistory.isNotEmpty() && (uaHistory.last().peerUri == h.peerUri)) {
uaHistory.last().directions.add(direction)
uaHistory.last().indexes.add(i)
} else {
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))
}
if (uaHistory.isNotEmpty() && (uaHistory.last().peerUri == h.peerUri))
uaHistory.last().details.add(CallRow.Details(direction, h.startTime, h.stopTime))
else
uaHistory.add(CallRow(h.aor, h.peerUri, direction, h.startTime, h.stopTime))
}
}
}
private fun removeUaHistoryAt(i: Int) {
for (index in uaHistory[i].indexes)
BaresipService.callHistory.removeAt(index)
for (details in uaHistory[i].details)
BaresipService.callHistory.removeAll {
it.startTime == details.startTime && it.stopTime == details.stopTime
}
uaHistory.removeAt(i)
}

View File

@ -88,6 +88,7 @@ class MainActivity : AppCompatActivity() {
private lateinit var restoreRequest: ActivityResultLauncher<Intent>
private lateinit var contactsRequest: ActivityResultLauncher<Intent>
private lateinit var callsRequest: ActivityResultLauncher<Intent>
private lateinit var callDetailsRequest: ActivityResultLauncher<Intent>
private var downloadsInputStream: FileInputStream? = null
private var downloadsOutputStream: FileOutputStream? = null
@ -1920,6 +1921,15 @@ class MainActivity : AppCompatActivity() {
i.putExtras(b)
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
}

View File

@ -18,13 +18,13 @@ import android.provider.MediaStore
import android.provider.OpenableColumns
import android.text.Editable
import android.text.TextWatcher
import android.text.format.DateUtils
import android.view.View
import android.view.WindowManager
import android.widget.TextView
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ProcessLifecycleOwner
@ -39,6 +39,7 @@ import java.util.zip.ZipOutputStream
import java.net.InetAddress
import java.net.NetworkInterface
import java.net.SocketException
import java.text.DateFormat
import javax.crypto.Cipher
import javax.crypto.SecretKeyFactory
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)
}
}
}
}

View File

@ -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>

View File

@ -14,6 +14,7 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:textSize="16sp"
android:gravity="center_horizontal" >
</TextView>

View File

@ -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>

View File

@ -1,13 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginBottom="0dp"
android:layout_marginTop="0dp"
android:layout_gravity="center_vertical"
android:descendantFocusability="blocksDescendants" >
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/TextAvatar"
@ -30,7 +26,7 @@
app:cardCornerRadius="18dp" >
<ImageView
android:id="@+id/CardImageAvatar"
android:id="@+id/ImageAvatar"
android:contentDescription="@string/avatar_image"
android:layout_height="36dp"
android:layout_width="36dp"

View File

@ -242,6 +242,10 @@
<string name="call">Soita</string>
<string name="calls_calls">puhelut</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
\'%1$s\'?
</string>

View File

@ -215,9 +215,14 @@
<string name="tap_to_start">Tap to start application</string>
<!-- Calls Activity -->
<string name="call_history">Call History</string>
<string name="call_details">Call Details</string>
<string name="call">Call</string>
<string name="calls_calls">calls</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_add_delete_question">Do you want to add \'%1$s\' to contacts or delete
%2$s from call history?