Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ If the app rejects calls from contacts on Android 10, allow _Contacts_ permissio
* CALL_SCREENING - block or allow call
* READ_CALL_LOG - check you have called/answered the number and count times the number have called you in X minutes
* READ_SMS - check you have sent a message to the number and you received a message from the number
* SEND_SMS - send a message to the number if the call is rejected
* NOTIFICATION_LISTENER - find mobile numbers in messages
* READ_PHONE_STATE - check on which SIM the number is calling
* RECEIVE_BOOT_COMPLETED - persist clean expired numbers job across reboots
Expand Down
6 changes: 6 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,10 @@ dependencies {
ksp(libs.androidx.room.compiler)
implementation(libs.google.libphonenumber)
implementation(libs.guardianproject.panic)
implementation("androidx.compose.ui:ui:1.4.0")
implementation("androidx.compose.material3:material3:1.0.0-alpha13")
implementation("androidx.compose.ui:ui-tooling-preview:1.4.0")
implementation("androidx.compose.runtime:runtime-livedata:1.4.0")
implementation("androidx.activity:activity-compose:1.4.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.4.0")
}
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
Expand Down Expand Up @@ -110,5 +111,7 @@
</meta-data>
</service>



</application>
</manifest>
44 changes: 43 additions & 1 deletion app/src/main/java/me/lucky/silence/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package me.lucky.silence

import android.Manifest
import android.app.AlertDialog
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import androidx.activity.ComponentActivity
Expand All @@ -10,13 +13,26 @@ import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.navigation.compose.rememberNavController
import me.lucky.silence.ui.App

// Define a constant to identify the SEND_SMS permission request
private const val MY_PERMISSIONS_REQUEST_SEND_SMS = 0

open class MainActivity : ComponentActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
NotificationManager(this).createNotificationChannels()

// Check and request SMS permission
if (ContextCompat.checkSelfPermission(this, Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) {
// If not, request the permission
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.SEND_SMS), MY_PERMISSIONS_REQUEST_SEND_SMS)
}

setContent {
val isAndroid12OrLater = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
val colorScheme = when {
Expand All @@ -30,4 +46,30 @@ open class MainActivity : ComponentActivity() {
}
}
}
}

// This method is called when the user responds to the permission request
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
// If the result is for the SEND_SMS permission request
MY_PERMISSIONS_REQUEST_SEND_SMS -> {
// If the permission is granted
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
// Show a dialog to check Settings
AlertDialog.Builder(this)
.setTitle("Check Settings")
.setMessage("You can set up an SMS notification in settings to be sent to a blocked number when it's blocked by the app.")
.setPositiveButton("OK") { dialog, _ ->
// Dismiss the dialog when the OK button is clicked
dialog.dismiss()
}
.show()
}
return
}
else -> {
// Ignore all other requests.
}
}
}
}
27 changes: 26 additions & 1 deletion app/src/main/java/me/lucky/silence/NotificationManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import androidx.core.app.NotificationChannelCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.app.Person
import android.telephony.SmsManager


class NotificationManager(private val ctx: Context) {
companion object {
Expand Down Expand Up @@ -43,4 +45,27 @@ class NotificationManager(private val ctx: Context) {
)
} catch (_: SecurityException) {}
}
}


// Function to send an SMS message
fun sendSMS(phoneNumber: String, message: String) {
// Get the default instance of the SmsManager
val smsManager = SmsManager.getDefault()
// Send a text message to the provided phone number
smsManager.sendTextMessage(phoneNumber, null, message, null, null)
}

// Function to send an SMS to a blocked call
fun smsBlockedCall(tel: String, sim: Sim?) {
// Get the SMS message from Preferences
val prefs = Preferences(ctx)
val message = prefs.smsMessage

// If the message is not empty, send an SMS to the blocked number
if (!message.isNullOrEmpty()) {
sendSMS(tel, message)
}



}}
5 changes: 5 additions & 0 deletions app/src/main/java/me/lucky/silence/Preferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class Preferences(ctx: Context) {
const val REPEATED_BURST_TIMEOUT = "repeated_burst_timeout"
const val MESSAGES = "messages"
const val MESSAGES_TEXT_TTL = "messages_text_ttl"
const val SMS_MESSAGE = "sms_message"

const val RESPONSE_OPTIONS = "call_screening_response_options"
const val UNKNOWN_NUMBERS_CHECKED = "unknown_numbers_checked"
Expand Down Expand Up @@ -131,6 +132,10 @@ class Preferences(ctx: Context) {
var regexPattern: String?
get() = prefs.getString(REGEX_PATTERN, "")
set(value) = prefs.edit { putString(REGEX_PATTERN, value) }

var smsMessage: String?
get() = prefs.getString(SMS_MESSAGE, "")
set(value) = prefs.edit { putString(SMS_MESSAGE, value) }
}

enum class Contact(val value: Int) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ class CallScreeningService : CallScreeningService() {
}
}
notificationManager.notifyBlockedCall(tel ?: return, sim)

// Here's where you would call smsBlockedCall
notificationManager.smsBlockedCall(tel ?: return, sim)
}
respondToCall(callDetails, response)
}
Expand Down
13 changes: 13 additions & 0 deletions app/src/main/java/me/lucky/silence/ui/MainScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,19 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
Expand All @@ -37,6 +43,7 @@ import me.lucky.silence.ui.common.ToggleableButton

@Composable
fun ModuleList(modules: List<Module>) {

LazyColumn {
items(modules) { module ->
if ((module.getPreference != null) && (module.setPreference != null) && (module.navigation != null)) {
Expand Down Expand Up @@ -83,6 +90,7 @@ fun MainScreen(
onNavigateToSettings: () -> Unit,
onNavigateToRegex: () -> Unit,
) {

fun getContactedPermissions(): Array<String> {
val contacted = prefs.contacted
val permissions = mutableSetOf<String>()
Expand Down Expand Up @@ -196,6 +204,9 @@ fun MainScreen(
setPreference = { prefs.isBlockEnabled = it },
),
)



Scaffold(topBar = {
TopAppBar(title = { Text(text = stringResource(R.string.app_name)) }, actions = {
IconButton(onClick = onNavigateToSettings) {
Expand All @@ -221,6 +232,8 @@ fun MainScreen(
)
}
})


}

@Preview
Expand Down
72 changes: 71 additions & 1 deletion app/src/main/java/me/lucky/silence/ui/SettingsScreen.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
package me.lucky.silence.ui

import android.app.AlertDialog
import android.content.Context
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import me.lucky.silence.ControlReceiver
import me.lucky.silence.Preferences
Expand All @@ -17,6 +28,7 @@ import me.lucky.silence.ui.common.Screen

@Composable
fun SettingsScreen(ctx: Context, prefs: Preferences, onBackPressed: () -> Boolean) {
var showSmsDialog by remember { mutableStateOf(false) }
val preferenceList = listOf(
Preference(
getValue = { Utils.isComponentEnabled(ctx, ControlReceiver::class.java) },
Expand Down Expand Up @@ -73,17 +85,75 @@ fun SettingsScreen(ctx: Context, prefs: Preferences, onBackPressed: () -> Boolea
},
name = R.string.settings_skip_notification,
description = R.string.settings_skip_notification_description,
),
Preference(
getValue = { prefs.smsMessage!!.isNotEmpty() },
setValue = { isChecked ->
if (isChecked) {
showSmsDialog = true
} else {
prefs.smsMessage = ""
}
},
name = R.string.enter_sms_message,
description = R.string.enter_sms_message_description,
)
)

Screen(title = R.string.settings,
onBackPressed = onBackPressed,
content = { PreferenceList(preferenceList) })
if (showSmsDialog) {
SmsMessageDialog(
onDismiss = { showSmsDialog = false },
onConfirm = { message ->
prefs.smsMessage = message
showSmsDialog = false
}
)
}
}


@Preview
@Composable
fun SettingsScreenPreview() {
MaterialTheme {
SettingsScreen(LocalContext.current, Preferences(LocalContext.current)) { true }
}
}

}

@Composable
fun SmsMessageDialog(onDismiss: () -> Unit, onConfirm: (String) -> Unit) {
val context = LocalContext.current
val input = remember { mutableStateOf("") }

AlertDialog(
onDismissRequest = { onDismiss() },
title = {
Text(text = stringResource(id = R.string.enter_sms_message))
},
text = {
Column {
Text(text = stringResource(id = R.string.enter_sms_message_description))
TextField(
value = input.value,
onValueChange = { input.value = it }
)
}
},
confirmButton = {
TextButton(onClick = {
onConfirm(input.value)
}) {
Text(text = stringResource(id = android.R.string.ok))
}
},
dismissButton = {
TextButton(onClick = { onDismiss() }) {
Text(text = stringResource(id = android.R.string.cancel))
}
}
)
}
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,6 @@
<string name="back">Back</string>
<string name="toggle_off">Off</string>
<string name="toggle_on">On</string>
<string name="enter_sms_message">SMS Message</string>
<string name="enter_sms_message_description">Enter the message to send when a call is blocked. Leave empty to not send an SMS.</string>
</resources>
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[versions]
agp = "8.3.2"
agp = "8.4.1"
kotlin = "1.9.23"
coreKtx = "1.12.0"
junit = "4.13.2"
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Tue Jun 14 21:51:27 MSK 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME