Merge branch 'master' into json-streams

This commit is contained in:
Naveen Singh 2024-12-25 18:10:09 +05:30 committed by GitHub
commit 188e8f9ea4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
96 changed files with 3782 additions and 257 deletions

View file

@ -71,9 +71,9 @@ class ManageBlockedKeywordsActivity : BaseSimpleActivity(), RefreshRecyclerViewL
private fun updateBlockedKeywords() {
ensureBackgroundThread {
val blockedKeywords = config.blockedKeywords
val blockedKeywords = config.blockedKeywords.sorted().toArrayList()
runOnUiThread {
ManageBlockedKeywordsAdapter(this, blockedKeywords.toArrayList(), this, binding.manageBlockedKeywordsList) {
ManageBlockedKeywordsAdapter(this, blockedKeywords, this, binding.manageBlockedKeywordsList) {
addOrEditBlockedKeyword(it as String)
}.apply {
binding.manageBlockedKeywordsList.adapter = this

View file

@ -10,9 +10,36 @@ import androidx.activity.result.contract.ActivityResultContracts
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.encodeToStream
import org.fossify.commons.activities.ManageBlockedNumbersActivity
import org.fossify.commons.dialogs.*
import org.fossify.commons.extensions.*
import org.fossify.commons.helpers.*
import org.fossify.commons.dialogs.ChangeDateTimeFormatDialog
import org.fossify.commons.dialogs.ConfirmationDialog
import org.fossify.commons.dialogs.FeatureLockedDialog
import org.fossify.commons.dialogs.RadioGroupDialog
import org.fossify.commons.dialogs.SecurityDialog
import org.fossify.commons.extensions.addLockedLabelIfNeeded
import org.fossify.commons.extensions.beGoneIf
import org.fossify.commons.extensions.beVisibleIf
import org.fossify.commons.extensions.getBlockedNumbers
import org.fossify.commons.extensions.getCustomizeColorsString
import org.fossify.commons.extensions.getFontSizeText
import org.fossify.commons.extensions.getProperPrimaryColor
import org.fossify.commons.extensions.isOrWasThankYouInstalled
import org.fossify.commons.extensions.launchPurchaseThankYouIntent
import org.fossify.commons.extensions.showErrorToast
import org.fossify.commons.extensions.toast
import org.fossify.commons.extensions.updateTextColors
import org.fossify.commons.extensions.viewBinding
import org.fossify.commons.helpers.FONT_SIZE_EXTRA_LARGE
import org.fossify.commons.helpers.FONT_SIZE_LARGE
import org.fossify.commons.helpers.FONT_SIZE_MEDIUM
import org.fossify.commons.helpers.FONT_SIZE_SMALL
import org.fossify.commons.helpers.NavigationIcon
import org.fossify.commons.helpers.PROTECTION_FINGERPRINT
import org.fossify.commons.helpers.SHOW_ALL_TABS
import org.fossify.commons.helpers.ensureBackgroundThread
import org.fossify.commons.helpers.isNougatPlus
import org.fossify.commons.helpers.isOreoPlus
import org.fossify.commons.helpers.isPiePlus
import org.fossify.commons.helpers.isTiramisuPlus
import org.fossify.commons.models.RadioItem
import org.fossify.messages.R
import org.fossify.messages.databinding.ActivitySettingsBinding
@ -20,7 +47,19 @@ import org.fossify.messages.dialogs.ExportMessagesDialog
import org.fossify.messages.extensions.config
import org.fossify.messages.extensions.emptyMessagesRecycleBin
import org.fossify.messages.extensions.messagesDB
import org.fossify.messages.helpers.*
import org.fossify.messages.helpers.FILE_SIZE_100_KB
import org.fossify.messages.helpers.FILE_SIZE_1_MB
import org.fossify.messages.helpers.FILE_SIZE_200_KB
import org.fossify.messages.helpers.FILE_SIZE_2_MB
import org.fossify.messages.helpers.FILE_SIZE_300_KB
import org.fossify.messages.helpers.FILE_SIZE_600_KB
import org.fossify.messages.helpers.FILE_SIZE_NONE
import org.fossify.messages.helpers.LOCK_SCREEN_NOTHING
import org.fossify.messages.helpers.LOCK_SCREEN_SENDER
import org.fossify.messages.helpers.LOCK_SCREEN_SENDER_MESSAGE
import org.fossify.messages.helpers.MessagesImporter
import org.fossify.messages.helpers.MessagesReader
import org.fossify.messages.helpers.refreshMessages
import java.util.Locale
import kotlin.system.exitProcess
@ -28,7 +67,14 @@ class SettingsActivity : SimpleActivity() {
private var blockedNumbersAtPause = -1
private var recycleBinMessages = 0
private val messagesFileType = "application/json"
private val messageImportFileTypes = listOf("application/json", "application/xml", "text/xml")
private val messageImportFileTypes = buildList {
add("application/json")
add("application/xml")
add("text/xml")
if (!isPiePlus()) {
add("application/octet-stream")
}
}
private val binding by viewBinding(ActivitySettingsBinding::inflate)
@ -43,7 +89,10 @@ class SettingsActivity : SimpleActivity() {
useTransparentNavigation = true,
useTopSearchMenu = false
)
setupMaterialScrollListener(scrollingView = binding.settingsNestedScrollview, toolbar = binding.settingsToolbar)
setupMaterialScrollListener(
scrollingView = binding.settingsNestedScrollview,
toolbar = binding.settingsToolbar
)
}
override fun onResume() {
@ -74,7 +123,9 @@ class SettingsActivity : SimpleActivity() {
setupMessagesImport()
updateTextColors(binding.settingsNestedScrollview)
if (blockedNumbersAtPause != -1 && blockedNumbersAtPause != getBlockedNumbers().hashCode()) {
if (
blockedNumbersAtPause != -1 && blockedNumbersAtPause != getBlockedNumbers().hashCode()
) {
refreshMessages()
}
@ -91,23 +142,25 @@ class SettingsActivity : SimpleActivity() {
}
}
private val getContent = registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
if (uri != null) {
MessagesImporter(this).importMessages(uri)
private val getContent =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
if (uri != null) {
MessagesImporter(this).importMessages(uri)
}
}
}
private val saveDocument = registerForActivityResult(ActivityResultContracts.CreateDocument(messagesFileType)) { uri ->
if (uri != null) {
toast(org.fossify.commons.R.string.exporting)
exportMessages(uri)
private val saveDocument =
registerForActivityResult(ActivityResultContracts.CreateDocument(messagesFileType)) { uri ->
if (uri != null) {
toast(org.fossify.commons.R.string.exporting)
exportMessages(uri)
}
}
}
private fun setupMessagesExport() {
binding.settingsExportMessagesHolder.setOnClickListener {
ExportMessagesDialog(this) { fileName ->
saveDocument.launch(fileName)
saveDocument.launch("$fileName.json")
}
}
}
@ -123,7 +176,10 @@ class SettingsActivity : SimpleActivity() {
ensureBackgroundThread {
var success = false
try {
MessagesReader(this).getMessagesToExport(config.exportSms, config.exportMms) { messagesToExport ->
MessagesReader(this).getMessagesToExport(
config.exportSms,
config.exportMms
) { messagesToExport ->
if (messagesToExport.isEmpty()) {
toast(org.fossify.commons.R.string.no_entries_for_exporting)
return@getMessagesToExport
@ -177,7 +233,10 @@ class SettingsActivity : SimpleActivity() {
}
private fun setupUseEnglish() = binding.apply {
settingsUseEnglishHolder.beVisibleIf((config.wasUseEnglishToggled || Locale.getDefault().language != "en") && !isTiramisuPlus())
settingsUseEnglishHolder.beVisibleIf(
(config.wasUseEnglishToggled || Locale.getDefault().language != "en")
&& !isTiramisuPlus()
)
settingsUseEnglish.isChecked = config.useEnglish
settingsUseEnglishHolder.setOnClickListener {
settingsUseEnglish.toggle()
@ -197,7 +256,8 @@ class SettingsActivity : SimpleActivity() {
// support for device-wise blocking came on Android 7, rely only on that
@TargetApi(Build.VERSION_CODES.N)
private fun setupManageBlockedNumbers() = binding.apply {
settingsManageBlockedNumbers.text = addLockedLabelIfNeeded(org.fossify.commons.R.string.manage_blocked_numbers)
settingsManageBlockedNumbers.text =
addLockedLabelIfNeeded(org.fossify.commons.R.string.manage_blocked_numbers)
settingsManageBlockedNumbersHolder.beVisibleIf(isNougatPlus())
settingsManageBlockedNumbersHolder.setOnClickListener {
@ -212,7 +272,8 @@ class SettingsActivity : SimpleActivity() {
}
private fun setupManageBlockedKeywords() = binding.apply {
settingsManageBlockedKeywords.text = addLockedLabelIfNeeded(R.string.manage_blocked_keywords)
settingsManageBlockedKeywords.text =
addLockedLabelIfNeeded(R.string.manage_blocked_keywords)
settingsManageBlockedKeywordsHolder.setOnClickListener {
if (isOrWasThankYouInstalled()) {
@ -240,7 +301,10 @@ class SettingsActivity : SimpleActivity() {
RadioItem(FONT_SIZE_SMALL, getString(org.fossify.commons.R.string.small)),
RadioItem(FONT_SIZE_MEDIUM, getString(org.fossify.commons.R.string.medium)),
RadioItem(FONT_SIZE_LARGE, getString(org.fossify.commons.R.string.large)),
RadioItem(FONT_SIZE_EXTRA_LARGE, getString(org.fossify.commons.R.string.extra_large))
RadioItem(
FONT_SIZE_EXTRA_LARGE,
getString(org.fossify.commons.R.string.extra_large)
)
)
RadioGroupDialog(this@SettingsActivity, items, config.fontSize) {
@ -362,7 +426,11 @@ class SettingsActivity : SimpleActivity() {
recycleBinMessages = messagesDB.getArchivedCount()
runOnUiThread {
settingsEmptyRecycleBinSize.text =
resources.getQuantityString(R.plurals.delete_messages, recycleBinMessages, recycleBinMessages)
resources.getQuantityString(
R.plurals.delete_messages,
recycleBinMessages,
recycleBinMessages
)
}
}
@ -382,7 +450,11 @@ class SettingsActivity : SimpleActivity() {
}
recycleBinMessages = 0
settingsEmptyRecycleBinSize.text =
resources.getQuantityString(R.plurals.delete_messages, recycleBinMessages, recycleBinMessages)
resources.getQuantityString(
R.plurals.delete_messages,
recycleBinMessages,
recycleBinMessages
)
}
}
}
@ -391,8 +463,17 @@ class SettingsActivity : SimpleActivity() {
private fun setupAppPasswordProtection() = binding.apply {
settingsAppPasswordProtection.isChecked = config.isAppPasswordProtectionOn
settingsAppPasswordProtectionHolder.setOnClickListener {
val tabToShow = if (config.isAppPasswordProtectionOn) config.appProtectionType else SHOW_ALL_TABS
SecurityDialog(this@SettingsActivity, config.appPasswordHash, tabToShow) { hash, type, success ->
val tabToShow = if (config.isAppPasswordProtectionOn) {
config.appProtectionType
} else {
SHOW_ALL_TABS
}
SecurityDialog(
activity = this@SettingsActivity,
requiredHash = config.appPasswordHash,
showTabIndex = tabToShow
) { hash, type, success ->
if (success) {
val hasPasswordProtection = config.isAppPasswordProtectionOn
settingsAppPasswordProtection.isChecked = !hasPasswordProtection
@ -401,13 +482,20 @@ class SettingsActivity : SimpleActivity() {
config.appProtectionType = type
if (config.isAppPasswordProtectionOn) {
val confirmationTextId = if (config.appProtectionType == PROTECTION_FINGERPRINT) {
org.fossify.commons.R.string.fingerprint_setup_successfully
} else {
org.fossify.commons.R.string.protection_setup_successfully
}
val confirmationTextId =
if (config.appProtectionType == PROTECTION_FINGERPRINT) {
org.fossify.commons.R.string.fingerprint_setup_successfully
} else {
org.fossify.commons.R.string.protection_setup_successfully
}
ConfirmationDialog(this@SettingsActivity, "", confirmationTextId, org.fossify.commons.R.string.ok, 0) { }
ConfirmationDialog(
activity = this@SettingsActivity,
message = "",
messageId = confirmationTextId,
positive = org.fossify.commons.R.string.ok,
negative = 0
) { }
}
}
}

View file

@ -278,11 +278,11 @@ fun Context.getConversations(threadId: Long? = null, privateContacts: ArrayList<
projection += Threads.ARCHIVED
}
var selection = "${Threads.MESSAGE_COUNT} > ?"
var selectionArgs = arrayOf("0")
var selection = "${Threads.MESSAGE_COUNT} > 0"
var selectionArgs = arrayOf<String>()
if (threadId != null) {
selection += " AND ${Threads._ID} = ?"
selectionArgs = arrayOf("0", threadId.toString())
selectionArgs += threadId.toString()
}
val sortOrder = "${Threads.DATE} DESC"
@ -355,11 +355,10 @@ private fun Context.queryCursorUnsafe(
fun Context.getConversationIds(): List<Long> {
val uri = Uri.parse("${Threads.CONTENT_URI}?simple=true")
val projection = arrayOf(Threads._ID)
val selection = "${Threads.MESSAGE_COUNT} > ?"
val selectionArgs = arrayOf("0")
val selection = "${Threads.MESSAGE_COUNT} > 0"
val sortOrder = "${Threads.DATE} ASC"
val conversationIds = mutableListOf<Long>()
queryCursor(uri, projection, selection, selectionArgs, sortOrder, true) { cursor ->
queryCursor(uri, projection, selection, null, sortOrder, true) { cursor ->
val id = cursor.getLongValue(Threads._ID)
conversationIds.add(id)
}
@ -1058,16 +1057,9 @@ fun Context.insertOrUpdateConversation(
conversation: Conversation,
cachedConv: Conversation? = conversationsDB.getConversationWithThreadId(conversation.threadId)
) {
val updatedConv = if (cachedConv != null) {
val usesCustomTitle = cachedConv.usesCustomTitle
val title = if (usesCustomTitle) {
cachedConv.title
} else {
conversation.title
}
conversation.copy(title = title, usesCustomTitle = usesCustomTitle)
} else {
conversation
var updatedConv = conversation
if (cachedConv != null && cachedConv.usesCustomTitle) {
updatedConv = updatedConv.copy(title = cachedConv.title, usesCustomTitle = cachedConv.usesCustomTitle)
}
conversationsDB.insertOrUpdate(updatedConv)
}

View file

@ -0,0 +1,17 @@
package org.fossify.messages.helpers
import android.content.Context
import org.fossify.messages.extensions.config
object ReceiverUtils {
fun isMessageFilteredOut(context: Context, body: String): Boolean {
for (blockedKeyword in context.config.blockedKeywords) {
if (body.contains(blockedKeyword, ignoreCase = true)) {
return true
}
}
return false
}
}

View file

@ -6,13 +6,14 @@ import android.os.Handler
import android.os.Looper
import com.bumptech.glide.Glide
import com.klinker.android.send_message.MmsReceivedReceiver
import org.fossify.commons.extensions.isNumberBlocked
import org.fossify.commons.extensions.normalizePhoneNumber
import org.fossify.commons.extensions.showErrorToast
import org.fossify.commons.extensions.*
import org.fossify.commons.helpers.SimpleContactsHelper
import org.fossify.commons.helpers.ensureBackgroundThread
import org.fossify.messages.R
import org.fossify.messages.extensions.*
import org.fossify.messages.helpers.ReceiverUtils.isMessageFilteredOut
import org.fossify.messages.helpers.refreshMessages
import org.fossify.messages.models.Message
// more info at https://github.com/klinker41/android-smsmms
class MmsReceiver : MmsReceivedReceiver() {
@ -27,29 +28,52 @@ class MmsReceiver : MmsReceivedReceiver() {
val address = mms.getSender()?.phoneNumbers?.first()?.normalizedNumber ?: ""
val size = context.resources.getDimension(R.dimen.notification_large_icon_size).toInt()
val privateCursor = context.getMyContactsCursor(false, true)
ensureBackgroundThread {
val glideBitmap = try {
Glide.with(context)
.asBitmap()
.load(mms.attachment!!.attachments.first().getUri())
.centerCrop()
.into(size, size)
.get()
} catch (e: Exception) {
null
}
Handler(Looper.getMainLooper()).post {
context.showReceivedMessageNotification(mms.id, address, mms.body, mms.threadId, glideBitmap)
val conversation = context.getConversations(mms.threadId).firstOrNull() ?: return@post
ensureBackgroundThread {
context.insertOrUpdateConversation(conversation)
context.updateUnreadCountBadge(context.conversationsDB.getUnreadConversations())
refreshMessages()
if (context.baseConfig.blockUnknownNumbers) {
val simpleContactsHelper = SimpleContactsHelper(context)
simpleContactsHelper.exists(address, privateCursor) { exists ->
if (exists) {
handleMmsMessage(context, mms, size, address)
}
}
} else {
handleMmsMessage(context, mms, size, address)
}
}
}
override fun onError(context: Context, error: String) = context.showErrorToast(context.getString(R.string.couldnt_download_mms))
private fun handleMmsMessage(
context: Context,
mms: Message,
size: Int,
address: String
) {
if (isMessageFilteredOut(context, mms.body)) {
return
}
val glideBitmap = try {
Glide.with(context)
.asBitmap()
.load(mms.attachment!!.attachments.first().getUri())
.centerCrop()
.into(size, size)
.get()
} catch (e: Exception) {
null
}
Handler(Looper.getMainLooper()).post {
context.showReceivedMessageNotification(mms.id, address, mms.body, mms.threadId, glideBitmap)
val conversation = context.getConversations(mms.threadId).firstOrNull() ?: return@post
ensureBackgroundThread {
context.insertOrUpdateConversation(conversation)
context.updateUnreadCountBadge(context.conversationsDB.getUnreadConversations())
refreshMessages()
}
}
}
}

View file

@ -14,6 +14,7 @@ import org.fossify.commons.helpers.ensureBackgroundThread
import org.fossify.commons.models.PhoneNumber
import org.fossify.commons.models.SimpleContact
import org.fossify.messages.extensions.*
import org.fossify.messages.helpers.ReceiverUtils.isMessageFilteredOut
import org.fossify.messages.helpers.refreshMessages
import org.fossify.messages.models.Message
@ -40,7 +41,6 @@ class SmsReceiver : BroadcastReceiver() {
date = System.currentTimeMillis()
threadId = context.getThreadId(address)
}
if (context.baseConfig.blockUnknownNumbers) {
val simpleContactsHelper = SimpleContactsHelper(context)
simpleContactsHelper.exists(address, privateCursor) { exists ->
@ -122,14 +122,4 @@ class SmsReceiver : BroadcastReceiver() {
}
}
}
private fun isMessageFilteredOut(context: Context, body: String): Boolean {
for (blockedKeyword in context.config.blockedKeywords) {
if (body.contains(blockedKeyword, ignoreCase = true)) {
return true
}
}
return false
}
}