diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/MainActivity.kt index a975e180..85429134 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/MainActivity.kt @@ -19,8 +19,7 @@ import com.simplemobiletools.smsmessenger.adapters.MessagesAdapter import com.simplemobiletools.smsmessenger.extensions.config import com.simplemobiletools.smsmessenger.extensions.getMessages import com.simplemobiletools.smsmessenger.helpers.THREAD_ID -import com.simplemobiletools.smsmessenger.helpers.THREAD_NAME -import com.simplemobiletools.smsmessenger.helpers.THREAD_NUMBER +import com.simplemobiletools.smsmessenger.helpers.THREAD_TITLE import com.simplemobiletools.smsmessenger.models.Events import com.simplemobiletools.smsmessenger.models.Message import kotlinx.android.synthetic.main.activity_main.* @@ -140,8 +139,7 @@ class MainActivity : SimpleActivity() { MessagesAdapter(this, messages, messages_list, messages_fastscroller) { Intent(this, ThreadActivity::class.java).apply { putExtra(THREAD_ID, (it as Message).thread) - putExtra(THREAD_NAME, it.participants.first().name) - putExtra(THREAD_NUMBER, it.participants.first().phoneNumber) + putExtra(THREAD_TITLE, it.getThreadTitle()) startActivity(this) } }.apply { diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewMessageActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewMessageActivity.kt index dffbc673..f6c68103 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewMessageActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/NewMessageActivity.kt @@ -11,8 +11,7 @@ import com.simplemobiletools.smsmessenger.extensions.config import com.simplemobiletools.smsmessenger.extensions.getAvailableContacts import com.simplemobiletools.smsmessenger.extensions.getThreadId import com.simplemobiletools.smsmessenger.helpers.THREAD_ID -import com.simplemobiletools.smsmessenger.helpers.THREAD_NAME -import com.simplemobiletools.smsmessenger.helpers.THREAD_NUMBER +import com.simplemobiletools.smsmessenger.helpers.THREAD_TITLE import com.simplemobiletools.smsmessenger.models.Contact import kotlinx.android.synthetic.main.activity_new_message.* @@ -76,8 +75,7 @@ class NewMessageActivity : SimpleActivity() { private fun launchThreadActivity(phoneNumber: String, name: String) { Intent(this, ThreadActivity::class.java).apply { putExtra(THREAD_ID, getThreadId(phoneNumber).toInt()) - putExtra(THREAD_NAME, name) - putExtra(THREAD_NUMBER, phoneNumber) + putExtra(THREAD_TITLE, name) startActivity(this) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt index 938dccbe..49699b4a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt @@ -12,6 +12,7 @@ import android.view.MenuItem import android.view.View import android.view.inputmethod.EditorInfo import android.widget.LinearLayout +import android.widget.LinearLayout.LayoutParams import android.widget.RelativeLayout import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.extensions.* @@ -32,11 +33,11 @@ import org.greenrobot.eventbus.ThreadMode class ThreadActivity : SimpleActivity() { private val MIN_DATE_TIME_DIFF_SECS = 300 - private var targetNumber = "" private var threadId = 0 private var threadItems = ArrayList() private var bus: EventBus? = null - private var selectedContacts = ArrayList() + private var participants = ArrayList() + private var messages = ArrayList() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -50,28 +51,21 @@ class ThreadActivity : SimpleActivity() { } threadId = intent.getIntExtra(THREAD_ID, 0) - var thread = getThreadInfo(threadId) - if (thread == null) { - if (extras.containsKey(THREAD_NUMBER)) { - val threadTitle = extras.getString(THREAD_NAME) ?: getString(R.string.app_launcher_name) - targetNumber = extras.getString(THREAD_NUMBER)!! - thread = MessagingThread(threadId, threadTitle, targetNumber) - } else { - toast(R.string.unknown_error_occurred) - finish() - return - } + intent.getStringExtra(THREAD_TITLE)?.let { + supportActionBar?.title = it } - title = thread.title - targetNumber = thread.address bus = EventBus.getDefault() bus!!.register(this) - val contact = Contact(0, thread.title, "", targetNumber, false) - selectedContacts.add(contact) ensureBackgroundThread { + messages = getMessages(threadId) + participants = messages.first().participants setupAdapter() + + runOnUiThread { + supportActionBar?.title = messages.first().getThreadTitle() + } } setupButtons() } @@ -101,8 +95,7 @@ class ThreadActivity : SimpleActivity() { } private fun setupAdapter() { - val threadId = intent.getIntExtra(THREAD_ID, 0) - threadItems = getThreadItems(threadId) + threadItems = getThreadItems() invalidateOptionsMenu() runOnUiThread { @@ -115,7 +108,7 @@ class ThreadActivity : SimpleActivity() { val adapter = AutoCompleteTextViewAdapter(this, it) new_message_to.setAdapter(adapter) new_message_to.imeOptions = EditorInfo.IME_ACTION_NEXT - new_message_to.setOnItemClickListener { parent, view, position, id -> + new_message_to.setOnItemClickListener { _, _, position, _ -> val currContacts = (new_message_to.adapter as AutoCompleteTextViewAdapter).resultList val selectedContact = currContacts[position] addSelectedContact(selectedContact) @@ -135,14 +128,16 @@ class ThreadActivity : SimpleActivity() { return@setOnClickListener } - val intent = Intent(this, SmsSentReceiver::class.java).apply { - putExtra(MESSAGE_BODY, msg) - putExtra(MESSAGE_ADDRESS, targetNumber) - } + participants.forEach { + val intent = Intent(this, SmsSentReceiver::class.java).apply { + putExtra(MESSAGE_BODY, msg) + putExtra(MESSAGE_ADDRESS, it.phoneNumber) + } - val pendingIntent = PendingIntent.getBroadcast(this, threadId, intent, PendingIntent.FLAG_UPDATE_CURRENT) - val smsManager = SmsManager.getDefault() - smsManager.sendTextMessage(targetNumber, null, msg, pendingIntent, null) + val pendingIntent = PendingIntent.getBroadcast(this, threadId, intent, PendingIntent.FLAG_UPDATE_CURRENT) + val smsManager = SmsManager.getDefault() + smsManager.sendTextMessage(it.phoneNumber, null, msg, pendingIntent, null) + } thread_type_message.setText("") } @@ -156,7 +151,7 @@ class ThreadActivity : SimpleActivity() { hideKeyboard() thread_add_contacts.beGone() - val numbers = selectedContacts.map { it.phoneNumber }.toSet() + val numbers = participants.map { it.phoneNumber }.toSet() val threadId = getThreadId(numbers).toInt() Intent(this, ThreadActivity::class.java).apply { putExtra(THREAD_ID, threadId) @@ -168,7 +163,7 @@ class ThreadActivity : SimpleActivity() { private fun blockNumber() { val baseString = R.string.block_confirmation - val numbers = selectedContacts.map { it.phoneNumber }.toTypedArray() + val numbers = participants.map { it.phoneNumber }.toTypedArray() val numbersString = TextUtils.join(", ", numbers) val question = String.format(resources.getString(baseString), numbersString) @@ -205,12 +200,12 @@ class ThreadActivity : SimpleActivity() { private fun showSelectedContacts() { val views = ArrayList() - selectedContacts.forEach { + participants.forEach { val contact = it layoutInflater.inflate(R.layout.item_selected_contact, null).apply { selected_contact_name.text = contact.name selected_contact_remove.setOnClickListener { - if (contact.id != selectedContacts.first().id) { + if (contact.id != participants.first().id) { removeSelectedContact(contact.id) } } @@ -222,16 +217,15 @@ class ThreadActivity : SimpleActivity() { private fun addSelectedContact(contact: Contact) { new_message_to.setText("") - if (selectedContacts.map { it.id }.contains(contact.id)) { + if (participants.map { it.id }.contains(contact.id)) { return } - selectedContacts.add(contact) + participants.add(contact) showSelectedContacts() } - private fun getThreadItems(threadID: Int): ArrayList { - val messages = getMessages(threadID) + private fun getThreadItems(): ArrayList { messages.sortBy { it.date } val items = ArrayList() @@ -267,8 +261,7 @@ class ThreadActivity : SimpleActivity() { private fun showSelectedContact(views: ArrayList) { selected_contacts.removeAllViews() var newLinearLayout = LinearLayout(this) - newLinearLayout.layoutParams = - LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + newLinearLayout.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT) newLinearLayout.orientation = LinearLayout.HORIZONTAL val sideMargin = (selected_contacts.layoutParams as RelativeLayout.LayoutParams).leftMargin @@ -277,14 +270,15 @@ class ThreadActivity : SimpleActivity() { val firstRowWidth = parentWidth - resources.getDimension(R.dimen.normal_icon_size).toInt() + sideMargin / 2 var widthSoFar = 0 var isFirstRow = true + for (i in views.indices) { val LL = LinearLayout(this) LL.orientation = LinearLayout.HORIZONTAL LL.gravity = Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM - LL.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT) + LL.layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT) views[i].measure(0, 0) - var params = LinearLayout.LayoutParams(views[i].measuredWidth, LinearLayout.LayoutParams.WRAP_CONTENT) + var params = LayoutParams(views[i].measuredWidth, LayoutParams.WRAP_CONTENT) params.setMargins(0, 0, mediumMargin, 0) LL.addView(views[i], params) LL.measure(0, 0) @@ -295,16 +289,15 @@ class ThreadActivity : SimpleActivity() { isFirstRow = false selected_contacts.addView(newLinearLayout) newLinearLayout = LinearLayout(this) - newLinearLayout.layoutParams = - LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) + newLinearLayout.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT) newLinearLayout.orientation = LinearLayout.HORIZONTAL - params = LinearLayout.LayoutParams(LL.measuredWidth, LL.measuredHeight) + params = LayoutParams(LL.measuredWidth, LL.measuredHeight) params.topMargin = mediumMargin newLinearLayout.addView(LL, params) widthSoFar = LL.measuredWidth } else { if (!isFirstRow) { - (LL.layoutParams as LinearLayout.LayoutParams).topMargin = mediumMargin + (LL.layoutParams as LayoutParams).topMargin = mediumMargin } newLinearLayout.addView(LL) } @@ -313,12 +306,13 @@ class ThreadActivity : SimpleActivity() { } private fun removeSelectedContact(id: Int) { - selectedContacts = selectedContacts.filter { it.id != id }.toMutableList() as ArrayList + participants = participants.filter { it.id != id }.toMutableList() as ArrayList showSelectedContacts() } - @Subscribe(threadMode = ThreadMode.MAIN) + @Subscribe(threadMode = ThreadMode.ASYNC) fun refreshMessages(event: Events.RefreshMessages) { + messages = getMessages(threadId) setupAdapter() } } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Context.kt index 31111df4..dcc834ae 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Context.kt @@ -11,7 +11,6 @@ import android.provider.ContactsContract.CommonDataKinds import android.provider.ContactsContract.CommonDataKinds.Organization import android.provider.ContactsContract.CommonDataKinds.StructuredName import android.provider.ContactsContract.PhoneLookup -import android.provider.Telephony import android.provider.Telephony.* import android.text.TextUtils import com.simplemobiletools.commons.extensions.* @@ -23,7 +22,6 @@ import com.simplemobiletools.smsmessenger.helpers.Config import com.simplemobiletools.smsmessenger.models.Contact import com.simplemobiletools.smsmessenger.models.MMS import com.simplemobiletools.smsmessenger.models.Message -import com.simplemobiletools.smsmessenger.models.MessagingThread import java.util.* import kotlin.collections.ArrayList @@ -78,6 +76,7 @@ fun Context.getMessages(threadId: Int? = null): ArrayList { return messages } +// as soon as a message contains multiple recipients it count as an MMS instead of SMS fun Context.getMMS(threadId: Int? = null): ArrayList { val uri = Mms.CONTENT_URI val projection = arrayOf( @@ -107,11 +106,9 @@ fun Context.getMMS(threadId: Int? = null): ArrayList { val date = cursor.getLongValue(Mms.DATE).toInt() val read = cursor.getIntValue(Mms.READ) == 1 val thread = cursor.getIntValue(Mms.THREAD_ID) - val senderName = getThreadRecipients(thread) - val senderNumber = senderName + val participants = getThreadParticipants(thread) val mms = getMmsContent(id) - val participant = Contact(0, senderName, "", senderNumber, false) - val message = Message(id, mms?.text ?: "", type, arrayListOf(participant), date, read, thread) + val message = Message(id, mms?.text ?: "", type, participants, date, read, thread) messages.add(message) } return messages @@ -148,32 +145,34 @@ fun Context.getMmsContent(id: Int): MMS? { return mms } -fun Context.getThreadRecipients(threadId: Int): String { +fun Context.getThreadParticipants(threadId: Int): ArrayList { val uri = Uri.parse("${MmsSms.CONTENT_CONVERSATIONS_URI}?simple=true") val projection = arrayOf( ThreadsColumns.RECIPIENT_IDS ) val selection = "${Mms._ID} = ?" val selectionArgs = arrayOf(threadId.toString()) + val participants = ArrayList() try { val cursor = contentResolver.query(uri, projection, selection, selectionArgs, null) cursor?.use { if (cursor.moveToFirst()) { val address = cursor.getStringValue(ThreadsColumns.RECIPIENT_IDS) - var recipient = "" address.split(" ").filter { it.areDigitsOnly() }.forEach { - recipient += "${getNameFromAddressId(it.toInt())}, " + val phoneNumber = getPhoneNumberFromAddressId(it.toInt()) + val name = getNameFromPhoneNumber(phoneNumber) + val contact = Contact(0, name, "", phoneNumber, false) + participants.add(contact) } - return recipient.removeSuffix(", ") } } } catch (e: Exception) { showErrorToast(e) } - return "" + return participants } -fun Context.getNameFromAddressId(canonicalAddressId: Int): String { +fun Context.getPhoneNumberFromAddressId(canonicalAddressId: Int): String { val uri = Uri.withAppendedPath(MmsSms.CONTENT_URI, "canonical-addresses") val projection = arrayOf( Mms.Addr.ADDRESS @@ -184,8 +183,7 @@ fun Context.getNameFromAddressId(canonicalAddressId: Int): String { val cursor = contentResolver.query(uri, projection, selection, selectionArgs, null) cursor?.use { if (cursor.moveToFirst()) { - val phoneNumber = cursor.getStringValue(Mms.Addr.ADDRESS) - return getNameFromPhoneNumber(phoneNumber) + return cursor.getStringValue(Mms.Addr.ADDRESS) } } } catch (e: Exception) { @@ -206,40 +204,6 @@ private fun Context.getMmsImage(uri: Uri, id: String): Bitmap? { return bitmap } -fun Context.getThreadInfo(id: Int): MessagingThread? { - val uri = Sms.CONTENT_URI - val projection = arrayOf( - Sms._ID, - Sms.ADDRESS, - Sms.PERSON - ) - val selection = "${Sms.THREAD_ID} = ?" - val selectionArgs = arrayOf(id.toString()) - try { - val cursor = contentResolver.query(uri, projection, selection, selectionArgs, null) - cursor?.use { - if (cursor.moveToFirst()) { - val person = cursor.getIntValue(Sms.PERSON) - val address = cursor.getStringValue(Sms.ADDRESS) - var title = address - - if (title != null && person != 0) { - title = getPersonsName(person) ?: title - } else if (title.areDigitsOnly()) { - val contactId = getContactIdFromPhoneNumber(title) - if (contactId != null) { - title = getPersonsName(contactId) ?: title - } - } - - return MessagingThread(id, title, address) - } - } - } catch (e: Exception) { - } - return null -} - fun Context.getPersonsName(id: Int): String? { val uri = ContactsContract.Data.CONTENT_URI val projection = arrayOf( @@ -328,27 +292,6 @@ fun Context.getAvailableContacts(callback: (ArrayList) -> Unit) { } } -fun Context.getContactIdFromPhoneNumber(number: String): Int? { - val uri = CommonDataKinds.Phone.CONTENT_URI - val projection = arrayOf( - ContactsContract.Data.CONTACT_ID - ) - - val selection = "${CommonDataKinds.Phone.NUMBER} = ? OR ${CommonDataKinds.Phone.NORMALIZED_NUMBER} = ?" - val selectionArgs = arrayOf(number, number) - try { - val cursor = contentResolver.query(uri, projection, selection, selectionArgs, null) - cursor.use { - if (cursor?.moveToFirst() == true) { - return cursor.getIntValue(ContactsContract.Data.CONTACT_ID) - } - } - } catch (e: Exception) { - showErrorToast(e) - } - return null -} - fun Context.getNameFromPhoneNumber(number: String): String { if (!hasPermission(PERMISSION_READ_CONTACTS)) { return number @@ -488,7 +431,7 @@ fun Context.markSMSRead(id: Int) { @SuppressLint("NewApi") fun Context.getThreadId(address: String): Long { return if (isMarshmallowPlus()) { - Telephony.Threads.getOrCreateThreadId(this, address) + Threads.getOrCreateThreadId(this, address) } else { 0 } @@ -497,7 +440,7 @@ fun Context.getThreadId(address: String): Long { @SuppressLint("NewApi") fun Context.getThreadId(addresses: Set): Long { return if (isMarshmallowPlus()) { - Telephony.Threads.getOrCreateThreadId(this, addresses) + Threads.getOrCreateThreadId(this, addresses) } else { 0 } 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 e8f6b4d0..dcc40a20 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/Constants.kt @@ -4,8 +4,7 @@ import com.simplemobiletools.smsmessenger.models.Events import org.greenrobot.eventbus.EventBus const val THREAD_ID = "thread_id" -const val THREAD_NAME = "thread_name" -const val THREAD_NUMBER = "thread_number" +const val THREAD_TITLE = "thread_title" // view types for the thread list view const val THREAD_DATE_TIME = 1 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 800c7ae3..1876dd7f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Message.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Message.kt @@ -1,9 +1,12 @@ package com.simplemobiletools.smsmessenger.models import android.provider.Telephony +import android.text.TextUtils data class Message( val id: Int, val body: String, val type: Int, val participants: ArrayList, val date: Int, val read: Boolean, val thread: Int ) : ThreadItem() { fun isReceivedMessage() = type == Telephony.Sms.MESSAGE_TYPE_INBOX + + fun getThreadTitle() = TextUtils.join(", ", participants.map { it.name }.toTypedArray()) } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MessagingThread.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MessagingThread.kt deleted file mode 100644 index 43d80e86..00000000 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MessagingThread.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.simplemobiletools.smsmessenger.models - -data class MessagingThread(val id: Int, val title: String, val address: String) diff --git a/app/src/main/res/layout/activity_new_message.xml b/app/src/main/res/layout/activity_new_message.xml index 62fddb70..c328920d 100644 --- a/app/src/main/res/layout/activity_new_message.xml +++ b/app/src/main/res/layout/activity_new_message.xml @@ -14,7 +14,7 @@ android:layout_toStartOf="@+id/new_message_confirm" android:background="@android:color/transparent" android:gravity="center_vertical" - android:hint="@string/select_contact_or_number" + android:hint="@string/add_contact_or_number" android:inputType="textCapWords" android:textSize="@dimen/big_text_size" /> diff --git a/app/src/main/res/layout/activity_thread.xml b/app/src/main/res/layout/activity_thread.xml index 3b71df0d..01cc40e1 100644 --- a/app/src/main/res/layout/activity_thread.xml +++ b/app/src/main/res/layout/activity_thread.xml @@ -51,7 +51,7 @@ android:background="@android:color/transparent" android:completionThreshold="2" android:gravity="center_vertical" - android:hint="@string/select_contact_or_number" + android:hint="@string/add_contact_or_number" android:inputType="textCapWords" android:textSize="@dimen/big_text_size" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b4a0e861..28dab393 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -7,7 +7,7 @@ Create new message - Select Contact or Number… + Add Contact or Number… Received SMS