Remove support for Android and older versions
See https://github.com/orgs/FossifyOrg/discussions/241
|
|
@ -6,20 +6,31 @@ import android.content.Intent
|
|||
import android.media.AudioAttributes
|
||||
import android.media.AudioManager
|
||||
import android.media.RingtoneManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import org.fossify.commons.extensions.*
|
||||
import org.fossify.commons.extensions.applyColorFilter
|
||||
import org.fossify.commons.extensions.beGone
|
||||
import org.fossify.commons.extensions.beVisible
|
||||
import org.fossify.commons.extensions.beVisibleIf
|
||||
import org.fossify.commons.extensions.getProperPrimaryColor
|
||||
import org.fossify.commons.extensions.getProperTextColor
|
||||
import org.fossify.commons.extensions.notificationManager
|
||||
import org.fossify.commons.extensions.updateTextColors
|
||||
import org.fossify.commons.extensions.viewBinding
|
||||
import org.fossify.commons.helpers.NavigationIcon
|
||||
import org.fossify.commons.helpers.ensureBackgroundThread
|
||||
import org.fossify.commons.helpers.isOreoPlus
|
||||
import org.fossify.commons.models.SimpleContact
|
||||
import org.fossify.messages.adapters.ContactsAdapter
|
||||
import org.fossify.messages.databinding.ActivityConversationDetailsBinding
|
||||
import org.fossify.messages.dialogs.RenameConversationDialog
|
||||
import org.fossify.messages.extensions.*
|
||||
import org.fossify.messages.extensions.config
|
||||
import org.fossify.messages.extensions.conversationsDB
|
||||
import org.fossify.messages.extensions.getContactFromAddress
|
||||
import org.fossify.messages.extensions.getThreadParticipants
|
||||
import org.fossify.messages.extensions.messagesDB
|
||||
import org.fossify.messages.extensions.renameConversation
|
||||
import org.fossify.messages.extensions.startContactDetailsIntent
|
||||
import org.fossify.messages.helpers.THREAD_ID
|
||||
import org.fossify.messages.models.Conversation
|
||||
|
||||
|
|
@ -42,7 +53,10 @@ class ConversationDetailsActivity : SimpleActivity() {
|
|||
useTransparentNavigation = true,
|
||||
useTopSearchMenu = false
|
||||
)
|
||||
setupMaterialScrollListener(scrollingView = binding.participantsRecyclerview, toolbar = binding.conversationDetailsToolbar)
|
||||
setupMaterialScrollListener(
|
||||
scrollingView = binding.participantsRecyclerview,
|
||||
toolbar = binding.conversationDetailsToolbar
|
||||
)
|
||||
|
||||
threadId = intent.getLongExtra(THREAD_ID, 0L)
|
||||
ensureBackgroundThread {
|
||||
|
|
@ -56,9 +70,7 @@ class ConversationDetailsActivity : SimpleActivity() {
|
|||
runOnUiThread {
|
||||
setupTextViews()
|
||||
setupParticipants()
|
||||
if (isOreoPlus()) {
|
||||
setupCustomNotifications()
|
||||
}
|
||||
setupCustomNotifications()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -73,7 +85,6 @@ class ConversationDetailsActivity : SimpleActivity() {
|
|||
binding.membersHeading.setTextColor(primaryColor)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private fun setupCustomNotifications() {
|
||||
binding.apply {
|
||||
notificationsHeading.beVisible()
|
||||
|
|
@ -104,7 +115,6 @@ class ConversationDetailsActivity : SimpleActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private fun createNotificationChannel() {
|
||||
val name = conversation?.title
|
||||
val audioAttributes = AudioAttributes.Builder()
|
||||
|
|
@ -116,27 +126,36 @@ class ConversationDetailsActivity : SimpleActivity() {
|
|||
NotificationChannel(threadId.toString(), name, NotificationManager.IMPORTANCE_HIGH).apply {
|
||||
setBypassDnd(false)
|
||||
enableLights(true)
|
||||
setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), audioAttributes)
|
||||
setSound(
|
||||
RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION),
|
||||
audioAttributes
|
||||
)
|
||||
enableVibration(true)
|
||||
notificationManager.createNotificationChannel(this)
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private fun removeNotificationChannel() {
|
||||
notificationManager.deleteNotificationChannel(threadId.toString())
|
||||
}
|
||||
|
||||
private fun setupTextViews() {
|
||||
binding.conversationName.apply {
|
||||
ResourcesCompat.getDrawable(resources, org.fossify.commons.R.drawable.ic_edit_vector, theme)?.apply {
|
||||
ResourcesCompat.getDrawable(
|
||||
resources,
|
||||
org.fossify.commons.R.drawable.ic_edit_vector,
|
||||
theme
|
||||
)?.apply {
|
||||
applyColorFilter(getProperTextColor())
|
||||
setCompoundDrawablesWithIntrinsicBounds(null, null, this, null)
|
||||
}
|
||||
|
||||
text = conversation?.title
|
||||
setOnClickListener {
|
||||
RenameConversationDialog(this@ConversationDetailsActivity, conversation!!) { title ->
|
||||
RenameConversationDialog(
|
||||
this@ConversationDetailsActivity,
|
||||
conversation!!
|
||||
) { title ->
|
||||
text = title
|
||||
ensureBackgroundThread {
|
||||
conversation = renameConversation(conversation!!, newTitle = title)
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ import org.fossify.commons.helpers.PERMISSION_READ_SMS
|
|||
import org.fossify.commons.helpers.PERMISSION_SEND_SMS
|
||||
import org.fossify.commons.helpers.SHORT_ANIMATION_DURATION
|
||||
import org.fossify.commons.helpers.ensureBackgroundThread
|
||||
import org.fossify.commons.helpers.isNougatMR1Plus
|
||||
import org.fossify.commons.helpers.isQPlus
|
||||
import org.fossify.commons.models.FAQItem
|
||||
import org.fossify.commons.models.Release
|
||||
|
|
@ -494,7 +493,7 @@ class MainActivity : SimpleActivity() {
|
|||
@SuppressLint("NewApi")
|
||||
private fun checkShortcut() {
|
||||
val appIconColor = config.appIconColor
|
||||
if (isNougatMR1Plus() && config.lastHandledShortcutColor != appIconColor) {
|
||||
if (config.lastHandledShortcutColor != appIconColor) {
|
||||
val newConversation = getCreateNewContactShortcut(appIconColor)
|
||||
|
||||
val manager = getSystemService(ShortcutManager::class.java)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
package org.fossify.messages.activities
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.DocumentsContract
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
|
|
@ -16,7 +14,9 @@ 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.beGone
|
||||
import org.fossify.commons.extensions.beGoneIf
|
||||
import org.fossify.commons.extensions.beVisible
|
||||
import org.fossify.commons.extensions.beVisibleIf
|
||||
import org.fossify.commons.extensions.getBlockedNumbers
|
||||
import org.fossify.commons.extensions.getCustomizeColorsString
|
||||
|
|
@ -36,8 +36,6 @@ 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
|
||||
|
|
@ -226,7 +224,6 @@ class SettingsActivity : SimpleActivity() {
|
|||
}
|
||||
|
||||
private fun setupCustomizeNotifications() = binding.apply {
|
||||
settingsCustomizeNotificationsHolder.beVisibleIf(isOreoPlus())
|
||||
settingsCustomizeNotificationsHolder.setOnClickListener {
|
||||
launchCustomizeNotificationsIntent()
|
||||
}
|
||||
|
|
@ -247,19 +244,20 @@ class SettingsActivity : SimpleActivity() {
|
|||
|
||||
private fun setupLanguage() = binding.apply {
|
||||
settingsLanguage.text = Locale.getDefault().displayLanguage
|
||||
settingsLanguageHolder.beVisibleIf(isTiramisuPlus())
|
||||
settingsLanguageHolder.setOnClickListener {
|
||||
launchChangeAppLanguageIntent()
|
||||
if (isTiramisuPlus()) {
|
||||
settingsLanguageHolder.beVisible()
|
||||
settingsLanguageHolder.setOnClickListener {
|
||||
launchChangeAppLanguageIntent()
|
||||
}
|
||||
} else {
|
||||
settingsLanguageHolder.beGone()
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
settingsManageBlockedNumbersHolder.beVisibleIf(isNougatPlus())
|
||||
|
||||
settingsManageBlockedNumbersHolder.beVisible()
|
||||
settingsManageBlockedNumbersHolder.setOnClickListener {
|
||||
if (isOrWasThankYouInstalled()) {
|
||||
Intent(this@SettingsActivity, ManageBlockedNumbersActivity::class.java).apply {
|
||||
|
|
|
|||
|
|
@ -95,8 +95,6 @@ import org.fossify.commons.helpers.PERMISSION_READ_PHONE_STATE
|
|||
import org.fossify.commons.helpers.SimpleContactsHelper
|
||||
import org.fossify.commons.helpers.VcfExporter
|
||||
import org.fossify.commons.helpers.ensureBackgroundThread
|
||||
import org.fossify.commons.helpers.isNougatPlus
|
||||
import org.fossify.commons.helpers.isOreoPlus
|
||||
import org.fossify.commons.helpers.isSPlus
|
||||
import org.fossify.commons.models.PhoneNumber
|
||||
import org.fossify.commons.models.RadioItem
|
||||
|
|
@ -349,7 +347,7 @@ class ThreadActivity : SimpleActivity() {
|
|||
findItem(R.id.conversation_details).isVisible = conversation != null && !isRecycleBin
|
||||
findItem(R.id.block_number).title =
|
||||
addLockedLabelIfNeeded(org.fossify.commons.R.string.block_number)
|
||||
findItem(R.id.block_number).isVisible = isNougatPlus() && !isRecycleBin
|
||||
findItem(R.id.block_number).isVisible = !isRecycleBin
|
||||
findItem(R.id.dial_number).isVisible =
|
||||
participants.size == 1 && !isSpecialNumber() && !isRecycleBin
|
||||
findItem(R.id.manage_people).isVisible = !isSpecialNumber() && !isRecycleBin
|
||||
|
|
@ -983,9 +981,7 @@ class ThreadActivity : SimpleActivity() {
|
|||
text = getString(R.string.invalid_short_code_desc)
|
||||
)
|
||||
}
|
||||
if (isOreoPlus()) {
|
||||
tooltipText = getString(org.fossify.commons.R.string.more_info)
|
||||
}
|
||||
tooltipText = getString(org.fossify.commons.R.string.more_info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,21 +5,34 @@ import android.text.TextUtils
|
|||
import android.view.Menu
|
||||
import org.fossify.commons.dialogs.ConfirmationDialog
|
||||
import org.fossify.commons.dialogs.FeatureLockedDialog
|
||||
import org.fossify.commons.extensions.*
|
||||
import org.fossify.commons.extensions.addBlockedNumber
|
||||
import org.fossify.commons.extensions.addLockedLabelIfNeeded
|
||||
import org.fossify.commons.extensions.copyToClipboard
|
||||
import org.fossify.commons.extensions.isOrWasThankYouInstalled
|
||||
import org.fossify.commons.extensions.launchActivityIntent
|
||||
import org.fossify.commons.extensions.notificationManager
|
||||
import org.fossify.commons.helpers.KEY_PHONE
|
||||
import org.fossify.commons.helpers.ensureBackgroundThread
|
||||
import org.fossify.commons.helpers.isNougatPlus
|
||||
import org.fossify.commons.views.MyRecyclerView
|
||||
import org.fossify.messages.R
|
||||
import org.fossify.messages.activities.SimpleActivity
|
||||
import org.fossify.messages.dialogs.RenameConversationDialog
|
||||
import org.fossify.messages.extensions.*
|
||||
import org.fossify.messages.extensions.config
|
||||
import org.fossify.messages.extensions.deleteConversation
|
||||
import org.fossify.messages.extensions.dialNumber
|
||||
import org.fossify.messages.extensions.markThreadMessagesRead
|
||||
import org.fossify.messages.extensions.markThreadMessagesUnread
|
||||
import org.fossify.messages.extensions.renameConversation
|
||||
import org.fossify.messages.extensions.updateConversationArchivedStatus
|
||||
import org.fossify.messages.helpers.refreshMessages
|
||||
import org.fossify.messages.messaging.isShortCodeWithLetters
|
||||
import org.fossify.messages.models.Conversation
|
||||
|
||||
class ConversationsAdapter(
|
||||
activity: SimpleActivity, recyclerView: MyRecyclerView, onRefresh: () -> Unit, itemClick: (Any) -> Unit
|
||||
activity: SimpleActivity,
|
||||
recyclerView: MyRecyclerView,
|
||||
onRefresh: () -> Unit,
|
||||
itemClick: (Any) -> Unit
|
||||
) : BaseConversationsAdapter(activity, recyclerView, onRefresh, itemClick) {
|
||||
override fun getActionMenuId() = R.menu.cab_conversations
|
||||
|
||||
|
|
@ -31,12 +44,16 @@ class ConversationsAdapter(
|
|||
val archiveAvailable = activity.config.isArchiveAvailable
|
||||
|
||||
menu.apply {
|
||||
findItem(R.id.cab_block_number).title = activity.addLockedLabelIfNeeded(org.fossify.commons.R.string.block_number)
|
||||
findItem(R.id.cab_block_number).isVisible = isNougatPlus()
|
||||
findItem(R.id.cab_add_number_to_contact).isVisible = isSingleSelection && !isGroupConversation
|
||||
findItem(R.id.cab_dial_number).isVisible = isSingleSelection && !isGroupConversation && !isShortCodeWithLetters(selectedConversation.phoneNumber)
|
||||
findItem(R.id.cab_block_number).title =
|
||||
activity.addLockedLabelIfNeeded(org.fossify.commons.R.string.block_number)
|
||||
findItem(R.id.cab_add_number_to_contact).isVisible =
|
||||
isSingleSelection && !isGroupConversation
|
||||
findItem(R.id.cab_dial_number).isVisible =
|
||||
isSingleSelection && !isGroupConversation &&
|
||||
!isShortCodeWithLetters(selectedConversation.phoneNumber)
|
||||
findItem(R.id.cab_copy_number).isVisible = isSingleSelection && !isGroupConversation
|
||||
findItem(R.id.cab_rename_conversation).isVisible = isSingleSelection && isGroupConversation
|
||||
findItem(R.id.cab_rename_conversation).isVisible =
|
||||
isSingleSelection && isGroupConversation
|
||||
findItem(R.id.cab_mark_as_read).isVisible = selectedItems.any { !it.read }
|
||||
findItem(R.id.cab_mark_as_unread).isVisible = selectedItems.any { it.read }
|
||||
findItem(R.id.cab_archive).isVisible = archiveAvailable
|
||||
|
|
@ -76,7 +93,10 @@ class ConversationsAdapter(
|
|||
private fun askConfirmBlock() {
|
||||
val numbers = getSelectedItems().distinctBy { it.phoneNumber }.map { it.phoneNumber }
|
||||
val numbersString = TextUtils.join(", ", numbers)
|
||||
val question = String.format(resources.getString(org.fossify.commons.R.string.block_confirmation), numbersString)
|
||||
val question = String.format(
|
||||
resources.getString(org.fossify.commons.R.string.block_confirmation),
|
||||
numbersString
|
||||
)
|
||||
|
||||
ConfirmationDialog(activity, question) {
|
||||
blockNumbers()
|
||||
|
|
@ -149,7 +169,8 @@ class ConversationsAdapter(
|
|||
return
|
||||
}
|
||||
|
||||
val conversationsToRemove = currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
|
||||
val conversationsToRemove =
|
||||
currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
|
||||
conversationsToRemove.forEach {
|
||||
activity.updateConversationArchivedStatus(it.threadId, true)
|
||||
activity.notificationManager.cancel(it.threadId.hashCode())
|
||||
|
|
@ -179,7 +200,8 @@ class ConversationsAdapter(
|
|||
return
|
||||
}
|
||||
|
||||
val conversationsToRemove = currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
|
||||
val conversationsToRemove =
|
||||
currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
|
||||
conversationsToRemove.forEach {
|
||||
activity.deleteConversation(it.threadId)
|
||||
activity.notificationManager.cancel(it.threadId.hashCode())
|
||||
|
|
@ -224,7 +246,8 @@ class ConversationsAdapter(
|
|||
return
|
||||
}
|
||||
|
||||
val conversationsMarkedAsRead = currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
|
||||
val conversationsMarkedAsRead =
|
||||
currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
|
||||
ensureBackgroundThread {
|
||||
conversationsMarkedAsRead.filter { conversation -> !conversation.read }.forEach {
|
||||
activity.markThreadMessagesRead(it.threadId)
|
||||
|
|
@ -239,7 +262,8 @@ class ConversationsAdapter(
|
|||
return
|
||||
}
|
||||
|
||||
val conversationsMarkedAsUnread = currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
|
||||
val conversationsMarkedAsUnread =
|
||||
currentList.filter { selectedKeys.contains(it.hashCode()) } as ArrayList<Conversation>
|
||||
ensureBackgroundThread {
|
||||
conversationsMarkedAsUnread.filter { conversation -> conversation.read }.forEach {
|
||||
activity.markThreadMessagesUnread(it.threadId)
|
||||
|
|
@ -280,8 +304,10 @@ class ConversationsAdapter(
|
|||
private fun checkPinBtnVisibility(menu: Menu) {
|
||||
val pinnedConversations = activity.config.pinnedConversations
|
||||
val selectedConversations = getSelectedItems()
|
||||
menu.findItem(R.id.cab_pin_conversation).isVisible = selectedConversations.any { !pinnedConversations.contains(it.threadId.toString()) }
|
||||
menu.findItem(R.id.cab_unpin_conversation).isVisible = selectedConversations.any { pinnedConversations.contains(it.threadId.toString()) }
|
||||
menu.findItem(R.id.cab_pin_conversation).isVisible =
|
||||
selectedConversations.any { !pinnedConversations.contains(it.threadId.toString()) }
|
||||
menu.findItem(R.id.cab_unpin_conversation).isVisible =
|
||||
selectedConversations.any { pinnedConversations.contains(it.threadId.toString()) }
|
||||
}
|
||||
|
||||
private fun refreshConversations() {
|
||||
|
|
|
|||
|
|
@ -14,21 +14,49 @@ import android.os.Handler
|
|||
import android.os.Looper
|
||||
import android.provider.ContactsContract.PhoneLookup
|
||||
import android.provider.OpenableColumns
|
||||
import android.provider.Telephony.*
|
||||
import android.provider.Telephony.Mms
|
||||
import android.provider.Telephony.MmsSms
|
||||
import android.provider.Telephony.Sms
|
||||
import android.provider.Telephony.Threads
|
||||
import android.provider.Telephony.ThreadsColumns
|
||||
import android.telephony.SubscriptionManager
|
||||
import android.text.TextUtils
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import me.leolin.shortcutbadger.ShortcutBadger
|
||||
import org.fossify.commons.extensions.*
|
||||
import org.fossify.commons.helpers.*
|
||||
import org.fossify.commons.extensions.areDigitsOnly
|
||||
import org.fossify.commons.extensions.getBlockedNumbers
|
||||
import org.fossify.commons.extensions.getIntValue
|
||||
import org.fossify.commons.extensions.getLongValue
|
||||
import org.fossify.commons.extensions.getMyContactsCursor
|
||||
import org.fossify.commons.extensions.getStringValue
|
||||
import org.fossify.commons.extensions.hasPermission
|
||||
import org.fossify.commons.extensions.isNumberBlocked
|
||||
import org.fossify.commons.extensions.normalizeString
|
||||
import org.fossify.commons.extensions.notificationManager
|
||||
import org.fossify.commons.extensions.queryCursor
|
||||
import org.fossify.commons.extensions.showErrorToast
|
||||
import org.fossify.commons.extensions.toInt
|
||||
import org.fossify.commons.extensions.toast
|
||||
import org.fossify.commons.extensions.trimToComparableNumber
|
||||
import org.fossify.commons.helpers.DAY_SECONDS
|
||||
import org.fossify.commons.helpers.MONTH_SECONDS
|
||||
import org.fossify.commons.helpers.MyContactsContentProvider
|
||||
import org.fossify.commons.helpers.PERMISSION_READ_CONTACTS
|
||||
import org.fossify.commons.helpers.SimpleContactsHelper
|
||||
import org.fossify.commons.helpers.ensureBackgroundThread
|
||||
import org.fossify.commons.helpers.isQPlus
|
||||
import org.fossify.commons.models.PhoneNumber
|
||||
import org.fossify.commons.models.SimpleContact
|
||||
import org.fossify.messages.R
|
||||
import org.fossify.messages.databases.MessagesDatabase
|
||||
import org.fossify.messages.helpers.*
|
||||
import org.fossify.messages.helpers.AttachmentUtils.parseAttachmentNames
|
||||
import org.fossify.messages.helpers.Config
|
||||
import org.fossify.messages.helpers.FILE_SIZE_NONE
|
||||
import org.fossify.messages.helpers.MESSAGES_LIMIT
|
||||
import org.fossify.messages.helpers.NotificationHelper
|
||||
import org.fossify.messages.helpers.generateRandomId
|
||||
import org.fossify.messages.interfaces.AttachmentsDao
|
||||
import org.fossify.messages.interfaces.ConversationsDao
|
||||
import org.fossify.messages.interfaces.MessageAttachmentsDao
|
||||
|
|
@ -36,7 +64,12 @@ import org.fossify.messages.interfaces.MessagesDao
|
|||
import org.fossify.messages.messaging.MessagingUtils
|
||||
import org.fossify.messages.messaging.MessagingUtils.Companion.ADDRESS_SEPARATOR
|
||||
import org.fossify.messages.messaging.SmsSender
|
||||
import org.fossify.messages.models.*
|
||||
import org.fossify.messages.models.Attachment
|
||||
import org.fossify.messages.models.Conversation
|
||||
import org.fossify.messages.models.Message
|
||||
import org.fossify.messages.models.MessageAttachment
|
||||
import org.fossify.messages.models.NamePhoto
|
||||
import org.fossify.messages.models.RecycleBinMessage
|
||||
import java.io.FileNotFoundException
|
||||
|
||||
val Context.config: Config get() = Config.newInstance(applicationContext)
|
||||
|
|
@ -114,7 +147,15 @@ fun Context.getMessages(
|
|||
val participants = senderNumber.split(ADDRESS_SEPARATOR).map { number ->
|
||||
val phoneNumber = PhoneNumber(number, 0, "", number)
|
||||
val participantPhoto = getNameAndPhotoFromPhoneNumber(number)
|
||||
SimpleContact(0, 0, participantPhoto.name, photoUri, arrayListOf(phoneNumber), ArrayList(), ArrayList())
|
||||
SimpleContact(
|
||||
0,
|
||||
0,
|
||||
participantPhoto.name,
|
||||
photoUri,
|
||||
arrayListOf(phoneNumber),
|
||||
ArrayList(),
|
||||
ArrayList()
|
||||
)
|
||||
}
|
||||
val isMMS = false
|
||||
val message =
|
||||
|
|
@ -159,7 +200,12 @@ fun Context.getMessages(
|
|||
}
|
||||
|
||||
// as soon as a message contains multiple recipients it counts as an MMS instead of SMS
|
||||
fun Context.getMMS(threadId: Long? = null, getImageResolutions: Boolean = false, sortOrder: String? = null, dateFrom: Int = -1): ArrayList<Message> {
|
||||
fun Context.getMMS(
|
||||
threadId: Long? = null,
|
||||
getImageResolutions: Boolean = false,
|
||||
sortOrder: String? = null,
|
||||
dateFrom: Int = -1
|
||||
): ArrayList<Message> {
|
||||
val uri = Mms.CONTENT_URI
|
||||
val projection = arrayOf(
|
||||
Mms._ID,
|
||||
|
|
@ -175,7 +221,8 @@ fun Context.getMMS(threadId: Long? = null, getImageResolutions: Boolean = false,
|
|||
var selectionArgs: Array<String>? = null
|
||||
|
||||
if (threadId == null && dateFrom != -1) {
|
||||
selection = "${Sms.DATE} < ${dateFrom.toLong()}" //Should not multiply 1000 here, because date in mms's database is different from sms's.
|
||||
selection =
|
||||
"${Sms.DATE} < ${dateFrom.toLong()}" //Should not multiply 1000 here, because date in mms's database is different from sms's.
|
||||
} else if (threadId != null && dateFrom == -1) {
|
||||
selection = "${Sms.THREAD_ID} = ?"
|
||||
selectionArgs = arrayOf(threadId.toString())
|
||||
|
|
@ -262,7 +309,10 @@ fun Context.getMMSSender(msgId: Long): String {
|
|||
return ""
|
||||
}
|
||||
|
||||
fun Context.getConversations(threadId: Long? = null, privateContacts: ArrayList<SimpleContact> = ArrayList()): ArrayList<Conversation> {
|
||||
fun Context.getConversations(
|
||||
threadId: Long? = null,
|
||||
privateContacts: ArrayList<SimpleContact> = ArrayList()
|
||||
): ArrayList<Conversation> {
|
||||
val archiveAvailable = config.isArchiveAvailable
|
||||
|
||||
val uri = Uri.parse("${Threads.CONTENT_URI}?simple=true")
|
||||
|
|
@ -291,7 +341,13 @@ fun Context.getConversations(threadId: Long? = null, privateContacts: ArrayList<
|
|||
val simpleContactHelper = SimpleContactsHelper(this)
|
||||
val blockedNumbers = getBlockedNumbers()
|
||||
try {
|
||||
queryCursorUnsafe(uri, projection.toTypedArray(), selection, selectionArgs, sortOrder) { cursor ->
|
||||
queryCursorUnsafe(
|
||||
uri,
|
||||
projection.toTypedArray(),
|
||||
selection,
|
||||
selectionArgs,
|
||||
sortOrder
|
||||
) { cursor ->
|
||||
val id = cursor.getLongValue(Threads._ID)
|
||||
var snippet = cursor.getStringValue(Threads.SNIPPET) ?: ""
|
||||
if (snippet.isEmpty()) {
|
||||
|
|
@ -304,19 +360,39 @@ fun Context.getConversations(threadId: Long? = null, privateContacts: ArrayList<
|
|||
}
|
||||
|
||||
val rawIds = cursor.getStringValue(Threads.RECIPIENT_IDS)
|
||||
val recipientIds = rawIds.split(" ").filter { it.areDigitsOnly() }.map { it.toInt() }.toMutableList()
|
||||
val recipientIds =
|
||||
rawIds.split(" ").filter { it.areDigitsOnly() }.map { it.toInt() }.toMutableList()
|
||||
val phoneNumbers = getThreadPhoneNumbers(recipientIds)
|
||||
if (phoneNumbers.isEmpty() || phoneNumbers.any { isNumberBlocked(it, blockedNumbers) }) {
|
||||
if (phoneNumbers.isEmpty() || phoneNumbers.any {
|
||||
isNumberBlocked(
|
||||
it,
|
||||
blockedNumbers
|
||||
)
|
||||
}) {
|
||||
return@queryCursorUnsafe
|
||||
}
|
||||
|
||||
val names = getThreadContactNames(phoneNumbers, privateContacts)
|
||||
val title = TextUtils.join(", ", names.toTypedArray())
|
||||
val photoUri = if (phoneNumbers.size == 1) simpleContactHelper.getPhotoUriFromPhoneNumber(phoneNumbers.first()) else ""
|
||||
val photoUri =
|
||||
if (phoneNumbers.size == 1) simpleContactHelper.getPhotoUriFromPhoneNumber(
|
||||
phoneNumbers.first()
|
||||
) else ""
|
||||
val isGroupConversation = phoneNumbers.size > 1
|
||||
val read = cursor.getIntValue(Threads.READ) == 1
|
||||
val archived = if (archiveAvailable) cursor.getIntValue(Threads.ARCHIVED) == 1 else false
|
||||
val conversation = Conversation(id, snippet, date.toInt(), read, title, photoUri, isGroupConversation, phoneNumbers.first(), isArchived = archived)
|
||||
val archived =
|
||||
if (archiveAvailable) cursor.getIntValue(Threads.ARCHIVED) == 1 else false
|
||||
val conversation = Conversation(
|
||||
id,
|
||||
snippet,
|
||||
date.toInt(),
|
||||
read,
|
||||
title,
|
||||
photoUri,
|
||||
isGroupConversation,
|
||||
phoneNumbers.first(),
|
||||
isArchived = archived
|
||||
)
|
||||
conversations.add(conversation)
|
||||
}
|
||||
} catch (sqliteException: SQLiteException) {
|
||||
|
|
@ -399,7 +475,11 @@ fun Context.getMmsAttachment(id: Long, getImageResolutions: Boolean): MessageAtt
|
|||
try {
|
||||
val options = BitmapFactory.Options()
|
||||
options.inJustDecodeBounds = true
|
||||
BitmapFactory.decodeStream(contentResolver.openInputStream(fileUri), null, options)
|
||||
BitmapFactory.decodeStream(
|
||||
contentResolver.openInputStream(fileUri),
|
||||
null,
|
||||
options
|
||||
)
|
||||
width = options.outWidth
|
||||
height = options.outHeight
|
||||
} catch (e: Exception) {
|
||||
|
|
@ -410,7 +490,15 @@ fun Context.getMmsAttachment(id: Long, getImageResolutions: Boolean): MessageAtt
|
|||
messageAttachment.attachments.add(attachment)
|
||||
} else if (mimetype != "application/smil") {
|
||||
val attachmentName = attachmentNames?.getOrNull(attachmentCount) ?: ""
|
||||
val attachment = Attachment(partId, id, Uri.withAppendedPath(uri, partId.toString()).toString(), mimetype, 0, 0, attachmentName)
|
||||
val attachment = Attachment(
|
||||
partId,
|
||||
id,
|
||||
Uri.withAppendedPath(uri, partId.toString()).toString(),
|
||||
mimetype,
|
||||
0,
|
||||
0,
|
||||
attachmentName
|
||||
)
|
||||
messageAttachment.attachments.add(attachment)
|
||||
attachmentCount++
|
||||
} else {
|
||||
|
|
@ -476,7 +564,10 @@ fun Context.getMessageRecipientAddress(messageId: Long): String {
|
|||
return ""
|
||||
}
|
||||
|
||||
fun Context.getThreadParticipants(threadId: Long, contactsMap: HashMap<Int, SimpleContact>?): ArrayList<SimpleContact> {
|
||||
fun Context.getThreadParticipants(
|
||||
threadId: Long,
|
||||
contactsMap: HashMap<Int, SimpleContact>?
|
||||
): ArrayList<SimpleContact> {
|
||||
val uri = Uri.parse("${MmsSms.CONTENT_CONVERSATIONS_URI}?simple=true")
|
||||
val projection = arrayOf(
|
||||
ThreadsColumns.RECIPIENT_IDS
|
||||
|
|
@ -501,7 +592,15 @@ fun Context.getThreadParticipants(threadId: Long, contactsMap: HashMap<Int, Simp
|
|||
val name = namePhoto.name
|
||||
val photoUri = namePhoto.photoUri ?: ""
|
||||
val phoneNumber = PhoneNumber(number, 0, "", number)
|
||||
val contact = SimpleContact(addressId, addressId, name, photoUri, arrayListOf(phoneNumber), ArrayList(), ArrayList())
|
||||
val contact = SimpleContact(
|
||||
addressId,
|
||||
addressId,
|
||||
name,
|
||||
photoUri,
|
||||
arrayListOf(phoneNumber),
|
||||
ArrayList(),
|
||||
ArrayList()
|
||||
)
|
||||
participants.add(contact)
|
||||
}
|
||||
}
|
||||
|
|
@ -520,7 +619,10 @@ fun Context.getThreadPhoneNumbers(recipientIds: List<Int>): ArrayList<String> {
|
|||
return numbers
|
||||
}
|
||||
|
||||
fun Context.getThreadContactNames(phoneNumbers: List<String>, privateContacts: ArrayList<SimpleContact>): ArrayList<String> {
|
||||
fun Context.getThreadContactNames(
|
||||
phoneNumbers: List<String>,
|
||||
privateContacts: ArrayList<SimpleContact>
|
||||
): ArrayList<String> {
|
||||
val names = ArrayList<String>()
|
||||
phoneNumbers.forEach { number ->
|
||||
val name = SimpleContactsHelper(this).getNameFromPhoneNumber(number)
|
||||
|
|
@ -578,7 +680,8 @@ fun Context.getSuggestedContacts(privateContacts: ArrayList<SimpleContact>): Arr
|
|||
return@queryCursor
|
||||
} else if (namePhoto.name == senderNumber) {
|
||||
if (privateContacts.isNotEmpty()) {
|
||||
val privateContact = privateContacts.firstOrNull { it.phoneNumbers.first().normalizedNumber == senderNumber }
|
||||
val privateContact =
|
||||
privateContacts.firstOrNull { it.phoneNumbers.first().normalizedNumber == senderNumber }
|
||||
if (privateContact != null) {
|
||||
senderName = privateContact.name
|
||||
photoUri = privateContact.photoUri
|
||||
|
|
@ -591,8 +694,17 @@ fun Context.getSuggestedContacts(privateContacts: ArrayList<SimpleContact>): Arr
|
|||
}
|
||||
|
||||
val phoneNumber = PhoneNumber(senderNumber, 0, "", senderNumber)
|
||||
val contact = SimpleContact(0, 0, senderName, photoUri, arrayListOf(phoneNumber), ArrayList(), ArrayList())
|
||||
if (!contacts.map { it.phoneNumbers.first().normalizedNumber.trimToComparableNumber() }.contains(senderNumber.trimToComparableNumber())) {
|
||||
val contact = SimpleContact(
|
||||
0,
|
||||
0,
|
||||
senderName,
|
||||
photoUri,
|
||||
arrayListOf(phoneNumber),
|
||||
ArrayList(),
|
||||
ArrayList()
|
||||
)
|
||||
if (!contacts.map { it.phoneNumbers.first().normalizedNumber.trimToComparableNumber() }
|
||||
.contains(senderNumber.trimToComparableNumber())) {
|
||||
contacts.add(contact)
|
||||
}
|
||||
}
|
||||
|
|
@ -690,7 +802,7 @@ fun Context.deleteConversation(threadId: Long) {
|
|||
conversationsDB.deleteThreadId(threadId)
|
||||
messagesDB.deleteThreadMessages(threadId)
|
||||
|
||||
if (config.customNotifications.contains(threadId.toString()) && isOreoPlus()) {
|
||||
if (config.customNotifications.contains(threadId.toString())) {
|
||||
config.removeCustomNotificationsByThreadId(threadId)
|
||||
notificationManager.deleteNotificationChannel(threadId.toString())
|
||||
}
|
||||
|
|
@ -853,13 +965,26 @@ fun Context.getThreadId(addresses: Set<String>): Long {
|
|||
}
|
||||
}
|
||||
|
||||
fun Context.showReceivedMessageNotification(messageId: Long, address: String, body: String, threadId: Long, bitmap: Bitmap?) {
|
||||
fun Context.showReceivedMessageNotification(
|
||||
messageId: Long,
|
||||
address: String,
|
||||
body: String,
|
||||
threadId: Long,
|
||||
bitmap: Bitmap?
|
||||
) {
|
||||
val privateCursor = getMyContactsCursor(favoritesOnly = false, withPhoneNumbersOnly = true)
|
||||
ensureBackgroundThread {
|
||||
val senderName = getNameFromAddress(address, privateCursor)
|
||||
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
notificationHelper.showMessageNotification(messageId, address, body, threadId, bitmap, senderName)
|
||||
notificationHelper.showMessageNotification(
|
||||
messageId,
|
||||
address,
|
||||
body,
|
||||
threadId,
|
||||
bitmap,
|
||||
senderName
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -993,7 +1118,8 @@ fun Context.updateLastConversationMessage(threadId: Long) {
|
|||
// following Android code (which runs even if no messages are deleted):
|
||||
// https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/android14-release/src/com/android/providers/telephony/MmsSmsProvider.java#1409
|
||||
val uri = Threads.CONTENT_URI
|
||||
val selection = "1 = 0" // always-false condition, because we don't actually want to delete any messages
|
||||
val selection =
|
||||
"1 = 0" // always-false condition, because we don't actually want to delete any messages
|
||||
try {
|
||||
contentResolver.delete(uri, selection, null)
|
||||
val newConversation = getConversations(threadId)[0]
|
||||
|
|
@ -1017,20 +1143,21 @@ fun Context.getFileSizeFromUri(uri: Uri): Long {
|
|||
|
||||
// if "content://" uri scheme, try contentResolver table
|
||||
if (uri.scheme.equals(ContentResolver.SCHEME_CONTENT)) {
|
||||
return contentResolver.query(uri, arrayOf(OpenableColumns.SIZE), null, null, null)?.use { cursor ->
|
||||
// maybe shouldn't trust ContentResolver for size:
|
||||
// https://stackoverflow.com/questions/48302972/content-resolver-returns-wrong-size
|
||||
val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
|
||||
if (sizeIndex == -1) {
|
||||
return@use FILE_SIZE_NONE
|
||||
}
|
||||
cursor.moveToFirst()
|
||||
return try {
|
||||
cursor.getLong(sizeIndex)
|
||||
} catch (_: Throwable) {
|
||||
FILE_SIZE_NONE
|
||||
}
|
||||
} ?: FILE_SIZE_NONE
|
||||
return contentResolver.query(uri, arrayOf(OpenableColumns.SIZE), null, null, null)
|
||||
?.use { cursor ->
|
||||
// maybe shouldn't trust ContentResolver for size:
|
||||
// https://stackoverflow.com/questions/48302972/content-resolver-returns-wrong-size
|
||||
val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
|
||||
if (sizeIndex == -1) {
|
||||
return@use FILE_SIZE_NONE
|
||||
}
|
||||
cursor.moveToFirst()
|
||||
return try {
|
||||
cursor.getLong(sizeIndex)
|
||||
} catch (_: Throwable) {
|
||||
FILE_SIZE_NONE
|
||||
}
|
||||
} ?: FILE_SIZE_NONE
|
||||
} else {
|
||||
return FILE_SIZE_NONE
|
||||
}
|
||||
|
|
@ -1061,7 +1188,8 @@ fun Context.insertOrUpdateConversation(
|
|||
) {
|
||||
var updatedConv = conversation
|
||||
if (cachedConv != null && cachedConv.usesCustomTitle) {
|
||||
updatedConv = updatedConv.copy(title = cachedConv.title, usesCustomTitle = cachedConv.usesCustomTitle)
|
||||
updatedConv =
|
||||
updatedConv.copy(title = cachedConv.title, usesCustomTitle = cachedConv.usesCustomTitle)
|
||||
}
|
||||
conversationsDB.insertOrUpdate(updatedConv)
|
||||
}
|
||||
|
|
@ -1076,10 +1204,15 @@ fun Context.renameConversation(conversation: Conversation, newTitle: String): Co
|
|||
return updatedConv
|
||||
}
|
||||
|
||||
fun Context.createTemporaryThread(message: Message, threadId: Long = generateRandomId(), cachedConv: Conversation?) {
|
||||
fun Context.createTemporaryThread(
|
||||
message: Message,
|
||||
threadId: Long = generateRandomId(),
|
||||
cachedConv: Conversation?
|
||||
) {
|
||||
val simpleContactHelper = SimpleContactsHelper(this)
|
||||
val addresses = message.participants.getAddresses()
|
||||
val photoUri = if (addresses.size == 1) simpleContactHelper.getPhotoUriFromPhoneNumber(addresses.first()) else ""
|
||||
val photoUri =
|
||||
if (addresses.size == 1) simpleContactHelper.getPhotoUriFromPhoneNumber(addresses.first()) else ""
|
||||
val title = if (cachedConv != null && cachedConv.usesCustomTitle) {
|
||||
cachedConv.title
|
||||
} else {
|
||||
|
|
@ -1132,4 +1265,5 @@ fun Context.clearExpiredScheduledMessages(threadId: Long, messagesToDelete: List
|
|||
}
|
||||
}
|
||||
|
||||
fun Context.getDefaultKeyboardHeight() = resources.getDimensionPixelSize(R.dimen.default_keyboard_height)
|
||||
fun Context.getDefaultKeyboardHeight() =
|
||||
resources.getDimensionPixelSize(R.dimen.default_keyboard_height)
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@ import androidx.core.app.RemoteInput
|
|||
import org.fossify.commons.extensions.getProperPrimaryColor
|
||||
import org.fossify.commons.extensions.notificationManager
|
||||
import org.fossify.commons.helpers.SimpleContactsHelper
|
||||
import org.fossify.commons.helpers.isNougatPlus
|
||||
import org.fossify.commons.helpers.isOreoPlus
|
||||
import org.fossify.messages.R
|
||||
import org.fossify.messages.activities.ThreadActivity
|
||||
import org.fossify.messages.extensions.config
|
||||
|
|
@ -45,10 +43,12 @@ class NotificationHelper(private val context: Context) {
|
|||
sender: String?,
|
||||
alertOnlyOnce: Boolean = false
|
||||
) {
|
||||
val hasCustomNotifications = context.config.customNotifications.contains(threadId.toString())
|
||||
val notificationChannelId = if (hasCustomNotifications) threadId.toString() else NOTIFICATION_CHANNEL_ID
|
||||
val hasCustomNotifications =
|
||||
context.config.customNotifications.contains(threadId.toString())
|
||||
val notificationChannelId =
|
||||
if (hasCustomNotifications) threadId.toString() else NOTIFICATION_CHANNEL_ID
|
||||
if (!hasCustomNotifications) {
|
||||
maybeCreateChannel(notificationChannelId, context.getString(R.string.channel_received_sms))
|
||||
createChannel(notificationChannelId, context.getString(R.string.channel_received_sms))
|
||||
}
|
||||
|
||||
val notificationId = threadId.hashCode()
|
||||
|
|
@ -56,25 +56,40 @@ class NotificationHelper(private val context: Context) {
|
|||
putExtra(THREAD_ID, threadId)
|
||||
}
|
||||
val contentPendingIntent =
|
||||
PendingIntent.getActivity(context, notificationId, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
|
||||
PendingIntent.getActivity(
|
||||
context,
|
||||
notificationId,
|
||||
contentIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
|
||||
)
|
||||
|
||||
val markAsReadIntent = Intent(context, MarkAsReadReceiver::class.java).apply {
|
||||
action = MARK_AS_READ
|
||||
putExtra(THREAD_ID, threadId)
|
||||
}
|
||||
val markAsReadPendingIntent =
|
||||
PendingIntent.getBroadcast(context, notificationId, markAsReadIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
|
||||
PendingIntent.getBroadcast(
|
||||
context,
|
||||
notificationId,
|
||||
markAsReadIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
|
||||
)
|
||||
|
||||
val deleteSmsIntent = Intent(context, DeleteSmsReceiver::class.java).apply {
|
||||
putExtra(THREAD_ID, threadId)
|
||||
putExtra(MESSAGE_ID, messageId)
|
||||
}
|
||||
val deleteSmsPendingIntent =
|
||||
PendingIntent.getBroadcast(context, notificationId, deleteSmsIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
|
||||
PendingIntent.getBroadcast(
|
||||
context,
|
||||
notificationId,
|
||||
deleteSmsIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
|
||||
)
|
||||
|
||||
var replyAction: NotificationCompat.Action? = null
|
||||
val isNoReplySms = isShortCodeWithLetters(address)
|
||||
if (isNougatPlus() && !isNoReplySms) {
|
||||
if (!isNoReplySms) {
|
||||
val replyLabel = context.getString(R.string.reply)
|
||||
val remoteInput = RemoteInput.Builder(REPLY)
|
||||
.setLabel(replyLabel)
|
||||
|
|
@ -92,7 +107,11 @@ class NotificationHelper(private val context: Context) {
|
|||
replyIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
|
||||
)
|
||||
replyAction = NotificationCompat.Action.Builder(R.drawable.ic_send_vector, replyLabel, replyPendingIntent)
|
||||
replyAction = NotificationCompat.Action.Builder(
|
||||
R.drawable.ic_send_vector,
|
||||
replyLabel,
|
||||
replyPendingIntent
|
||||
)
|
||||
.addRemoteInput(remoteInput)
|
||||
.build()
|
||||
}
|
||||
|
|
@ -113,7 +132,9 @@ class NotificationHelper(private val context: Context) {
|
|||
setContentTitle(sender)
|
||||
setLargeIcon(largeIcon)
|
||||
val summaryText = context.getString(R.string.new_message)
|
||||
setStyle(NotificationCompat.BigTextStyle().setSummaryText(summaryText).bigText(body))
|
||||
setStyle(
|
||||
NotificationCompat.BigTextStyle().setSummaryText(summaryText).bigText(body)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -132,7 +153,11 @@ class NotificationHelper(private val context: Context) {
|
|||
builder.addAction(replyAction)
|
||||
}
|
||||
|
||||
builder.addAction(org.fossify.commons.R.drawable.ic_check_vector, context.getString(R.string.mark_as_read), markAsReadPendingIntent)
|
||||
builder.addAction(
|
||||
org.fossify.commons.R.drawable.ic_check_vector,
|
||||
context.getString(R.string.mark_as_read),
|
||||
markAsReadPendingIntent
|
||||
)
|
||||
.setChannelId(notificationChannelId)
|
||||
if (isNoReplySms) {
|
||||
builder.addAction(
|
||||
|
|
@ -146,19 +171,27 @@ class NotificationHelper(private val context: Context) {
|
|||
|
||||
@SuppressLint("NewApi")
|
||||
fun showSendingFailedNotification(recipientName: String, threadId: Long) {
|
||||
val hasCustomNotifications = context.config.customNotifications.contains(threadId.toString())
|
||||
val notificationChannelId = if (hasCustomNotifications) threadId.toString() else NOTIFICATION_CHANNEL_ID
|
||||
val hasCustomNotifications =
|
||||
context.config.customNotifications.contains(threadId.toString())
|
||||
val notificationChannelId =
|
||||
if (hasCustomNotifications) threadId.toString() else NOTIFICATION_CHANNEL_ID
|
||||
if (!hasCustomNotifications) {
|
||||
maybeCreateChannel(notificationChannelId, context.getString(R.string.message_not_sent_short))
|
||||
createChannel(notificationChannelId, context.getString(R.string.message_not_sent_short))
|
||||
}
|
||||
|
||||
val notificationId = generateRandomId().hashCode()
|
||||
val intent = Intent(context, ThreadActivity::class.java).apply {
|
||||
putExtra(THREAD_ID, threadId)
|
||||
}
|
||||
val contentPendingIntent = PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
|
||||
val contentPendingIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
notificationId,
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
|
||||
)
|
||||
|
||||
val summaryText = String.format(context.getString(R.string.message_sending_error), recipientName)
|
||||
val summaryText =
|
||||
String.format(context.getString(R.string.message_sending_error), recipientName)
|
||||
val largeIcon = SimpleContactsHelper(context).getContactLetterIcon(recipientName)
|
||||
val builder = NotificationCompat.Builder(context, notificationChannelId)
|
||||
.setContentTitle(context.getString(R.string.message_not_sent_short))
|
||||
|
|
@ -177,26 +210,29 @@ class NotificationHelper(private val context: Context) {
|
|||
notificationManager.notify(notificationId, builder.build())
|
||||
}
|
||||
|
||||
private fun maybeCreateChannel(id: String, name: String) {
|
||||
if (isOreoPlus()) {
|
||||
val audioAttributes = AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
||||
.setLegacyStreamType(AudioManager.STREAM_NOTIFICATION)
|
||||
.build()
|
||||
private fun createChannel(id: String, name: String) {
|
||||
val audioAttributes = AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
||||
.setLegacyStreamType(AudioManager.STREAM_NOTIFICATION)
|
||||
.build()
|
||||
|
||||
val importance = IMPORTANCE_HIGH
|
||||
NotificationChannel(id, name, importance).apply {
|
||||
setBypassDnd(false)
|
||||
enableLights(true)
|
||||
setSound(soundUri, audioAttributes)
|
||||
enableVibration(true)
|
||||
notificationManager.createNotificationChannel(this)
|
||||
}
|
||||
val importance = IMPORTANCE_HIGH
|
||||
NotificationChannel(id, name, importance).apply {
|
||||
setBypassDnd(false)
|
||||
enableLights(true)
|
||||
setSound(soundUri, audioAttributes)
|
||||
enableVibration(true)
|
||||
notificationManager.createNotificationChannel(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMessagesStyle(address: String, body: String, notificationId: Int, name: String?): NotificationCompat.MessagingStyle {
|
||||
private fun getMessagesStyle(
|
||||
address: String,
|
||||
body: String,
|
||||
notificationId: Int,
|
||||
name: String?
|
||||
): NotificationCompat.MessagingStyle {
|
||||
val sender = if (name != null) {
|
||||
Person.Builder()
|
||||
.setName(name)
|
||||
|
|
@ -210,18 +246,20 @@ class NotificationHelper(private val context: Context) {
|
|||
getOldMessages(notificationId).forEach {
|
||||
style.addMessage(it)
|
||||
}
|
||||
val newMessage = NotificationCompat.MessagingStyle.Message(body, System.currentTimeMillis(), sender)
|
||||
val newMessage =
|
||||
NotificationCompat.MessagingStyle.Message(body, System.currentTimeMillis(), sender)
|
||||
style.addMessage(newMessage)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOldMessages(notificationId: Int): List<NotificationCompat.MessagingStyle.Message> {
|
||||
if (!isNougatPlus()) {
|
||||
return emptyList()
|
||||
}
|
||||
val currentNotification = notificationManager.activeNotifications.find { it.id == notificationId }
|
||||
val currentNotification =
|
||||
notificationManager.activeNotifications.find { it.id == notificationId }
|
||||
return if (currentNotification != null) {
|
||||
val activeStyle = NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification(currentNotification.notification)
|
||||
val activeStyle =
|
||||
NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification(
|
||||
currentNotification.notification
|
||||
)
|
||||
activeStyle?.messages.orEmpty()
|
||||
} else {
|
||||
emptyList()
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 890 B |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 5 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 7 KiB |
|
Before Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 7.3 KiB |