Merge pull request #2 from SimpleMobileTools/master

upd
This commit is contained in:
solokot 2020-05-13 17:57:30 +03:00 committed by GitHub
commit 5b14084d8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 178 additions and 37 deletions

View File

@ -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)*
----------------------------

View File

@ -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'

View File

@ -154,6 +154,15 @@
android:exported="true"
android:taskAffinity="${applicationId}.SMS_SENT" />
<receiver
android:name=".receivers.MarkAsReadReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.simplemobiletools.smsmessenger.action.mark_as_read" />
</intent-filter>
</receiver>
<activity-alias
android:name=".activities.SplashActivity.Red"
android:enabled="false"

View File

@ -274,7 +274,7 @@ class ThreadActivity : SimpleActivity() {
@SuppressLint("MissingPermission")
private fun setupSIMSelector() {
val availableSIMs = SubscriptionManager.from(this).activeSubscriptionInfoList
val availableSIMs = SubscriptionManager.from(this).activeSubscriptionInfoList ?: return
if (availableSIMs.size > 1) {
availableSIMs.forEachIndexed { index, subscriptionInfo ->
var label = subscriptionInfo.displayName.toString()
@ -370,16 +370,24 @@ class ThreadActivity : SimpleActivity() {
showSelectedContacts()
}
@SuppressLint("MissingPermission")
private fun getThreadItems(): ArrayList<ThreadItem> {
messages.sortBy { it.date }
val subscriptionIdToSimId = HashMap<Int, String>()
subscriptionIdToSimId[-1] = "?"
SubscriptionManager.from(this).activeSubscriptionInfoList?.forEachIndexed { index, subscriptionInfo ->
subscriptionIdToSimId[subscriptionInfo.subscriptionId] = "${index + 1}"
}
val items = ArrayList<ThreadItem>()
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)

View File

@ -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<Conversation>
override fun onViewRecycled(holder: ViewHolder) {
super.onViewRecycled(holder)
if (!activity.isDestroyed && !activity.isFinishing) {

View File

@ -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<ThreadItem
itemClick: (Any) -> 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<ThreadItem
view.apply {
thread_date_time.text = dateTime.date.formatDateOrTime(context, false)
thread_date_time.setTextColor(textColor)
thread_sim_icon.beVisibleIf(hasMultipleSIMCards)
thread_sim_number.beVisibleIf(hasMultipleSIMCards)
if (hasMultipleSIMCards) {
thread_sim_number.text = dateTime.simID
thread_sim_number.setTextColor(textColor.getContrastColor())
thread_sim_icon.applyColorFilter(textColor)
}
}
}
}

View File

@ -22,9 +22,9 @@ import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.commons.models.SimpleContact
import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.activities.ThreadActivity
import com.simplemobiletools.smsmessenger.helpers.Config
import com.simplemobiletools.smsmessenger.helpers.THREAD_ID
import com.simplemobiletools.smsmessenger.helpers.*
import com.simplemobiletools.smsmessenger.models.*
import com.simplemobiletools.smsmessenger.receivers.MarkAsReadReceiver
import java.util.*
import kotlin.collections.ArrayList
@ -39,7 +39,8 @@ fun Context.getMessages(threadId: Int): ArrayList<Message> {
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<Message> {
val blockStatus = HashMap<String, Boolean>()
var messages = ArrayList<Message>()
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<Message> {
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<Conversation> {
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<SimpleContact> {
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())
}

View File

@ -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

View File

@ -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)

View File

@ -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<SimpleContact>, 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
}

View File

@ -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()

View File

@ -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)
}
}
}
}

View File

@ -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)
}
}

View File

@ -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()
}
}

View File

@ -1,10 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/thread_date_time"
android:id="@+id/thread_date_time_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/normal_margin"
android:gravity="center_horizontal"
android:textSize="@dimen/normal_text_size"
tools:text="13 March, 13:30" />
android:layout_marginTop="@dimen/medium_margin">
<TextView
android:id="@+id/thread_date_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textSize="@dimen/normal_text_size"
tools:text="13 March, 13:30" />
<ImageView
android:id="@+id/thread_sim_icon"
android:layout_width="@dimen/activity_margin"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/thread_date_time"
android:layout_alignBottom="@id/thread_date_time"
android:layout_marginEnd="@dimen/small_margin"
android:layout_toStartOf="@id/thread_date_time"
android:src="@drawable/ic_sim_vector" />
<TextView
android:id="@+id/thread_sim_number"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignStart="@+id/thread_sim_icon"
android:layout_alignTop="@+id/thread_sim_icon"
android:layout_alignEnd="@+id/thread_sim_icon"
android:layout_alignBottom="@+id/thread_sim_icon"
android:gravity="center"
android:textColor="@color/md_grey_black"
android:textSize="@dimen/smaller_text_size"
tools:text="1" />
</RelativeLayout>

View File

@ -1,6 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/cab_add_number_to_contact"
android:icon="@drawable/ic_add_person_vector"
android:title="@string/add_number_to_contact"
app:showAsAction="ifRoom" />
<item
android:id="@+id/cab_select_all"
android:icon="@drawable/ic_select_all_vector"

View File

@ -1,11 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/block_number"
android:icon="@drawable/ic_block_vector"
android:title="@string/block_number"
app:showAsAction="ifRoom" />
<item
android:id="@+id/delete"
android:icon="@drawable/ic_delete_vector"
@ -16,4 +11,9 @@
android:icon="@drawable/ic_add_person_vector"
android:title="@string/add_person"
app:showAsAction="ifRoom" />
<item
android:id="@+id/block_number"
android:icon="@drawable/ic_block_vector"
android:title="@string/block_number"
app:showAsAction="never" />
</menu>

View File

@ -0,0 +1,3 @@
* 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