diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0d621cc5..569884ab 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,13 @@
Changelog
==========
+Version 5.1.2 *(2020-05-13)*
+----------------------------
+
+ * Improved the handling of multiple SIM cards at once
+ * Added a Mark as Read action button in incoming message notifications
+ * Allow saving unknown numbers from the main screen easily
+
Version 5.1.1 *(2020-05-08)*
----------------------------
diff --git a/app/build.gradle b/app/build.gradle
index 8490e2a1..46335361 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -16,8 +16,8 @@ android {
applicationId "com.simplemobiletools.smsmessenger"
minSdkVersion 22
targetSdkVersion 29
- versionCode 4
- versionName "5.1.1"
+ versionCode 5
+ versionName "5.1.2"
setProperty("archivesBaseName", "sms-messenger")
}
@@ -56,7 +56,7 @@ android {
}
dependencies {
- implementation 'com.simplemobiletools:commons:5.27.24'
+ implementation 'com.simplemobiletools:commons:5.27.29'
implementation 'org.greenrobot:eventbus:3.2.0'
implementation 'com.klinkerapps:android-smsmms:5.2.6'
implementation 'com.github.tibbi:IndicatorFastScroll:08f512858a'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c2f17766..770b80db 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -154,6 +154,15 @@
android:exported="true"
android:taskAffinity="${applicationId}.SMS_SENT" />
+
+
+
+
+
+
1) {
availableSIMs.forEachIndexed { index, subscriptionInfo ->
var label = subscriptionInfo.displayName.toString()
@@ -370,16 +370,24 @@ class ThreadActivity : SimpleActivity() {
showSelectedContacts()
}
+ @SuppressLint("MissingPermission")
private fun getThreadItems(): ArrayList {
messages.sortBy { it.date }
+ val subscriptionIdToSimId = HashMap()
+ subscriptionIdToSimId[-1] = "?"
+ SubscriptionManager.from(this).activeSubscriptionInfoList?.forEachIndexed { index, subscriptionInfo ->
+ subscriptionIdToSimId[subscriptionInfo.subscriptionId] = "${index + 1}"
+ }
+
val items = ArrayList()
var prevDateTime = 0
var hadUnreadItems = false
messages.forEach {
// do not show the date/time above every message, only if the difference between the 2 messages is at least MIN_DATE_TIME_DIFF_SECS
if (it.date - prevDateTime > MIN_DATE_TIME_DIFF_SECS) {
- items.add(ThreadDateTime(it.date))
+ val simCardID = subscriptionIdToSimId[it.subscriptionId] ?: "?"
+ items.add(ThreadDateTime(it.date, simCardID))
prevDateTime = it.date
}
items.add(it)
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ConversationsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ConversationsAdapter.kt
index 2677c10f..ed427e89 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ConversationsAdapter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ConversationsAdapter.kt
@@ -1,5 +1,6 @@
package com.simplemobiletools.smsmessenger.adapters
+import android.content.Intent
import android.graphics.Typeface
import android.view.Menu
import android.view.View
@@ -9,6 +10,8 @@ import com.bumptech.glide.Glide
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.extensions.formatDateOrTime
+import com.simplemobiletools.commons.extensions.toast
+import com.simplemobiletools.commons.helpers.KEY_PHONE
import com.simplemobiletools.commons.helpers.SimpleContactsHelper
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
import com.simplemobiletools.commons.views.FastScroller
@@ -29,7 +32,11 @@ class ConversationsAdapter(activity: SimpleActivity, var conversations: ArrayLis
override fun getActionMenuId() = R.menu.cab_conversations
- override fun prepareActionMode(menu: Menu) {}
+ override fun prepareActionMode(menu: Menu) {
+ menu.apply {
+ findItem(R.id.cab_add_number_to_contact).isVisible = isOneItemSelected() && getSelectedItems().firstOrNull()?.isGroupConversation == false
+ }
+ }
override fun actionItemPressed(id: Int) {
if (selectedKeys.isEmpty()) {
@@ -37,6 +44,7 @@ class ConversationsAdapter(activity: SimpleActivity, var conversations: ArrayLis
}
when (id) {
+ R.id.cab_add_number_to_contact -> addNumberToContact()
R.id.cab_select_all -> selectAll()
R.id.cab_delete -> askConfirmDelete()
}
@@ -105,6 +113,23 @@ class ConversationsAdapter(activity: SimpleActivity, var conversations: ArrayLis
}
}
+ private fun addNumberToContact() {
+ val conversation = getSelectedItems().firstOrNull() ?: return
+ Intent().apply {
+ action = Intent.ACTION_INSERT_OR_EDIT
+ type = "vnd.android.cursor.item/contact"
+ putExtra(KEY_PHONE, conversation.phoneNumber)
+
+ if (resolveActivity(activity.packageManager) != null) {
+ activity.startActivity(this)
+ } else {
+ activity.toast(R.string.no_app_found)
+ }
+ }
+ }
+
+ private fun getSelectedItems() = conversations.filter { selectedKeys.contains(it.id) } as ArrayList
+
override fun onViewRecycled(holder: ViewHolder) {
super.onViewRecycled(holder)
if (!activity.isDestroyed && !activity.isFinishing) {
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ThreadAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ThreadAdapter.kt
index 0a609b19..0f5a6531 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ThreadAdapter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ThreadAdapter.kt
@@ -1,8 +1,10 @@
package com.simplemobiletools.smsmessenger.adapters
+import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.drawable.Drawable
import android.net.Uri
+import android.telephony.SubscriptionManager
import android.view.Menu
import android.view.View
import android.view.ViewGroup
@@ -42,6 +44,8 @@ class ThreadAdapter(activity: SimpleActivity, var messages: ArrayList Unit) : MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
private val roundedCornersRadius = resources.getDimension(R.dimen.normal_margin).toInt()
+ @SuppressLint("MissingPermission")
+ private val hasMultipleSIMCards = SubscriptionManager.from(activity).activeSubscriptionInfoList?.size ?: 0 > 1
init {
setupDragListener(true)
@@ -283,6 +287,14 @@ class ThreadAdapter(activity: SimpleActivity, var messages: ArrayList {
Sms.ADDRESS,
Sms.DATE,
Sms.READ,
- Sms.THREAD_ID
+ Sms.THREAD_ID,
+ Sms.SUBSCRIPTION_ID
)
val selection = "${Sms.THREAD_ID} = ?"
@@ -49,7 +50,7 @@ fun Context.getMessages(threadId: Int): ArrayList {
val blockStatus = HashMap()
var messages = ArrayList()
queryCursor(uri, projection, selection, selectionArgs, sortOrder, showErrors = true) { cursor ->
- val senderNumber = cursor.getStringValue(Sms.ADDRESS)
+ val senderNumber = cursor.getStringValue(Sms.ADDRESS) ?: return@queryCursor
val isNumberBlocked = if (blockStatus.containsKey(senderNumber)) {
blockStatus[senderNumber]!!
@@ -72,9 +73,10 @@ fun Context.getMessages(threadId: Int): ArrayList {
val date = (cursor.getLongValue(Sms.DATE) / 1000).toInt()
val read = cursor.getIntValue(Sms.READ) == 1
val thread = cursor.getIntValue(Sms.THREAD_ID)
+ val subscriptionId = cursor.getIntValue(Sms.SUBSCRIPTION_ID)
val participant = SimpleContact(0, 0, senderName, photoUri, senderNumber)
val isMMS = false
- val message = Message(id, body, type, arrayListOf(participant), date, read, thread, isMMS, null, senderName, photoUri)
+ val message = Message(id, body, type, arrayListOf(participant), date, read, thread, isMMS, null, senderName, photoUri, subscriptionId)
messages.add(message)
}
@@ -93,7 +95,8 @@ fun Context.getMMS(threadId: Int? = null, sortOrder: String? = null): ArrayList<
Mms.DATE,
Mms.READ,
Mms.MESSAGE_BOX,
- Mms.THREAD_ID
+ Mms.THREAD_ID,
+ Mms.SUBSCRIPTION_ID
)
val selection = if (threadId == null) {
@@ -117,6 +120,7 @@ fun Context.getMMS(threadId: Int? = null, sortOrder: String? = null): ArrayList<
val date = cursor.getLongValue(Mms.DATE).toInt()
val read = cursor.getIntValue(Mms.READ) == 1
val threadId = cursor.getIntValue(Mms.THREAD_ID)
+ val subscriptionId = cursor.getIntValue(Mms.SUBSCRIPTION_ID)
val participants = if (threadParticipants.containsKey(threadId)) {
threadParticipants[threadId]!!
} else {
@@ -140,7 +144,7 @@ fun Context.getMMS(threadId: Int? = null, sortOrder: String? = null): ArrayList<
}
}
- val message = Message(mmsId, body, type, participants, date, read, threadId, isMMS, attachment, senderName, senderPhotoUri)
+ val message = Message(mmsId, body, type, participants, date, read, threadId, isMMS, attachment, senderName, senderPhotoUri, subscriptionId)
messages.add(message)
participants.forEach {
@@ -206,7 +210,7 @@ fun Context.getConversations(): ArrayList {
val title = TextUtils.join(", ", names.toTypedArray())
val photoUri = if (phoneNumbers.size == 1) SimpleContactsHelper(this).getPhotoUriFromPhoneNumber(phoneNumbers.first()) else ""
val isGroupConversation = phoneNumbers.size > 1
- val conversation = Conversation(id, snippet, date.toInt(), read, title, photoUri, isGroupConversation)
+ val conversation = Conversation(id, snippet, date.toInt(), read, title, photoUri, isGroupConversation, phoneNumbers.first())
conversations.add(conversation)
}
@@ -371,7 +375,7 @@ fun Context.getSuggestedContacts(): ArrayList {
val sortOrder = "${Sms.DATE} DESC LIMIT 20"
queryCursor(uri, projection, selection, selectionArgs, sortOrder, showErrors = true) { cursor ->
- val senderNumber = cursor.getStringValue(Sms.ADDRESS)
+ val senderNumber = cursor.getStringValue(Sms.ADDRESS) ?: return@queryCursor
val namePhoto = getNameAndPhotoFromPhoneNumber(senderNumber)
if (namePhoto == null || namePhoto.name == senderNumber || isNumberBlocked(senderNumber)) {
return@queryCursor
@@ -415,7 +419,7 @@ fun Context.getNameAndPhotoFromPhoneNumber(number: String): NamePhoto? {
return NamePhoto(number, null)
}
-fun Context.insertNewSMS(address: String, subject: String, body: String, date: Long, read: Int, threadId: Long, type: Int) {
+fun Context.insertNewSMS(address: String, subject: String, body: String, date: Long, read: Int, threadId: Long, type: Int, subscriptionId: Int): Int {
val uri = Sms.CONTENT_URI
val contentValues = ContentValues().apply {
put(Sms.ADDRESS, address)
@@ -425,9 +429,11 @@ fun Context.insertNewSMS(address: String, subject: String, body: String, date: L
put(Sms.READ, read)
put(Sms.THREAD_ID, threadId)
put(Sms.TYPE, type)
+ put(Sms.SUBSCRIPTION_ID, subscriptionId)
}
- contentResolver.insert(uri, contentValues)
+ val newUri = contentResolver.insert(uri, contentValues)
+ return newUri?.lastPathSegment?.toInt() ?: 0
}
fun Context.deleteConversation(id: Int) {
@@ -487,7 +493,7 @@ fun Context.isNumberBlocked(number: String): Boolean {
}
@SuppressLint("NewApi")
-fun Context.showReceivedMessageNotification(address: String, body: String, threadID: Int, bitmap: Bitmap? = null) {
+fun Context.showReceivedMessageNotification(address: String, body: String, threadID: Int, bitmap: Bitmap?, messageId: Int, isMMS: Boolean) {
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val channelId = "simple_sms_messenger"
@@ -517,6 +523,13 @@ fun Context.showReceivedMessageNotification(address: String, body: String, threa
val summaryText = getString(R.string.new_message)
val sender = getNameAndPhotoFromPhoneNumber(address)?.name ?: ""
+ val markAsReadIntent = Intent(this, MarkAsReadReceiver::class.java).apply {
+ action = MARK_AS_READ
+ putExtra(MESSAGE_ID, messageId)
+ putExtra(MESSAGE_IS_MMS, isMMS)
+ }
+ val markAsReadPendingIntent = PendingIntent.getBroadcast(this, 0, markAsReadIntent, PendingIntent.FLAG_CANCEL_CURRENT)
+
val largeIcon = bitmap ?: SimpleContactsHelper(this).getContactLetterIcon(sender)
val builder = NotificationCompat.Builder(this, channelId)
.setContentTitle(sender)
@@ -530,7 +543,8 @@ fun Context.showReceivedMessageNotification(address: String, body: String, threa
.setCategory(Notification.CATEGORY_MESSAGE)
.setAutoCancel(true)
.setSound(soundUri, AudioManager.STREAM_NOTIFICATION)
+ .addAction(R.drawable.ic_check_vector, getString(R.string.mark_as_read), markAsReadPendingIntent)
.setChannelId(channelId)
- notificationManager.notify(threadID, builder.build())
+ notificationManager.notify(messageId, builder.build())
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/Constants.kt
index 33fb77fd..8620bfa8 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/Constants.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/Constants.kt
@@ -11,6 +11,11 @@ const val THREAD_ATTACHMENT_URI = "thread_attachment_uri"
const val THREAD_ATTACHMENT_URIS = "thread_attachment_uris"
const val USE_SIM_ID_PREFIX = "use_sim_id_"
+private const val PATH = "com.simplemobiletools.smsmessenger.action."
+const val MARK_AS_READ = PATH + "mark_as_read"
+const val MESSAGE_ID = "message_id"
+const val MESSAGE_IS_MMS = "message_is_mms"
+
// view types for the thread list view
const val THREAD_DATE_TIME = 1
const val THREAD_RECEIVED_MESSAGE = 2
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Conversation.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Conversation.kt
index 81420432..65329fc8 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Conversation.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Conversation.kt
@@ -2,5 +2,4 @@ package com.simplemobiletools.smsmessenger.models
data class Conversation(
val id: Int, val snippet: String, val date: Int, val read: Boolean, val title: String, val photoUri: String,
- val isGroupConversation: Boolean
-)
+ val isGroupConversation: Boolean, val phoneNumber: String)
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Message.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Message.kt
index 2b6f24c2..4285d527 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Message.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Message.kt
@@ -5,6 +5,6 @@ import com.simplemobiletools.commons.models.SimpleContact
data class Message(
val id: Int, val body: String, val type: Int, val participants: ArrayList, val date: Int, val read: Boolean, val thread: Int,
- val isMMS: Boolean, val attachment: MessageAttachment?, val senderName: String, val senderPhotoUri: String) : ThreadItem() {
+ val isMMS: Boolean, val attachment: MessageAttachment?, val senderName: String, val senderPhotoUri: String, val subscriptionId: Int) : ThreadItem() {
fun isReceivedMessage() = type == Telephony.Sms.MESSAGE_TYPE_INBOX
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/ThreadDateTime.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/ThreadDateTime.kt
index 7b2d9293..d69d81fa 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/ThreadDateTime.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/ThreadDateTime.kt
@@ -1,3 +1,3 @@
package com.simplemobiletools.smsmessenger.models
-open class ThreadDateTime(val date: Int) : ThreadItem()
+open class ThreadDateTime(val date: Int, val simID: String) : ThreadItem()
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MarkAsReadReceiver.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MarkAsReadReceiver.kt
new file mode 100644
index 00000000..f0cdff85
--- /dev/null
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MarkAsReadReceiver.kt
@@ -0,0 +1,23 @@
+package com.simplemobiletools.smsmessenger.receivers
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import com.simplemobiletools.commons.extensions.notificationManager
+import com.simplemobiletools.smsmessenger.extensions.markMessageRead
+import com.simplemobiletools.smsmessenger.helpers.MARK_AS_READ
+import com.simplemobiletools.smsmessenger.helpers.MESSAGE_ID
+import com.simplemobiletools.smsmessenger.helpers.MESSAGE_IS_MMS
+
+class MarkAsReadReceiver : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ when (intent.action) {
+ MARK_AS_READ -> {
+ val messageId = intent.getIntExtra(MESSAGE_ID, 0)
+ val isMMS = intent.getBooleanExtra(MESSAGE_IS_MMS, false)
+ context.markMessageRead(messageId, isMMS)
+ context.notificationManager.cancel(messageId)
+ }
+ }
+ }
+}
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MmsReceiver.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MmsReceiver.kt
index a35b51f5..865fb5a3 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MmsReceiver.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MmsReceiver.kt
@@ -31,7 +31,7 @@ class MmsReceiver : com.klinker.android.send_message.MmsReceivedReceiver() {
null
}
- context.showReceivedMessageNotification(address, mms.body, mms.thread, glideBitmap)
+ context.showReceivedMessageNotification(address, mms.body, mms.thread, glideBitmap, mms.id, true)
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsReceiver.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsReceiver.kt
index 3649bc9d..17c6f62b 100644
--- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsReceiver.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsReceiver.kt
@@ -20,6 +20,7 @@ class SmsReceiver : BroadcastReceiver() {
var threadId = 0L
val type = Telephony.Sms.MESSAGE_TYPE_INBOX
val read = 0
+ val subscriptionId = intent.getIntExtra("subscription", -1)
messages.forEach {
address = it.originatingAddress ?: ""
@@ -30,8 +31,8 @@ class SmsReceiver : BroadcastReceiver() {
}
if (!context.isNumberBlocked(address)) {
- context.insertNewSMS(address, subject, body, date, read, threadId, type)
- context.showReceivedMessageNotification(address, body, threadId.toInt())
+ val messageId = context.insertNewSMS(address, subject, body, date, read, threadId, type, subscriptionId)
+ context.showReceivedMessageNotification(address, body, threadId.toInt(), null, messageId, false)
refreshMessages()
}
}
diff --git a/app/src/main/res/layout/item_thread_date_time.xml b/app/src/main/res/layout/item_thread_date_time.xml
index 5f93edcf..413c3ef8 100644
--- a/app/src/main/res/layout/item_thread_date_time.xml
+++ b/app/src/main/res/layout/item_thread_date_time.xml
@@ -1,10 +1,40 @@
-
+ android:layout_marginTop="@dimen/medium_margin">
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/menu/cab_conversations.xml b/app/src/main/res/menu/cab_conversations.xml
index 2a2792e0..54c3891e 100644
--- a/app/src/main/res/menu/cab_conversations.xml
+++ b/app/src/main/res/menu/cab_conversations.xml
@@ -1,6 +1,11 @@