Skip to content

Commit bdeefdf

Browse files
author
lucky
committed
repeated burst protection
1 parent ecc243e commit bdeefdf

File tree

8 files changed

+72
-19
lines changed

8 files changed

+72
-19
lines changed

app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ android {
1111
applicationId "me.lucky.silence"
1212
minSdk 29
1313
targetSdk 32
14-
versionCode 49
15-
versionName "1.11.5"
14+
versionCode 50
15+
versionName "1.11.6"
1616

1717
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1818

app/src/main/java/me/lucky/silence/Preferences.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class Preferences(ctx: Context) {
1717
private const val GROUPS = "groups"
1818
private const val REPEATED_COUNT = "repeated_count"
1919
private const val REPEATED_MINUTES = "repeated_minutes"
20+
private const val REPEATED_BURST_TIMEOUT = "repeated_burst_timeout"
2021
private const val MESSAGES = "messages"
2122
private const val MESSAGES_TEXT_TTL = "messages_text_ttl"
2223

@@ -71,6 +72,10 @@ class Preferences(ctx: Context) {
7172
get() = prefs.getInt(REPEATED_MINUTES, DEFAULT_REPEATED_MINUTES)
7273
set(value) = prefs.edit { putInt(REPEATED_MINUTES, value) }
7374

75+
var repeatedBurstTimeout: Int
76+
get() = prefs.getInt(REPEATED_BURST_TIMEOUT, 0)
77+
set(value) = prefs.edit { putInt(REPEATED_BURST_TIMEOUT, value) }
78+
7479
var isMessagesChecked: Boolean
7580
get() = prefs.getBoolean(MESSAGES_CHECKED, false)
7681
set(value) = prefs.edit { putBoolean(MESSAGES_CHECKED, value) }

app/src/main/java/me/lucky/silence/fragment/RepeatedFragment.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,19 @@ class RepeatedFragment : Fragment() {
3333
binding.apply {
3434
count.editText?.setText(prefs.repeatedCount.toString())
3535
minutes.editText?.setText(prefs.repeatedMinutes.toString())
36+
burstTimeout.editText?.setText(prefs.repeatedBurstTimeout.toString())
3637
}
3738
}
3839

3940
private fun setup() = binding.apply {
4041
count.editText?.doAfterTextChanged {
41-
try {
42-
prefs.repeatedCount = it?.toString()?.toInt() ?: return@doAfterTextChanged
43-
} catch (exc: NumberFormatException) {}
42+
prefs.repeatedCount = it?.toString()?.toIntOrNull() ?: return@doAfterTextChanged
4443
}
4544
minutes.editText?.doAfterTextChanged {
46-
try {
47-
prefs.repeatedMinutes = it?.toString()?.toInt() ?: return@doAfterTextChanged
48-
} catch (exc: NumberFormatException) {}
45+
prefs.repeatedMinutes = it?.toString()?.toIntOrNull() ?: return@doAfterTextChanged
46+
}
47+
burstTimeout.editText?.doAfterTextChanged {
48+
prefs.repeatedBurstTimeout = it?.toString()?.toIntOrNull() ?: return@doAfterTextChanged
4949
}
5050
}
5151
}

app/src/main/java/me/lucky/silence/screening/CallScreeningHelper.kt

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import android.net.Uri
66
import android.provider.CallLog
77
import android.provider.ContactsContract
88
import android.provider.Telephony
9+
import android.telecom.Call
910
import android.telephony.TelephonyManager
1011

1112
import com.google.i18n.phonenumbers.PhoneNumberUtil
@@ -18,12 +19,12 @@ class CallScreeningHelper(private val ctx: Context) {
1819
private val phoneNumberUtil = PhoneNumberUtil.getInstance()
1920
private val db = AppDatabase.getInstance(ctx).allowNumberDao()
2021

21-
fun check(number: Phonenumber.PhoneNumber): Boolean {
22+
fun check(number: Phonenumber.PhoneNumber, callDetails: Call.Details): Boolean {
2223
return (
2324
(prefs.isContactsChecked && checkContacts(number)) ||
2425
(prefs.isContactedChecked && checkContacted(number)) ||
2526
(prefs.isGroupsChecked && checkGroups(number)) ||
26-
(prefs.isRepeatedChecked && checkRepeated(number)) ||
27+
(prefs.isRepeatedChecked && checkRepeated(number, callDetails)) ||
2728
(prefs.isMessagesChecked && checkMessages(number))
2829
)
2930
}
@@ -54,7 +55,7 @@ class CallScreeningHelper(private val ctx: Context) {
5455
)
5556
} catch (exc: SecurityException) {}
5657
cursor?.apply {
57-
if (moveToFirst()) { result = true }
58+
if (moveToFirst()) result = true
5859
close()
5960
}
6061
return result
@@ -76,7 +77,7 @@ class CallScreeningHelper(private val ctx: Context) {
7677
)
7778
} catch (exc: SecurityException) {}
7879
cursor?.apply {
79-
if (moveToFirst()) { result = true }
80+
if (moveToFirst()) result = true
8081
close()
8182
}
8283
return result
@@ -104,23 +105,37 @@ class CallScreeningHelper(private val ctx: Context) {
104105
return result
105106
}
106107

107-
private fun checkRepeated(number: Phonenumber.PhoneNumber): Boolean {
108+
private fun checkRepeated(number: Phonenumber.PhoneNumber, callDetails: Call.Details): Boolean {
108109
val cursor: Cursor?
109110
try {
110111
cursor = ctx.contentResolver.query(
111112
makeContentUri(CallLog.Calls.CONTENT_FILTER_URI, number),
112-
arrayOf(CallLog.Calls._ID),
113+
arrayOf(CallLog.Calls._ID, CallLog.Calls.DATE),
113114
"${CallLog.Calls.TYPE} = ? AND ${CallLog.Calls.DATE} > ?",
114115
arrayOf(
115116
CallLog.Calls.BLOCKED_TYPE.toString(),
116117
(System.currentTimeMillis() - prefs.repeatedMinutes * 60 * 1000).toString(),
117118
),
118-
null,
119+
CallLog.Calls.DEFAULT_SORT_ORDER,
119120
)
120121
} catch (exc: SecurityException) { return false }
121122
var result = false
122123
cursor?.apply {
123-
if (count >= prefs.repeatedCount - 1) { result = true }
124+
val i: Int
125+
val burstTimeout = prefs.repeatedBurstTimeout * 1000L
126+
if (burstTimeout == 0L) {
127+
i = count
128+
} else {
129+
var j = 0
130+
var tm = callDetails.creationTimeMillis
131+
while (moveToNext()) {
132+
val date = getLong(getColumnIndexOrThrow(CallLog.Calls.DATE))
133+
if (tm - date >= burstTimeout) j++
134+
tm = date
135+
}
136+
i = j
137+
}
138+
if (i >= prefs.repeatedCount - 1) result = true
124139
close()
125140
}
126141
return result
@@ -157,7 +172,7 @@ class CallScreeningHelper(private val ctx: Context) {
157172
)
158173
} catch (exc: SecurityException) {}
159174
cursor?.apply {
160-
if (moveToFirst()) { result = true }
175+
if (moveToFirst()) result = true
161176
close()
162177
}
163178
return result
@@ -187,7 +202,7 @@ class CallScreeningHelper(private val ctx: Context) {
187202
} catch (exc: SecurityException) { return false }
188203
var result = false
189204
cursor?.apply {
190-
if (moveToFirst()) { result = true }
205+
if (moveToFirst()) result = true
191206
close()
192207
}
193208
return result

app/src/main/java/me/lucky/silence/screening/CallScreeningService.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class CallScreeningService : CallScreeningService() {
7575
respondNotAllow(callDetails)
7676
return
7777
}
78-
if (callScreeningHelper.check(number)) respondAllow(callDetails)
78+
if (callScreeningHelper.check(number, callDetails)) respondAllow(callDetails)
7979
else respondNotAllow(callDetails)
8080
}
8181

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
33
xmlns:tools="http://schemas.android.com/tools"
4+
xmlns:app="http://schemas.android.com/apk/res-auto"
45
android:layout_width="match_parent"
56
android:layout_height="match_parent"
67
tools:context=".fragment.RepeatedFragment">
@@ -64,6 +65,26 @@
6465
android:text="@string/repeated_settings_description"
6566
android:textAppearance="?attr/textAppearanceBodySmall" />
6667

68+
<Space
69+
android:layout_width="match_parent"
70+
android:layout_height="wrap_content"
71+
android:layout_marginVertical="10dp" />
72+
73+
<com.google.android.material.textfield.TextInputLayout
74+
android:id="@+id/burstTimeout"
75+
android:hint="@string/repeated_burst_timeout_hint"
76+
app:helperText="@string/repeated_burst_timeout_helper_text"
77+
app:helperTextEnabled="true"
78+
android:layout_width="match_parent"
79+
android:layout_height="wrap_content">
80+
81+
<com.google.android.material.textfield.TextInputEditText
82+
android:layout_width="match_parent"
83+
android:layout_height="wrap_content"
84+
android:inputType="number" />
85+
86+
</com.google.android.material.textfield.TextInputLayout>
87+
6788
</LinearLayout>
6889
</ScrollView>
6990
</FrameLayout>

app/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
<string name="repeated_count">Count</string>
2525
<string name="repeated_minutes">Minutes</string>
2626
<string name="repeated_settings_description">Count has to be lower than minutes. Because Android caches the result, calls have to be out of the cache interval.</string>
27+
<string name="repeated_burst_timeout_hint">Timeout</string>
28+
<string name="repeated_burst_timeout_helper_text">Minimal timeout in seconds between repeated calls.</string>
2729
<string name="messages_main">Messages</string>
2830
<string name="messages_description">Allow calls from numbers found in messages.</string>
2931
<string name="messages_inbox">Inbox</string>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
add repeated burst protection
2+
update Arabic, Turkish, French, Japanese, English, Norwegian Bokmål, Italian translations
3+
4+
Thanks to:
5+
DJEBBARI.ABDELHAMID (@dxing96)
6+
Oğuz Ersen (@ersen0)
7+
Nathanaël Gagnepain (@Ilithy)
8+
Guillaume BOEHM (@guillaumeboehm)
9+
Allan Nordhøy (@comradekingu)
10+
Giovanni Donisi (@gdonisi + @giovannidonisi)

0 commit comments

Comments
 (0)