mirror of
https://github.com/SimpleMobileTools/Simple-SMS-Messenger.git
synced 2025-02-17 04:00:35 +01:00
Handle sending scheduled messages
This commit is contained in:
parent
16ea540d48
commit
2ff0880cb5
@ -11,6 +11,7 @@
|
||||
<uses-permission android:name="android.permission.RECEIVE_MMS" />
|
||||
<uses-permission android:name="android.provider.Telephony.SMS_RECEIVED" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
@ -212,6 +213,10 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".receivers.ScheduledMessageReceiver"
|
||||
android:exported="false" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.provider"
|
||||
|
@ -243,7 +243,7 @@ class MainActivity : SimpleActivity() {
|
||||
|
||||
if (config.appRunCount == 1) {
|
||||
conversations.map { it.threadId }.forEach { threadId ->
|
||||
val messages = getMessages(threadId, false)
|
||||
val messages = getMessages(threadId, getImageResolutions = false, includeScheduledMessages = false)
|
||||
messages.chunked(30).forEach { currentMessages ->
|
||||
messagesDB.insertMessages(*currentMessages.toTypedArray())
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ import android.os.Bundle
|
||||
import android.provider.ContactsContract
|
||||
import android.provider.MediaStore
|
||||
import android.provider.Telephony
|
||||
import android.provider.Telephony.Sms.MESSAGE_TYPE_QUEUED
|
||||
import android.provider.Telephony.Sms.STATUS_NONE
|
||||
import android.telephony.SmsManager
|
||||
import android.telephony.SmsMessage
|
||||
import android.telephony.SubscriptionInfo
|
||||
@ -92,6 +94,7 @@ class ThreadActivity : SimpleActivity() {
|
||||
private var oldestMessageDate = -1
|
||||
|
||||
private var isScheduledMessage: Boolean = false
|
||||
private var scheduledMessage: Message? = null
|
||||
private lateinit var scheduledDateTime: DateTime
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -260,8 +263,8 @@ class ThreadActivity : SimpleActivity() {
|
||||
val cachedMessagesCode = messages.clone().hashCode()
|
||||
messages = getMessages(threadId, true)
|
||||
|
||||
val hasParticipantWithoutName = participants.any {
|
||||
it.phoneNumbers.map { it.normalizedNumber }.contains(it.name)
|
||||
val hasParticipantWithoutName = participants.any { contact ->
|
||||
contact.phoneNumbers.map { it.normalizedNumber }.contains(contact.name)
|
||||
}
|
||||
|
||||
try {
|
||||
@ -327,10 +330,8 @@ class ThreadActivity : SimpleActivity() {
|
||||
|
||||
val currAdapter = thread_messages_list.adapter
|
||||
if (currAdapter == null) {
|
||||
ThreadAdapter(this, threadItems, thread_messages_list) {
|
||||
(it as? ThreadError)?.apply {
|
||||
thread_type_message.setText(it.messageText)
|
||||
}
|
||||
ThreadAdapter(this, threadItems, thread_messages_list) { any ->
|
||||
handleItemClick(any)
|
||||
}.apply {
|
||||
thread_messages_list.adapter = this
|
||||
}
|
||||
@ -373,6 +374,13 @@ class ThreadActivity : SimpleActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleItemClick(any: Any) {
|
||||
when {
|
||||
any is Message && any.isScheduled -> showScheduledMessageInfo(any)
|
||||
any is ThreadError -> thread_type_message.setText(any.messageText)
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchNextMessages() {
|
||||
if (messages.isEmpty() || allMessagesFetched || loadingOlderMessages) {
|
||||
return
|
||||
@ -590,8 +598,7 @@ class ThreadActivity : SimpleActivity() {
|
||||
|
||||
val defaultSmsSubscriptionId = SmsManager.getDefaultSmsSubscriptionId()
|
||||
val systemPreferredSimIdx = if (defaultSmsSubscriptionId >= 0) {
|
||||
val defaultSmsSIM = subscriptionManagerCompat().getActiveSubscriptionInfo(defaultSmsSubscriptionId)
|
||||
availableSIMs.indexOfFirstOrNull { it.subscriptionId == defaultSmsSIM.subscriptionId }
|
||||
availableSIMs.indexOfFirstOrNull { it.subscriptionId == defaultSmsSubscriptionId }
|
||||
} else {
|
||||
null
|
||||
}
|
||||
@ -600,13 +607,7 @@ class ThreadActivity : SimpleActivity() {
|
||||
}
|
||||
|
||||
private fun blockNumber() {
|
||||
val numbers = ArrayList<String>()
|
||||
participants.forEach {
|
||||
it.phoneNumbers.forEach {
|
||||
numbers.add(it.normalizedNumber)
|
||||
}
|
||||
}
|
||||
|
||||
val numbers = participants.getAddresses()
|
||||
val numbersString = TextUtils.join(", ", numbers)
|
||||
val question = String.format(resources.getString(R.string.block_confirmation), numbersString)
|
||||
|
||||
@ -939,21 +940,44 @@ class ThreadActivity : SimpleActivity() {
|
||||
|
||||
text = removeDiacriticsIfNeeded(text)
|
||||
|
||||
val addresses = participants
|
||||
.flatMap { it.phoneNumbers }
|
||||
.map { it.normalizedNumber }
|
||||
val subscriptionId = availableSIMCards.getOrNull(currentSIMCardIndex)?.subscriptionId ?: SmsManager.getDefaultSmsSubscriptionId()
|
||||
|
||||
val currentSubscriptionId = availableSIMCards.getOrNull(currentSIMCardIndex)?.subscriptionId
|
||||
val attachments = attachmentSelections.values.map { it.uri }
|
||||
if (isScheduledMessage) {
|
||||
sendScheduledMessage(text, subscriptionId)
|
||||
} else {
|
||||
sendNormalMessage(text, subscriptionId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendScheduledMessage(text: String, subscriptionId: Int) {
|
||||
refreshedSinceSent = false
|
||||
try {
|
||||
ensureBackgroundThread {
|
||||
val messageId = scheduledMessage?.id ?: generateRandomMessageId()
|
||||
val message = buildScheduledMessage(text, subscriptionId, messageId)
|
||||
messagesDB.insertOrUpdate(message)
|
||||
scheduleMessage(message)
|
||||
}
|
||||
clearCurrentMessage()
|
||||
hideScheduleSendUi()
|
||||
|
||||
if (!refreshedSinceSent) {
|
||||
refreshMessages()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
showErrorToast(e.localizedMessage ?: getString(R.string.unknown_error_occurred))
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendNormalMessage(text: String, subscriptionId: Int) {
|
||||
val addresses = participants.getAddresses()
|
||||
val attachments = attachmentSelections.values
|
||||
.map { it.uri }
|
||||
|
||||
try {
|
||||
refreshedSinceSent = false
|
||||
sendTransactionMessage(text, addresses, currentSubscriptionId, attachments)
|
||||
|
||||
thread_type_message.setText("")
|
||||
attachmentSelections.clear()
|
||||
thread_attachments_holder.beGone()
|
||||
thread_attachments_wrapper.removeAllViews()
|
||||
sendMessage(text, addresses, subscriptionId, attachments)
|
||||
clearCurrentMessage()
|
||||
|
||||
if (!refreshedSinceSent) {
|
||||
refreshMessages()
|
||||
@ -965,6 +989,13 @@ class ThreadActivity : SimpleActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearCurrentMessage() {
|
||||
thread_type_message.setText("")
|
||||
attachmentSelections.clear()
|
||||
thread_attachments_holder.beGone()
|
||||
thread_attachments_wrapper.removeAllViews()
|
||||
}
|
||||
|
||||
// show selected contacts, properly split to new lines when appropriate
|
||||
// based on https://stackoverflow.com/a/13505029/1967672
|
||||
private fun showSelectedContact(views: ArrayList<View>) {
|
||||
@ -1115,10 +1146,10 @@ class ThreadActivity : SimpleActivity() {
|
||||
messages.filter { !it.isReceivedMessage() && it.id > lastMaxId }.forEach { latestMessage ->
|
||||
// subscriptionIds seem to be not filled out at sending with multiple SIM cards, so fill it manually
|
||||
if ((subscriptionManagerCompat().activeSubscriptionInfoList?.size ?: 0) > 1) {
|
||||
val SIMId = availableSIMCards.getOrNull(currentSIMCardIndex)?.subscriptionId
|
||||
if (SIMId != null) {
|
||||
updateMessageSubscriptionId(latestMessage.id, SIMId)
|
||||
latestMessage.subscriptionId = SIMId
|
||||
val subscriptionId = availableSIMCards.getOrNull(currentSIMCardIndex)?.subscriptionId
|
||||
if (subscriptionId != null) {
|
||||
updateMessageSubscriptionId(latestMessage.id, subscriptionId)
|
||||
latestMessage.subscriptionId = subscriptionId
|
||||
}
|
||||
}
|
||||
|
||||
@ -1129,11 +1160,15 @@ class ThreadActivity : SimpleActivity() {
|
||||
setupSIMSelector()
|
||||
}
|
||||
|
||||
private fun updateMessageType() {
|
||||
val text = thread_type_message.text.toString()
|
||||
private fun isMmsMessage(text: String): Boolean {
|
||||
val isGroupMms = participants.size > 1 && config.sendGroupMessageMMS
|
||||
val isLongMmsMessage = isLongMmsMessage(text) && config.sendLongMessageMMS
|
||||
val stringId = if (attachmentSelections.isNotEmpty() || isGroupMms || isLongMmsMessage) {
|
||||
return attachmentSelections.isNotEmpty() || isGroupMms || isLongMmsMessage
|
||||
}
|
||||
|
||||
private fun updateMessageType() {
|
||||
val text = thread_type_message.text.toString()
|
||||
val stringId = if (isMmsMessage(text)) {
|
||||
R.string.mms
|
||||
} else {
|
||||
R.string.sms
|
||||
@ -1150,6 +1185,27 @@ class ThreadActivity : SimpleActivity() {
|
||||
return File.createTempFile("IMG_", ".jpg", outputDirectory)
|
||||
}
|
||||
|
||||
private fun showScheduledMessageInfo(message: Message) {
|
||||
// todo: maybe show options to edit, delete, and send the message now
|
||||
editScheduledMessage(message)
|
||||
}
|
||||
|
||||
private fun editScheduledMessage(message: Message) {
|
||||
scheduledMessage = message
|
||||
clearCurrentMessage()
|
||||
thread_type_message.setText(message.body)
|
||||
|
||||
val messageAttachment = message.attachment
|
||||
if (messageAttachment != null) {
|
||||
for (attachment in messageAttachment.attachments) {
|
||||
addAttachment(attachment.getUri())
|
||||
}
|
||||
}
|
||||
|
||||
scheduledDateTime = DateTime(message.millis())
|
||||
showScheduleSendUi()
|
||||
}
|
||||
|
||||
private fun launchScheduleSendDialog(originalDt: DateTime? = null) {
|
||||
ScheduleSendDialog(this, originalDt) { newDt ->
|
||||
if (newDt != null) {
|
||||
@ -1175,13 +1231,19 @@ class ThreadActivity : SimpleActivity() {
|
||||
applyColorFilter(textColor)
|
||||
setOnClickListener {
|
||||
hideScheduleSendUi()
|
||||
if (scheduledMessage != null) {
|
||||
ensureBackgroundThread {
|
||||
messagesDB.delete(scheduledMessage!!.id)
|
||||
refreshMessages()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showScheduleSendUi() {
|
||||
isScheduledMessage = true
|
||||
updateSendButton()
|
||||
updateSendButtonDrawable()
|
||||
scheduled_message_holder.beVisible()
|
||||
scheduled_message_button.text = scheduledDateTime.humanize(this)
|
||||
}
|
||||
@ -1189,10 +1251,10 @@ class ThreadActivity : SimpleActivity() {
|
||||
private fun hideScheduleSendUi() {
|
||||
isScheduledMessage = false
|
||||
scheduled_message_holder.beGone()
|
||||
updateSendButton()
|
||||
updateSendButtonDrawable()
|
||||
}
|
||||
|
||||
private fun updateSendButton() {
|
||||
private fun updateSendButtonDrawable() {
|
||||
val drawableResId = if (isScheduledMessage) {
|
||||
R.drawable.ic_schedule_send_vector
|
||||
} else {
|
||||
@ -1203,4 +1265,30 @@ class ThreadActivity : SimpleActivity() {
|
||||
thread_send_message.setCompoundDrawablesWithIntrinsicBounds(null, this, null, null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildScheduledMessage(text: String, subscriptionId: Int, messageId: Long): Message {
|
||||
return Message(
|
||||
id = messageId,
|
||||
body = text,
|
||||
type = MESSAGE_TYPE_QUEUED,
|
||||
status = STATUS_NONE,
|
||||
participants = participants,
|
||||
date = (scheduledDateTime.millis / 1000).toInt(),
|
||||
read = false,
|
||||
threadId = threadId,
|
||||
isMMS = isMmsMessage(text),
|
||||
attachment = buildMessageAttachment(text, messageId),
|
||||
senderName = "",
|
||||
senderPhotoUri = "",
|
||||
subscriptionId = subscriptionId,
|
||||
isScheduled = true
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildMessageAttachment(text: String, messageId: Long): MessageAttachment {
|
||||
val attachments = attachmentSelections.values
|
||||
.map { Attachment(null, messageId, it.uri.toString(), "*/*", 0, 0, "") }
|
||||
.toArrayList()
|
||||
return MessageAttachment(messageId, text, attachments)
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,10 @@ import android.annotation.SuppressLint
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.telephony.SubscriptionManager
|
||||
import android.util.TypedValue
|
||||
import android.view.Menu
|
||||
import android.view.View
|
||||
@ -40,7 +40,12 @@ import com.simplemobiletools.smsmessenger.models.*
|
||||
import kotlinx.android.synthetic.main.item_attachment_image.view.*
|
||||
import kotlinx.android.synthetic.main.item_attachment_vcard.view.*
|
||||
import kotlinx.android.synthetic.main.item_received_message.view.*
|
||||
import kotlinx.android.synthetic.main.item_received_message.view.thread_mesage_attachments_holder
|
||||
import kotlinx.android.synthetic.main.item_received_message.view.thread_message_body
|
||||
import kotlinx.android.synthetic.main.item_received_message.view.thread_message_holder
|
||||
import kotlinx.android.synthetic.main.item_received_message.view.thread_message_play_outline
|
||||
import kotlinx.android.synthetic.main.item_received_unknown_attachment.view.*
|
||||
import kotlinx.android.synthetic.main.item_sent_message.view.*
|
||||
import kotlinx.android.synthetic.main.item_sent_unknown_attachment.view.*
|
||||
import kotlinx.android.synthetic.main.item_thread_date_time.view.*
|
||||
import kotlinx.android.synthetic.main.item_thread_error.view.*
|
||||
@ -252,29 +257,9 @@ class ThreadAdapter(
|
||||
thread_message_body.beVisibleIf(message.body.isNotEmpty())
|
||||
|
||||
if (message.isReceivedMessage()) {
|
||||
thread_message_sender_photo.beVisible()
|
||||
thread_message_sender_photo.setOnClickListener {
|
||||
val contact = message.participants.first()
|
||||
context.getContactFromAddress(contact.phoneNumbers.first().normalizedNumber) {
|
||||
if (it != null) {
|
||||
(activity as ThreadActivity).startContactDetailsIntent(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
thread_message_body.setTextColor(textColor)
|
||||
thread_message_body.setLinkTextColor(context.getProperPrimaryColor())
|
||||
|
||||
if (!activity.isFinishing && !activity.isDestroyed) {
|
||||
SimpleContactsHelper(context).loadContactImage(message.senderPhotoUri, thread_message_sender_photo, message.senderName)
|
||||
}
|
||||
setupReceivedMessageView(view, message)
|
||||
} else {
|
||||
thread_message_sender_photo?.beGone()
|
||||
val background = context.getProperPrimaryColor()
|
||||
thread_message_body.background.applyColorFilter(background)
|
||||
|
||||
val contrastColor = background.getContrastColor()
|
||||
thread_message_body.setTextColor(contrastColor)
|
||||
thread_message_body.setLinkTextColor(contrastColor)
|
||||
setupSentMessageView(view, message)
|
||||
}
|
||||
|
||||
thread_message_body.setOnLongClickListener {
|
||||
@ -304,6 +289,55 @@ class ThreadAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupReceivedMessageView(view: View, message: Message) {
|
||||
view.apply {
|
||||
thread_message_sender_photo.beVisible()
|
||||
thread_message_sender_photo.setOnClickListener {
|
||||
val contact = message.participants.first()
|
||||
context.getContactFromAddress(contact.phoneNumbers.first().normalizedNumber) {
|
||||
if (it != null) {
|
||||
(activity as ThreadActivity).startContactDetailsIntent(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
thread_message_body.setTextColor(textColor)
|
||||
thread_message_body.setLinkTextColor(context.getProperPrimaryColor())
|
||||
|
||||
if (!activity.isFinishing && !activity.isDestroyed) {
|
||||
SimpleContactsHelper(context).loadContactImage(message.senderPhotoUri, thread_message_sender_photo, message.senderName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupSentMessageView(view: View, message: Message) {
|
||||
view.apply {
|
||||
thread_message_sender_photo?.beGone()
|
||||
val background = context.getProperPrimaryColor()
|
||||
thread_message_body.background.applyColorFilter(background)
|
||||
|
||||
val contrastColor = background.getContrastColor()
|
||||
thread_message_body.setTextColor(contrastColor)
|
||||
thread_message_body.setLinkTextColor(contrastColor)
|
||||
|
||||
val padding = thread_message_body.paddingStart
|
||||
if (message.isScheduled) {
|
||||
thread_message_scheduled_icon.beVisible()
|
||||
thread_message_scheduled_icon.applyColorFilter(contrastColor)
|
||||
|
||||
thread_message_scheduled_icon.onGlobalLayout {
|
||||
val rightPadding = padding + thread_message_scheduled_icon.measuredWidth
|
||||
thread_message_body.setPadding(padding, padding, rightPadding, padding)
|
||||
}
|
||||
thread_message_body.typeface = Typeface.create(Typeface.DEFAULT, Typeface.ITALIC)
|
||||
} else {
|
||||
thread_message_scheduled_icon.beGone()
|
||||
|
||||
thread_message_body.setPadding(padding, padding, padding, padding)
|
||||
thread_message_body.typeface = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupImageView(holder: ViewHolder, parent: View, message: Message, attachment: Attachment) {
|
||||
val mimetype = attachment.mimetype
|
||||
val uri = attachment.getUri()
|
||||
|
@ -1,6 +0,0 @@
|
||||
package com.simplemobiletools.smsmessenger.extensions
|
||||
|
||||
import android.text.TextUtils
|
||||
import com.simplemobiletools.commons.models.SimpleContact
|
||||
|
||||
fun ArrayList<SimpleContact>.getThreadTitle() = TextUtils.join(", ", map { it.name }.toTypedArray())
|
@ -30,3 +30,5 @@ fun Map<String, Any>.toContentValues(): ContentValues {
|
||||
|
||||
return contentValues
|
||||
}
|
||||
|
||||
fun <T> Collection<T>.toArrayList() = ArrayList(this)
|
||||
|
@ -57,7 +57,7 @@ val Context.messageAttachmentsDB: MessageAttachmentsDao get() = getMessagesDB().
|
||||
|
||||
val Context.messagesDB: MessagesDao get() = getMessagesDB().MessagesDao()
|
||||
|
||||
fun Context.getMessages(threadId: Long, getImageResolutions: Boolean, dateFrom: Int = -1): ArrayList<Message> {
|
||||
fun Context.getMessages(threadId: Long, getImageResolutions: Boolean, dateFrom: Int = -1, includeScheduledMessages: Boolean = true): ArrayList<Message> {
|
||||
val uri = Sms.CONTENT_URI
|
||||
val projection = arrayOf(
|
||||
Sms._ID,
|
||||
@ -116,8 +116,17 @@ fun Context.getMessages(threadId: Long, getImageResolutions: Boolean, dateFrom:
|
||||
}
|
||||
|
||||
messages.addAll(getMMS(threadId, getImageResolutions, sortOrder))
|
||||
messages = messages.filter { it.participants.isNotEmpty() }
|
||||
.sortedWith(compareBy<Message> { it.date }.thenBy { it.id }).toMutableList() as ArrayList<Message>
|
||||
|
||||
if (includeScheduledMessages) {
|
||||
val scheduledMessages = messagesDB.getScheduledThreadMessages(threadId)
|
||||
messages.addAll(scheduledMessages)
|
||||
}
|
||||
|
||||
messages = messages
|
||||
.filter { it.participants.isNotEmpty() }
|
||||
.filterNot { it.isScheduled && it.millis() < System.currentTimeMillis() }
|
||||
.sortedWith(compareBy<Message> { it.date }.thenBy { it.id })
|
||||
.toMutableList() as ArrayList<Message>
|
||||
|
||||
return messages
|
||||
}
|
||||
|
@ -14,6 +14,6 @@ fun DateTime.humanize(context: Context, now: DateTime = DateTime.now(), pattern:
|
||||
return if (yearOfCentury().get() > now.yearOfCentury().get()) {
|
||||
toString(pattern)
|
||||
} else {
|
||||
DateUtils.getRelativeDateTimeString(context, millis, DateUtils.MINUTE_IN_MILLIS, DateUtils.DAY_IN_MILLIS, 0).toString()
|
||||
DateUtils.getRelativeDateTimeString(context, millis, DateUtils.SECOND_IN_MILLIS, DateUtils.DAY_IN_MILLIS, 0).toString()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
package com.simplemobiletools.smsmessenger.extensions
|
||||
|
||||
import android.text.TextUtils
|
||||
import com.simplemobiletools.commons.models.SimpleContact
|
||||
|
||||
fun ArrayList<SimpleContact>.getThreadTitle(): String = TextUtils.join(", ", map { it.name }.toTypedArray()).orEmpty()
|
||||
|
||||
fun ArrayList<SimpleContact>.getAddresses() = flatMap { it.phoneNumbers }.map { it.normalizedNumber }
|
@ -29,6 +29,7 @@ const val IMPORT_SMS = "import_sms"
|
||||
const val IMPORT_MMS = "import_mms"
|
||||
const val WAS_DB_CLEARED = "was_db_cleared_2"
|
||||
const val EXTRA_VCARD_URI = "vcard"
|
||||
const val SCHEDULED_MESSAGE_ID = "scheduled_message_id"
|
||||
|
||||
private const val PATH = "com.simplemobiletools.smsmessenger.action."
|
||||
const val MARK_AS_READ = PATH + "mark_as_read"
|
||||
|
@ -1,16 +1,28 @@
|
||||
package com.simplemobiletools.smsmessenger.helpers
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import androidx.core.app.AlarmManagerCompat
|
||||
import com.klinker.android.send_message.Settings
|
||||
import com.klinker.android.send_message.Transaction
|
||||
import com.klinker.android.send_message.Utils
|
||||
import com.simplemobiletools.commons.extensions.showErrorToast
|
||||
import com.simplemobiletools.commons.helpers.isMarshmallowPlus
|
||||
import com.simplemobiletools.smsmessenger.R
|
||||
import com.simplemobiletools.smsmessenger.extensions.config
|
||||
import com.simplemobiletools.smsmessenger.models.Message
|
||||
import com.simplemobiletools.smsmessenger.receivers.ScheduledMessageReceiver
|
||||
import com.simplemobiletools.smsmessenger.receivers.SmsStatusDeliveredReceiver
|
||||
import com.simplemobiletools.smsmessenger.receivers.SmsStatusSentReceiver
|
||||
import org.joda.time.DateTime
|
||||
import org.joda.time.DateTimeZone
|
||||
import kotlin.math.abs
|
||||
import kotlin.random.Random
|
||||
|
||||
fun Context.getSendMessageSettings(): Settings {
|
||||
val settings = Settings()
|
||||
@ -22,7 +34,7 @@ fun Context.getSendMessageSettings(): Settings {
|
||||
return settings
|
||||
}
|
||||
|
||||
fun Context.sendTransactionMessage(text: String, addresses: List<String>, subscriptionId: Int?, attachments: List<Uri>) {
|
||||
fun Context.sendMessage(text: String, addresses: List<String>, subscriptionId: Int?, attachments: List<Uri>) {
|
||||
val settings = getSendMessageSettings()
|
||||
if (subscriptionId != null) {
|
||||
settings.subscriptionId = subscriptionId
|
||||
@ -50,10 +62,35 @@ fun Context.sendTransactionMessage(text: String, addresses: List<String>, subscr
|
||||
|
||||
transaction.setExplicitBroadcastForSentSms(smsSentIntent)
|
||||
transaction.setExplicitBroadcastForDeliveredSms(deliveredIntent)
|
||||
transaction.sendNewMessage(message)
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
transaction.sendNewMessage(message)
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.scheduleMessage(message: Message) {
|
||||
val intent = Intent(this, ScheduledMessageReceiver::class.java)
|
||||
intent.putExtra(THREAD_ID, message.threadId)
|
||||
intent.putExtra(SCHEDULED_MESSAGE_ID, message.id)
|
||||
|
||||
var flags = PendingIntent.FLAG_UPDATE_CURRENT
|
||||
if (isMarshmallowPlus()) {
|
||||
flags = flags or PendingIntent.FLAG_IMMUTABLE
|
||||
}
|
||||
val pendingIntent = PendingIntent.getBroadcast(this, message.id.toInt(), intent, flags)
|
||||
val triggerAtMillis = message.millis()
|
||||
|
||||
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent)
|
||||
}
|
||||
|
||||
fun Context.isLongMmsMessage(text: String): Boolean {
|
||||
val settings = getSendMessageSettings()
|
||||
return Utils.getNumPages(settings, text) > settings.sendLongAsMmsAfter
|
||||
}
|
||||
|
||||
/** Not to be used with real messages persisted in the telephony db. This is for internal use only (e.g. scheduled messages). */
|
||||
fun generateRandomMessageId(length: Int = 8): Long {
|
||||
val millis = DateTime.now(DateTimeZone.UTC).millis
|
||||
val random = abs(Random(millis).nextLong())
|
||||
return random.toString().takeLast(length).toLong()
|
||||
}
|
||||
|
@ -3,9 +3,50 @@ package com.simplemobiletools.smsmessenger.receivers
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.PowerManager
|
||||
import com.simplemobiletools.commons.extensions.showErrorToast
|
||||
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
|
||||
import com.simplemobiletools.smsmessenger.R
|
||||
import com.simplemobiletools.smsmessenger.extensions.getAddresses
|
||||
import com.simplemobiletools.smsmessenger.extensions.messagesDB
|
||||
import com.simplemobiletools.smsmessenger.helpers.SCHEDULED_MESSAGE_ID
|
||||
import com.simplemobiletools.smsmessenger.helpers.THREAD_ID
|
||||
import com.simplemobiletools.smsmessenger.helpers.refreshMessages
|
||||
import com.simplemobiletools.smsmessenger.helpers.sendMessage
|
||||
|
||||
class ScheduledMessageReceiver: BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
TODO("Not yet implemented")
|
||||
class ScheduledMessageReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||
val wakelock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "simple.messenger:scheduled.message.receiver")
|
||||
wakelock.acquire(3000)
|
||||
|
||||
|
||||
ensureBackgroundThread {
|
||||
handleIntent(context, intent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleIntent(context: Context, intent: Intent) {
|
||||
val threadId = intent.getLongExtra(THREAD_ID, 0L)
|
||||
val messageId = intent.getLongExtra(SCHEDULED_MESSAGE_ID, 0L)
|
||||
val message = try {
|
||||
context.messagesDB.getScheduledMessageWithId(threadId, messageId)
|
||||
} catch (e: Exception) {
|
||||
return
|
||||
}
|
||||
|
||||
val addresses = message.participants.getAddresses()
|
||||
val attachments = message.attachment?.attachments?.mapNotNull { it.getUri() } ?: emptyList()
|
||||
|
||||
try {
|
||||
context.sendMessage(message.body, addresses, message.subscriptionId, attachments)
|
||||
context.messagesDB.delete(messageId)
|
||||
refreshMessages()
|
||||
} catch (e: Exception) {
|
||||
context.showErrorToast(e)
|
||||
} catch (e: Error) {
|
||||
context.showErrorToast(e.localizedMessage ?: context.getString(R.string.unknown_error_occurred))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,4 +48,15 @@
|
||||
android:textSize="@dimen/normal_text_size"
|
||||
tools:text="Sent message" />
|
||||
</RelativeLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/thread_message_scheduled_icon"
|
||||
android:layout_width="@dimen/small_icon_size"
|
||||
android:layout_height="@dimen/small_icon_size"
|
||||
android:layout_margin="@dimen/tiny_margin"
|
||||
android:src="@drawable/ic_clock_vector"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
tools:visibility="visible" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
@ -8,4 +8,5 @@
|
||||
<dimen name="pin_icon_size">15dp</dimen>
|
||||
<dimen name="vcard_property_start_margin">64dp</dimen>
|
||||
<dimen name="date_time_text_size">36sp</dimen>
|
||||
<dimen name="small_icon_size">20dp</dimen>
|
||||
</resources>
|
||||
|
Loading…
x
Reference in New Issue
Block a user