klinker41 / android-smsmms

Library for easily sending SMS and MMS for Android devices
670 stars 247 forks source link

Mms Send Stuck on "Sending" #197

Open IbrahimEzzatSaad opened 1 week ago

IbrahimEzzatSaad commented 1 week ago

I have noticed this problem on the following devices: realme 9i android 13 network - vi samesung m53 android 13 network - jio redmi note10s android 13 network - jio

Some of those devices give "error code: 5" and some devices is just stuck on "Sending" without sending anything https://drive.google.com/file/d/1sSI_niLAFBP4gWOlsVRzM1MSjxOYZiJK/view?usp=sharing https://drive.google.com/file/d/1A2tZZ1Zz07bERa1WiBBMpHfYsClKL53f/view?usp=sharing https://drive.google.com/file/d/12rEq8JP0L5mKnP0nxwxjSkVqiNKa5Qh-/view?usp=sharing

Here's my code

fun Context.getSendMessageSettings(): Settings {
    val settings = Settings()
    settings.useSystemSending = true
    settings.deliveryReports = config.enableDeliveryReports
    settings.sendLongAsMms = config.sendLongMessageMMS
    settings.sendLongAsMmsAfter = 1
    settings.group = config.sendGroupMessageMMS
    return settings
}
/** Sends the message using the in-app SmsManager API wrappers if it's an SMS or using android-smsmms for MMS. */
fun Context.sendMessageCompat(text: String, addresses: List<String>, subId: Int?, attachments: List<Attachment>, messageId: Long? = null) {
    val settings = getSendMessageSettings()
    if (subId != null) {
        settings.subscriptionId = subId
    }
    Log.i("subId", subId.toString())

    val messagingUtils = messagingUtils
    val isMms = attachments.isNotEmpty() || isLongMmsMessage(text, settings) || addresses.size > 1 && settings.group
    if (isMms) {
        // we send all MMS attachments separately to reduces the chances of hitting provider MMS limit.
        if (attachments.isNotEmpty()) {
            val lastIndex = attachments.lastIndex
            if (attachments.size > 1) {
                for (i in 0 until lastIndex) {
                    val attachment = attachments[i]
                    messagingUtils.sendMmsMessage("", addresses, attachment, settings, messageId)
                }
            }

            val lastAttachment = attachments[lastIndex]
            messagingUtils.sendMmsMessage(text, addresses, lastAttachment, settings, messageId)
        } else {
            messagingUtils.sendMmsMessage(text, addresses, null, settings, messageId)
        }
    } else {
        try {
            messagingUtils.sendSmsMessage(text, addresses.toSet(), settings.subscriptionId, settings.deliveryReports, messageId)
        } catch (e: SmsException) {
            when (e.errorCode) {
                EMPTY_DESTINATION_ADDRESS -> toast(id = R.string.empty_destination_address, length = LENGTH_LONG)
                ERROR_PERSISTING_MESSAGE -> toast(id = R.string.unable_to_save_message, length = LENGTH_LONG)
                ERROR_SENDING_MESSAGE -> toast(
                    msg = getString(R.string.unknown_error_occurred_sending_message, e.errorCode),
                    length = LENGTH_LONG
                )
            }
        } catch (e: Exception) {
            showErrorToast(e)
        }
    }
}
fun sendMmsMessage(text: String, addresses: List<String>, attachment: Attachment?, settings: Settings, messageId: Long? = null) {
        val transaction = Transaction(context, settings)
        val message = Message(text, addresses.toTypedArray())

        if (attachment != null) {
            try {
                val uri = attachment.getUri()
                context.contentResolver.openInputStream(uri)?.use {
                    val bytes = it.readBytes()
                    val mimeType = if (attachment.mimetype.isPlainTextMimeType()) {
                        "application/txt"
                    } else {
                        attachment.mimetype
                    }
                    val name = attachment.filename
                    message.addMedia(bytes, mimeType, name)
                }
            } catch (e: Exception) {
                context.showErrorToast(e)
            } catch (e: Error) {
                context.showErrorToast(e.localizedMessage ?: context.getString(com.simplemobiletools.commons.R.string.unknown_error_occurred))
            }
        }

        val mmsSentIntent = Intent(context, MmsSentReceiver::class.java)
        mmsSentIntent.putExtra(MmsSentReceiver.EXTRA_ORIGINAL_RESENT_MESSAGE_ID, messageId)
        transaction.setExplicitBroadcastForSentMms(mmsSentIntent)

        try {
            transaction.sendNewMessage(message)
        } catch (e: Exception) {
            context.showErrorToast(e)
        }
    }
@AndroidEntryPoint
class MmsSentReceiver : SendStatusReceiver() {
    @Inject
    lateinit var cache: Cache
    private val myCoroutineScope = CoroutineScope(Dispatchers.IO)

    override fun updateAndroidDatabase(context: Context, intent: Intent, receiverResultCode: Int) {
        val uri = Uri.parse(intent.getStringExtra(EXTRA_CONTENT_URI))
        val originalResentMessageId = intent.getLongExtra(EXTRA_ORIGINAL_RESENT_MESSAGE_ID, -1L)
        val messageBox = if (receiverResultCode == Activity.RESULT_OK) {
            Telephony.Mms.MESSAGE_BOX_SENT
        } else {
            val msg = context.getString(R.string.unknown_error_occurred_sending_message, receiverResultCode)
            context.toast(msg = msg, length = Toast.LENGTH_LONG)

            Telephony.Mms.MESSAGE_BOX_FAILED
        }

        val values = ContentValues(1).apply {
            put(Telephony.Mms.MESSAGE_BOX, messageBox)
        }

        try {
            context.contentResolver.update(uri, values, null, null)
        } catch (e: SQLiteException) {
            context.showErrorToast(e)
        }

        // In case of resent message, delete original to prevent duplication
        if (originalResentMessageId != -1L) {
            myCoroutineScope.launch {
                context.deleteMessage(originalResentMessageId, true)
                cache.deleteMessage(originalResentMessageId)
            }
        }

        val filePath = intent.getStringExtra(EXTRA_FILE_PATH)
        if (filePath != null) {
            File(filePath).delete()
        }
    }

    override fun updateAppDatabase(context: Context, intent: Intent, receiverResultCode: Int) {
        val messageUri: Uri? = intent.data
        if (messageUri != null) {
            val messageId = messageUri.lastPathSegment?.toLong() ?: 0L
            myCoroutineScope.launch {
                if (resultCode != Telephony.Sms.Sent.STATUS_NONE) {
                    cache.updateMessageStatus(messageId, receiverResultCode)
                }
            }
        }
    }

    companion object {
        private const val EXTRA_CONTENT_URI = "content_uri"
        private const val EXTRA_FILE_PATH = "file_path"
        const val EXTRA_ORIGINAL_RESENT_MESSAGE_ID = "original_message_id"
    }
}
Barkerww commented 1 week ago

Your code looks normal. Maybe you need to check the APN/proxy/port setting

IbrahimEzzatSaad commented 1 week ago

Your code looks normal. Maybe you need to check the APN/proxy/port setting

Can you give me an example of that? Are there specifics for each SIM proxy and port? I thought just data connection was the only thing that was required

The problem also exists in this app which uses the same library https://play.google.com/store/apps/details?id=com.simplemobiletools.smsmessenger&hl=en