c'est presque bon, je sais pas encore où je vais trouver le temps de tout faire tho
This commit is contained in:
parent
e9b8e5020f
commit
7678e79fee
|
@ -17,6 +17,7 @@
|
|||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
|
@ -51,14 +52,19 @@
|
|||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".messages.NornMMSReceiver"
|
||||
<receiver
|
||||
android:name="com.android.mms.transaction.PushReceiver"
|
||||
android:permission="android.permission.BROADCAST_WAP_PUSH">
|
||||
<intent-filter android:priority="999">
|
||||
<intent-filter>
|
||||
<action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
|
||||
<data android:mimeType="application/vnd.wap.mms-message" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".messages.NornMMSReceiver"
|
||||
android:taskAffinity="com.klinker.android.messaging.MMS_RECEIVED" />
|
||||
|
||||
<receiver android:name=".messages.NornLocaleChangedReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.LOCALE_CHANGED"/>
|
||||
|
|
|
@ -26,7 +26,7 @@ class ComposeActivity : ComposeView.SendActivity() {
|
|||
|
||||
companion object {
|
||||
|
||||
class SendTask(context: Context, val number: String, val text: String, val medias: ArrayList<NornMedia>) : AsyncTask<Void, Void, NornMessage?>() {
|
||||
class SendTask(context: Context, val number: String, val text: String, private val medias: Array<NornMedia>) : AsyncTask<Void, Void, NornMessage?>() {
|
||||
|
||||
val context = WeakReference<Context>(context)
|
||||
|
||||
|
@ -76,7 +76,7 @@ class ComposeActivity : ComposeView.SendActivity() {
|
|||
|
||||
override val layout = R.layout.activity_compose
|
||||
|
||||
override fun sendMessage(text: String, medias: ArrayList<NornMedia>) {
|
||||
override fun sendMessage(text: String, medias: Array<NornMedia>) {
|
||||
// trouver le destinataire saisi par l'utilisateur
|
||||
val dest = number.text.toString()
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ class ConversationActivity: ComposeView.SendActivity() {
|
|||
|
||||
}
|
||||
|
||||
class SendTask(activity: ConversationActivity, val text: String, val medias: ArrayList<NornMedia>) : AsyncTask<Void, Void, NornMessage?>() {
|
||||
class SendTask(activity: ConversationActivity, val text: String, private val medias: Array<NornMedia>) : AsyncTask<Void, Void, NornMessage?>() {
|
||||
|
||||
val activity = WeakReference<ConversationActivity>(activity)
|
||||
|
||||
|
@ -143,7 +143,7 @@ class ConversationActivity: ComposeView.SendActivity() {
|
|||
this.title = this.conversation.name
|
||||
}
|
||||
|
||||
override fun sendMessage(text: String, medias: ArrayList<NornMedia>) {
|
||||
override fun sendMessage(text: String, medias: Array<NornMedia>) {
|
||||
// envoyer le message en arrière plan
|
||||
SendTask(this, text, medias).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
|
||||
}
|
||||
|
|
|
@ -1,19 +1,376 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Jacob Klinker
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package xyz.johnny.norntalk.messages
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.AsyncTask
|
||||
import android.os.Parcelable
|
||||
import android.provider.Telephony
|
||||
import android.telephony.SmsManager
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import com.android.mms.service_alt.MmsConfig
|
||||
import com.android.mms.transaction.DownloadManager
|
||||
import com.android.mms.transaction.HttpUtils
|
||||
import com.android.mms.transaction.TransactionSettings
|
||||
import com.android.mms.util.SendingProgressTokenManager
|
||||
import com.google.android.mms.InvalidHeaderValueException
|
||||
import com.google.android.mms.MmsException
|
||||
import com.google.android.mms.pdu_alt.*
|
||||
import com.google.android.mms.pdu_alt.PduHeaders.STATUS_RETRIEVED
|
||||
import com.google.android.mms.util_alt.SqliteWrapper
|
||||
import com.klinker.android.send_message.Utils
|
||||
import java.io.*
|
||||
import java.lang.ref.WeakReference
|
||||
import java.nio.charset.Charset
|
||||
import java.util.*
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
/**
|
||||
* Classe recevant les MMS.
|
||||
*/
|
||||
class NornMMSReceiver: BroadcastReceiver() {
|
||||
class NornMMSReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
Log.d(this::class.java.simpleName, "MMS received")
|
||||
Toast.makeText(context, "MMS received", Toast.LENGTH_LONG).show()
|
||||
// Override this and provide the MMSC to send the ACK to.
|
||||
// some carriers will download duplicate MMS messages without this ACK. When using the
|
||||
// system sending method, apparently Google does not do this for us. Not sure why.
|
||||
// You might have to have users manually enter their APN settings if you cannot get them
|
||||
// from the system somehow.
|
||||
val mmscInfoForReceptionAck: MmscInformation?
|
||||
get() = null
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
Log.d(TAG, "MMS has finished downloading, persisting it to the database")
|
||||
|
||||
val path = intent.getStringExtra(EXTRA_FILE_PATH)
|
||||
Log.d(TAG, path)
|
||||
|
||||
var errorMessage: String? = null
|
||||
|
||||
try {
|
||||
val mDownloadFile = File(path)
|
||||
val nBytes = mDownloadFile.length().toInt()
|
||||
FileInputStream(mDownloadFile).use { reader ->
|
||||
val response = ByteArray(nBytes)
|
||||
reader.read(response, 0, nBytes)
|
||||
val tasks = getNotificationTask(context, intent, response)
|
||||
|
||||
val pdu = PduParser(response).parse() as RetrieveConf
|
||||
|
||||
val message = this.createMessage(context, pdu)
|
||||
message.insertMessage(context)
|
||||
NornMessageDispatcher.send(message)
|
||||
|
||||
Log.v(TAG, "response saved successfully")
|
||||
Log.v(TAG, "response length: " + response.size)
|
||||
mDownloadFile.delete()
|
||||
|
||||
if (tasks != null) {
|
||||
Log.v(TAG, "running the common async notifier for download")
|
||||
for (task in tasks)
|
||||
task.executeOnExecutor(RECEIVE_NOTIFICATION_EXECUTOR)
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e: FileNotFoundException) {
|
||||
errorMessage = "MMS received, file not found exception"
|
||||
Log.e(TAG, errorMessage, e)
|
||||
} catch (e: IOException) {
|
||||
errorMessage = "MMS received, io exception"
|
||||
Log.e(TAG, errorMessage, e)
|
||||
}
|
||||
|
||||
handleHttpError(context, intent)
|
||||
DownloadManager.finishDownload(intent.getStringExtra(EXTRA_LOCATION_URL))
|
||||
|
||||
if (errorMessage != null) {
|
||||
onError(errorMessage)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
fun createMessage(context: Context, pdu: RetrieveConf): NornMessage {
|
||||
val medias = ArrayList<NornMedia>()
|
||||
var text = ""
|
||||
|
||||
for (i in 0..(pdu.body.partsNum - 1)) {
|
||||
val part = pdu.body.getPart(i)
|
||||
val mimeType = part.contentType!!.toString(Charset.defaultCharset())
|
||||
|
||||
if (mimeType.startsWith("image")) {
|
||||
val uri = this.writeFile(context, part.data)
|
||||
medias.add(NornMedia(context, mimeType, uri))
|
||||
} else if (mimeType == "text/plain")
|
||||
text = part.data.toString(Charset.defaultCharset())
|
||||
}
|
||||
|
||||
val addresses = setOf(pdu.from.string).plus(pdu.to.map { it.string }.toTypedArray())
|
||||
val members = addresses.map { NornContact.getContact(it, context) }.toTypedArray()
|
||||
val conversation = NornConversation.getConversation(members, context)
|
||||
val message = NornMessage(text, conversation, Date(), context)
|
||||
for (media in medias)
|
||||
message.medias.add(media)
|
||||
|
||||
return message
|
||||
}
|
||||
|
||||
fun writeFile(context: Context, data: ByteArray): Uri {
|
||||
val fileName = "media." + System.currentTimeMillis() + "_" + Math.abs(Random().nextInt()).toString() + ".dat"
|
||||
val file = File(context.cacheDir, fileName)
|
||||
val writerUri = Uri.Builder()
|
||||
.authority("xyz.johnny.norntalk.messages.NornMMSFileProvider")
|
||||
.path(fileName)
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.build()
|
||||
|
||||
FileOutputStream(file).use { writer ->
|
||||
writer.write(data)
|
||||
}
|
||||
|
||||
val uri = writerUri
|
||||
return uri
|
||||
}
|
||||
|
||||
protected fun onError(error: String) {
|
||||
|
||||
}
|
||||
|
||||
private fun handleHttpError(context: Context, intent: Intent) {
|
||||
val httpError = intent.getIntExtra(SmsManager.EXTRA_MMS_HTTP_STATUS, 0)
|
||||
if (httpError == 404 || httpError == 400) {
|
||||
// Delete the corresponding NotificationInd
|
||||
SqliteWrapper.delete(context,
|
||||
context.contentResolver,
|
||||
Telephony.Mms.CONTENT_URI,
|
||||
LOCATION_SELECTION,
|
||||
arrayOf(Integer.toString(PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND), intent.getStringExtra(EXTRA_LOCATION_URL)))
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class CommonAsyncTask internal constructor(context: Context, protected val mTransactionSettings: TransactionSettings, internal val mNotificationInd: NotificationInd) : AsyncTask<Void, Void, Void>() {
|
||||
private val context = WeakReference<Context>(context)
|
||||
internal val mContentLocation: String
|
||||
|
||||
init {
|
||||
mContentLocation = String(mNotificationInd.contentLocation)
|
||||
}
|
||||
|
||||
/**
|
||||
* A common method to send a PDU to MMSC.
|
||||
*
|
||||
* @param pdu A byte array which contains the data of the PDU.
|
||||
* @param mmscUrl Url of the recipient MMSC.
|
||||
* @return A byte array which contains the response data.
|
||||
* If an HTTP error code is returned, an IOException will be thrown.
|
||||
* @throws java.io.IOException if any error occurred on network interface or
|
||||
* an HTTP error code(>=400) returned from the server.
|
||||
* @throws com.google.android.mms.MmsException if pdu is null.
|
||||
*/
|
||||
@Throws(IOException::class, MmsException::class)
|
||||
internal fun sendPdu(pdu: ByteArray, mmscUrl: String): ByteArray {
|
||||
return sendPdu(SendingProgressTokenManager.NO_TOKEN, pdu, mmscUrl)
|
||||
}
|
||||
|
||||
/**
|
||||
* A common method to send a PDU to MMSC.
|
||||
*
|
||||
* @param pdu A byte array which contains the data of the PDU.
|
||||
* @return A byte array which contains the response data.
|
||||
* If an HTTP error code is returned, an IOException will be thrown.
|
||||
* @throws java.io.IOException if any error occurred on network interface or
|
||||
* an HTTP error code(>=400) returned from the server.
|
||||
* @throws com.google.android.mms.MmsException if pdu is null.
|
||||
*/
|
||||
@Throws(IOException::class, MmsException::class)
|
||||
internal fun sendPdu(pdu: ByteArray): ByteArray {
|
||||
return sendPdu(SendingProgressTokenManager.NO_TOKEN, pdu,
|
||||
mTransactionSettings.mmscUrl)
|
||||
}
|
||||
|
||||
/**
|
||||
* A common method to send a PDU to MMSC.
|
||||
*
|
||||
* @param token The token to identify the sending progress.
|
||||
* @param pdu A byte array which contains the data of the PDU.
|
||||
* @param mmscUrl Url of the recipient MMSC.
|
||||
* @return A byte array which contains the response data.
|
||||
* If an HTTP error code is returned, an IOException will be thrown.
|
||||
* @throws java.io.IOException if any error occurred on network interface or
|
||||
* an HTTP error code(>=400) returned from the server.
|
||||
* @throws com.google.android.mms.MmsException if pdu is null.
|
||||
*/
|
||||
@Throws(IOException::class, MmsException::class)
|
||||
private fun sendPdu(token: Long, pdu: ByteArray?,
|
||||
mmscUrl: String?): ByteArray {
|
||||
if (pdu == null) {
|
||||
throw MmsException()
|
||||
}
|
||||
|
||||
if (mmscUrl == null) {
|
||||
throw IOException("Cannot establish route: mmscUrl is null")
|
||||
}
|
||||
|
||||
val mContext = this.context.get()
|
||||
|
||||
if (com.android.mms.transaction.Transaction.useWifi(mContext)) {
|
||||
return HttpUtils.httpConnection(
|
||||
mContext, token,
|
||||
mmscUrl,
|
||||
pdu, HttpUtils.HTTP_POST_METHOD,
|
||||
false, null, 0)
|
||||
}
|
||||
|
||||
Utils.ensureRouteToHost(mContext, mmscUrl, mTransactionSettings.proxyAddress)
|
||||
return HttpUtils.httpConnection(
|
||||
mContext, token,
|
||||
mmscUrl,
|
||||
pdu, HttpUtils.HTTP_POST_METHOD,
|
||||
mTransactionSettings.isProxySet,
|
||||
mTransactionSettings.proxyAddress,
|
||||
mTransactionSettings.proxyPort)
|
||||
}
|
||||
}
|
||||
|
||||
private class NotifyRespTask internal constructor(context: Context, ind: NotificationInd, settings: TransactionSettings) : CommonAsyncTask(context, settings, ind) {
|
||||
|
||||
private val context = WeakReference<Context>(context)
|
||||
|
||||
override fun doInBackground(vararg params: Void): Void? {
|
||||
// Create the M-NotifyResp.ind
|
||||
var notifyRespInd: NotifyRespInd? = null
|
||||
try {
|
||||
notifyRespInd = NotifyRespInd(
|
||||
PduHeaders.CURRENT_MMS_VERSION,
|
||||
mNotificationInd.transactionId,
|
||||
STATUS_RETRIEVED)
|
||||
|
||||
val mContext = this.context.get()
|
||||
|
||||
// Pack M-NotifyResp.ind and send it
|
||||
if (com.android.mms.MmsConfig.getNotifyWapMMSC()) {
|
||||
sendPdu(PduComposer(mContext, notifyRespInd).make(), mContentLocation)
|
||||
} else {
|
||||
sendPdu(PduComposer(mContext, notifyRespInd).make())
|
||||
}
|
||||
} catch (e: MmsException) {
|
||||
Log.e(TAG, "error", e)
|
||||
} catch (e: IOException) {
|
||||
Log.e(TAG, "error", e)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private class AcknowledgeIndTask internal constructor(context: Context, ind: NotificationInd, settings: TransactionSettings, private val mRetrieveConf: RetrieveConf) : CommonAsyncTask(context, settings, ind) {
|
||||
|
||||
private val context = WeakReference<Context>(context)
|
||||
|
||||
override fun doInBackground(vararg params: Void): Void? {
|
||||
// Send M-Acknowledge.ind to MMSC if required.
|
||||
// If the Transaction-ID isn't set in the M-Retrieve.conf, it means
|
||||
// the MMS proxy-relay doesn't require an ACK.
|
||||
val tranId = mRetrieveConf.transactionId
|
||||
if (tranId != null) {
|
||||
Log.v(TAG, "sending ACK to MMSC: " + mTransactionSettings.mmscUrl)
|
||||
// Create M-Acknowledge.ind
|
||||
var acknowledgeInd: com.google.android.mms.pdu_alt.AcknowledgeInd? = null
|
||||
|
||||
try {
|
||||
acknowledgeInd = com.google.android.mms.pdu_alt.AcknowledgeInd(
|
||||
PduHeaders.CURRENT_MMS_VERSION, tranId)
|
||||
|
||||
val mContext = context.get()
|
||||
|
||||
// insert the 'from' address per spec
|
||||
val lineNumber = Utils.getMyPhoneNumber(mContext)
|
||||
acknowledgeInd.from = EncodedStringValue(lineNumber)
|
||||
|
||||
// Pack M-Acknowledge.ind and send it
|
||||
if (com.android.mms.MmsConfig.getNotifyWapMMSC()) {
|
||||
sendPdu(PduComposer(mContext, acknowledgeInd).make(), mContentLocation)
|
||||
} else {
|
||||
sendPdu(PduComposer(mContext, acknowledgeInd).make())
|
||||
}
|
||||
} catch (e: InvalidHeaderValueException) {
|
||||
Log.e(TAG, "error", e)
|
||||
} catch (e: MmsException) {
|
||||
Log.e(TAG, "error", e)
|
||||
} catch (e: IOException) {
|
||||
Log.e(TAG, "error", e)
|
||||
}
|
||||
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getNotificationTask(context: Context, intent: Intent, response: ByteArray): List<CommonAsyncTask>? {
|
||||
if (response.size == 0) {
|
||||
Log.v(TAG, "MmsReceivedReceiver.sendNotification blank response")
|
||||
return null
|
||||
}
|
||||
|
||||
if (mmscInfoForReceptionAck == null) {
|
||||
Log.v(TAG, "No MMSC information set, so no notification tasks will be able to complete")
|
||||
return null
|
||||
}
|
||||
|
||||
val pdu = PduParser(response, MmsConfig.Overridden(MmsConfig(context), null).supportMmsContentDisposition).parse()
|
||||
if (pdu == null || pdu !is RetrieveConf) {
|
||||
android.util.Log.e(TAG, "MmsReceivedReceiver.sendNotification failed to parse pdu")
|
||||
return null
|
||||
}
|
||||
|
||||
try {
|
||||
val ind = getNotificationInd(context, intent)
|
||||
val mmsc = mmscInfoForReceptionAck
|
||||
val transactionSettings = TransactionSettings(mmsc!!.mmscUrl, mmsc.mmsProxy, mmsc.proxyPort)
|
||||
|
||||
val responseTasks = ArrayList<CommonAsyncTask>()
|
||||
responseTasks.add(AcknowledgeIndTask(context, ind, transactionSettings, pdu))
|
||||
responseTasks.add(NotifyRespTask(context, ind, transactionSettings))
|
||||
|
||||
return responseTasks
|
||||
} catch (e: MmsException) {
|
||||
Log.e(TAG, "error", e)
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MmscInformation(internal var mmscUrl: String, internal var mmsProxy: String, internal var proxyPort: Int)
|
||||
|
||||
companion object {
|
||||
private val TAG = "MmsReceivedReceiver"
|
||||
|
||||
val MMS_RECEIVED = "com.klinker.android.messaging.MMS_RECEIVED"
|
||||
val EXTRA_FILE_PATH = "file_path"
|
||||
val EXTRA_LOCATION_URL = "location_url"
|
||||
val EXTRA_TRIGGER_PUSH = "trigger_push"
|
||||
val EXTRA_URI = "notification_ind_uri"
|
||||
|
||||
private val LOCATION_SELECTION =
|
||||
Telephony.Mms.MESSAGE_TYPE + "=? AND " + Telephony.Mms.CONTENT_LOCATION + " =?"
|
||||
|
||||
private val RECEIVE_NOTIFICATION_EXECUTOR = Executors.newSingleThreadExecutor()
|
||||
|
||||
@Throws(MmsException::class)
|
||||
private fun getNotificationInd(context: Context, intent: Intent): NotificationInd {
|
||||
return PduPersister.getPduPersister(context).load(intent.getParcelableExtra<Parcelable>(EXTRA_URI) as Uri) as NotificationInd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,6 @@ class NornMedia private constructor(context: Context, val mimeType: String) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
|
||||
fun from(context: Context, media: Media): NornMedia {
|
||||
|
|
|
@ -18,7 +18,9 @@ package xyz.johnny.norntalk.messages
|
|||
|
||||
import android.app.Activity
|
||||
import android.app.PendingIntent
|
||||
import android.content.*
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Looper
|
||||
|
@ -34,12 +36,14 @@ import com.android.mms.util.RateController
|
|||
import com.google.android.mms.ContentType
|
||||
import com.google.android.mms.InvalidHeaderValueException
|
||||
import com.google.android.mms.MMSPart
|
||||
import com.google.android.mms.MmsException
|
||||
import com.google.android.mms.pdu_alt.*
|
||||
import com.google.android.mms.smil.SmilHelper
|
||||
import com.klinker.android.logger.Log
|
||||
import com.klinker.android.send_message.*
|
||||
import java.io.*
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
|
@ -98,46 +102,6 @@ class NornTransaction constructor(private val context: Context) {
|
|||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional: define a [BroadcastReceiver] that will get started when Android notifies us that the SMS has
|
||||
* been marked as "sent". If you do not define a receiver here, it will look for the .SMS_SENT receiver
|
||||
* that was defined in the AndroidManifest, as discussed in the README.md.
|
||||
*
|
||||
* @param intent the receiver that you want to start when the message gets marked as sent.
|
||||
*/
|
||||
fun setExplicitBroadcastForSentSms(intent: Intent): NornTransaction {
|
||||
explicitSentSmsReceiver = intent
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional: define a [BroadcastReceiver] that will get started when Android notifies us that the MMS has
|
||||
* been marked as "sent". If you do not define a receiver here, it will look for the .MMS_SENT receiver
|
||||
* that was defined in the AndroidManifest, as discussed in the README.md.
|
||||
*
|
||||
* @param intent the receiver that you want to start when the message gets marked as sent.
|
||||
*/
|
||||
fun setExplicitBroadcastForSentMms(intent: Intent): NornTransaction {
|
||||
explicitSentMmsReceiver = intent
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional: define a [BroadcastReceiver] that will get started when Android notifies us that the SMS has
|
||||
* been marked as "delivered". If you do not define a receiver here, it will look for the .SMS_DELIVERED
|
||||
* receiver that was defined in the AndroidManifest, as discussed in the README.md.
|
||||
*
|
||||
*
|
||||
* Providing a receiver here does not guarantee that it will ever get started. If the [Settings]
|
||||
* object does not have delivery reports turned on, this receiver will never get called.
|
||||
*
|
||||
* @param intent the receiver that you want to start when the message gets marked as sent.
|
||||
*/
|
||||
fun setExplicitBroadcastForDeliveredSms(intent: Intent): NornTransaction {
|
||||
explicitDeliveredSmsReceiver = intent
|
||||
return this
|
||||
}
|
||||
|
||||
private fun sendSmsMessage(message: NornMessage, insert: Boolean, raw: Boolean) {
|
||||
// envoyer le message chiffré si la conversation est sécurisée
|
||||
val body = message.messageBody(raw)
|
||||
|
@ -273,12 +237,6 @@ class NornTransaction constructor(private val context: Context) {
|
|||
sendMmsThroughSystem(context, message.subject, data, message.addresses, explicitSentMmsReceiver)
|
||||
}
|
||||
|
||||
class MessageInfo {
|
||||
var token: Long = 0
|
||||
var location: Uri? = null
|
||||
var bytes: ByteArray? = null
|
||||
}
|
||||
|
||||
// splits text and adds split counter when applicable
|
||||
private fun splitByLength(s: String, chunkSize: Int, counter: Boolean): Array<String?> {
|
||||
val arraySize = Math.ceil(s.length.toDouble() / chunkSize).toInt()
|
||||
|
@ -307,20 +265,6 @@ class NornTransaction constructor(private val context: Context) {
|
|||
return returnArray
|
||||
}
|
||||
|
||||
/**
|
||||
* A method for checking whether or not a certain message will be sent as mms depending on its contents and the settings
|
||||
*
|
||||
* @param message is the message that you are checking against
|
||||
* @return true if the message will be mms, otherwise false
|
||||
*/
|
||||
fun checkMMS(message: Message): Boolean {
|
||||
return message.images.size != 0 ||
|
||||
message.parts.size != 0 ||
|
||||
settings.sendLongAsMms && Utils.getNumPages(settings, message.text) > settings.sendLongAsMmsAfter ||
|
||||
message.addresses.size > 1 && settings.group ||
|
||||
message.subject != null
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val TAG = "NornTransaction"
|
||||
|
@ -335,118 +279,6 @@ class NornTransaction constructor(private val context: Context) {
|
|||
|
||||
val NO_THREAD_ID: Long = 0
|
||||
|
||||
@Throws(MmsException::class)
|
||||
fun getBytes(context: Context, saveMessage: Boolean, recipients: Array<String>,
|
||||
parts: Array<MMSPart>?, subject: String?): MessageInfo {
|
||||
val sendRequest = SendReq()
|
||||
|
||||
// create send request addresses
|
||||
for (i in recipients.indices) {
|
||||
val phoneNumbers = EncodedStringValue.extract(recipients[i])
|
||||
|
||||
if (phoneNumbers != null && phoneNumbers.size > 0) {
|
||||
sendRequest.addTo(phoneNumbers[0])
|
||||
}
|
||||
}
|
||||
|
||||
if (subject != null) {
|
||||
sendRequest.subject = EncodedStringValue(subject)
|
||||
}
|
||||
|
||||
sendRequest.date = Calendar.getInstance().timeInMillis / 1000L
|
||||
|
||||
try {
|
||||
sendRequest.from = EncodedStringValue(Utils.getMyPhoneNumber(context))
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "error getting from address", e)
|
||||
}
|
||||
|
||||
val pduBody = PduBody()
|
||||
|
||||
// assign parts to the pdu body which contains sending data
|
||||
var size: Long = 0
|
||||
if (parts != null) {
|
||||
for (i in parts.indices) {
|
||||
val part = parts[i]
|
||||
if (part != null) {
|
||||
try {
|
||||
val partPdu = PduPart()
|
||||
partPdu.name = part.Name.toByteArray()
|
||||
partPdu.contentType = part.MimeType.toByteArray()
|
||||
|
||||
if (part.MimeType.startsWith("text")) {
|
||||
partPdu.charset = CharacterSets.UTF_8
|
||||
}
|
||||
// Set Content-Location.
|
||||
partPdu.contentLocation = part.Name.toByteArray()
|
||||
val index = part.Name.lastIndexOf(".")
|
||||
val contentId = if (index == -1)
|
||||
part.Name
|
||||
else
|
||||
part.Name.substring(0, index)
|
||||
partPdu.contentId = contentId.toByteArray()
|
||||
partPdu.data = part.Data
|
||||
|
||||
pduBody.addPart(partPdu)
|
||||
size += (2 * part.Name.toByteArray().size + part.MimeType.toByteArray().size + part.Data.size + contentId.toByteArray().size).toLong()
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val out = ByteArrayOutputStream()
|
||||
SmilXmlSerializer.serialize(SmilHelper.createSmilDocument(pduBody), out)
|
||||
val smilPart = PduPart()
|
||||
smilPart.contentId = "smil".toByteArray()
|
||||
smilPart.contentLocation = "smil.xml".toByteArray()
|
||||
smilPart.contentType = ContentType.APP_SMIL.toByteArray()
|
||||
smilPart.data = out.toByteArray()
|
||||
pduBody.addPart(0, smilPart)
|
||||
|
||||
sendRequest.body = pduBody
|
||||
|
||||
Log.v(TAG, "setting message size to $size bytes")
|
||||
sendRequest.messageSize = size
|
||||
|
||||
// add everything else that could be set
|
||||
sendRequest.priority = PduHeaders.PRIORITY_NORMAL
|
||||
sendRequest.deliveryReport = PduHeaders.VALUE_NO
|
||||
sendRequest.expiry = (1000 * 60 * 60 * 24 * 7).toLong()
|
||||
sendRequest.messageClass = PduHeaders.MESSAGE_CLASS_PERSONAL_STR.toByteArray()
|
||||
sendRequest.readReport = PduHeaders.VALUE_NO
|
||||
|
||||
// create byte array which will actually be sent
|
||||
val composer = PduComposer(context, sendRequest)
|
||||
val bytesToSend: ByteArray
|
||||
|
||||
try {
|
||||
bytesToSend = composer.make()
|
||||
} catch (e: OutOfMemoryError) {
|
||||
throw MmsException("Out of memory!")
|
||||
}
|
||||
|
||||
val info = MessageInfo()
|
||||
info.bytes = bytesToSend
|
||||
|
||||
try {
|
||||
val query = context.contentResolver.query(info.location!!, arrayOf("thread_id"), null, null, null)
|
||||
if (query != null && query.moveToFirst()) {
|
||||
info.token = query.getLong(query.getColumnIndex("thread_id"))
|
||||
query.close()
|
||||
} else {
|
||||
// just default sending token for what I had before
|
||||
info.token = 4444L
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "exception thrown", e)
|
||||
info.token = 4444L
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
val DEFAULT_EXPIRY_TIME = (7 * 24 * 60 * 60).toLong()
|
||||
val DEFAULT_PRIORITY = PduHeaders.PRIORITY_NORMAL
|
||||
|
||||
|
@ -494,7 +326,6 @@ class NornTransaction constructor(private val context: Context) {
|
|||
contentUri, null, configOverrides, pendingIntent)
|
||||
} else {
|
||||
Log.e(TAG, "Error writing sending Mms")
|
||||
println("aaajoai")
|
||||
pendingIntent.send(SmsManager.MMS_ERROR_IO_ERROR)
|
||||
}
|
||||
|
||||
|
@ -581,57 +412,6 @@ class NornTransaction constructor(private val context: Context) {
|
|||
return part.data.size
|
||||
}
|
||||
|
||||
// create the image part to be stored in database
|
||||
@Throws(Exception::class)
|
||||
private fun createPartImage(context: Context, id: String, imageBytes: ByteArray, mimeType: String): Uri {
|
||||
val mmsPartValue = ContentValues()
|
||||
mmsPartValue.put("mid", id)
|
||||
mmsPartValue.put("ct", mimeType)
|
||||
mmsPartValue.put("cid", "<" + System.currentTimeMillis() + ">")
|
||||
val partUri = Uri.parse("content://mms/$id/part")
|
||||
val res = context.contentResolver.insert(partUri, mmsPartValue)
|
||||
|
||||
// Add data to part
|
||||
val os = context.contentResolver.openOutputStream(res!!)
|
||||
val `is` = ByteArrayInputStream(imageBytes)
|
||||
val buffer = ByteArray(256)
|
||||
|
||||
var len = `is`.read(buffer)
|
||||
while (len != -1) {
|
||||
os!!.write(buffer, 0, len)
|
||||
len = `is`.read(buffer)
|
||||
}
|
||||
|
||||
os!!.close()
|
||||
`is`.close()
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// create the text part to be stored in database
|
||||
@Throws(Exception::class)
|
||||
private fun createPartText(context: Context, id: String, text: String): Uri? {
|
||||
val mmsPartValue = ContentValues()
|
||||
mmsPartValue.put("mid", id)
|
||||
mmsPartValue.put("ct", "text/plain")
|
||||
mmsPartValue.put("cid", "<" + System.currentTimeMillis() + ">")
|
||||
mmsPartValue.put("text", text)
|
||||
val partUri = Uri.parse("content://mms/$id/part")
|
||||
|
||||
return context.contentResolver.insert(partUri, mmsPartValue)
|
||||
}
|
||||
|
||||
// add address to the request
|
||||
@Throws(Exception::class)
|
||||
private fun createAddr(context: Context, id: String, addr: String): Uri? {
|
||||
val addrValues = ContentValues()
|
||||
addrValues.put("address", addr)
|
||||
addrValues.put("charset", "106")
|
||||
addrValues.put("type", 151) // TO
|
||||
val addrUri = Uri.parse("content://mms/$id/addr")
|
||||
|
||||
return context.contentResolver.insert(addrUri, addrValues)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -47,7 +47,8 @@ class ComposeView: View {
|
|||
fun sendMessage(view: View) {
|
||||
val text = composeInput.text.toString()
|
||||
this.composeInput.text.clear()
|
||||
this.sendMessage(text, this.medias)
|
||||
this.sendMessage(text, this.medias.toTypedArray().copyOf())
|
||||
this.medias.removeAll { true }
|
||||
}
|
||||
|
||||
fun pickPicture() {
|
||||
|
@ -75,7 +76,7 @@ class ComposeView: View {
|
|||
* @param text Contenu du message
|
||||
* @param medias Documents à envoyer
|
||||
*/
|
||||
abstract fun sendMessage(text: String, medias: ArrayList<NornMedia>)
|
||||
abstract fun sendMessage(text: String, medias: Array<NornMedia>)
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue