11package com.addev.listaspam
22
33import android.Manifest
4- import android.app.Activity
54import android.app.NotificationChannel
65import android.app.NotificationManager
76import android.content.Context
@@ -21,6 +20,9 @@ import okhttp3.Response
2120import org.jsoup.Jsoup
2221import java.io.IOException
2322
23+ /* *
24+ * Utility class for handling spam number checks and notifications.
25+ */
2426class SpamUtils {
2527
2628 companion object {
@@ -30,71 +32,114 @@ class SpamUtils {
3032 private const val RESPONDERONO_URL_TEMPLATE = " https://www.responderono.es/numero-de-telefono/%s"
3133 private const val NOTIFICATION_CHANNEL_ID = " NOTIFICATION_CHANNEL"
3234 private const val NOTIFICATION_ID = 1
35+ private const val SPAM_REPORT_THRESHOLD = 1
3336 }
3437
38+ /* *
39+ * Checks if a given phone number is considered spam by querying spam databases.
40+ * @param context Context for accessing resources.
41+ * @param number Phone number to check.
42+ * @param callback Callback function to handle the result.
43+ */
3544 fun checkSpamNumber (context : Context , number : String , callback : (isSpam: Boolean ) -> Unit ) {
3645 val url = SPAM_URL_TEMPLATE .format(number)
3746 val request = Request .Builder ().url(url).build()
3847
3948 OkHttpClient ().newCall(request).enqueue(object : Callback {
4049 override fun onFailure (call : Call , e : IOException ) {
41- // Handle error gracefully
42- Handler (Looper .getMainLooper()).post {
43- showToast(context, " Failed to check number in www.listaspam.com" , Toast .LENGTH_LONG )
44- callback(false )
45- }
50+ handleNetworkFailure(context, " Failed to check number in www.listaspam.com" , e, callback)
4651 }
4752
4853 override fun onResponse (call : Call , response : Response ) {
4954 response.body?.string()?.let { body ->
5055 val spamData = parseHtmlForSpamReports(body)
51- if (spamData.reports > 1 ) {
52- saveSpamNumber(context, number)
53- sendNotification(context, number)
54- callback(true )
56+ if (spamData.reports > SPAM_REPORT_THRESHOLD ) {
57+ handleSpamNumber(context, number, callback)
5558 } else {
5659 checkResponderono(context, number) { isResponderONoNegative ->
5760 if (isResponderONoNegative) {
58- saveSpamNumber(context, number)
59- sendNotification(context, number)
60- callback(true )
61+ handleSpamNumber(context, number, callback)
6162 } else {
62- Handler (Looper .getMainLooper()).post {
63- showToast(context, " Incoming call is not spam" , Toast .LENGTH_LONG )
64- }
65- removeSpamNumber(context, number)
66- callback(false )
63+ handleNonSpamNumber(context, number, callback)
6764 }
6865 }
6966 }
70- }
67+ } ? : handleNetworkFailure(context, " Empty response from www.listaspam.com " , null , callback)
7168 }
7269 })
7370 }
7471
75- fun checkResponderono (context : Context , number : String , callback : (isNegative: Boolean ) -> Unit ) {
72+ /* *
73+ * Checks if a given phone number is considered negative by the ResponderONo database.
74+ * @param context Context for accessing resources.
75+ * @param number Phone number to check.
76+ * @param callback Callback function to handle the result.
77+ */
78+ private fun checkResponderono (context : Context , number : String , callback : (isNegative: Boolean ) -> Unit ) {
7679 val url = RESPONDERONO_URL_TEMPLATE .format(number)
7780 val request = Request .Builder ().url(url).build()
7881
7982 OkHttpClient ().newCall(request).enqueue(object : Callback {
8083 override fun onFailure (call : Call , e : IOException ) {
81- // Handle error gracefully
82- Handler (Looper .getMainLooper()).post {
83- showToast(context, " Failed to check number in www.responderono.es" , Toast .LENGTH_LONG )
84- callback(false )
85- }
84+ handleNetworkFailure(context, " Failed to check number in www.responderono.es" , e, callback)
8685 }
8786
8887 override fun onResponse (call : Call , response : Response ) {
8988 response.body?.string()?.let { body ->
9089 val isResponderONoNegative = body.contains(" .scoreContainer .score.negative" )
9190 callback(isResponderONoNegative)
92- }
91+ } ? : handleNetworkFailure(context, " Empty response from www.responderono.es " , null , callback)
9392 }
9493 })
9594 }
9695
97- fun saveSpamNumber (context : Context , number : String ) {
96+ /* *
97+ * Handles the scenario when a phone number is identified as spam.
98+ * @param context Context for accessing resources.
99+ * @param number Phone number identified as spam.
100+ * @param callback Callback function to handle the result.
101+ */
102+ private fun handleSpamNumber (context : Context , number : String , callback : (isSpam: Boolean ) -> Unit ) {
103+ saveSpamNumber(context, number)
104+ sendNotification(context, number)
105+ callback(true )
106+ }
107+
108+ /* *
109+ * Handles the scenario when a phone number is not identified as spam.
110+ * @param context Context for accessing resources.
111+ * @param number Phone number identified as not spam.
112+ * @param callback Callback function to handle the result.
113+ */
114+ private fun handleNonSpamNumber (context : Context , number : String , callback : (isSpam: Boolean ) -> Unit ) {
115+ Handler (Looper .getMainLooper()).post {
116+ showToast(context, " Incoming call is not spam" , Toast .LENGTH_LONG )
117+ }
118+ removeSpamNumber(context, number)
119+ callback(false )
120+ }
121+
122+ /* *
123+ * Handles network failures by showing a toast message and logging the error.
124+ * @param context Context for accessing resources.
125+ * @param message Error message to display.
126+ * @param e Exception that occurred (optional).
127+ * @param callback Callback function to handle the result.
128+ */
129+ private fun handleNetworkFailure (context : Context , message : String , e : IOException ? , callback : (Boolean ) -> Unit ) {
130+ Handler (Looper .getMainLooper()).post {
131+ showToast(context, message, Toast .LENGTH_LONG )
132+ }
133+ e?.printStackTrace()
134+ callback(false )
135+ }
136+
137+ /* *
138+ * Saves a phone number as spam in SharedPreferences.
139+ * @param context Context for accessing resources.
140+ * @param number Phone number to save as spam.
141+ */
142+ private fun saveSpamNumber (context : Context , number : String ) {
98143 val sharedPreferences = context.getSharedPreferences(SPAM_PREFS , Context .MODE_PRIVATE )
99144 val blockedNumbers = sharedPreferences.getStringSet(BLOCK_NUMBERS_KEY , mutableSetOf ())?.toMutableSet()
100145 blockedNumbers?.add(number)
@@ -104,7 +149,12 @@ class SpamUtils {
104149 }
105150 }
106151
107- fun removeSpamNumber (context : Context , number : String ) {
152+ /* *
153+ * Removes a phone number from spam list in SharedPreferences.
154+ * @param context Context for accessing resources.
155+ * @param number Phone number to remove from spam list.
156+ */
157+ private fun removeSpamNumber (context : Context , number : String ) {
108158 val sharedPreferences = context.getSharedPreferences(SPAM_PREFS , Context .MODE_PRIVATE )
109159 val blockedNumbers = sharedPreferences.getStringSet(BLOCK_NUMBERS_KEY , mutableSetOf ())?.toMutableSet()
110160 blockedNumbers?.remove(number)
@@ -114,11 +164,24 @@ class SpamUtils {
114164 }
115165 }
116166
117- fun showToast (context : Context , message : String , duration : Int = Toast .LENGTH_SHORT ) {
118- Toast .makeText(context, message, duration).show()
167+ /* *
168+ * Displays a toast message.
169+ * @param context Context for displaying the toast.
170+ * @param message Message to display.
171+ * @param duration Duration of the toast display.
172+ */
173+ private fun showToast (context : Context , message : String , duration : Int = Toast .LENGTH_SHORT ) {
174+ Handler (Looper .getMainLooper()).post {
175+ Toast .makeText(context, message, duration).show()
176+ }
119177 }
120178
121- fun sendNotification (context : Context , number : String ) {
179+ /* *
180+ * Sends a notification indicating that a spam number has been blocked.
181+ * @param context Context for sending the notification.
182+ * @param number Phone number that was blocked.
183+ */
184+ private fun sendNotification (context : Context , number : String ) {
122185 createNotificationChannel(context)
123186 val notification = NotificationCompat .Builder (context, NOTIFICATION_CHANNEL_ID )
124187 .setSmallIcon(R .mipmap.ic_launcher)
@@ -138,6 +201,10 @@ class SpamUtils {
138201 NotificationManagerCompat .from(context).notify(NOTIFICATION_ID , notification)
139202 }
140203
204+ /* *
205+ * Creates a notification channel for spam notifications.
206+ * @param context Context for creating the notification channel.
207+ */
141208 private fun createNotificationChannel (context : Context ) {
142209 if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O ) {
143210 val name = " Spam Blocker Channel"
@@ -153,7 +220,12 @@ class SpamUtils {
153220 }
154221 }
155222
156- fun parseHtmlForSpamReports (html : String ): SpamData {
223+ /* *
224+ * Parses HTML content to extract spam report data.
225+ * @param html HTML content to parse.
226+ * @return [SpamData] containing the number of reports and searches.
227+ */
228+ private fun parseHtmlForSpamReports (html : String ): SpamData {
157229 val document = Jsoup .parse(html)
158230 val elementReports = document.select(" .n_reports .result" ).first()
159231 val elementSearches = document.select(" .n_search .result" ).first()
0 commit comments