diff --git a/res/drawable-hdpi/ic_note_to_self.png b/res/drawable-hdpi/ic_note_to_self.png new file mode 100644 index 0000000000..1cca57650f Binary files /dev/null and b/res/drawable-hdpi/ic_note_to_self.png differ diff --git a/res/drawable-mdpi/ic_note_to_self.png b/res/drawable-mdpi/ic_note_to_self.png new file mode 100644 index 0000000000..6ed37fdb10 Binary files /dev/null and b/res/drawable-mdpi/ic_note_to_self.png differ diff --git a/res/drawable-xhdpi/ic_note_to_self.png b/res/drawable-xhdpi/ic_note_to_self.png new file mode 100644 index 0000000000..cd1520cf74 Binary files /dev/null and b/res/drawable-xhdpi/ic_note_to_self.png differ diff --git a/res/drawable-xxhdpi/ic_note_to_self.png b/res/drawable-xxhdpi/ic_note_to_self.png new file mode 100644 index 0000000000..59bf9e76aa Binary files /dev/null and b/res/drawable-xxhdpi/ic_note_to_self.png differ diff --git a/res/drawable-xxxhdpi/ic_note_to_self.png b/res/drawable-xxxhdpi/ic_note_to_self.png new file mode 100644 index 0000000000..149489384f Binary files /dev/null and b/res/drawable-xxxhdpi/ic_note_to_self.png differ diff --git a/res/layout/conversation_title_view.xml b/res/layout/conversation_title_view.xml index affbee4a19..69efe6dfab 100644 --- a/res/layout/conversation_title_view.xml +++ b/res/layout/conversation_title_view.xml @@ -20,6 +20,7 @@ android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_centerVertical="true" + android:background="?selectableItemBackgroundBorderless" android:visibility="visible"/> - + + + + + + android:layout_marginRight="3dp" + android:layout_marginEnd="3dp" + android:layout_gravity="bottom" + android:alpha="0.7" + android:visibility="gone"/> - - - - + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 31b3b9e7bd..d954992de7 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -6,6 +6,7 @@ Delete Please wait... Save + Note to Self New message diff --git a/src/org/thoughtcrime/securesms/ConversationListItem.java b/src/org/thoughtcrime/securesms/ConversationListItem.java index 0e26856e67..7add0076ce 100644 --- a/src/org/thoughtcrime/securesms/ConversationListItem.java +++ b/src/org/thoughtcrime/securesms/ConversationListItem.java @@ -24,18 +24,12 @@ import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.Spanned; -import android.text.TextUtils; import android.text.style.StyleSpan; import android.util.AttributeSet; import android.view.View; import android.widget.RelativeLayout; import android.widget.TextView; -import com.annimon.stream.Stream; - import org.thoughtcrime.securesms.components.AlertView; import org.thoughtcrime.securesms.components.AvatarImageView; import org.thoughtcrime.securesms.components.DeliveryStatusView; @@ -49,13 +43,11 @@ import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.search.model.MessageResult; import org.thoughtcrime.securesms.util.DateUtils; import org.thoughtcrime.securesms.util.SearchUtil; -import org.thoughtcrime.securesms.util.SearchUtil.StyleFactory; import org.thoughtcrime.securesms.util.ThemeUtil; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.ViewUtil; import java.util.Collections; -import java.util.List; import java.util.Locale; import java.util.Set; @@ -147,7 +139,9 @@ public class ConversationListItem extends RelativeLayout this.recipient.addListener(this); if (highlightSubstring != null) { - this.fromView.setText(SearchUtil.getHighlightedSpan(locale, () -> new StyleSpan(Typeface.BOLD), recipient.getName(), highlightSubstring)); + String name = recipient.isLocalNumber() ? getContext().getString(R.string.note_to_self) : recipient.getName(); + + this.fromView.setText(SearchUtil.getHighlightedSpan(locale, () -> new StyleSpan(Typeface.BOLD), name, highlightSubstring)); } else { this.fromView.setText(recipient, unreadCount == 0); } @@ -201,7 +195,9 @@ public class ConversationListItem extends RelativeLayout this.recipient.addListener(this); - fromView.setText(SearchUtil.getHighlightedSpan(locale, () -> new StyleSpan(Typeface.BOLD), recipient.getName(), highlightSubstring)); + String name = recipient.isLocalNumber() ? getContext().getString(R.string.note_to_self) : recipient.getName(); + + fromView.setText(SearchUtil.getHighlightedSpan(locale, () -> new StyleSpan(Typeface.BOLD), name, highlightSubstring)); subjectView.setText(SearchUtil.getHighlightedSpan(locale, () -> new StyleSpan(Typeface.BOLD), contact.getAddress().toPhoneString(), highlightSubstring)); dateView.setText(""); archivedView.setVisibility(GONE); diff --git a/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java b/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java index b01616fe7a..be8a53eab8 100644 --- a/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java +++ b/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java @@ -29,6 +29,10 @@ import android.support.v7.widget.Toolbar; import android.telephony.PhoneNumberUtils; import org.thoughtcrime.securesms.components.SwitchPreferenceCompat; +import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; +import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto; +import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto; +import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto; import org.thoughtcrime.securesms.database.GroupDatabase; import org.thoughtcrime.securesms.jobs.RotateProfileKeyJob; import org.thoughtcrime.securesms.logging.Log; @@ -202,14 +206,19 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi } private void setHeader(@NonNull Recipient recipient) { - glideRequests.load(recipient.getContactPhoto()) - .fallback(recipient.getFallbackContactPhoto().asCallCard(this)) - .error(recipient.getFallbackContactPhoto().asCallCard(this)) + ContactPhoto contactPhoto = recipient.isLocalNumber() ? new ProfileContactPhoto(recipient.getAddress(), String.valueOf(TextSecurePreferences.getProfileAvatarId(this))) + : recipient.getContactPhoto(); + FallbackContactPhoto fallbackPhoto = recipient.isLocalNumber() ? new ResourceContactPhoto(R.drawable.ic_profile_default, R.drawable.ic_person_large) + : recipient.getFallbackContactPhoto(); + + glideRequests.load(contactPhoto) + .fallback(fallbackPhoto.asCallCard(this)) + .error(fallbackPhoto.asCallCard(this)) .diskCacheStrategy(DiskCacheStrategy.ALL) .into(this.avatar); - if (recipient.getContactPhoto() == null) this.avatar.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - else this.avatar.setScaleType(ImageView.ScaleType.CENTER_CROP); + if (contactPhoto == null) this.avatar.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + else this.avatar.setScaleType(ImageView.ScaleType.CENTER_CROP); this.avatar.setBackgroundColor(recipient.getColor().toActionBarColor(this)); this.toolbarLayout.setTitle(recipient.toShortString()); @@ -356,6 +365,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi private void setSummaries(Recipient recipient) { CheckBoxPreference mutePreference = (CheckBoxPreference) this.findPreference(PREFERENCE_MUTED); + Preference customPreference = this.findPreference(PREFERENCE_CUSTOM_NOTIFICATIONS); Preference ringtoneMessagePreference = this.findPreference(PREFERENCE_MESSAGE_TONE); Preference ringtoneCallPreference = this.findPreference(PREFERENCE_CALL_TONE); ListPreference vibrateMessagePreference = (ListPreference) this.findPreference(PREFERENCE_MESSAGE_VIBRATE); @@ -384,7 +394,19 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi vibrateCallPreference.setSummary(vibrateCallSummary.first); vibrateCallPreference.setValueIndex(vibrateCallSummary.second); - if (recipient.isGroupRecipient()) { + if (recipient.isLocalNumber()) { + mutePreference.setVisible(false); + customPreference.setVisible(false); + ringtoneMessagePreference.setVisible(false); + vibrateMessagePreference.setVisible(false); + + if (identityPreference != null) identityPreference.setVisible(false); + if (aboutCategory != null) aboutCategory.setVisible(false); + if (aboutDivider != null) aboutDivider.setVisible(false); + if (privacyCategory != null) privacyCategory.setVisible(false); + if (divider != null) divider.setVisible(false); + if (callCategory != null) callCategory.setVisible(false); + } if (recipient.isGroupRecipient()) { if (colorPreference != null) colorPreference.setVisible(false); if (identityPreference != null) identityPreference.setVisible(false); if (callCategory != null) callCategory.setVisible(false); diff --git a/src/org/thoughtcrime/securesms/components/FromTextView.java b/src/org/thoughtcrime/securesms/components/FromTextView.java index 30c1af3dca..0344fbb8aa 100644 --- a/src/org/thoughtcrime/securesms/components/FromTextView.java +++ b/src/org/thoughtcrime/securesms/components/FromTextView.java @@ -17,6 +17,7 @@ import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.components.emoji.EmojiTextView; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.ResUtil; +import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.spans.CenterAlignedRelativeSizeSpan; public class FromTextView extends EmojiTextView { @@ -52,7 +53,10 @@ public class FromTextView extends EmojiTextView { fromSpan.setSpan(new StyleSpan(typeface), 0, builder.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); - if (recipient.getName() == null && !TextUtils.isEmpty(recipient.getProfileName())) { + + if (recipient.isLocalNumber()) { + builder.append(getContext().getString(R.string.note_to_self)); + } else if (recipient.getName() == null && !TextUtils.isEmpty(recipient.getProfileName())) { SpannableString profileName = new SpannableString(" (~" + recipient.getProfileName() + ") "); profileName.setSpan(new CenterAlignedRelativeSizeSpan(0.75f), 0, profileName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); profileName.setSpan(new TypefaceSpan("sans-serif-light"), 0, profileName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); diff --git a/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java b/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java index 1551cd3e0f..2910a971e9 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java @@ -29,9 +29,11 @@ import android.provider.ContactsContract.PhoneLookup; import android.telephony.PhoneNumberUtils; import android.text.TextUtils; +import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.GroupDatabase; +import org.thoughtcrime.securesms.util.TextSecurePreferences; import java.util.ArrayList; import java.util.Collection; @@ -204,6 +206,12 @@ public class ContactAccessor { reader.close(); } + if (context.getString(R.string.note_to_self).toLowerCase().contains(constraint.toLowerCase()) && + !numberList.contains(TextSecurePreferences.getLocalNumber(context))) + { + numberList.add(TextSecurePreferences.getLocalNumber(context)); + } + return numberList; } diff --git a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java index b8d0803b7c..3901182356 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java @@ -40,6 +40,7 @@ import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.util.StickyHeaderDecoration.StickyHeaderAdapter; +import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import java.util.HashMap; diff --git a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java index e6773f9311..d1574fe603 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java @@ -75,6 +75,10 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM this.numberView.setTextColor(color); this.contactPhotoImage.setAvatar(glideRequests, recipient, false); + if (!multiSelect && recipient != null && recipient.isLocalNumber()) { + name = getContext().getString(R.string.note_to_self); + } + setText(type, name, number, label); if (multiSelect) this.checkBox.setVisibility(View.VISIBLE); diff --git a/src/org/thoughtcrime/securesms/contacts/ContactsDatabase.java b/src/org/thoughtcrime/securesms/contacts/ContactsDatabase.java index 91a8f8e921..adab0bca51 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactsDatabase.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactsDatabase.java @@ -24,6 +24,8 @@ import android.content.Context; import android.content.OperationApplicationException; import android.database.Cursor; import android.database.CursorWrapper; +import android.database.MatrixCursor; +import android.database.MergeCursor; import android.net.Uri; import android.os.Build; import android.os.RemoteException; @@ -38,6 +40,7 @@ import android.util.Pair; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.logging.Log; +import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.libsignal.util.guava.Optional; @@ -222,6 +225,25 @@ public class ContactsDatabase { new String[] {CONTACT_MIMETYPE, "%" + filter + "%", "%" + filter + "%"}, sort); + + if (context.getString(R.string.note_to_self).toLowerCase().contains(filter.toLowerCase())) { + Optional self = getSystemContactInfo(Address.fromSerialized(TextSecurePreferences.getLocalNumber(context))); + boolean shouldAdd = true; + + if (self.isPresent()) { + boolean nameMatch = self.get().name != null && self.get().name.toLowerCase().contains(filter.toLowerCase()); + boolean numberMatch = self.get().number != null && self.get().number.contains(filter); + + shouldAdd = !nameMatch && !numberMatch; + } + + if (shouldAdd) { + MatrixCursor selfCursor = new MatrixCursor(projection); + selfCursor.addRow(new Object[]{ context.getString(R.string.note_to_self), TextSecurePreferences.getLocalNumber(context)}); + + cursor = cursor == null ? selfCursor : new MergeCursor(new Cursor[]{ cursor, selfCursor }); + } + } } return new ProjectionMappingCursor(cursor, projectionMap, diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java index 95de9b70d2..6dcdbeabaa 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -652,6 +652,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity inflater.inflate(R.menu.conversation_add_to_contacts, menu); } + if (recipient != null && recipient.isLocalNumber()) { + if (isSecureText) menu.findItem(R.id.menu_call_secure).setVisible(false); + else menu.findItem(R.id.menu_call_insecure).setVisible(false); + + menu.findItem(R.id.menu_mute_notifications).setVisible(false); + } + searchViewItem = menu.findItem(R.id.menu_search); SearchView searchView = (SearchView) searchViewItem.getActionView(); diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java index 5b80465d20..2108e67bf6 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -429,7 +429,7 @@ public class ConversationItem extends LinearLayout @NonNull Recipient conversationRecipient, boolean isGroupThread) { - boolean showControls = !messageRecord.isFailed() && !Util.isOwnNumber(context, conversationRecipient.getAddress()); + boolean showControls = !messageRecord.isFailed(); if (hasSharedContact(messageRecord)) { sharedContactStub.get().setVisibility(VISIBLE); diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationTitleView.java b/src/org/thoughtcrime/securesms/conversation/ConversationTitleView.java index f2cc33cebf..4e88960e5f 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationTitleView.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationTitleView.java @@ -32,6 +32,7 @@ public class ConversationTitleView extends RelativeLayout { private TextView title; private TextView subtitle; private ImageView verified; + private View subtitleContainer; public ConversationTitleView(Context context) { this(context, null); @@ -46,12 +47,13 @@ public class ConversationTitleView extends RelativeLayout { public void onFinishInflate() { super.onFinishInflate(); - this.back = ViewUtil.findById(this, R.id.up_button); - this.content = ViewUtil.findById(this, R.id.content); - this.title = ViewUtil.findById(this, R.id.title); - this.subtitle = ViewUtil.findById(this, R.id.subtitle); - this.verified = ViewUtil.findById(this, R.id.verified_indicator); - this.avatar = ViewUtil.findById(this, R.id.contact_photo_image); + this.back = ViewUtil.findById(this, R.id.up_button); + this.content = ViewUtil.findById(this, R.id.content); + this.title = ViewUtil.findById(this, R.id.title); + this.subtitle = ViewUtil.findById(this, R.id.subtitle); + this.verified = ViewUtil.findById(this, R.id.verified_indicator); + this.subtitleContainer = ViewUtil.findById(this, R.id.subtitle_container); + this.avatar = ViewUtil.findById(this, R.id.contact_photo_image); ViewUtil.setTextViewGravityStart(this.title, getContext()); ViewUtil.setTextViewGravityStart(this.subtitle, getContext()); @@ -102,6 +104,7 @@ public class ConversationTitleView extends RelativeLayout { private void setRecipientTitle(Recipient recipient) { if (recipient.isGroupRecipient()) setGroupRecipientTitle(recipient); + else if (recipient.isLocalNumber()) setSelfTitle(); else if (TextUtils.isEmpty(recipient.getName())) setNonContactRecipientTitle(recipient); else setContactRecipientTitle(recipient); } @@ -116,11 +119,18 @@ public class ConversationTitleView extends RelativeLayout { .collect(Collectors.joining(", "))); this.subtitle.setVisibility(View.VISIBLE); + this.subtitleContainer.setVisibility(VISIBLE); + } + + private void setSelfTitle() { + this.title.setText(R.string.note_to_self); + this.subtitleContainer.setVisibility(View.GONE); } @SuppressLint("SetTextI18n") private void setNonContactRecipientTitle(Recipient recipient) { this.title.setText(recipient.getAddress().serialize()); + this.subtitleContainer.setVisibility(VISIBLE); if (TextUtils.isEmpty(recipient.getProfileName())) { this.subtitle.setText(null); @@ -138,5 +148,6 @@ public class ConversationTitleView extends RelativeLayout { else this.subtitle.setText(recipient.getAddress().serialize()); this.subtitle.setVisibility(View.VISIBLE); + this.subtitleContainer.setVisibility(VISIBLE); } } diff --git a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index 13e31fffc2..343bdafe8f 100644 --- a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -61,8 +61,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { private static final int ATTACHMENT_CAPTIONS_FIX = 15; private static final int PREVIEWS = 16; private static final int CONVERSATION_SEARCH = 17; + private static final int SELF_ATTACHMENT_CLEANUP = 18; - private static final int DATABASE_VERSION = 17; + private static final int DATABASE_VERSION = 18; private static final String DATABASE_NAME = "signal.db"; private final Context context; @@ -383,6 +384,22 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { Log.i(TAG, "Indexing finished. Total time: " + (mmsFinished - start) + " ms"); } + if (oldVersion < SELF_ATTACHMENT_CLEANUP) { + String localNumber = TextSecurePreferences.getLocalNumber(context); + + try (Cursor threadCursor = db.rawQuery("SELECT _id FROM thread WHERE recipient_ids = ?", new String[]{ localNumber })) { + if (threadCursor != null && threadCursor.moveToFirst()) { + long threadId = threadCursor.getLong(0); + ContentValues updateValues = new ContentValues(1); + + updateValues.put("pending_push", 0); + + int count = db.update("part", updateValues, "mid IN (SELECT _id FROM mms WHERE thread_id = ?)", new String[]{ String.valueOf(threadId) }); + Log.i(TAG, "Updated " + count + " self-sent attachments."); + } + } + } + db.setTransactionSuccessful(); } finally { db.endTransaction(); diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 42899049ab..7deb4f43ea 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -733,6 +733,12 @@ public class PushDecryptJob extends ContextJob { message.getMessage().getExpiresInSeconds() * 1000L); } + if (recipients.isLocalNumber()) { + SyncMessageId id = new SyncMessageId(recipients.getAddress(), message.getTimestamp()); + DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(id, System.currentTimeMillis()); + DatabaseFactory.getMmsSmsDatabase(context).incrementReadReceiptCount(id, System.currentTimeMillis()); + } + return threadId; } @@ -825,6 +831,12 @@ public class PushDecryptJob extends ContextJob { .scheduleDeletion(messageId, isGroup, message.getExpirationStartTimestamp(), expiresInMillis); } + if (recipient.isLocalNumber()) { + SyncMessageId id = new SyncMessageId(recipient.getAddress(), message.getTimestamp()); + DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(id, System.currentTimeMillis()); + DatabaseFactory.getMmsSmsDatabase(context).incrementReadReceiptCount(id, System.currentTimeMillis()); + } + return threadId; } diff --git a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java index d01e9b9b24..fcbead5371 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -11,8 +11,8 @@ import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.attachments.DatabaseAttachment; import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil; import org.thoughtcrime.securesms.database.Address; -import org.thoughtcrime.securesms.database.AttachmentDatabase; import org.thoughtcrime.securesms.database.DatabaseFactory; +import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId; import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.NoSuchMessageException; import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode; @@ -20,7 +20,6 @@ import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.ChainParameters; import org.thoughtcrime.securesms.jobmanager.JobManager; import org.thoughtcrime.securesms.jobmanager.SafeData; -import org.thoughtcrime.securesms.linkpreview.LinkPreview; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.mms.MmsException; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; @@ -32,10 +31,12 @@ import org.thoughtcrime.securesms.transport.UndeliverableMessageException; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalServiceMessageSender; +import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair; import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Preview; +import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage; import org.whispersystems.signalservice.api.messages.shared.SharedContact; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException; @@ -131,7 +132,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { try { log(TAG, "Sending message: " + messageId); - + Recipient recipient = message.getRecipient().resolve(); byte[] profileKey = recipient.getProfileKey(); UnidentifiedAccessMode accessMode = recipient.getUnidentifiedAccessMode(); @@ -142,6 +143,12 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { markAttachmentsUploaded(messageId, message.getAttachments()); database.markUnidentified(messageId, unidentified); + if (recipient.isLocalNumber()) { + SyncMessageId id = new SyncMessageId(recipient.getAddress(), message.getSentTimeMillis()); + DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(id, System.currentTimeMillis()); + DatabaseFactory.getMmsSmsDatabase(context).incrementReadReceiptCount(id, System.currentTimeMillis()); + } + if (TextSecurePreferences.isUnidentifiedDeliveryEnabled(context)) { if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN && profileKey == null) { log(TAG, "Marking recipient as UD-unrestricted following a UD send."); @@ -215,7 +222,15 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { .asExpirationUpdate(message.isExpirationUpdate()) .build(); - return messageSender.sendMessage(address, UnidentifiedAccessUtil.getAccessFor(context, message.getRecipient()), mediaMessage).getSuccess().isUnidentified(); + if (address.getNumber().equals(TextSecurePreferences.getLocalNumber(context))) { + Optional syncAccess = UnidentifiedAccessUtil.getAccessForSync(context); + SignalServiceSyncMessage syncMessage = buildSelfSendSyncMessage(context, mediaMessage, syncAccess); + + messageSender.sendMessage(syncMessage, syncAccess); + return syncAccess.isPresent(); + } else { + return messageSender.sendMessage(address, UnidentifiedAccessUtil.getAccessFor(context, message.getRecipient()), mediaMessage).getSuccess().isUnidentified(); + } } catch (UnregisteredUserException e) { warn(TAG, e); throw new InsecureFallbackApprovalException(e); diff --git a/src/org/thoughtcrime/securesms/jobs/PushSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushSendJob.java index 8461ebfa92..e53865bd2b 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushSendJob.java @@ -20,7 +20,6 @@ import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.events.PartProgressEvent; import org.thoughtcrime.securesms.jobmanager.JobParameters; -import org.thoughtcrime.securesms.linkpreview.LinkPreview; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; @@ -34,16 +33,20 @@ import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.libsignal.util.guava.Optional; +import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair; import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Preview; +import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage; +import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage; import org.whispersystems.signalservice.api.messages.shared.SharedContact; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; @@ -280,5 +283,16 @@ public abstract class PushSendJob extends SendJob { } } + protected SignalServiceSyncMessage buildSelfSendSyncMessage(@NonNull Context context, @NonNull SignalServiceDataMessage message, Optional syncAccess) { + String localNumber = TextSecurePreferences.getLocalNumber(context); + SentTranscriptMessage transcript = new SentTranscriptMessage(localNumber, + message.getTimestamp(), + message, + message.getExpiresInSeconds(), + Collections.singletonMap(localNumber, syncAccess.isPresent())); + return SignalServiceSyncMessage.forSentTranscript(transcript); + } + + protected abstract void onPushSend() throws Exception; } diff --git a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java index 7a894f8cfb..38dfda7667 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java @@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; import android.support.annotation.NonNull; +import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId; import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode; import org.thoughtcrime.securesms.jobmanager.SafeData; @@ -25,6 +26,7 @@ import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair; import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; +import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException; @@ -94,6 +96,12 @@ public class PushTextSendJob extends PushSendJob implements InjectableType { database.markAsSent(messageId, true); database.markUnidentified(messageId, unidentified); + if (recipient.isLocalNumber()) { + SyncMessageId id = new SyncMessageId(recipient.getAddress(), record.getDateSent()); + DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(id, System.currentTimeMillis()); + DatabaseFactory.getMmsSmsDatabase(context).incrementReadReceiptCount(id, System.currentTimeMillis()); + } + if (TextSecurePreferences.isUnidentifiedDeliveryEnabled(context)) { if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN && profileKey == null) { log(TAG, "Marking recipient as UD-unrestricted following a UD send."); @@ -166,7 +174,15 @@ public class PushTextSendJob extends PushSendJob implements InjectableType { .asEndSessionMessage(message.isEndSession()) .build(); - return messageSender.sendMessage(address, unidentifiedAccess, textSecureMessage).getSuccess().isUnidentified(); + if (address.getNumber().equals(TextSecurePreferences.getLocalNumber(context))) { + Optional syncAccess = UnidentifiedAccessUtil.getAccessForSync(context); + SignalServiceSyncMessage syncMessage = buildSelfSendSyncMessage(context, textSecureMessage, syncAccess); + + messageSender.sendMessage(syncMessage, syncAccess); + return syncAccess.isPresent(); + } else { + return messageSender.sendMessage(address, unidentifiedAccess, textSecureMessage).getSuccess().isUnidentified(); + } } catch (UnregisteredUserException e) { warn(TAG, "Failure", e); throw new InsecureFallbackApprovalException(e); diff --git a/src/org/thoughtcrime/securesms/recipients/Recipient.java b/src/org/thoughtcrime/securesms/recipients/Recipient.java index b963acd013..a26e857693 100644 --- a/src/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/src/org/thoughtcrime/securesms/recipients/Recipient.java @@ -73,6 +73,7 @@ public class Recipient implements RecipientModifiedListener { private @Nullable String name; private @Nullable String customLabel; private boolean resolving; + private boolean isLocalNumber; private @Nullable Uri systemContactPhoto; private @Nullable Long groupAvatarId; @@ -119,15 +120,16 @@ public class Recipient implements RecipientModifiedListener { @NonNull Optional details, @NonNull ListenableFutureTask future) { - this.address = address; - this.color = null; - this.resolving = true; + this.address = address; + this.color = null; + this.resolving = true; if (stale != null) { this.name = stale.name; this.contactUri = stale.contactUri; this.systemContactPhoto = stale.systemContactPhoto; this.groupAvatarId = stale.groupAvatarId; + this.isLocalNumber = stale.isLocalNumber; this.color = stale.color; this.customLabel = stale.customLabel; this.messageRingtone = stale.messageRingtone; @@ -155,6 +157,7 @@ public class Recipient implements RecipientModifiedListener { this.name = details.get().name; this.systemContactPhoto = details.get().systemContactPhoto; this.groupAvatarId = details.get().groupAvatarId; + this.isLocalNumber = details.get().isLocalNumber; this.color = details.get().color; this.messageRingtone = details.get().messageRingtone; this.callRingtone = details.get().callRingtone; @@ -186,6 +189,7 @@ public class Recipient implements RecipientModifiedListener { Recipient.this.contactUri = result.contactUri; Recipient.this.systemContactPhoto = result.systemContactPhoto; Recipient.this.groupAvatarId = result.groupAvatarId; + Recipient.this.isLocalNumber = result.isLocalNumber; Recipient.this.color = result.color; Recipient.this.customLabel = result.customLabel; Recipient.this.messageRingtone = result.messageRingtone; @@ -234,6 +238,7 @@ public class Recipient implements RecipientModifiedListener { this.name = details.name; this.systemContactPhoto = details.systemContactPhoto; this.groupAvatarId = details.groupAvatarId; + this.isLocalNumber = details.isLocalNumber; this.color = details.color; this.customLabel = details.customLabel; this.messageRingtone = details.messageRingtone; @@ -257,6 +262,10 @@ public class Recipient implements RecipientModifiedListener { this.resolving = false; } + public boolean isLocalNumber() { + return isLocalNumber; + } + public synchronized @Nullable Uri getContactUri() { return this.contactUri; } @@ -434,6 +443,7 @@ public class Recipient implements RecipientModifiedListener { } public synchronized @NonNull FallbackContactPhoto getFallbackContactPhoto() { + if (isLocalNumber) return new ResourceContactPhoto(R.drawable.ic_note_to_self); if (isResolving()) return new TransparentContactPhoto(); else if (isGroupRecipient()) return new ResourceContactPhoto(R.drawable.ic_group_white_24dp, R.drawable.ic_group_large); else if (!TextUtils.isEmpty(name)) return new GeneratedContactPhoto(name, R.drawable.ic_profile_default); @@ -441,7 +451,8 @@ public class Recipient implements RecipientModifiedListener { } public synchronized @Nullable ContactPhoto getContactPhoto() { - if (isGroupRecipient() && groupAvatarId != null) return new GroupRecordContactPhoto(address, groupAvatarId); + if (isLocalNumber) return null; + else if (isGroupRecipient() && groupAvatarId != null) return new GroupRecordContactPhoto(address, groupAvatarId); else if (systemContactPhoto != null) return new SystemContactPhoto(address, systemContactPhoto, 0); else if (profileAvatar != null) return new ProfileContactPhoto(address, profileAvatar); else return null; diff --git a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java index bdccf32a56..47aae97c96 100644 --- a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java +++ b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java @@ -33,6 +33,7 @@ import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessM import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState; import org.thoughtcrime.securesms.util.ListenableFutureTask; import org.thoughtcrime.securesms.util.SoftHashMap; +import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.libsignal.util.guava.Optional; @@ -52,7 +53,7 @@ class RecipientProvider { private static final ExecutorService asyncRecipientResolver = Util.newSingleThreadedLifoExecutor(); private static final Map STATIC_DETAILS = new HashMap() {{ - put("262966", new RecipientDetails("Amazon", null, false, null, null)); + put("262966", new RecipientDetails("Amazon", null, false, false, null, null)); }}; @NonNull Recipient getRecipient(@NonNull Context context, @NonNull Address address, @NonNull Optional settings, @NonNull Optional groupRecord, boolean asynchronous) { @@ -85,7 +86,8 @@ class RecipientProvider { if (address.isGroup() && settings.isPresent() && groupRecord.isPresent()) { return Optional.of(getGroupRecipientDetails(context, address, groupRecord, settings, true)); } else if (!address.isGroup() && settings.isPresent()) { - return Optional.of(new RecipientDetails(null, null, !TextUtils.isEmpty(settings.get().getSystemDisplayName()), settings.get(), null)); + boolean isLocalNumber = address.serialize().equals(TextSecurePreferences.getLocalNumber(context)); + return Optional.of(new RecipientDetails(null, null, !TextUtils.isEmpty(settings.get().getSystemDisplayName()), isLocalNumber, settings.get(), null)); } return Optional.absent(); @@ -114,7 +116,8 @@ class RecipientProvider { return STATIC_DETAILS.get(address.serialize()); } else { boolean systemContact = settings.isPresent() && !TextUtils.isEmpty(settings.get().getSystemDisplayName()); - return new RecipientDetails(null, null, systemContact, settings.orNull(), null); + boolean isLocalNumber = address.serialize().equals(TextSecurePreferences.getLocalNumber(context)); + return new RecipientDetails(null, null, systemContact, isLocalNumber, settings.orNull(), null); } } @@ -146,10 +149,10 @@ class RecipientProvider { avatarId = groupRecord.get().getAvatarId(); } - return new RecipientDetails(title, avatarId, false, settings.orNull(), members); + return new RecipientDetails(title, avatarId, false, false, settings.orNull(), members); } - return new RecipientDetails(context.getString(R.string.RecipientProvider_unnamed_group), null, false, settings.orNull(), null); + return new RecipientDetails(context.getString(R.string.RecipientProvider_unnamed_group), null, false, false, settings.orNull(), null); } static class RecipientDetails { @@ -175,11 +178,12 @@ class RecipientProvider { @Nullable final String profileAvatar; final boolean profileSharing; final boolean systemContact; + final boolean isLocalNumber; @Nullable final String notificationChannel; @NonNull final UnidentifiedAccessMode unidentifiedAccessMode; RecipientDetails(@Nullable String name, @Nullable Long groupAvatarId, - boolean systemContact, @Nullable RecipientSettings settings, + boolean systemContact, boolean isLocalNumber, @Nullable RecipientSettings settings, @Nullable List participants) { this.groupAvatarId = groupAvatarId; @@ -203,6 +207,7 @@ class RecipientProvider { this.profileAvatar = settings != null ? settings.getProfileAvatar() : null; this.profileSharing = settings != null && settings.isProfileSharing(); this.systemContact = systemContact; + this.isLocalNumber = isLocalNumber; this.notificationChannel = settings != null ? settings.getNotificationChannel() : null; this.unidentifiedAccessMode = settings != null ? settings.getUnidentifiedAccessMode() : UnidentifiedAccessMode.DISABLED; diff --git a/src/org/thoughtcrime/securesms/sms/MessageSender.java b/src/org/thoughtcrime/securesms/sms/MessageSender.java index ca3a47a374..c017188fd1 100644 --- a/src/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/src/org/thoughtcrime/securesms/sms/MessageSender.java @@ -18,8 +18,12 @@ package org.thoughtcrime.securesms.sms; import android.content.Context; import android.support.annotation.NonNull; + +import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId; +import org.thoughtcrime.securesms.database.MmsSmsDatabase; +import org.thoughtcrime.securesms.database.NoSuchMessageException; +import org.thoughtcrime.securesms.database.model.SmsMessageRecord; import org.thoughtcrime.securesms.logging.Log; -import android.util.Pair; import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.attachments.Attachment; @@ -31,7 +35,6 @@ import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.database.SmsDatabase; import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.database.model.MessageRecord; -import org.thoughtcrime.securesms.database.model.MmsMessageRecord; import org.thoughtcrime.securesms.jobmanager.JobManager; import org.thoughtcrime.securesms.jobs.MmsSendJob; import org.thoughtcrime.securesms.jobs.PushGroupSendJob; @@ -44,7 +47,6 @@ import org.thoughtcrime.securesms.push.AccountManagerFactory; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.service.ExpiringMessageManager; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.thoughtcrime.securesms.util.Util; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.push.ContactTokenDetails; @@ -75,7 +77,7 @@ public class MessageSender { long messageId = database.insertMessageOutbox(allocatedThreadId, message, forceSms, System.currentTimeMillis(), insertListener); - sendTextMessage(context, recipient, forceSms, keyExchange, messageId, message.getExpiresIn()); + sendTextMessage(context, recipient, forceSms, keyExchange, messageId); return allocatedThreadId; } @@ -116,28 +118,23 @@ public class MessageSender { } public static void resend(Context context, MessageRecord messageRecord) { - try { - long messageId = messageRecord.getId(); - boolean forceSms = messageRecord.isForcedSms(); - boolean keyExchange = messageRecord.isKeyExchange(); - long expiresIn = messageRecord.getExpiresIn(); - Recipient recipient = messageRecord.getRecipient(); + long messageId = messageRecord.getId(); + boolean forceSms = messageRecord.isForcedSms(); + boolean keyExchange = messageRecord.isKeyExchange(); + long expiresIn = messageRecord.getExpiresIn(); + Recipient recipient = messageRecord.getRecipient(); - if (messageRecord.isMms()) { - sendMediaMessage(context, recipient, forceSms, messageId, expiresIn); - } else { - sendTextMessage(context, recipient, forceSms, keyExchange, messageId, expiresIn); - } - } catch (MmsException e) { - Log.w(TAG, e); + if (messageRecord.isMms()) { + sendMediaMessage(context, recipient, forceSms, messageId, expiresIn); + } else { + sendTextMessage(context, recipient, forceSms, keyExchange, messageId); } } private static void sendMediaMessage(Context context, Recipient recipient, boolean forceSms, long messageId, long expiresIn) - throws MmsException { - if (!forceSms && isSelfSend(context, recipient)) { - sendMediaSelf(context, messageId, expiresIn); + if (isLocalSelfSend(context, recipient, forceSms)) { + sendLocalMediaSelf(context, messageId); } else if (isGroupPushSend(recipient)) { sendGroupPush(context, recipient, messageId, null); } else if (!forceSms && isPushMediaSend(context, recipient)) { @@ -149,10 +146,10 @@ public class MessageSender { private static void sendTextMessage(Context context, Recipient recipient, boolean forceSms, boolean keyExchange, - long messageId, long expiresIn) + long messageId) { - if (!forceSms && isSelfSend(context, recipient)) { - sendTextSelf(context, messageId, expiresIn); + if (isLocalSelfSend(context, recipient, forceSms)) { + sendLocalTextSelf(context, messageId); } else if (!forceSms && isPushTextSend(context, recipient, keyExchange)) { sendTextPush(context, recipient, messageId); } else { @@ -160,38 +157,6 @@ public class MessageSender { } } - private static void sendTextSelf(Context context, long messageId, long expiresIn) { - SmsDatabase database = DatabaseFactory.getSmsDatabase(context); - - database.markAsSent(messageId, true); - - Pair messageAndThreadId = database.copyMessageInbox(messageId); - database.markAsPush(messageAndThreadId.first); - - if (expiresIn > 0) { - ExpiringMessageManager expiringMessageManager = ApplicationContext.getInstance(context).getExpiringMessageManager(); - - database.markExpireStarted(messageId); - expiringMessageManager.scheduleDeletion(messageId, false, expiresIn); - } - } - - private static void sendMediaSelf(Context context, long messageId, long expiresIn) - throws MmsException - { - ExpiringMessageManager expiringMessageManager = ApplicationContext.getInstance(context).getExpiringMessageManager(); - MmsDatabase database = DatabaseFactory.getMmsDatabase(context); - - database.markAsSent(messageId, true); - database.copyMessageInbox(messageId); - markAttachmentsAsUploaded(messageId, database, DatabaseFactory.getAttachmentDatabase(context)); - - if (expiresIn > 0) { - database.markExpireStarted(messageId); - expiringMessageManager.scheduleDeletion(messageId, true, expiresIn); - } - } - private static void sendTextPush(Context context, Recipient recipient, long messageId) { JobManager jobManager = ApplicationContext.getInstance(context).getJobManager(); jobManager.add(new PushTextSendJob(context, messageId, recipient.getAddress())); @@ -246,18 +211,6 @@ public class MessageSender { !recipient.getAddress().isMmsGroup(); } - private static boolean isSelfSend(Context context, Recipient recipient) { - if (!TextSecurePreferences.isPushRegistered(context)) { - return false; - } - - if (recipient.isGroupRecipient()) { - return false; - } - - return Util.isOwnNumber(context, recipient.getAddress()); - } - private static boolean isPushDestination(Context context, Recipient destination) { if (destination.resolve().getRegistered() == RecipientDatabase.RegisteredState.REGISTERED) { return true; @@ -282,15 +235,61 @@ public class MessageSender { } } - private static void markAttachmentsAsUploaded(long mmsId, @NonNull MmsDatabase mmsDatabase, @NonNull AttachmentDatabase attachmentDatabase) { - try (MmsDatabase.Reader reader = mmsDatabase.readerFor(mmsDatabase.getMessage(mmsId))) { - MessageRecord message = reader.getNext(); + private static boolean isLocalSelfSend(@NonNull Context context, @NonNull Recipient recipient, boolean forceSms) { + return recipient.isLocalNumber() && + !forceSms && + TextSecurePreferences.isPushRegistered(context) && + !TextSecurePreferences.isMultiDevice(context); + } - if (message != null && message.isMms()) { - for (Attachment attachment : ((MmsMessageRecord) message).getSlideDeck().asAttachments()) { - attachmentDatabase.markAttachmentUploaded(mmsId, attachment); - } + private static void sendLocalMediaSelf(Context context, long messageId) { + try { + ExpiringMessageManager expirationManager = ApplicationContext.getInstance(context).getExpiringMessageManager(); + AttachmentDatabase attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context); + MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context); + MmsSmsDatabase mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(context); + OutgoingMediaMessage message = mmsDatabase.getOutgoingMessage(messageId); + SyncMessageId syncId = new SyncMessageId(Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), message.getSentTimeMillis()); + + for (Attachment attachment : message.getAttachments()) { + attachmentDatabase.markAttachmentUploaded(messageId, attachment); } + + mmsDatabase.markAsSent(messageId, true); + mmsDatabase.markUnidentified(messageId, true); + + mmsSmsDatabase.incrementDeliveryReceiptCount(syncId, System.currentTimeMillis()); + mmsSmsDatabase.incrementReadReceiptCount(syncId, System.currentTimeMillis()); + + if (message.getExpiresIn() > 0 && !message.isExpirationUpdate()) { + mmsDatabase.markExpireStarted(messageId); + expirationManager.scheduleDeletion(messageId, true, message.getExpiresIn()); + } + } catch (NoSuchMessageException | MmsException e) { + Log.w("Failed to update self-sent message.", e); + } + } + + private static void sendLocalTextSelf(Context context, long messageId) { + try { + ExpiringMessageManager expirationManager = ApplicationContext.getInstance(context).getExpiringMessageManager(); + SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context); + MmsSmsDatabase mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(context); + SmsMessageRecord message = smsDatabase.getMessage(messageId); + SyncMessageId syncId = new SyncMessageId(Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), message.getDateSent()); + + smsDatabase.markAsSent(messageId, true); + smsDatabase.markUnidentified(messageId, true); + + mmsSmsDatabase.incrementDeliveryReceiptCount(syncId, System.currentTimeMillis()); + mmsSmsDatabase.incrementReadReceiptCount(syncId, System.currentTimeMillis()); + + if (message.getExpiresIn() > 0) { + smsDatabase.markExpireStarted(messageId); + expirationManager.scheduleDeletion(message.getId(), message.isMms(), message.getExpiresIn()); + } + } catch (NoSuchMessageException e) { + Log.w("Failed to update self-sent message.", e); } } }