Skip to content

Commit dc48fb2

Browse files
committed
Add call log UI
1 parent 3b73966 commit dc48fb2

File tree

11 files changed

+170
-19
lines changed

11 files changed

+170
-19
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
</activity>
4141

4242
<service
43-
android:name=".MyCallScreeningService"
43+
android:name=".services.MyCallScreeningService"
4444
android:exported="true"
4545
android:permission="android.permission.BIND_SCREENING_SERVICE">
4646
<intent-filter>
@@ -49,7 +49,7 @@
4949
</service>
5050

5151
<receiver
52-
android:name=".MyCallReceiver"
52+
android:name=".services.MyCallReceiver"
5353
android:exported="true">
5454
<intent-filter>
5555
<action android:name="android.intent.action.PHONE_STATE" />

app/src/main/java/com/addev/listaspam/MainActivity.kt

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import android.content.Intent
77
import android.content.pm.PackageManager
88
import android.os.Build
99
import android.os.Bundle
10-
import android.provider.Settings
1110
import android.telecom.TelecomManager
1211
import android.widget.Toast
1312
import androidx.activity.result.ActivityResultLauncher
@@ -18,6 +17,11 @@ import androidx.core.app.ActivityCompat
1817
import androidx.core.content.ContextCompat
1918
import androidx.core.view.ViewCompat
2019
import androidx.core.view.WindowInsetsCompat
20+
import androidx.recyclerview.widget.LinearLayoutManager
21+
import androidx.recyclerview.widget.RecyclerView
22+
import com.addev.listaspam.calllog.CallLogAdapter
23+
import com.addev.listaspam.calllog.getCallLogs
24+
import com.addev.listaspam.utils.SpamUtils
2125

2226
/**
2327
* MainActivity for handling permissions and requesting call screening role.
@@ -32,6 +36,8 @@ class MainActivity : AppCompatActivity() {
3236
}
3337

3438
private lateinit var intentLauncher: ActivityResultLauncher<Intent>
39+
private lateinit var recyclerView: RecyclerView
40+
private lateinit var adapter: CallLogAdapter
3541

3642
/**
3743
* Called when the activity is starting.
@@ -48,6 +54,22 @@ class MainActivity : AppCompatActivity() {
4854
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
4955
requestCallScreeningRole()
5056
}
57+
58+
refreshCallLogs()
59+
}
60+
61+
fun refreshCallLogs() {
62+
val blockedNumbers = getBlockedNumbers()
63+
val callLogs = getCallLogs(this)
64+
65+
val recyclerView: RecyclerView = findViewById(R.id.recyclerView)
66+
recyclerView.layoutManager = LinearLayoutManager(this)
67+
recyclerView.adapter = CallLogAdapter(this, callLogs, blockedNumbers)
68+
}
69+
70+
private fun getBlockedNumbers(): Set<String> {
71+
val sharedPreferences = getSharedPreferences(SpamUtils.SPAM_PREFS, Context.MODE_PRIVATE)
72+
return sharedPreferences.getStringSet(SpamUtils.BLOCK_NUMBERS_KEY, emptySet()) ?: emptySet()
5173
}
5274

5375
/**
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// CallLogAdapter.kt
2+
package com.addev.listaspam.calllog
3+
4+
import android.content.Context
5+
import android.view.LayoutInflater
6+
import android.view.View
7+
import android.view.ViewGroup
8+
import android.widget.TextView
9+
import androidx.core.content.ContextCompat
10+
import androidx.recyclerview.widget.RecyclerView
11+
import com.addev.listaspam.R
12+
13+
class CallLogAdapter(
14+
private val context: Context,
15+
private val callLogs: List<CallLogEntry>,
16+
private val blockedNumbers: Set<String>
17+
) : RecyclerView.Adapter<CallLogAdapter.CallLogViewHolder>() {
18+
19+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CallLogViewHolder {
20+
val view = LayoutInflater.from(context).inflate(R.layout.item_call_log, parent, false)
21+
return CallLogViewHolder(view)
22+
}
23+
24+
override fun onBindViewHolder(holder: CallLogViewHolder, position: Int) {
25+
val callLog = callLogs[position]
26+
holder.bind(callLog, blockedNumbers.contains(callLog.number))
27+
}
28+
29+
override fun getItemCount(): Int = callLogs.size
30+
31+
inner class CallLogViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
32+
private val numberTextView: TextView = itemView.findViewById(R.id.numberTextView)
33+
private val dateTextView: TextView = itemView.findViewById(R.id.dateTextView)
34+
private val durationTextView: TextView = itemView.findViewById(R.id.durationTextView)
35+
36+
fun bind(callLog: CallLogEntry, isBlocked: Boolean) {
37+
numberTextView.text = "${callLog.number}${if (isBlocked) " (blocked)" else ""}"
38+
dateTextView.text = callLog.date.toString()
39+
durationTextView.text = "Duration: ${callLog.duration} seconds"
40+
41+
if (isBlocked) {
42+
numberTextView.setTextColor(ContextCompat.getColor(context, android.R.color.holo_red_dark))
43+
} else {
44+
numberTextView.setTextColor(ContextCompat.getColor(context, android.R.color.black))
45+
}
46+
}
47+
}
48+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// CallLogUtils.kt
2+
package com.addev.listaspam.calllog
3+
4+
import android.content.Context
5+
import android.database.Cursor
6+
import android.provider.CallLog
7+
import java.util.*
8+
9+
data class CallLogEntry(
10+
val number: String,
11+
val type: Int,
12+
val date: Date,
13+
val duration: Long
14+
)
15+
16+
fun getCallLogs(context: Context): List<CallLogEntry> {
17+
val callLogs = mutableListOf<CallLogEntry>()
18+
val cursor: Cursor? = context.contentResolver.query(
19+
CallLog.Calls.CONTENT_URI,
20+
null,
21+
null,
22+
null,
23+
CallLog.Calls.DATE + " DESC"
24+
)
25+
26+
cursor?.use {
27+
val numberIndex = it.getColumnIndex(CallLog.Calls.NUMBER)
28+
val typeIndex = it.getColumnIndex(CallLog.Calls.TYPE)
29+
val dateIndex = it.getColumnIndex(CallLog.Calls.DATE)
30+
val durationIndex = it.getColumnIndex(CallLog.Calls.DURATION)
31+
32+
while (it.moveToNext()) {
33+
val number = it.getString(numberIndex)
34+
val type = it.getInt(typeIndex)
35+
val date = Date(it.getLong(dateIndex))
36+
val duration = it.getLong(durationIndex)
37+
callLogs.add(CallLogEntry(number, type, date, duration))
38+
}
39+
}
40+
41+
return callLogs
42+
}

app/src/main/java/com/addev/listaspam/SpamData.kt renamed to app/src/main/java/com/addev/listaspam/model/SpamData.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.addev.listaspam
1+
package com.addev.listaspam.model
22

33
class SpamData(
44
val reports: Int,

app/src/main/java/com/addev/listaspam/MyCallReceiver.kt renamed to app/src/main/java/com/addev/listaspam/services/MyCallReceiver.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.addev.listaspam
1+
package com.addev.listaspam.services
22

33
import android.annotation.SuppressLint
44
import android.content.BroadcastReceiver
@@ -8,6 +8,7 @@ import android.os.Build
88
import android.telecom.TelecomManager
99
import android.telephony.TelephonyManager
1010
import androidx.annotation.RequiresApi
11+
import com.addev.listaspam.utils.SpamUtils
1112

1213
/**
1314
* BroadcastReceiver for handling incoming call events and checking for spam numbers.

app/src/main/java/com/addev/listaspam/MyCallScreeningService.kt renamed to app/src/main/java/com/addev/listaspam/services/MyCallScreeningService.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
package com.addev.listaspam
1+
package com.addev.listaspam.services
22

3-
import android.content.Context
43
import android.net.Uri
54
import android.os.Build
65
import android.telecom.Call
76
import android.telecom.CallScreeningService
87
import android.telecom.TelecomManager
98
import android.telephony.TelephonyManager
109
import androidx.annotation.RequiresApi
10+
import com.addev.listaspam.utils.SpamUtils
1111

1212
/**
1313
* Call screening service to identify and block spam calls.

app/src/main/java/com/addev/listaspam/SpamUtils.kt renamed to app/src/main/java/com/addev/listaspam/utils/SpamUtils.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.addev.listaspam
1+
package com.addev.listaspam.utils
22

33
import android.Manifest
44
import android.app.NotificationChannel
@@ -12,7 +12,8 @@ import android.widget.Toast
1212
import androidx.core.app.ActivityCompat
1313
import androidx.core.app.NotificationCompat
1414
import androidx.core.app.NotificationManagerCompat
15-
import com.addev.listaspam.MyCallScreeningService.Companion
15+
import com.addev.listaspam.R
16+
import com.addev.listaspam.model.SpamData
1617
import okhttp3.Call
1718
import okhttp3.Callback
1819
import okhttp3.OkHttpClient
@@ -27,8 +28,8 @@ import java.io.IOException
2728
class SpamUtils {
2829

2930
companion object {
30-
private const val SPAM_PREFS = "SPAM_PREFS"
31-
private const val BLOCK_NUMBERS_KEY = "BLOCK_NUMBERS"
31+
const val SPAM_PREFS = "SPAM_PREFS"
32+
const val BLOCK_NUMBERS_KEY = "BLOCK_NUMBERS"
3233
private const val SPAM_URL_TEMPLATE = "https://www.listaspam.com/busca.php?Telefono=%s"
3334
private const val RESPONDERONO_URL_TEMPLATE =
3435
"https://www.responderono.es/numero-de-telefono/%s"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// WhitelistUtils.kt
2+
package com.addev.listaspam.utils
3+
4+
object WhitelistUtils {
5+
const val WHITELIST_KEY = "WHITELIST"
6+
}

app/src/main/res/layout/activity_main.xml

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,19 @@
77
android:layout_height="match_parent"
88
tools:context=".MainActivity">
99

10-
<TextView
11-
android:layout_width="wrap_content"
12-
android:layout_height="wrap_content"
13-
android:text="Blocking spam calls"
14-
app:layout_constraintBottom_toBottomOf="parent"
15-
app:layout_constraintEnd_toEndOf="parent"
16-
app:layout_constraintStart_toStartOf="parent"
17-
app:layout_constraintTop_toTopOf="parent" />
10+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
11+
xmlns:tools="http://schemas.android.com/tools"
12+
android:layout_width="match_parent"
13+
android:layout_height="match_parent"
14+
android:orientation="vertical"
15+
tools:context=".MainActivity">
16+
17+
<androidx.recyclerview.widget.RecyclerView
18+
android:id="@+id/recyclerView"
19+
android:layout_width="match_parent"
20+
android:layout_height="match_parent"
21+
tools:listitem="@layout/item_call_log" />
22+
23+
</LinearLayout>
1824

1925
</androidx.constraintlayout.widget.ConstraintLayout>

0 commit comments

Comments
 (0)