mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-19 19:28:26 +00:00
Support for dual-sim SMS/MMS functionality
Allow source selection for sending SMS/MMS, and display the SIM that received SMS/MMS. Fixes #555 Closes #5199 // FREEBIE
This commit is contained in:
parent
c1106d98dd
commit
6da86e482d
@ -113,6 +113,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingRight="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:src="?menu_lock_icon_small"
|
||||
android:contentDescription="@string/conversation_item__secure_message_description"
|
||||
android:visibility="gone"
|
||||
@ -126,6 +128,19 @@
|
||||
android:visibility="gone"/>
|
||||
|
||||
<TextView android:id="@+id/conversation_item_date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:paddingTop="1dip"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?conversation_item_received_text_secondary_color"
|
||||
android:textSize="@dimen/conversation_item_date_text_size"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:autoLink="none"
|
||||
android:linksClickable="false"
|
||||
tools:text="Now"/>
|
||||
|
||||
<TextView android:id="@+id/sim_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
@ -137,7 +152,10 @@
|
||||
android:textSize="@dimen/conversation_item_date_text_size"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:autoLink="none"
|
||||
android:linksClickable="false" />
|
||||
android:linksClickable="false"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
tools:text="from SIM1"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -125,6 +125,25 @@
|
||||
android:paddingBottom="2dp"
|
||||
tools:text="30 mins" />
|
||||
|
||||
<TextView android:id="@+id/sim_info"
|
||||
android:autoLink="none"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="15sp"
|
||||
android:linksClickable="false"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:layout_gravity="right"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:textColor="?conversation_item_sent_text_secondary_color"
|
||||
android:textSize="@dimen/conversation_item_date_text_size"
|
||||
android:paddingTop="1dip"
|
||||
android:paddingBottom="2dp"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingStart="4dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
tools:text="to SIM1"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.DeliveryStatusView
|
||||
android:id="@+id/delivery_status"
|
||||
android:layout_width="20dp"
|
||||
|
@ -8,6 +8,7 @@
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp">
|
||||
|
||||
<ImageView android:id="@+id/icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@ -16,11 +17,28 @@
|
||||
android:contentDescription="@string/transport_selection_list_item__transport_icon"
|
||||
tools:src="@drawable/ic_send_push_white_24dp"
|
||||
tools:backgroundTint="@color/textsecure_primary" />
|
||||
<TextView android:id="@+id/text"
|
||||
android:paddingLeft="10dp"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:textSize="16sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="TextSecure" />
|
||||
|
||||
<LinearLayout android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="10dp">
|
||||
|
||||
<TextView android:id="@+id/text"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:textSize="16sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="TextSecure" />
|
||||
|
||||
<TextView android:id="@+id/subtext"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:textSize="12dp"
|
||||
android:visibility="gone"
|
||||
tools:text="From Home"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
@ -100,6 +100,8 @@
|
||||
<string name="ConversationItem_click_to_approve_unencrypted_mms_dialog_title">Fallback to unencrypted MMS?</string>
|
||||
<string name="ConversationItem_click_to_approve_unencrypted_dialog_message">This message will <b>not</b> be encrypted because the recipient is no longer a Signal user.\n\nSend unsecured message?</string>
|
||||
<string name="ConversationItem_unable_to_open_media">Can\'t find an app able to open this media.</string>
|
||||
<string name="ConversationItem_from_s">from %s</string>
|
||||
<string name="ConversationItem_to_s">to %s</string>
|
||||
|
||||
<!-- ConversationActivity -->
|
||||
<string name="ConversationActivity_reset_secure_session_question">Reset secure session?</string>
|
||||
|
@ -535,7 +535,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
final Context context = getApplicationContext();
|
||||
|
||||
OutgoingEndSessionMessage endSessionMessage =
|
||||
new OutgoingEndSessionMessage(new OutgoingTextMessage(getRecipients(), "TERMINATE"));
|
||||
new OutgoingEndSessionMessage(new OutgoingTextMessage(getRecipients(), "TERMINATE", -1));
|
||||
|
||||
new AsyncTask<OutgoingEndSessionMessage, Void, Long>() {
|
||||
@Override
|
||||
@ -823,22 +823,43 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
private void onSecurityUpdated() {
|
||||
updateInviteReminder();
|
||||
updateRecipientPreferences();
|
||||
}
|
||||
|
||||
protected void updateInviteReminder() {
|
||||
if (TextSecurePreferences.isPushRegistered(this) &&
|
||||
!isSecureText &&
|
||||
recipients.isSingleRecipient() &&
|
||||
recipients.getPrimaryRecipient() != null &&
|
||||
private void updateRecipientPreferences() {
|
||||
if (recipients.getPrimaryRecipient() != null &&
|
||||
recipients.getPrimaryRecipient().getContactUri() != null)
|
||||
{
|
||||
new ShowInviteReminderTask().execute(recipients);
|
||||
new RecipientPreferencesTask().execute(recipients);
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateInviteReminder(boolean seenInvite) {
|
||||
Log.w(TAG, "updateInviteReminder(" + seenInvite+")");
|
||||
if (TextSecurePreferences.isPushRegistered(this) &&
|
||||
!isSecureText &&
|
||||
!seenInvite &&
|
||||
recipients.isSingleRecipient())
|
||||
{
|
||||
InviteReminder reminder = new InviteReminder(this, recipients);
|
||||
reminder.setOkListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
handleInviteLink();
|
||||
reminderView.requestDismiss();
|
||||
}
|
||||
});
|
||||
reminderView.showReminder(reminder);
|
||||
} else {
|
||||
reminderView.hide();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDefaultSubscriptionId(Optional<Integer> defaultSubscriptionId) {
|
||||
Log.w(TAG, "updateDefaultSubscriptionId(" + defaultSubscriptionId.orNull() + ")");
|
||||
sendButton.setDefaultSubscriptionId(defaultSubscriptionId);
|
||||
}
|
||||
|
||||
private void initializeMmsEnabledCheck() {
|
||||
new AsyncTask<Void, Void, Boolean>() {
|
||||
@Override
|
||||
@ -896,11 +917,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
sendButton.setEnabled(true);
|
||||
sendButton.addOnTransportChangedListener(new OnTransportChangedListener() {
|
||||
@Override
|
||||
public void onChange(TransportOption newTransport) {
|
||||
public void onChange(TransportOption newTransport, boolean manuallySelected) {
|
||||
calculateCharactersRemaining();
|
||||
composeText.setTransport(newTransport);
|
||||
buttonToggle.getBackground().setColorFilter(newTransport.getBackgroundColor(), Mode.MULTIPLY);
|
||||
buttonToggle.getBackground().invalidateSelf();
|
||||
if (manuallySelected) recordSubscriptionIdPreference(newTransport.getSimSubscriptionId());
|
||||
}
|
||||
});
|
||||
|
||||
@ -968,7 +990,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
titleView.setTitle(recipients);
|
||||
setBlockedUserState(recipients);
|
||||
setActionBarColor(recipients.getColor());
|
||||
updateInviteReminder();
|
||||
updateRecipientPreferences();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1242,8 +1264,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
|
||||
private void sendMessage() {
|
||||
try {
|
||||
Recipients recipients = getRecipients();
|
||||
boolean forceSms = sendButton.isManualSelection() && sendButton.getSelectedTransport().isSms();
|
||||
Recipients recipients = getRecipients();
|
||||
boolean forceSms = sendButton.isManualSelection() && sendButton.getSelectedTransport().isSms();
|
||||
int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().or(-1);
|
||||
|
||||
Log.w(TAG, "isManual Selection: " + sendButton.isManualSelection());
|
||||
Log.w(TAG, "forceSms: " + forceSms);
|
||||
@ -1255,9 +1278,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
if ((!recipients.isSingleRecipient() || recipients.isEmailRecipient()) && !isMmsEnabled) {
|
||||
handleManualMmsRequired();
|
||||
} else if (attachmentManager.isAttachmentPresent() || !recipients.isSingleRecipient() || recipients.isGroupRecipient() || recipients.isEmailRecipient()) {
|
||||
sendMediaMessage(forceSms);
|
||||
sendMediaMessage(forceSms, subscriptionId);
|
||||
} else {
|
||||
sendTextMessage(forceSms);
|
||||
sendTextMessage(forceSms, subscriptionId);
|
||||
}
|
||||
} catch (RecipientFormattingException ex) {
|
||||
Toast.makeText(ConversationActivity.this,
|
||||
@ -1271,13 +1294,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
}
|
||||
|
||||
private void sendMediaMessage(final boolean forceSms)
|
||||
private void sendMediaMessage(final boolean forceSms, final int subscriptionId)
|
||||
throws InvalidMessageException
|
||||
{
|
||||
sendMediaMessage(forceSms, getMessage(), attachmentManager.buildSlideDeck());
|
||||
sendMediaMessage(forceSms, getMessage(), attachmentManager.buildSlideDeck(), subscriptionId);
|
||||
}
|
||||
|
||||
private ListenableFuture<Void> sendMediaMessage(final boolean forceSms, String body, SlideDeck slideDeck)
|
||||
private ListenableFuture<Void> sendMediaMessage(final boolean forceSms, String body, SlideDeck slideDeck, final int subscriptionId)
|
||||
throws InvalidMessageException
|
||||
{
|
||||
final SettableFuture<Void> future = new SettableFuture<>();
|
||||
@ -1286,6 +1309,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
slideDeck,
|
||||
body,
|
||||
System.currentTimeMillis(),
|
||||
subscriptionId,
|
||||
distributionType);
|
||||
|
||||
if (isSecureText && !forceSms) {
|
||||
@ -1311,7 +1335,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
return future;
|
||||
}
|
||||
|
||||
private void sendTextMessage(final boolean forceSms)
|
||||
private void sendTextMessage(final boolean forceSms, final int subscriptionId)
|
||||
throws InvalidMessageException
|
||||
{
|
||||
final Context context = getApplicationContext();
|
||||
@ -1320,7 +1344,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
if (isSecureText && !forceSms) {
|
||||
message = new OutgoingEncryptedMessage(recipients, getMessage());
|
||||
} else {
|
||||
message = new OutgoingTextMessage(recipients, getMessage());
|
||||
message = new OutgoingTextMessage(recipients, getMessage(), subscriptionId);
|
||||
}
|
||||
|
||||
this.composeText.setText("");
|
||||
@ -1348,6 +1372,17 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
}
|
||||
|
||||
private void recordSubscriptionIdPreference(final Optional<Integer> subscriptionId) {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
DatabaseFactory.getRecipientPreferenceDatabase(ConversationActivity.this)
|
||||
.setDefaultSubscriptionId(recipients, subscriptionId.or(-1));
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachmentDrawerStateChanged(DrawerState drawerState) {
|
||||
if (drawerState == DrawerState.FULL_EXPANDED) {
|
||||
@ -1398,12 +1433,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
@Override
|
||||
public void onSuccess(final @NonNull Pair<Uri, Long> result) {
|
||||
try {
|
||||
boolean forceSms = sendButton.isManualSelection() && sendButton.getSelectedTransport().isSms();
|
||||
AudioSlide audioSlide = new AudioSlide(ConversationActivity.this, result.first, result.second, ContentType.AUDIO_AAC);
|
||||
SlideDeck slideDeck = new SlideDeck();
|
||||
boolean forceSms = sendButton.isManualSelection() && sendButton.getSelectedTransport().isSms();
|
||||
int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().or(-1);
|
||||
AudioSlide audioSlide = new AudioSlide(ConversationActivity.this, result.first, result.second, ContentType.AUDIO_AAC);
|
||||
SlideDeck slideDeck = new SlideDeck();
|
||||
slideDeck.addSlide(audioSlide);
|
||||
|
||||
sendMediaMessage(forceSms, "", slideDeck).addListener(new AssertedSuccessListener<Void>() {
|
||||
sendMediaMessage(forceSms, "", slideDeck, subscriptionId).addListener(new AssertedSuccessListener<Void>() {
|
||||
@Override
|
||||
public void onSuccess(Void nothing) {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@ -1568,30 +1604,23 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
updateToggleButtonState();
|
||||
}
|
||||
|
||||
private class ShowInviteReminderTask extends AsyncTask<Recipients, Void, Pair<Recipients,Boolean>> {
|
||||
private class RecipientPreferencesTask extends AsyncTask<Recipients, Void, Pair<Recipients,RecipientsPreferences>> {
|
||||
@Override
|
||||
protected Pair<Recipients, Boolean> doInBackground(Recipients... recipients) {
|
||||
if (recipients.length != 1 || recipients[0] == null) throw new AssertionError("task needs exactly one Recipients object");
|
||||
protected Pair<Recipients, RecipientsPreferences> doInBackground(Recipients... recipients) {
|
||||
if (recipients.length != 1 || recipients[0] == null) {
|
||||
throw new AssertionError("task needs exactly one Recipients object");
|
||||
}
|
||||
|
||||
Optional<RecipientsPreferences> prefs = DatabaseFactory.getRecipientPreferenceDatabase(ConversationActivity.this)
|
||||
.getRecipientsPreferences(recipients[0].getIds());
|
||||
return new Pair<>(recipients[0], prefs.isPresent() && prefs.get().hasSeenInviteReminder());
|
||||
return new Pair<>(recipients[0], prefs.orNull());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Pair<Recipients, Boolean> result) {
|
||||
if (!result.second && result.first == recipients) {
|
||||
InviteReminder reminder = new InviteReminder(ConversationActivity.this, result.first);
|
||||
reminder.setOkListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
handleInviteLink();
|
||||
reminderView.requestDismiss();
|
||||
}
|
||||
});
|
||||
reminderView.showReminder(reminder);
|
||||
} else {
|
||||
reminderView.hide();
|
||||
protected void onPostExecute(@NonNull Pair<Recipients, RecipientsPreferences> result) {
|
||||
if (result.first == recipients) {
|
||||
updateInviteReminder(result.second != null && result.second.hasSeenInviteReminder());
|
||||
updateDefaultSubscriptionId(result.second != null ? result.second.getDefaultSubscriptionId() : Optional.<Integer>absent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,9 @@ import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.dualsim.SubscriptionInfoCompat;
|
||||
import org.thoughtcrime.securesms.util.dualsim.SubscriptionManagerCompat;
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@ -93,6 +96,7 @@ public class ConversationItem extends LinearLayout
|
||||
private View bodyBubble;
|
||||
private TextView bodyText;
|
||||
private TextView dateText;
|
||||
private TextView simInfoText;
|
||||
private TextView indicatorText;
|
||||
private TextView groupStatusText;
|
||||
private ImageView secureImage;
|
||||
@ -135,6 +139,7 @@ public class ConversationItem extends LinearLayout
|
||||
|
||||
this.bodyText = (TextView) findViewById(R.id.conversation_item_body);
|
||||
this.dateText = (TextView) findViewById(R.id.conversation_item_date);
|
||||
this.simInfoText = (TextView) findViewById(R.id.sim_info);
|
||||
this.indicatorText = (TextView) findViewById(R.id.indicator_text);
|
||||
this.groupStatusText = (TextView) findViewById(R.id.group_message_status);
|
||||
this.secureImage = (ImageView) findViewById(R.id.secure_indicator);
|
||||
@ -188,6 +193,7 @@ public class ConversationItem extends LinearLayout
|
||||
setGroupMessageStatus(messageRecord, recipient);
|
||||
setMinimumWidth();
|
||||
setMediaAttributes(messageRecord);
|
||||
setSimInfo(messageRecord);
|
||||
}
|
||||
|
||||
private void initializeAttributes() {
|
||||
@ -327,6 +333,25 @@ public class ConversationItem extends LinearLayout
|
||||
}
|
||||
}
|
||||
|
||||
private void setSimInfo(MessageRecord messageRecord) {
|
||||
if (messageRecord.getSubscriptionId() == -1) {
|
||||
simInfoText.setVisibility(View.GONE);
|
||||
} else {
|
||||
SubscriptionManagerCompat subscriptionManager = new SubscriptionManagerCompat(context);
|
||||
Optional<SubscriptionInfoCompat> subscriptionInfo = subscriptionManager.getActiveSubscriptionInfo(messageRecord.getSubscriptionId());
|
||||
|
||||
if (subscriptionInfo.isPresent() && messageRecord.isOutgoing()) {
|
||||
simInfoText.setText(getContext().getString(R.string.ConversationItem_from_s, subscriptionInfo.get().getDisplayName()));
|
||||
simInfoText.setVisibility(View.VISIBLE);
|
||||
} else if (subscriptionInfo.isPresent()) {
|
||||
simInfoText.setText(getContext().getString(R.string.ConversationItem_to_s, subscriptionInfo.get().getDisplayName()));
|
||||
simInfoText.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
simInfoText.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setFailedStatusIcons() {
|
||||
alertView.setFailed();
|
||||
deliveryStatusIndicator.setNone();
|
||||
|
@ -121,7 +121,7 @@ public class ConversationPopupActivity extends ConversationActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateInviteReminder() {
|
||||
protected void updateInviteReminder(boolean seenInvite) {
|
||||
reminderView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
@ -28,13 +28,15 @@ import org.thoughtcrime.securesms.components.ContactFilterToolbar;
|
||||
import org.thoughtcrime.securesms.components.ContactFilterToolbar.OnFilterChangedListener;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture.Listener;
|
||||
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@ -227,9 +229,14 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
|
||||
if (context == null) return null;
|
||||
|
||||
for (String number : numbers) {
|
||||
final Recipients recipients = RecipientFactory.getRecipientsFromString(context, number, false);
|
||||
if (recipients != null && recipients.getPrimaryRecipient() != null) {
|
||||
MessageSender.send(context, masterSecret, new OutgoingTextMessage(recipients, message), -1L, true);
|
||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, number, false);
|
||||
|
||||
if (recipients.getPrimaryRecipient() != null) {
|
||||
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(recipients.getIds());
|
||||
int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1;
|
||||
|
||||
MessageSender.send(context, masterSecret, new OutgoingTextMessage(recipients, message, subscriptionId), -1L, true);
|
||||
|
||||
if (recipients.getPrimaryRecipient().getContactUri() != null) {
|
||||
DatabaseFactory.getRecipientPreferenceDatabase(context).setSeenInviteReminder(recipients, true);
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.util.CharacterCalculator;
|
||||
import org.thoughtcrime.securesms.util.CharacterCalculator.CharacterState;
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
|
||||
public class TransportOption {
|
||||
|
||||
@ -12,19 +14,34 @@ public class TransportOption {
|
||||
TEXTSECURE
|
||||
}
|
||||
|
||||
private int drawable;
|
||||
private int backgroundColor;
|
||||
private String text;
|
||||
private Type type;
|
||||
private String composeHint;
|
||||
private CharacterCalculator characterCalculator;
|
||||
private final int drawable;
|
||||
private final int backgroundColor;
|
||||
private final @NonNull String text;
|
||||
private final @NonNull Type type;
|
||||
private final @NonNull String composeHint;
|
||||
private final @NonNull CharacterCalculator characterCalculator;
|
||||
private final @NonNull Optional<CharSequence> simName;
|
||||
private final @NonNull Optional<Integer> simSubscriptionId;
|
||||
|
||||
public TransportOption(Type type,
|
||||
public TransportOption(@NonNull Type type,
|
||||
@DrawableRes int drawable,
|
||||
int backgroundColor,
|
||||
String text,
|
||||
String composeHint,
|
||||
CharacterCalculator characterCalculator)
|
||||
@NonNull String text,
|
||||
@NonNull String composeHint,
|
||||
@NonNull CharacterCalculator characterCalculator)
|
||||
{
|
||||
this(type, drawable, backgroundColor, text, composeHint, characterCalculator,
|
||||
Optional.<CharSequence>absent(), Optional.<Integer>absent());
|
||||
}
|
||||
|
||||
public TransportOption(@NonNull Type type,
|
||||
@DrawableRes int drawable,
|
||||
int backgroundColor,
|
||||
@NonNull String text,
|
||||
@NonNull String composeHint,
|
||||
@NonNull CharacterCalculator characterCalculator,
|
||||
@NonNull Optional<CharSequence> simName,
|
||||
@NonNull Optional<Integer> simSubscriptionId)
|
||||
{
|
||||
this.type = type;
|
||||
this.drawable = drawable;
|
||||
@ -32,9 +49,12 @@ public class TransportOption {
|
||||
this.text = text;
|
||||
this.composeHint = composeHint;
|
||||
this.characterCalculator = characterCalculator;
|
||||
this.simName = simName;
|
||||
this.simSubscriptionId = simSubscriptionId;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
|
||||
public @NonNull Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@ -58,11 +78,22 @@ public class TransportOption {
|
||||
return backgroundColor;
|
||||
}
|
||||
|
||||
public String getComposeHint() {
|
||||
public @NonNull String getComposeHint() {
|
||||
return composeHint;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
public @NonNull String getDescription() {
|
||||
return text;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Optional<CharSequence> getSimName() {
|
||||
return simName;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Optional<Integer> getSimSubscriptionId() {
|
||||
return simSubscriptionId;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,15 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.util.CharacterCalculator;
|
||||
import org.thoughtcrime.securesms.util.MmsCharacterCalculator;
|
||||
import org.thoughtcrime.securesms.util.PushCharacterCalculator;
|
||||
import org.thoughtcrime.securesms.util.SmsCharacterCalculator;
|
||||
import org.thoughtcrime.securesms.util.dualsim.SubscriptionInfoCompat;
|
||||
import org.thoughtcrime.securesms.util.dualsim.SubscriptionManagerCompat;
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
|
||||
import java.util.LinkedList;
|
||||
@ -20,49 +25,76 @@ public class TransportOptions {
|
||||
private final Context context;
|
||||
private final List<TransportOption> enabledTransports;
|
||||
|
||||
private Type selectedType;
|
||||
private boolean manuallySelected;
|
||||
private Type defaultTransportType = Type.SMS;
|
||||
private Optional<Integer> defaultSubscriptionId = Optional.absent();
|
||||
private Optional<TransportOption> selectedOption = Optional.absent();
|
||||
|
||||
public TransportOptions(Context context, boolean media) {
|
||||
this.context = context;
|
||||
this.enabledTransports = initializeAvailableTransports(media);
|
||||
|
||||
setDefaultTransport(Type.SMS);
|
||||
}
|
||||
|
||||
public void reset(boolean media) {
|
||||
List<TransportOption> transportOptions = initializeAvailableTransports(media);
|
||||
|
||||
this.enabledTransports.clear();
|
||||
this.enabledTransports.addAll(transportOptions);
|
||||
|
||||
if (!find(selectedType).isPresent()) {
|
||||
this.manuallySelected = false;
|
||||
setTransport(Type.SMS);
|
||||
if (selectedOption.isPresent() && !isEnabled(selectedOption.get())) {
|
||||
setSelectedTransport(null);
|
||||
} else {
|
||||
this.defaultTransportType = Type.SMS;
|
||||
this.defaultSubscriptionId = Optional.absent();
|
||||
|
||||
notifyTransportChangeListeners();
|
||||
}
|
||||
}
|
||||
|
||||
public void setDefaultTransport(Type type) {
|
||||
if (!this.manuallySelected) {
|
||||
setTransport(type);
|
||||
this.defaultTransportType = type;
|
||||
|
||||
if (!selectedOption.isPresent()) {
|
||||
notifyTransportChangeListeners();
|
||||
}
|
||||
}
|
||||
|
||||
public void setSelectedTransport(Type type) {
|
||||
this.manuallySelected= true;
|
||||
setTransport(type);
|
||||
public void setDefaultSubscriptionId(Optional<Integer> subscriptionId) {
|
||||
this.defaultSubscriptionId = subscriptionId;
|
||||
|
||||
if (!selectedOption.isPresent()) {
|
||||
notifyTransportChangeListeners();
|
||||
}
|
||||
}
|
||||
|
||||
public void setSelectedTransport(@Nullable TransportOption transportOption) {
|
||||
this.selectedOption = Optional.fromNullable(transportOption);
|
||||
notifyTransportChangeListeners();
|
||||
}
|
||||
|
||||
public boolean isManualSelection() {
|
||||
return manuallySelected;
|
||||
return this.selectedOption.isPresent();
|
||||
}
|
||||
|
||||
public TransportOption getSelectedTransport() {
|
||||
Optional<TransportOption> option = find(selectedType);
|
||||
public @NonNull TransportOption getSelectedTransport() {
|
||||
if (selectedOption.isPresent()) return selectedOption.get();
|
||||
|
||||
if (option.isPresent()) return option.get();
|
||||
else throw new AssertionError("Selected type isn't present!");
|
||||
if (defaultSubscriptionId.isPresent()) {
|
||||
for (TransportOption transportOption : enabledTransports) {
|
||||
if (transportOption.getType() == defaultTransportType &&
|
||||
(int)defaultSubscriptionId.get() == transportOption.getSimSubscriptionId().or(-1))
|
||||
{
|
||||
return transportOption;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (TransportOption transportOption : enabledTransports) {
|
||||
if (transportOption.getType() == defaultTransportType) {
|
||||
return transportOption;
|
||||
}
|
||||
}
|
||||
|
||||
throw new AssertionError("No options of default type!");
|
||||
}
|
||||
|
||||
public void disableTransport(Type type) {
|
||||
@ -71,8 +103,8 @@ public class TransportOptions {
|
||||
if (option.isPresent()) {
|
||||
enabledTransports.remove(option.get());
|
||||
|
||||
if (manuallySelected && type == selectedType) {
|
||||
manuallySelected = false;
|
||||
if (selectedOption.isPresent() && selectedOption.get().getType() == type) {
|
||||
setSelectedTransport(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -89,17 +121,13 @@ public class TransportOptions {
|
||||
List<TransportOption> results = new LinkedList<>();
|
||||
|
||||
if (isMediaMessage) {
|
||||
results.add(new TransportOption(Type.SMS, R.drawable.ic_send_sms_white_24dp,
|
||||
context.getResources().getColor(R.color.grey_600),
|
||||
context.getString(R.string.ConversationActivity_transport_insecure_mms),
|
||||
context.getString(R.string.conversation_activity__type_message_mms_insecure),
|
||||
new MmsCharacterCalculator()));
|
||||
results.addAll(getTransportOptionsForSimCards(context.getString(R.string.ConversationActivity_transport_insecure_mms),
|
||||
context.getString(R.string.conversation_activity__type_message_mms_insecure),
|
||||
new MmsCharacterCalculator()));
|
||||
} else {
|
||||
results.add(new TransportOption(Type.SMS, R.drawable.ic_send_sms_white_24dp,
|
||||
context.getResources().getColor(R.color.grey_600),
|
||||
context.getString(R.string.ConversationActivity_transport_insecure_sms),
|
||||
context.getString(R.string.conversation_activity__type_message_sms_insecure),
|
||||
new SmsCharacterCalculator()));
|
||||
results.addAll(getTransportOptionsForSimCards(context.getString(R.string.ConversationActivity_transport_insecure_sms),
|
||||
context.getString(R.string.conversation_activity__type_message_sms_insecure),
|
||||
new SmsCharacterCalculator()));
|
||||
}
|
||||
|
||||
results.add(new TransportOption(Type.TEXTSECURE, R.drawable.ic_send_push_white_24dp,
|
||||
@ -111,16 +139,34 @@ public class TransportOptions {
|
||||
return results;
|
||||
}
|
||||
|
||||
private @NonNull List<TransportOption> getTransportOptionsForSimCards(@NonNull String text,
|
||||
@NonNull String composeHint,
|
||||
@NonNull CharacterCalculator characterCalculator)
|
||||
{
|
||||
List<TransportOption> results = new LinkedList<>();
|
||||
SubscriptionManagerCompat subscriptionManager = new SubscriptionManagerCompat(context);
|
||||
List<SubscriptionInfoCompat> subscriptions = subscriptionManager.getActiveSubscriptionInfoList();
|
||||
|
||||
private void setTransport(Type type) {
|
||||
this.selectedType = type;
|
||||
if (subscriptions.size() < 2) {
|
||||
results.add(new TransportOption(Type.SMS, R.drawable.ic_send_sms_white_24dp,
|
||||
context.getResources().getColor(R.color.grey_600),
|
||||
text, composeHint, characterCalculator));
|
||||
} else {
|
||||
for (SubscriptionInfoCompat subscriptionInfo : subscriptions) {
|
||||
results.add(new TransportOption(Type.SMS, R.drawable.ic_send_sms_white_24dp,
|
||||
context.getResources().getColor(R.color.grey_600),
|
||||
text, composeHint, characterCalculator,
|
||||
Optional.of(subscriptionInfo.getDisplayName()),
|
||||
Optional.of(subscriptionInfo.getSubscriptionId())));
|
||||
}
|
||||
}
|
||||
|
||||
notifyTransportChangeListeners();
|
||||
return results;
|
||||
}
|
||||
|
||||
private void notifyTransportChangeListeners() {
|
||||
for (OnTransportChangedListener listener : listeners) {
|
||||
listener.onChange(getSelectedTransport());
|
||||
listener.onChange(getSelectedTransport(), selectedOption.isPresent());
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,7 +180,15 @@ public class TransportOptions {
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
private boolean isEnabled(TransportOption transportOption) {
|
||||
for (TransportOption option : enabledTransports) {
|
||||
if (option.equals(transportOption)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public interface OnTransportChangedListener {
|
||||
public void onChange(TransportOption newTransport);
|
||||
public void onChange(TransportOption newTransport, boolean manuallySelected);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TransportOptionsAdapter extends BaseAdapter {
|
||||
@ -51,14 +53,22 @@ public class TransportOptionsAdapter extends BaseAdapter {
|
||||
convertView = inflater.inflate(R.layout.transport_selection_list_item, parent, false);
|
||||
}
|
||||
|
||||
TransportOption transport = (TransportOption) getItem(position);
|
||||
ImageView imageView = (ImageView) convertView.findViewById(R.id.icon);
|
||||
TextView textView = (TextView) convertView.findViewById(R.id.text);
|
||||
TransportOption transport = (TransportOption) getItem(position);
|
||||
ImageView imageView = ViewUtil.findById(convertView, R.id.icon);
|
||||
TextView textView = ViewUtil.findById(convertView, R.id.text);
|
||||
TextView subtextView = ViewUtil.findById(convertView, R.id.subtext);
|
||||
|
||||
imageView.getBackground().setColorFilter(transport.getBackgroundColor(), Mode.MULTIPLY);
|
||||
imageView.setImageResource(transport.getDrawable());
|
||||
textView.setText(transport.getDescription());
|
||||
|
||||
if (transport.getSimName().isPresent()) {
|
||||
subtextView.setText(transport.getSimName().get());
|
||||
subtextView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
subtextView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,11 @@ package org.thoughtcrime.securesms.components;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.InputType;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextUtils.TruncateAt;
|
||||
import android.text.style.RelativeSizeSpan;
|
||||
@ -17,7 +19,9 @@ import org.thoughtcrime.securesms.components.emoji.EmojiEditText;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
public class ComposeText extends EmojiEditText {
|
||||
|
||||
private SpannableString hint;
|
||||
private SpannableString subHint;
|
||||
|
||||
public ComposeText(Context context) {
|
||||
super(context);
|
||||
@ -31,10 +35,18 @@ public class ComposeText extends EmojiEditText {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
|
||||
if (!TextUtils.isEmpty(hint)) {
|
||||
setHint(ellipsizeToWidth(hint));
|
||||
if (!TextUtils.isEmpty(subHint)) {
|
||||
setHint(new SpannableStringBuilder().append(ellipsizeToWidth(hint))
|
||||
.append("\n")
|
||||
.append(ellipsizeToWidth(subHint)));
|
||||
} else {
|
||||
setHint(ellipsizeToWidth(hint));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,10 +57,24 @@ public class ComposeText extends EmojiEditText {
|
||||
TruncateAt.END);
|
||||
}
|
||||
|
||||
public void setHint(@NonNull String hint) {
|
||||
public void setHint(@NonNull String hint, @Nullable CharSequence subHint) {
|
||||
this.hint = new SpannableString(hint);
|
||||
this.hint.setSpan(new RelativeSizeSpan(0.8f), 0, hint.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
super.setHint(ellipsizeToWidth(this.hint));
|
||||
|
||||
if (subHint != null) {
|
||||
this.subHint = new SpannableString(subHint);
|
||||
this.subHint.setSpan(new RelativeSizeSpan(0.8f), 0, subHint.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
|
||||
} else {
|
||||
this.subHint = null;
|
||||
}
|
||||
|
||||
if (this.subHint != null) {
|
||||
super.setHint(new SpannableStringBuilder().append(ellipsizeToWidth(this.hint))
|
||||
.append("\n")
|
||||
.append(ellipsizeToWidth(this.subHint)));
|
||||
} else {
|
||||
super.setHint(ellipsizeToWidth(this.hint));
|
||||
}
|
||||
}
|
||||
|
||||
public void appendInvite(String invite) {
|
||||
@ -88,6 +114,6 @@ public class ComposeText extends EmojiEditText {
|
||||
|
||||
setInputType(inputType);
|
||||
setImeOptions(imeOptions);
|
||||
setHint(transport.getComposeHint());
|
||||
setHint(transport.getComposeHint(), transport.getSimName().isPresent() ? "From " + transport.getSimName().get() : null);
|
||||
}
|
||||
}
|
||||
|
@ -83,14 +83,18 @@ public class SendButton extends ImageButton
|
||||
transportOptions.setDefaultTransport(type);
|
||||
}
|
||||
|
||||
public void setDefaultSubscriptionId(Optional<Integer> subscriptionId) {
|
||||
transportOptions.setDefaultSubscriptionId(subscriptionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelected(TransportOption option) {
|
||||
transportOptions.setSelectedTransport(option.getType());
|
||||
transportOptions.setSelectedTransport(option);
|
||||
getTransportOptionsPopup().dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(TransportOption newTransport) {
|
||||
public void onChange(TransportOption newTransport, boolean isManualSelection) {
|
||||
setImageResource(newTransport.getDrawable());
|
||||
setContentDescription(newTransport.getDescription());
|
||||
}
|
||||
|
@ -71,7 +71,8 @@ public class DatabaseFactory {
|
||||
private static final int INTRODUCED_ARCHIVE_VERSION = 24;
|
||||
private static final int INTRODUCED_CONVERSATION_LIST_STATUS_VERSION = 25;
|
||||
private static final int MIGRATED_CONVERSATION_LIST_STATUS_VERSION = 26;
|
||||
private static final int DATABASE_VERSION = 26;
|
||||
private static final int INTRODUCED_SUBSCRIPTION_ID_VERSION = 27;
|
||||
private static final int DATABASE_VERSION = 27;
|
||||
|
||||
private static final String DATABASE_NAME = "messages.db";
|
||||
private static final Object lock = new Object();
|
||||
@ -813,6 +814,12 @@ public class DatabaseFactory {
|
||||
}
|
||||
}
|
||||
|
||||
if (oldVersion < INTRODUCED_SUBSCRIPTION_ID_VERSION) {
|
||||
db.execSQL("ALTER TABLE recipient_preferences ADD COLUMN default_subscription_id INTEGER DEFAULT -1");
|
||||
db.execSQL("ALTER TABLE sms ADD COLUMN subscription_id INTEGER DEFAULT -1");
|
||||
db.execSQL("ALTER TABLE mms ADD COLUMN subscription_id INTEGER DEFAULT -1");
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
|
@ -20,27 +20,24 @@ import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.crypto.AsymmetricMasterCipher;
|
||||
import org.thoughtcrime.securesms.crypto.AsymmetricMasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
||||
import org.thoughtcrime.securesms.database.model.DisplayRecord;
|
||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||
import org.thoughtcrime.securesms.util.LRUCache;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class EncryptingSmsDatabase extends SmsDatabase {
|
||||
|
@ -24,7 +24,6 @@ import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
@ -110,7 +109,8 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
"retr_txt" + " TEXT, " + "retr_txt_cs" + " INTEGER, " + "read_status" + " INTEGER, " +
|
||||
"ct_cls" + " INTEGER, " + "resp_txt" + " TEXT, " + "d_tm" + " INTEGER, " +
|
||||
RECEIPT_COUNT + " INTEGER DEFAULT 0, " + MISMATCHED_IDENTITIES + " TEXT DEFAULT NULL, " +
|
||||
NETWORK_FAILURE + " TEXT DEFAULT NULL," + "d_rpt" + " INTEGER);";
|
||||
NETWORK_FAILURE + " TEXT DEFAULT NULL," + "d_rpt" + " INTEGER, " +
|
||||
SUBSCRIPTION_ID + " INTEGER DEFAULT -1);";
|
||||
|
||||
public static final String[] CREATE_INDEXS = {
|
||||
"CREATE INDEX IF NOT EXISTS mms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");",
|
||||
@ -129,7 +129,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
CONTENT_LOCATION, EXPIRY, MESSAGE_TYPE,
|
||||
MESSAGE_SIZE, STATUS, TRANSACTION_ID,
|
||||
BODY, PART_COUNT, ADDRESS, ADDRESS_DEVICE_ID,
|
||||
RECEIPT_COUNT, MISMATCHED_IDENTITIES, NETWORK_FAILURE,
|
||||
RECEIPT_COUNT, MISMATCHED_IDENTITIES, NETWORK_FAILURE, SUBSCRIPTION_ID,
|
||||
AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + " AS " + AttachmentDatabase.ATTACHMENT_ID_ALIAS,
|
||||
AttachmentDatabase.UNIQUE_ID,
|
||||
AttachmentDatabase.MMS_ID,
|
||||
@ -478,7 +478,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
return new Pair<>(messageId, threadId);
|
||||
}
|
||||
|
||||
public Optional<NotificationInd> getNotification(long messageId) {
|
||||
public Optional<Pair<NotificationInd, Integer>> getNotification(long messageId) {
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
@ -493,7 +493,8 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
builder.addLong(MESSAGE_SIZE, PduHeaders.MESSAGE_SIZE);
|
||||
builder.addText(TRANSACTION_ID, PduHeaders.TRANSACTION_ID);
|
||||
|
||||
return Optional.of(new NotificationInd(headers));
|
||||
return Optional.of(new Pair<>(new NotificationInd(headers),
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID))));
|
||||
} else {
|
||||
return Optional.absent();
|
||||
}
|
||||
@ -514,13 +515,14 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
cursor = rawQuery(RAW_ID_WHERE, new String[] {String.valueOf(messageId)});
|
||||
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
long outboxType = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX));
|
||||
String messageText = cursor.getString(cursor.getColumnIndexOrThrow(BODY));
|
||||
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT));
|
||||
List<Attachment> attachments = new LinkedList<Attachment>(attachmentDatabase.getAttachmentsForMessage(messageId));
|
||||
MmsAddresses addresses = addr.getAddressesForId(messageId);
|
||||
List<String> destinations = new LinkedList<>();
|
||||
String body = getDecryptedBody(masterSecret, messageText, outboxType);
|
||||
long outboxType = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX));
|
||||
String messageText = cursor.getString(cursor.getColumnIndexOrThrow(BODY));
|
||||
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID));
|
||||
List<Attachment> attachments = new LinkedList<Attachment>(attachmentDatabase.getAttachmentsForMessage(messageId));
|
||||
MmsAddresses addresses = addr.getAddressesForId(messageId);
|
||||
List<String> destinations = new LinkedList<>();
|
||||
String body = getDecryptedBody(masterSecret, messageText, outboxType);
|
||||
|
||||
destinations.addAll(addresses.getBcc());
|
||||
destinations.addAll(addresses.getCc());
|
||||
@ -532,7 +534,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
return new OutgoingGroupMediaMessage(recipients, body, attachments, timestamp);
|
||||
}
|
||||
|
||||
OutgoingMediaMessage message = new OutgoingMediaMessage(recipients, body, attachments, timestamp,
|
||||
OutgoingMediaMessage message = new OutgoingMediaMessage(recipients, body, attachments, timestamp, subscriptionId,
|
||||
!addresses.getBcc().isEmpty() ? ThreadDatabase.DistributionTypes.BROADCAST :
|
||||
ThreadDatabase.DistributionTypes.DEFAULT);
|
||||
if (Types.isSecureType(outboxType)) {
|
||||
@ -615,6 +617,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
contentValues.put(STATUS, Status.DOWNLOAD_INITIALIZED);
|
||||
contentValues.put(DATE_RECEIVED, generatePduCompatTimestamp());
|
||||
contentValues.put(PART_COUNT, retrieved.getAttachments().size());
|
||||
contentValues.put(SUBSCRIPTION_ID, retrieved.getSubscriptionId());
|
||||
contentValues.put(READ, 0);
|
||||
|
||||
if (!contentValues.containsKey(DATE_SENT)) {
|
||||
@ -673,7 +676,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
return insertMessageInbox(masterSecret, retrieved, "", threadId, type);
|
||||
}
|
||||
|
||||
public Pair<Long, Long> insertMessageInbox(@NonNull NotificationInd notification) {
|
||||
public Pair<Long, Long> insertMessageInbox(@NonNull NotificationInd notification, int subscriptionId) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
||||
long threadId = getThreadIdFor(notification);
|
||||
@ -702,6 +705,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
contentValues.put(STATUS, Status.DOWNLOAD_INITIALIZED);
|
||||
contentValues.put(DATE_RECEIVED, generatePduCompatTimestamp());
|
||||
contentValues.put(READ, Util.isDefaultSmsProvider(context) ? 0 : 1);
|
||||
contentValues.put(SUBSCRIPTION_ID, subscriptionId);
|
||||
|
||||
if (!contentValues.containsKey(DATE_SENT))
|
||||
contentValues.put(DATE_SENT, contentValues.getAsLong(DATE_RECEIVED));
|
||||
@ -761,6 +765,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
contentValues.put(THREAD_ID, threadId);
|
||||
contentValues.put(READ, 1);
|
||||
contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
||||
|
||||
if (message.getRecipients().isSingleRecipient()) {
|
||||
try {
|
||||
@ -1021,6 +1026,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
long expiry = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRY));
|
||||
int status = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.STATUS));
|
||||
int receiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.RECEIPT_COUNT));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.SUBSCRIPTION_ID));
|
||||
|
||||
byte[]contentLocationBytes = null;
|
||||
byte[]transactionIdBytes = null;
|
||||
@ -1035,7 +1041,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
return new NotificationMmsMessageRecord(context, id, recipients, recipients.getPrimaryRecipient(),
|
||||
addressDeviceId, dateSent, dateReceived, receiptCount, threadId,
|
||||
contentLocationBytes, messageSize, expiry, status,
|
||||
transactionIdBytes, mailbox);
|
||||
transactionIdBytes, mailbox, subscriptionId);
|
||||
}
|
||||
|
||||
private MediaMmsMessageRecord getMediaMmsMessageRecord(Cursor cursor) {
|
||||
@ -1051,6 +1057,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
int partCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.PART_COUNT));
|
||||
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.MISMATCHED_IDENTITIES));
|
||||
String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.NETWORK_FAILURE));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.SUBSCRIPTION_ID));
|
||||
|
||||
Recipients recipients = getRecipientsFor(address);
|
||||
List<IdentityKeyMismatch> mismatches = getMismatchedIdentities(mismatchDocument);
|
||||
@ -1059,7 +1066,8 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
|
||||
return new MediaMmsMessageRecord(context, id, recipients, recipients.getPrimaryRecipient(),
|
||||
addressDeviceId, dateSent, dateReceived, receiptCount,
|
||||
threadId, body, slideDeck, partCount, box, mismatches, networkFailures);
|
||||
threadId, body, slideDeck, partCount, box, mismatches,
|
||||
networkFailures, subscriptionId);
|
||||
}
|
||||
|
||||
private Recipients getRecipientsFor(String address) {
|
||||
|
@ -14,6 +14,7 @@ public interface MmsSmsColumns {
|
||||
public static final String RECEIPT_COUNT = "delivery_receipt_count";
|
||||
public static final String MISMATCHED_IDENTITIES = "mismatched_identities";
|
||||
public static final String UNIQUE_ROW_ID = "unique_row_id";
|
||||
public static final String SUBSCRIPTION_ID = "subscription_id";
|
||||
|
||||
public static class Types {
|
||||
protected static final long TOTAL_MASK = 0xFFFFFFFF;
|
||||
|
@ -52,7 +52,8 @@ public class MmsSmsDatabase extends Database {
|
||||
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY,
|
||||
MmsDatabase.STATUS, MmsSmsColumns.RECEIPT_COUNT,
|
||||
MmsSmsColumns.MISMATCHED_IDENTITIES,
|
||||
MmsDatabase.NETWORK_FAILURE, TRANSPORT,
|
||||
MmsDatabase.NETWORK_FAILURE,
|
||||
MmsSmsColumns.SUBSCRIPTION_ID, TRANSPORT,
|
||||
AttachmentDatabase.ATTACHMENT_ID_ALIAS,
|
||||
AttachmentDatabase.UNIQUE_ID,
|
||||
AttachmentDatabase.MMS_ID,
|
||||
@ -132,7 +133,7 @@ public class MmsSmsDatabase extends Database {
|
||||
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
|
||||
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY, MmsDatabase.STATUS,
|
||||
MmsSmsColumns.RECEIPT_COUNT, MmsSmsColumns.MISMATCHED_IDENTITIES,
|
||||
MmsDatabase.NETWORK_FAILURE, TRANSPORT,
|
||||
MmsSmsColumns.SUBSCRIPTION_ID, MmsDatabase.NETWORK_FAILURE, TRANSPORT,
|
||||
AttachmentDatabase.UNIQUE_ID,
|
||||
AttachmentDatabase.MMS_ID,
|
||||
AttachmentDatabase.SIZE,
|
||||
@ -156,6 +157,7 @@ public class MmsSmsDatabase extends Database {
|
||||
MmsDatabase.CONTENT_LOCATION, MmsDatabase.TRANSACTION_ID,
|
||||
MmsDatabase.MESSAGE_SIZE, MmsDatabase.EXPIRY, MmsDatabase.STATUS,
|
||||
MmsSmsColumns.RECEIPT_COUNT, MmsSmsColumns.MISMATCHED_IDENTITIES,
|
||||
MmsSmsColumns.SUBSCRIPTION_ID,
|
||||
MmsDatabase.NETWORK_FAILURE, TRANSPORT,
|
||||
AttachmentDatabase.UNIQUE_ID,
|
||||
AttachmentDatabase.MMS_ID,
|
||||
@ -192,6 +194,7 @@ public class MmsSmsDatabase extends Database {
|
||||
mmsColumnsPresent.add(MmsSmsColumns.ADDRESS_DEVICE_ID);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.RECEIPT_COUNT);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.MISMATCHED_IDENTITIES);
|
||||
mmsColumnsPresent.add(MmsSmsColumns.SUBSCRIPTION_ID);
|
||||
mmsColumnsPresent.add(MmsDatabase.MESSAGE_TYPE);
|
||||
mmsColumnsPresent.add(MmsDatabase.MESSAGE_BOX);
|
||||
mmsColumnsPresent.add(MmsDatabase.DATE_SENT);
|
||||
@ -222,6 +225,7 @@ public class MmsSmsDatabase extends Database {
|
||||
smsColumnsPresent.add(MmsSmsColumns.THREAD_ID);
|
||||
smsColumnsPresent.add(MmsSmsColumns.RECEIPT_COUNT);
|
||||
smsColumnsPresent.add(MmsSmsColumns.MISMATCHED_IDENTITIES);
|
||||
smsColumnsPresent.add(MmsSmsColumns.SUBSCRIPTION_ID);
|
||||
smsColumnsPresent.add(SmsDatabase.TYPE);
|
||||
smsColumnsPresent.add(SmsDatabase.SUBJECT);
|
||||
smsColumnsPresent.add(SmsDatabase.DATE_SENT);
|
||||
|
@ -23,15 +23,16 @@ public class RecipientPreferenceDatabase extends Database {
|
||||
private static final String TAG = RecipientPreferenceDatabase.class.getSimpleName();
|
||||
private static final String RECIPIENT_PREFERENCES_URI = "content://textsecure/recipients/";
|
||||
|
||||
private static final String TABLE_NAME = "recipient_preferences";
|
||||
private static final String ID = "_id";
|
||||
private static final String RECIPIENT_IDS = "recipient_ids";
|
||||
private static final String BLOCK = "block";
|
||||
private static final String NOTIFICATION = "notification";
|
||||
private static final String VIBRATE = "vibrate";
|
||||
private static final String MUTE_UNTIL = "mute_until";
|
||||
private static final String COLOR = "color";
|
||||
private static final String SEEN_INVITE_REMINDER = "seen_invite_reminder";
|
||||
private static final String TABLE_NAME = "recipient_preferences";
|
||||
private static final String ID = "_id";
|
||||
private static final String RECIPIENT_IDS = "recipient_ids";
|
||||
private static final String BLOCK = "block";
|
||||
private static final String NOTIFICATION = "notification";
|
||||
private static final String VIBRATE = "vibrate";
|
||||
private static final String MUTE_UNTIL = "mute_until";
|
||||
private static final String COLOR = "color";
|
||||
private static final String SEEN_INVITE_REMINDER = "seen_invite_reminder";
|
||||
private static final String DEFAULT_SUBSCRIPTION_ID = "default_subscription_id";
|
||||
|
||||
public enum VibrateState {
|
||||
DEFAULT(0), ENABLED(1), DISABLED(2);
|
||||
@ -60,7 +61,8 @@ public class RecipientPreferenceDatabase extends Database {
|
||||
VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " +
|
||||
MUTE_UNTIL + " INTEGER DEFAULT 0, " +
|
||||
COLOR + " TEXT DEFAULT NULL, " +
|
||||
SEEN_INVITE_REMINDER + " INTEGER DEFAULT 0);";
|
||||
SEEN_INVITE_REMINDER + " INTEGER DEFAULT 0, " +
|
||||
DEFAULT_SUBSCRIPTION_ID + " INTEGER DEFAULT -1);";
|
||||
|
||||
public RecipientPreferenceDatabase(Context context, SQLiteOpenHelper databaseHelper) {
|
||||
super(context, databaseHelper);
|
||||
@ -88,13 +90,14 @@ public class RecipientPreferenceDatabase extends Database {
|
||||
null, null, null);
|
||||
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
boolean blocked = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCK)) == 1;
|
||||
String notification = cursor.getString(cursor.getColumnIndexOrThrow(NOTIFICATION));
|
||||
int vibrateState = cursor.getInt(cursor.getColumnIndexOrThrow(VIBRATE));
|
||||
long muteUntil = cursor.getLong(cursor.getColumnIndexOrThrow(MUTE_UNTIL));
|
||||
String serializedColor = cursor.getString(cursor.getColumnIndexOrThrow(COLOR));
|
||||
Uri notificationUri = notification == null ? null : Uri.parse(notification);
|
||||
boolean seenInviteReminder = cursor.getInt(cursor.getColumnIndexOrThrow(SEEN_INVITE_REMINDER)) == 1;
|
||||
boolean blocked = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCK)) == 1;
|
||||
String notification = cursor.getString(cursor.getColumnIndexOrThrow(NOTIFICATION));
|
||||
int vibrateState = cursor.getInt(cursor.getColumnIndexOrThrow(VIBRATE));
|
||||
long muteUntil = cursor.getLong(cursor.getColumnIndexOrThrow(MUTE_UNTIL));
|
||||
String serializedColor = cursor.getString(cursor.getColumnIndexOrThrow(COLOR));
|
||||
Uri notificationUri = notification == null ? null : Uri.parse(notification);
|
||||
boolean seenInviteReminder = cursor.getInt(cursor.getColumnIndexOrThrow(SEEN_INVITE_REMINDER)) == 1;
|
||||
int defaultSubscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(DEFAULT_SUBSCRIPTION_ID));
|
||||
|
||||
MaterialColor color;
|
||||
|
||||
@ -109,7 +112,8 @@ public class RecipientPreferenceDatabase extends Database {
|
||||
|
||||
return Optional.of(new RecipientsPreferences(blocked, muteUntil,
|
||||
VibrateState.fromId(vibrateState),
|
||||
notificationUri, color, seenInviteReminder));
|
||||
notificationUri, color, seenInviteReminder,
|
||||
defaultSubscriptionId));
|
||||
}
|
||||
|
||||
return Optional.absent();
|
||||
@ -124,6 +128,13 @@ public class RecipientPreferenceDatabase extends Database {
|
||||
updateOrInsert(recipients, values);
|
||||
}
|
||||
|
||||
public void setDefaultSubscriptionId(@NonNull Recipients recipients, int defaultSubscriptionId) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(DEFAULT_SUBSCRIPTION_ID, defaultSubscriptionId);
|
||||
updateOrInsert(recipients, values);
|
||||
}
|
||||
|
||||
|
||||
public void setBlocked(Recipients recipients, boolean blocked) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(BLOCK, blocked ? 1 : 0);
|
||||
@ -181,19 +192,22 @@ public class RecipientPreferenceDatabase extends Database {
|
||||
private final Uri notification;
|
||||
private final MaterialColor color;
|
||||
private final boolean seenInviteReminder;
|
||||
private final int defaultSubscriptionId;
|
||||
|
||||
public RecipientsPreferences(boolean blocked, long muteUntil,
|
||||
@NonNull VibrateState vibrateState,
|
||||
@Nullable Uri notification,
|
||||
@Nullable MaterialColor color,
|
||||
boolean seenInviteReminder)
|
||||
boolean seenInviteReminder,
|
||||
int defaultSubscriptionId)
|
||||
{
|
||||
this.blocked = blocked;
|
||||
this.muteUntil = muteUntil;
|
||||
this.vibrateState = vibrateState;
|
||||
this.notification = notification;
|
||||
this.color = color;
|
||||
this.seenInviteReminder = seenInviteReminder;
|
||||
this.blocked = blocked;
|
||||
this.muteUntil = muteUntil;
|
||||
this.vibrateState = vibrateState;
|
||||
this.notification = notification;
|
||||
this.color = color;
|
||||
this.seenInviteReminder = seenInviteReminder;
|
||||
this.defaultSubscriptionId = defaultSubscriptionId;
|
||||
}
|
||||
|
||||
public @Nullable MaterialColor getColor() {
|
||||
@ -219,5 +233,9 @@ public class RecipientPreferenceDatabase extends Database {
|
||||
public boolean hasSeenInviteReminder() {
|
||||
return seenInviteReminder;
|
||||
}
|
||||
|
||||
public Optional<Integer> getDefaultSubscriptionId() {
|
||||
return defaultSubscriptionId != -1 ? Optional.of(defaultSubscriptionId) : Optional.<Integer>absent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,6 @@ import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
|
||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.LRUCache;
|
||||
import org.whispersystems.jobqueue.JobManager;
|
||||
import org.whispersystems.textsecure.api.util.InvalidNumberException;
|
||||
|
||||
@ -78,7 +77,7 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
DATE_RECEIVED + " INTEGER, " + DATE_SENT + " INTEGER, " + PROTOCOL + " INTEGER, " + READ + " INTEGER DEFAULT 0, " +
|
||||
STATUS + " INTEGER DEFAULT -1," + TYPE + " INTEGER, " + REPLY_PATH_PRESENT + " INTEGER, " +
|
||||
RECEIPT_COUNT + " INTEGER DEFAULT 0," + SUBJECT + " TEXT, " + BODY + " TEXT, " +
|
||||
MISMATCHED_IDENTITIES + " TEXT DEFAULT NULL, " + SERVICE_CENTER + " TEXT);";
|
||||
MISMATCHED_IDENTITIES + " TEXT DEFAULT NULL, " + SERVICE_CENTER + " TEXT, " + SUBSCRIPTION_ID + " INTEGER DEFAULT -1);";
|
||||
|
||||
public static final String[] CREATE_INDEXS = {
|
||||
"CREATE INDEX IF NOT EXISTS sms_thread_id_index ON " + TABLE_NAME + " (" + THREAD_ID + ");",
|
||||
@ -95,7 +94,7 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
DATE_SENT + " AS " + NORMALIZED_DATE_SENT,
|
||||
PROTOCOL, READ, STATUS, TYPE,
|
||||
REPLY_PATH_PRESENT, SUBJECT, BODY, SERVICE_CENTER, RECEIPT_COUNT,
|
||||
MISMATCHED_IDENTITIES
|
||||
MISMATCHED_IDENTITIES, SUBSCRIPTION_ID
|
||||
};
|
||||
|
||||
private static final EarlyReceiptCache earlyReceiptCache = new EarlyReceiptCache();
|
||||
@ -451,6 +450,7 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
values.put(DATE_SENT, message.getSentTimestampMillis());
|
||||
values.put(PROTOCOL, message.getProtocol());
|
||||
values.put(READ, unread ? 0 : 1);
|
||||
values.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
||||
|
||||
if (!TextUtils.isEmpty(message.getPseudoSubject()))
|
||||
values.put(SUBJECT, message.getPseudoSubject());
|
||||
@ -497,6 +497,7 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
contentValues.put(DATE_SENT, date);
|
||||
contentValues.put(READ, 1);
|
||||
contentValues.put(TYPE, type);
|
||||
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
||||
|
||||
try {
|
||||
contentValues.put(RECEIPT_COUNT, earlyReceiptCache.remove(date, canonicalizeNumber(context, address)));
|
||||
@ -663,6 +664,7 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
int status = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.STATUS));
|
||||
int receiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.RECEIPT_COUNT));
|
||||
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.MISMATCHED_IDENTITIES));
|
||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.SUBSCRIPTION_ID));
|
||||
|
||||
List<IdentityKeyMismatch> mismatches = getMismatches(mismatchDocument);
|
||||
Recipients recipients = getRecipientsFor(address);
|
||||
@ -672,7 +674,7 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
recipients.getPrimaryRecipient(),
|
||||
addressDeviceId,
|
||||
dateSent, dateReceived, receiptCount, type,
|
||||
threadId, status, mismatches);
|
||||
threadId, status, mismatches, subscriptionId);
|
||||
}
|
||||
|
||||
private Recipients getRecipientsFor(String address) {
|
||||
|
@ -21,8 +21,8 @@ import android.support.annotation.NonNull;
|
||||
import android.text.SpannableString;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.SmsDatabase.Status;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.SmsDatabase.Status;
|
||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
@ -53,10 +53,10 @@ public class MediaMmsMessageRecord extends MessageRecord {
|
||||
@NonNull SlideDeck slideDeck,
|
||||
int partCount, long mailbox,
|
||||
List<IdentityKeyMismatch> mismatches,
|
||||
List<NetworkFailure> failures)
|
||||
List<NetworkFailure> failures, int subscriptionId)
|
||||
{
|
||||
super(context, id, body, recipients, individualRecipient, recipientDeviceId, dateSent,
|
||||
dateReceived, threadId, Status.STATUS_NONE, receiptCount, mailbox, mismatches, failures);
|
||||
dateReceived, threadId, Status.STATUS_NONE, receiptCount, mailbox, mismatches, failures, subscriptionId);
|
||||
|
||||
this.context = context.getApplicationContext();
|
||||
this.partCount = partCount;
|
||||
|
@ -50,13 +50,15 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
private final long id;
|
||||
private final List<IdentityKeyMismatch> mismatches;
|
||||
private final List<NetworkFailure> networkFailures;
|
||||
private final int subscriptionId;
|
||||
|
||||
MessageRecord(Context context, long id, Body body, Recipients recipients,
|
||||
Recipient individualRecipient, int recipientDeviceId,
|
||||
long dateSent, long dateReceived, long threadId,
|
||||
int deliveryStatus, int receiptCount, long type,
|
||||
List<IdentityKeyMismatch> mismatches,
|
||||
List<NetworkFailure> networkFailures)
|
||||
List<NetworkFailure> networkFailures,
|
||||
int subscriptionId)
|
||||
{
|
||||
super(context, body, recipients, dateSent, dateReceived, threadId, deliveryStatus, receiptCount,
|
||||
type);
|
||||
@ -65,6 +67,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
this.recipientDeviceId = recipientDeviceId;
|
||||
this.mismatches = mismatches;
|
||||
this.networkFailures = networkFailures;
|
||||
this.subscriptionId = subscriptionId;
|
||||
}
|
||||
|
||||
public abstract boolean isMms();
|
||||
@ -195,4 +198,7 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
return (int)getId();
|
||||
}
|
||||
|
||||
public int getSubscriptionId() {
|
||||
return subscriptionId;
|
||||
}
|
||||
}
|
||||
|
@ -49,11 +49,12 @@ public class NotificationMmsMessageRecord extends MessageRecord {
|
||||
Recipient individualRecipient, int recipientDeviceId,
|
||||
long dateSent, long dateReceived, int receiptCount,
|
||||
long threadId, byte[] contentLocation, long messageSize,
|
||||
long expiry, int status, byte[] transactionId, long mailbox)
|
||||
long expiry, int status, byte[] transactionId, long mailbox,
|
||||
int subscriptionId)
|
||||
{
|
||||
super(context, id, new Body("", true), recipients, individualRecipient, recipientDeviceId,
|
||||
dateSent, dateReceived, threadId, Status.STATUS_NONE, receiptCount, mailbox,
|
||||
new LinkedList<IdentityKeyMismatch>(), new LinkedList<NetworkFailure>());
|
||||
new LinkedList<IdentityKeyMismatch>(), new LinkedList<NetworkFailure>(), subscriptionId);
|
||||
|
||||
this.contentLocation = contentLocation;
|
||||
this.messageSize = messageSize;
|
||||
|
@ -47,11 +47,12 @@ public class SmsMessageRecord extends MessageRecord {
|
||||
long dateSent, long dateReceived,
|
||||
int receiptCount,
|
||||
long type, long threadId,
|
||||
int status, List<IdentityKeyMismatch> mismatches)
|
||||
int status, List<IdentityKeyMismatch> mismatches,
|
||||
int subscriptionId)
|
||||
{
|
||||
super(context, id, body, recipients, individualRecipient, recipientDeviceId,
|
||||
dateSent, dateReceived, threadId, status, receiptCount, type,
|
||||
mismatches, new LinkedList<NetworkFailure>());
|
||||
mismatches, new LinkedList<NetworkFailure>(), subscriptionId);
|
||||
}
|
||||
|
||||
public long getType() {
|
||||
|
@ -107,8 +107,8 @@ public class GroupManager {
|
||||
avatarAttachment = new UriAttachment(avatarUri, ContentType.IMAGE_JPEG, AttachmentDatabase.TRANSFER_PROGRESS_DONE, avatar.length);
|
||||
}
|
||||
|
||||
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(groupRecipient, groupContext, avatarAttachment, System.currentTimeMillis());
|
||||
long threadId = MessageSender.send(context, masterSecret, outgoingMessage, -1, false);
|
||||
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(groupRecipient, groupContext, avatarAttachment, System.currentTimeMillis());
|
||||
long threadId = MessageSender.send(context, masterSecret, outgoingMessage, -1, false);
|
||||
|
||||
return new GroupActionResult(groupRecipient, threadId);
|
||||
}
|
||||
|
@ -9,9 +9,9 @@ import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.attachments.UriAttachment;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
|
||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
||||
import org.thoughtcrime.securesms.mms.ApnUnavailableException;
|
||||
import org.thoughtcrime.securesms.mms.CompatMmsConnection;
|
||||
@ -35,7 +35,6 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import ws.com.google.android.mms.ContentType;
|
||||
import ws.com.google.android.mms.MmsException;
|
||||
import ws.com.google.android.mms.pdu.EncodedStringValue;
|
||||
import ws.com.google.android.mms.pdu.NotificationInd;
|
||||
@ -75,8 +74,8 @@ public class MmsDownloadJob extends MasterSecretJob {
|
||||
|
||||
@Override
|
||||
public void onRun(MasterSecret masterSecret) {
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Optional<NotificationInd> notification = database.getNotification(messageId);
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Optional<Pair<NotificationInd, Integer>> notification = database.getNotification(messageId);
|
||||
|
||||
if (!notification.isPresent()) {
|
||||
Log.w(TAG, "No notification for ID: " + messageId);
|
||||
@ -84,22 +83,24 @@ public class MmsDownloadJob extends MasterSecretJob {
|
||||
}
|
||||
|
||||
try {
|
||||
if (notification.get().getContentLocation() == null) {
|
||||
if (notification.get().first.getContentLocation() == null) {
|
||||
throw new MmsException("Notification content location was null.");
|
||||
}
|
||||
|
||||
database.markDownloadState(messageId, MmsDatabase.Status.DOWNLOAD_CONNECTING);
|
||||
|
||||
String contentLocation = new String(notification.get().getContentLocation());
|
||||
byte[] transactionId = notification.get().getTransactionId();
|
||||
String contentLocation = new String(notification.get().first.getContentLocation());
|
||||
byte[] transactionId = notification.get().first.getTransactionId();
|
||||
|
||||
Log.w(TAG, "Downloading mms at " + Uri.parse(contentLocation).getHost());
|
||||
|
||||
RetrieveConf retrieveConf = new CompatMmsConnection(context).retrieve(contentLocation, transactionId);
|
||||
RetrieveConf retrieveConf = new CompatMmsConnection(context).retrieve(contentLocation, transactionId, notification.get().second);
|
||||
|
||||
if (retrieveConf == null) {
|
||||
throw new MmsException("RetrieveConf was null");
|
||||
}
|
||||
storeRetrievedMms(masterSecret, contentLocation, messageId, threadId, retrieveConf);
|
||||
|
||||
storeRetrievedMms(masterSecret, contentLocation, messageId, threadId, retrieveConf, notification.get().second);
|
||||
} catch (ApnUnavailableException e) {
|
||||
Log.w(TAG, e);
|
||||
handleDownloadError(masterSecret, messageId, threadId, MmsDatabase.Status.DOWNLOAD_APN_UNAVAILABLE,
|
||||
@ -146,7 +147,8 @@ public class MmsDownloadJob extends MasterSecretJob {
|
||||
}
|
||||
|
||||
private void storeRetrievedMms(MasterSecret masterSecret, String contentLocation,
|
||||
long messageId, long threadId, RetrieveConf retrieved)
|
||||
long messageId, long threadId, RetrieveConf retrieved,
|
||||
int subscriptionId)
|
||||
throws MmsException, NoSessionException, DuplicateMessageException, InvalidMessageException,
|
||||
LegacyMessageException
|
||||
{
|
||||
@ -192,7 +194,7 @@ public class MmsDownloadJob extends MasterSecretJob {
|
||||
|
||||
|
||||
|
||||
IncomingMediaMessage message = new IncomingMediaMessage(from, to, cc, body, retrieved.getDate() * 1000L, attachments);
|
||||
IncomingMediaMessage message = new IncomingMediaMessage(from, to, cc, body, retrieved.getDate() * 1000L, attachments, subscriptionId);
|
||||
|
||||
Pair<Long, Long> messageAndThreadId = database.insertMessageInbox(new MasterSecretUnion(masterSecret),
|
||||
message, contentLocation, threadId);
|
||||
|
@ -19,16 +19,20 @@ import ws.com.google.android.mms.pdu.PduParser;
|
||||
|
||||
public class MmsReceiveJob extends ContextJob {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String TAG = MmsReceiveJob.class.getSimpleName();
|
||||
|
||||
private final byte[] data;
|
||||
private final int subscriptionId;
|
||||
|
||||
public MmsReceiveJob(Context context, byte[] data) {
|
||||
public MmsReceiveJob(Context context, byte[] data, int subscriptionId) {
|
||||
super(context, JobParameters.newBuilder()
|
||||
.withWakeLock(true)
|
||||
.withPersistence().create());
|
||||
|
||||
this.data = data;
|
||||
this.data = data;
|
||||
this.subscriptionId = subscriptionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -54,7 +58,7 @@ public class MmsReceiveJob extends ContextJob {
|
||||
|
||||
if (isNotification(pdu) && !isBlocked(pdu)) {
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Pair<Long, Long> messageAndThreadId = database.insertMessageInbox((NotificationInd)pdu);
|
||||
Pair<Long, Long> messageAndThreadId = database.insertMessageInbox((NotificationInd)pdu, subscriptionId);
|
||||
|
||||
Log.w(TAG, "Inserted received MMS notification...");
|
||||
|
||||
|
@ -17,7 +17,6 @@ import org.thoughtcrime.securesms.mms.MmsSendResult;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
|
||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||
@ -25,12 +24,9 @@ import org.thoughtcrime.securesms.util.Hex;
|
||||
import org.thoughtcrime.securesms.util.NumberUtil;
|
||||
import org.thoughtcrime.securesms.util.SmilUtil;
|
||||
import org.thoughtcrime.securesms.util.TelephonyUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.jobqueue.JobParameters;
|
||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||
import org.whispersystems.textsecure.api.util.InvalidNumberException;
|
||||
import org.whispersystems.textsecure.api.util.PhoneNumberFormatter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
@ -83,7 +79,7 @@ public class MmsSendJob extends SendJob {
|
||||
validateDestinations(message, pdu);
|
||||
|
||||
final byte[] pduBytes = getPduBytes(pdu);
|
||||
final SendConf sendConf = new CompatMmsConnection(context).send(pduBytes);
|
||||
final SendConf sendConf = new CompatMmsConnection(context).send(pduBytes, message.getSubscriptionId());
|
||||
final MmsSendResult result = getSendResult(sendConf, pdu);
|
||||
|
||||
database.markAsSent(messageId);
|
||||
|
@ -261,7 +261,7 @@ public class PushDecryptJob extends ContextJob {
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(masterSecret, envelope.getSource(),
|
||||
localNumber, message.getTimestamp(),
|
||||
localNumber, message.getTimestamp(), -1,
|
||||
Optional.fromNullable(envelope.getRelay()),
|
||||
message.getBody(),
|
||||
message.getGroupInfo(),
|
||||
@ -293,7 +293,7 @@ public class PushDecryptJob extends ContextJob {
|
||||
Recipients recipients = getSyncMessageDestination(message);
|
||||
OutgoingMediaMessage mediaMessage = new OutgoingMediaMessage(recipients, message.getMessage().getBody().orNull(),
|
||||
PointerAttachment.forPointers(masterSecret, message.getMessage().getAttachments()),
|
||||
message.getTimestamp(), ThreadDatabase.DistributionTypes.DEFAULT);
|
||||
message.getTimestamp(), -1, ThreadDatabase.DistributionTypes.DEFAULT);
|
||||
|
||||
mediaMessage = new OutgoingSecureMediaMessage(mediaMessage);
|
||||
|
||||
@ -350,7 +350,7 @@ public class PushDecryptJob extends ContextJob {
|
||||
EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
|
||||
Recipients recipients = getSyncMessageDestination(message);
|
||||
String body = message.getMessage().getBody().or("");
|
||||
OutgoingTextMessage outgoingTextMessage = new OutgoingTextMessage(recipients, body);
|
||||
OutgoingTextMessage outgoingTextMessage = new OutgoingTextMessage(recipients, body, -1);
|
||||
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
||||
long messageId = database.insertMessageOutbox(masterSecret, threadId, outgoingTextMessage, false, message.getTimestamp());
|
||||
|
@ -23,17 +23,21 @@ import java.util.List;
|
||||
|
||||
public class SmsReceiveJob extends ContextJob {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String TAG = SmsReceiveJob.class.getSimpleName();
|
||||
|
||||
private final Object[] pdus;
|
||||
private final int subscriptionId;
|
||||
|
||||
public SmsReceiveJob(Context context, Object[] pdus) {
|
||||
public SmsReceiveJob(Context context, Object[] pdus, int subscriptionId) {
|
||||
super(context, JobParameters.newBuilder()
|
||||
.withPersistence()
|
||||
.withWakeLock(true)
|
||||
.create());
|
||||
|
||||
this.pdus = pdus;
|
||||
this.pdus = pdus;
|
||||
this.subscriptionId = subscriptionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -41,7 +45,7 @@ public class SmsReceiveJob extends ContextJob {
|
||||
|
||||
@Override
|
||||
public void onRun() {
|
||||
Optional<IncomingTextMessage> message = assembleMessageFragments(pdus);
|
||||
Optional<IncomingTextMessage> message = assembleMessageFragments(pdus, subscriptionId);
|
||||
MasterSecret masterSecret = KeyCachingService.getMasterSecret(context);
|
||||
|
||||
MasterSecretUnion masterSecretUnion;
|
||||
@ -95,11 +99,11 @@ public class SmsReceiveJob extends ContextJob {
|
||||
return messageAndThreadId;
|
||||
}
|
||||
|
||||
private Optional<IncomingTextMessage> assembleMessageFragments(Object[] pdus) {
|
||||
private Optional<IncomingTextMessage> assembleMessageFragments(Object[] pdus, int subscriptionId) {
|
||||
List<IncomingTextMessage> messages = new LinkedList<>();
|
||||
|
||||
for (Object pdu : pdus) {
|
||||
messages.add(new IncomingTextMessage(SmsMessage.createFromPdu((byte[])pdu)));
|
||||
messages.add(new IncomingTextMessage(SmsMessage.createFromPdu((byte[])pdu), subscriptionId));
|
||||
}
|
||||
|
||||
if (messages.isEmpty()) {
|
||||
|
@ -4,6 +4,7 @@ import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.telephony.SmsManager;
|
||||
import android.util.Log;
|
||||
@ -105,7 +106,7 @@ public class SmsSendJob extends SendJob {
|
||||
// catching it and marking the message as a failure. That way at least it doesn't
|
||||
// repeatedly crash every time you start the app.
|
||||
try {
|
||||
SmsManager.getDefault().sendMultipartTextMessage(recipient, null, messages, sentIntents, deliveredIntents);
|
||||
getSmsManagerFor(message.getSubscriptionId()).sendMultipartTextMessage(recipient, null, messages, sentIntents, deliveredIntents);
|
||||
} catch (NullPointerException npe) {
|
||||
Log.w(TAG, npe);
|
||||
Log.w(TAG, "Recipient: " + recipient);
|
||||
@ -113,9 +114,9 @@ public class SmsSendJob extends SendJob {
|
||||
|
||||
try {
|
||||
for (int i=0;i<messages.size();i++) {
|
||||
SmsManager.getDefault().sendTextMessage(recipient, null, messages.get(i),
|
||||
sentIntents.get(i),
|
||||
deliveredIntents == null ? null : deliveredIntents.get(i));
|
||||
getSmsManagerFor(message.getSubscriptionId()).sendTextMessage(recipient, null, messages.get(i),
|
||||
sentIntents.get(i),
|
||||
deliveredIntents == null ? null : deliveredIntents.get(i));
|
||||
}
|
||||
} catch (NullPointerException npe2) {
|
||||
Log.w(TAG, npe);
|
||||
@ -179,6 +180,14 @@ public class SmsSendJob extends SendJob {
|
||||
return pending;
|
||||
}
|
||||
|
||||
private SmsManager getSmsManagerFor(int subscriptionId) {
|
||||
if (Build.VERSION.SDK_INT >= 22 && subscriptionId != -1) {
|
||||
return SmsManager.getSmsManagerForSubscriptionId(subscriptionId);
|
||||
} else {
|
||||
return SmsManager.getDefault();
|
||||
}
|
||||
}
|
||||
|
||||
private static JobParameters constructParameters(Context context, String name) {
|
||||
JobParameters.Builder builder = JobParameters.newBuilder()
|
||||
.withPersistence()
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms.mms;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.support.annotation.NonNull;
|
||||
@ -26,38 +27,46 @@ public class CompatMmsConnection implements OutgoingMmsConnection, IncomingMmsCo
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public SendConf send(@NonNull byte[] pduBytes)
|
||||
public SendConf send(@NonNull byte[] pduBytes, int subscriptionId)
|
||||
throws UndeliverableMessageException
|
||||
{
|
||||
try {
|
||||
if (subscriptionId == -1 || VERSION.SDK_INT < 22) {
|
||||
Log.w(TAG, "Sending via legacy connection");
|
||||
return new OutgoingLegacyMmsConnection(context).send(pduBytes);
|
||||
} catch (UndeliverableMessageException | ApnUnavailableException e) {
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
|
||||
Log.w(TAG, "Falling back to try sending via Lollipop API");
|
||||
return new OutgoingLollipopMmsConnection(context).send(pduBytes);
|
||||
} else {
|
||||
throw new UndeliverableMessageException(e);
|
||||
try {
|
||||
return new OutgoingLegacyMmsConnection(context).send(pduBytes, subscriptionId);
|
||||
} catch (UndeliverableMessageException | ApnUnavailableException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
|
||||
return new OutgoingLollipopMmsConnection(context).send(pduBytes, subscriptionId);
|
||||
} else {
|
||||
throw new UndeliverableMessageException("Lollipop API not available to try...");
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public RetrieveConf retrieve(@NonNull String contentLocation,
|
||||
byte[] transactionId)
|
||||
byte[] transactionId,
|
||||
int subscriptionId)
|
||||
throws MmsException, MmsRadioException, ApnUnavailableException, IOException
|
||||
{
|
||||
try {
|
||||
if (VERSION.SDK_INT < 22 || subscriptionId == -1) {
|
||||
Log.w(TAG, "Receiving via legacy connection");
|
||||
return new IncomingLegacyMmsConnection(context).retrieve(contentLocation, transactionId);
|
||||
} catch (MmsRadioException | IOException | ApnUnavailableException e) {
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
|
||||
Log.w(TAG, "Falling back to try receiving via Lollipop API");
|
||||
return new IncomingLollipopMmsConnection(context).retrieve(contentLocation, transactionId);
|
||||
} else {
|
||||
throw e;
|
||||
try {
|
||||
return new IncomingLegacyMmsConnection(context).retrieve(contentLocation, transactionId, subscriptionId);
|
||||
} catch (MmsRadioException | ApnUnavailableException | IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
|
||||
Log.w(TAG, "Falling back to try receiving via Lollipop API");
|
||||
return new IncomingLollipopMmsConnection(context).retrieve(contentLocation, transactionId, subscriptionId);
|
||||
} else {
|
||||
throw new IOException("Not able to use Lollipop APIs, giving up...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ public class IncomingLegacyMmsConnection extends LegacyMmsConnection implements
|
||||
|
||||
@Override
|
||||
public @Nullable RetrieveConf retrieve(@NonNull String contentLocation,
|
||||
byte[] transactionId)
|
||||
byte[] transactionId, int subscriptionId)
|
||||
throws MmsRadioException, ApnUnavailableException, IOException
|
||||
{
|
||||
MmsRadio radio = MmsRadio.getInstance(context);
|
||||
|
@ -39,6 +39,7 @@ import ws.com.google.android.mms.pdu.PduParser;
|
||||
import ws.com.google.android.mms.pdu.RetrieveConf;
|
||||
|
||||
public class IncomingLollipopMmsConnection extends LollipopMmsConnection implements IncomingMmsConnection {
|
||||
|
||||
public static final String ACTION = IncomingLollipopMmsConnection.class.getCanonicalName() + "MMS_DOWNLOADED_ACTION";
|
||||
private static final String TAG = IncomingLollipopMmsConnection.class.getSimpleName();
|
||||
|
||||
@ -58,7 +59,8 @@ public class IncomingLollipopMmsConnection extends LollipopMmsConnection impleme
|
||||
@Override
|
||||
@TargetApi(VERSION_CODES.LOLLIPOP)
|
||||
public synchronized @Nullable RetrieveConf retrieve(@NonNull String contentLocation,
|
||||
byte[] transactionId) throws MmsException
|
||||
byte[] transactionId,
|
||||
int subscriptionId) throws MmsException
|
||||
{
|
||||
beginTransaction();
|
||||
|
||||
@ -66,11 +68,20 @@ public class IncomingLollipopMmsConnection extends LollipopMmsConnection impleme
|
||||
MmsBodyProvider.Pointer pointer = MmsBodyProvider.makeTemporaryPointer(getContext());
|
||||
|
||||
Log.w(TAG, "downloading multimedia from " + contentLocation + " to " + pointer.getUri());
|
||||
SmsManager.getDefault().downloadMultimediaMessage(getContext(),
|
||||
contentLocation,
|
||||
pointer.getUri(),
|
||||
null,
|
||||
getPendingIntent());
|
||||
|
||||
SmsManager smsManager;
|
||||
|
||||
if (VERSION.SDK_INT >= 22 && subscriptionId != -1) {
|
||||
smsManager = SmsManager.getSmsManagerForSubscriptionId(subscriptionId);
|
||||
} else {
|
||||
smsManager = SmsManager.getDefault();
|
||||
}
|
||||
|
||||
smsManager.downloadMultimediaMessage(getContext(),
|
||||
contentLocation,
|
||||
pointer.getUri(),
|
||||
null,
|
||||
getPendingIntent());
|
||||
|
||||
waitForResult();
|
||||
|
||||
|
@ -19,6 +19,7 @@ public class IncomingMediaMessage {
|
||||
private final String groupId;
|
||||
private final boolean push;
|
||||
private final long sentTimeMillis;
|
||||
private final int subscriptionId;
|
||||
|
||||
private final List<String> to = new LinkedList<>();
|
||||
private final List<String> cc = new LinkedList<>();
|
||||
@ -26,13 +27,14 @@ public class IncomingMediaMessage {
|
||||
|
||||
public IncomingMediaMessage(String from, List<String> to, List<String> cc,
|
||||
String body, long sentTimeMillis,
|
||||
List<Attachment> attachments)
|
||||
List<Attachment> attachments, int subscriptionId)
|
||||
{
|
||||
this.from = from;
|
||||
this.sentTimeMillis = sentTimeMillis;
|
||||
this.body = body;
|
||||
this.groupId = null;
|
||||
this.push = false;
|
||||
this.subscriptionId = subscriptionId;
|
||||
|
||||
this.to.addAll(to);
|
||||
this.cc.addAll(cc);
|
||||
@ -43,6 +45,7 @@ public class IncomingMediaMessage {
|
||||
String from,
|
||||
String to,
|
||||
long sentTimeMillis,
|
||||
int subscriptionId,
|
||||
Optional<String> relay,
|
||||
Optional<String> body,
|
||||
Optional<TextSecureGroup> group,
|
||||
@ -52,6 +55,7 @@ public class IncomingMediaMessage {
|
||||
this.from = from;
|
||||
this.sentTimeMillis = sentTimeMillis;
|
||||
this.body = body.orNull();
|
||||
this.subscriptionId = subscriptionId;
|
||||
|
||||
if (group.isPresent()) this.groupId = GroupUtil.getEncodedId(group.get().getGroupId());
|
||||
else this.groupId = null;
|
||||
@ -60,6 +64,10 @@ public class IncomingMediaMessage {
|
||||
this.attachments.addAll(PointerAttachment.forPointers(masterSecret, attachments));
|
||||
}
|
||||
|
||||
public int getSubscriptionId() {
|
||||
return subscriptionId;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
@ -9,5 +9,5 @@ import ws.com.google.android.mms.MmsException;
|
||||
import ws.com.google.android.mms.pdu.RetrieveConf;
|
||||
|
||||
public interface IncomingMmsConnection {
|
||||
@Nullable RetrieveConf retrieve(@NonNull String contentLocation, byte[] transactionId) throws MmsException, MmsRadioException, ApnUnavailableException, IOException;
|
||||
@Nullable RetrieveConf retrieve(@NonNull String contentLocation, byte[] transactionId, int subscriptionId) throws MmsException, MmsRadioException, ApnUnavailableException, IOException;
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ public class OutgoingLegacyMmsConnection extends LegacyMmsConnection implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable SendConf send(@NonNull byte[] pduBytes) throws UndeliverableMessageException {
|
||||
public @Nullable SendConf send(@NonNull byte[] pduBytes, int subscriptionId) throws UndeliverableMessageException {
|
||||
try {
|
||||
MmsRadio radio = MmsRadio.getInstance(context);
|
||||
|
||||
|
@ -59,17 +59,27 @@ public class OutgoingLollipopMmsConnection extends LollipopMmsConnection impleme
|
||||
|
||||
@Override
|
||||
@TargetApi(VERSION_CODES.LOLLIPOP)
|
||||
public @Nullable synchronized SendConf send(@NonNull byte[] pduBytes) throws UndeliverableMessageException {
|
||||
public @Nullable synchronized SendConf send(@NonNull byte[] pduBytes, int subscriptionId)
|
||||
throws UndeliverableMessageException
|
||||
{
|
||||
beginTransaction();
|
||||
try {
|
||||
MmsBodyProvider.Pointer pointer = MmsBodyProvider.makeTemporaryPointer(getContext());
|
||||
Util.copy(new ByteArrayInputStream(pduBytes), pointer.getOutputStream());
|
||||
|
||||
SmsManager.getDefault().sendMultimediaMessage(getContext(),
|
||||
pointer.getUri(),
|
||||
null,
|
||||
null,
|
||||
getPendingIntent());
|
||||
SmsManager smsManager;
|
||||
|
||||
if (VERSION.SDK_INT >= 22 && subscriptionId != -1) {
|
||||
smsManager = SmsManager.getSmsManagerForSubscriptionId(subscriptionId);
|
||||
} else {
|
||||
smsManager = SmsManager.getDefault();
|
||||
}
|
||||
|
||||
smsManager.sendMultimediaMessage(getContext(),
|
||||
pointer.getUri(),
|
||||
null,
|
||||
null,
|
||||
getPendingIntent());
|
||||
|
||||
waitForResult();
|
||||
|
||||
|
@ -14,9 +14,11 @@ public class OutgoingMediaMessage {
|
||||
protected final List<Attachment> attachments;
|
||||
private final long sentTimeMillis;
|
||||
private final int distributionType;
|
||||
private final int subscriptionId;
|
||||
|
||||
public OutgoingMediaMessage(Recipients recipients, String message,
|
||||
List<Attachment> attachments, long sentTimeMillis,
|
||||
int subscriptionId,
|
||||
int distributionType)
|
||||
{
|
||||
this.recipients = recipients;
|
||||
@ -24,14 +26,15 @@ public class OutgoingMediaMessage {
|
||||
this.sentTimeMillis = sentTimeMillis;
|
||||
this.distributionType = distributionType;
|
||||
this.attachments = attachments;
|
||||
this.subscriptionId = subscriptionId;
|
||||
}
|
||||
|
||||
public OutgoingMediaMessage(Recipients recipients, SlideDeck slideDeck, String message, long sentTimeMillis, int distributionType)
|
||||
public OutgoingMediaMessage(Recipients recipients, SlideDeck slideDeck, String message, long sentTimeMillis, int subscriptionId, int distributionType)
|
||||
{
|
||||
this(recipients,
|
||||
buildMessage(slideDeck, message),
|
||||
slideDeck.asAttachments(),
|
||||
sentTimeMillis,
|
||||
sentTimeMillis, subscriptionId,
|
||||
distributionType);
|
||||
}
|
||||
|
||||
@ -41,6 +44,7 @@ public class OutgoingMediaMessage {
|
||||
this.distributionType = that.distributionType;
|
||||
this.attachments = that.attachments;
|
||||
this.sentTimeMillis = that.sentTimeMillis;
|
||||
this.subscriptionId = that.subscriptionId;
|
||||
}
|
||||
|
||||
public Recipients getRecipients() {
|
||||
@ -71,6 +75,10 @@ public class OutgoingMediaMessage {
|
||||
return sentTimeMillis;
|
||||
}
|
||||
|
||||
public int getSubscriptionId() {
|
||||
return subscriptionId;
|
||||
}
|
||||
|
||||
private static String buildMessage(SlideDeck slideDeck, String message) {
|
||||
if (!TextUtils.isEmpty(message) && !TextUtils.isEmpty(slideDeck.getBody())) {
|
||||
return slideDeck.getBody() + "\n\n" + message;
|
||||
|
@ -8,5 +8,5 @@ import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||
import ws.com.google.android.mms.pdu.SendConf;
|
||||
|
||||
public interface OutgoingMmsConnection {
|
||||
@Nullable SendConf send(@NonNull byte[] pduBytes) throws UndeliverableMessageException;
|
||||
@Nullable SendConf send(@NonNull byte[] pduBytes, int subscriptionId) throws UndeliverableMessageException;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ public class OutgoingSecureMediaMessage extends OutgoingMediaMessage {
|
||||
long sentTimeMillis,
|
||||
int distributionType)
|
||||
{
|
||||
super(recipients, body, attachments, sentTimeMillis, distributionType);
|
||||
super(recipients, body, attachments, sentTimeMillis, -1, distributionType);
|
||||
}
|
||||
|
||||
public OutgoingSecureMediaMessage(OutgoingMediaMessage base) {
|
||||
|
@ -27,16 +27,16 @@ import android.support.v4.app.RemoteInput;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import ws.com.google.android.mms.pdu.PduBody;
|
||||
|
||||
/**
|
||||
* Get the response text from the Wearable Device and sends an message as a reply
|
||||
*/
|
||||
@ -66,11 +66,14 @@ public class WearReplyReceiver extends MasterSecretBroadcastReceiver {
|
||||
protected Void doInBackground(Void... params) {
|
||||
long threadId;
|
||||
|
||||
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(recipientIds);
|
||||
int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1;
|
||||
|
||||
if (recipients.isGroupRecipient()) {
|
||||
OutgoingMediaMessage reply = new OutgoingMediaMessage(recipients, responseText.toString(), new LinkedList<Attachment>(), System.currentTimeMillis(), 0);
|
||||
OutgoingMediaMessage reply = new OutgoingMediaMessage(recipients, responseText.toString(), new LinkedList<Attachment>(), System.currentTimeMillis(), subscriptionId, 0);
|
||||
threadId = MessageSender.send(context, masterSecret, reply, -1, false);
|
||||
} else {
|
||||
OutgoingTextMessage reply = new OutgoingTextMessage(recipients, responseText.toString());
|
||||
OutgoingTextMessage reply = new OutgoingTextMessage(recipients, responseText.toString(), subscriptionId);
|
||||
threadId = MessageSender.send(context, masterSecret, reply, -1, false);
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ public class RecipientFactory {
|
||||
return provider.getRecipients(context, recipientIds, asynchronous);
|
||||
}
|
||||
|
||||
public static Recipients getRecipientsFromString(Context context, @NonNull String rawText, boolean asynchronous) {
|
||||
public static @NonNull Recipients getRecipientsFromString(Context context, @NonNull String rawText, boolean asynchronous) {
|
||||
StringTokenizer tokenizer = new StringTokenizer(rawText, ",");
|
||||
List<String> ids = new LinkedList<>();
|
||||
|
||||
@ -81,7 +81,7 @@ public class RecipientFactory {
|
||||
return getRecipientsForIds(context, ids, asynchronous);
|
||||
}
|
||||
|
||||
public static Recipients getRecipientsFromStrings(@NonNull Context context, @NonNull List<String> numbers, boolean asynchronous) {
|
||||
public static @NonNull Recipients getRecipientsFromStrings(@NonNull Context context, @NonNull List<String> numbers, boolean asynchronous) {
|
||||
List<String> ids = new LinkedList<>();
|
||||
|
||||
for (String number : numbers) {
|
||||
@ -95,7 +95,7 @@ public class RecipientFactory {
|
||||
return getRecipientsForIds(context, ids, asynchronous);
|
||||
}
|
||||
|
||||
private static Recipients getRecipientsForIds(Context context, List<String> idStrings, boolean asynchronous) {
|
||||
private static @NonNull Recipients getRecipientsForIds(Context context, List<String> idStrings, boolean asynchronous) {
|
||||
long[] ids = new long[idStrings.size()];
|
||||
int i = 0;
|
||||
|
||||
|
@ -63,9 +63,11 @@ public class MmsListener extends BroadcastReceiver {
|
||||
isRelevant(context, intent)))
|
||||
{
|
||||
Log.w(TAG, "Relevant!");
|
||||
int subscriptionId = intent.getExtras().getInt("subscription", -1);
|
||||
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new MmsReceiveJob(context, intent.getByteArrayExtra("data")));
|
||||
.add(new MmsReceiveJob(context, intent.getByteArrayExtra("data"), subscriptionId));
|
||||
|
||||
abortBroadcast();
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ import android.widget.Toast;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
@ -17,6 +19,7 @@ import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||
import org.thoughtcrime.securesms.util.Rfc5724Uri;
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLDecoder;
|
||||
@ -49,14 +52,17 @@ public class QuickResponseService extends MasterSecretIntentService {
|
||||
if(numbers.contains("%")){
|
||||
numbers = URLDecoder.decode(numbers);
|
||||
}
|
||||
Recipients recipients = RecipientFactory.getRecipientsFromString(this, numbers, false);
|
||||
|
||||
Recipients recipients = RecipientFactory.getRecipientsFromString(this, numbers, false);
|
||||
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(this).getRecipientsPreferences(recipients.getIds());
|
||||
int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1;
|
||||
|
||||
if (!TextUtils.isEmpty(content)) {
|
||||
if (recipients.isSingleRecipient()) {
|
||||
MessageSender.send(this, masterSecret, new OutgoingTextMessage(recipients, content), -1, false);
|
||||
MessageSender.send(this, masterSecret, new OutgoingTextMessage(recipients, content, subscriptionId), -1, false);
|
||||
} else {
|
||||
MessageSender.send(this, masterSecret, new OutgoingMediaMessage(recipients, new SlideDeck(), content, System.currentTimeMillis(),
|
||||
ThreadDatabase.DistributionTypes.DEFAULT), -1, false);
|
||||
subscriptionId, ThreadDatabase.DistributionTypes.DEFAULT), -1, false);
|
||||
}
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
|
@ -84,16 +84,6 @@ public class SmsListener extends BroadcastReceiver {
|
||||
return bodyBuilder.toString();
|
||||
}
|
||||
|
||||
// private ArrayList<IncomingTextMessage> getAsTextMessages(Intent intent) {
|
||||
// Object[] pdus = (Object[])intent.getExtras().get("pdus");
|
||||
// ArrayList<IncomingTextMessage> messages = new ArrayList<IncomingTextMessage>(pdus.length);
|
||||
//
|
||||
// for (int i=0;i<pdus.length;i++)
|
||||
// messages.add(new IncomingTextMessage(SmsMessage.createFromPdu((byte[])pdus[i])));
|
||||
//
|
||||
// return messages;
|
||||
// }
|
||||
|
||||
private boolean isRelevant(Context context, Intent intent) {
|
||||
SmsMessage message = getSmsMessageFromIntent(intent);
|
||||
String messageBody = getSmsMessageBodyFromIntent(intent);
|
||||
@ -164,14 +154,10 @@ public class SmsListener extends BroadcastReceiver {
|
||||
} else if ((intent.getAction().equals(SMS_DELIVERED_ACTION)) ||
|
||||
(intent.getAction().equals(SMS_RECEIVED_ACTION)) && isRelevant(context, intent))
|
||||
{
|
||||
Object[] pdus = (Object[])intent.getExtras().get("pdus");
|
||||
ApplicationContext.getInstance(context).getJobManager().add(new SmsReceiveJob(context, pdus));
|
||||
Object[] pdus = (Object[]) intent.getExtras().get("pdus");
|
||||
int subscriptionId = intent.getExtras().getInt("subscription", -1);
|
||||
|
||||
// Intent receivedIntent = new Intent(context, SendReceiveService.class);
|
||||
// receivedIntent.setAction(SendReceiveService.RECEIVE_SMS_ACTION);
|
||||
// receivedIntent.putExtra("ResultCode", this.getResultCode());
|
||||
// receivedIntent.putParcelableArrayListExtra("text_messages",getAsTextMessages(intent));
|
||||
// context.startService(receivedIntent);
|
||||
ApplicationContext.getInstance(context).getJobManager().add(new SmsReceiveJob(context, pdus, subscriptionId));
|
||||
|
||||
abortBroadcast();
|
||||
}
|
||||
|
@ -35,8 +35,9 @@ public class IncomingTextMessage implements Parcelable {
|
||||
private final long sentTimestampMillis;
|
||||
private final String groupId;
|
||||
private final boolean push;
|
||||
private final int subscriptionId;
|
||||
|
||||
public IncomingTextMessage(SmsMessage message) {
|
||||
public IncomingTextMessage(SmsMessage message, int subscriptionId) {
|
||||
this.message = message.getDisplayMessageBody();
|
||||
this.sender = message.getDisplayOriginatingAddress();
|
||||
this.senderDeviceId = TextSecureAddress.DEFAULT_DEVICE_ID;
|
||||
@ -45,6 +46,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||
this.replyPathPresent = message.isReplyPathPresent();
|
||||
this.pseudoSubject = message.getPseudoSubject();
|
||||
this.sentTimestampMillis = message.getTimestampMillis();
|
||||
this.subscriptionId = subscriptionId;
|
||||
this.groupId = null;
|
||||
this.push = false;
|
||||
}
|
||||
@ -61,6 +63,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||
this.pseudoSubject = "";
|
||||
this.sentTimestampMillis = sentTimestampMillis;
|
||||
this.push = true;
|
||||
this.subscriptionId = -1;
|
||||
|
||||
if (group.isPresent()) {
|
||||
this.groupId = GroupUtil.getEncodedId(group.get().getGroupId());
|
||||
@ -80,6 +83,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||
this.sentTimestampMillis = in.readLong();
|
||||
this.groupId = in.readString();
|
||||
this.push = (in.readInt() == 1);
|
||||
this.subscriptionId = in.readInt();
|
||||
}
|
||||
|
||||
public IncomingTextMessage(IncomingTextMessage base, String newBody) {
|
||||
@ -93,6 +97,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||
this.sentTimestampMillis = base.getSentTimestampMillis();
|
||||
this.groupId = base.getGroupId();
|
||||
this.push = base.isPush();
|
||||
this.subscriptionId = base.getSubscriptionId();
|
||||
}
|
||||
|
||||
public IncomingTextMessage(List<IncomingTextMessage> fragments) {
|
||||
@ -112,6 +117,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||
this.sentTimestampMillis = fragments.get(0).getSentTimestampMillis();
|
||||
this.groupId = fragments.get(0).getGroupId();
|
||||
this.push = fragments.get(0).isPush();
|
||||
this.subscriptionId = fragments.get(0).getSubscriptionId();
|
||||
}
|
||||
|
||||
protected IncomingTextMessage(String sender, String groupId)
|
||||
@ -126,6 +132,11 @@ public class IncomingTextMessage implements Parcelable {
|
||||
this.sentTimestampMillis = System.currentTimeMillis();
|
||||
this.groupId = groupId;
|
||||
this.push = true;
|
||||
this.subscriptionId = -1;
|
||||
}
|
||||
|
||||
public int getSubscriptionId() {
|
||||
return subscriptionId;
|
||||
}
|
||||
|
||||
public long getSentTimestampMillis() {
|
||||
@ -209,5 +220,6 @@ public class IncomingTextMessage implements Parcelable {
|
||||
out.writeLong(sentTimestampMillis);
|
||||
out.writeString(groupId);
|
||||
out.writeInt(push ? 1 : 0);
|
||||
out.writeInt(subscriptionId);
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,8 @@ public class MessageSender {
|
||||
allocatedThreadId = threadId;
|
||||
}
|
||||
|
||||
long messageId = database.insertMessageOutbox(new MasterSecretUnion(masterSecret), allocatedThreadId, message, forceSms, System.currentTimeMillis());
|
||||
long messageId = database.insertMessageOutbox(new MasterSecretUnion(masterSecret), allocatedThreadId,
|
||||
message, forceSms, System.currentTimeMillis());
|
||||
|
||||
sendTextMessage(context, recipients, forceSms, keyExchange, messageId);
|
||||
|
||||
|
@ -6,7 +6,7 @@ import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
public class OutgoingEncryptedMessage extends OutgoingTextMessage {
|
||||
|
||||
public OutgoingEncryptedMessage(Recipients recipients, String body) {
|
||||
super(recipients, body);
|
||||
super(recipients, body, -1);
|
||||
}
|
||||
|
||||
private OutgoingEncryptedMessage(OutgoingEncryptedMessage base, String body) {
|
||||
|
@ -5,7 +5,7 @@ import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
public class OutgoingKeyExchangeMessage extends OutgoingTextMessage {
|
||||
|
||||
public OutgoingKeyExchangeMessage(Recipients recipients, String message) {
|
||||
super(recipients, message);
|
||||
super(recipients, message, -1);
|
||||
}
|
||||
|
||||
private OutgoingKeyExchangeMessage(OutgoingKeyExchangeMessage base, String body) {
|
||||
|
@ -7,15 +7,22 @@ public class OutgoingTextMessage {
|
||||
|
||||
private final Recipients recipients;
|
||||
private final String message;
|
||||
private final int subscriptionId;
|
||||
|
||||
public OutgoingTextMessage(Recipients recipients, String message) {
|
||||
this.recipients = recipients;
|
||||
this.message = message;
|
||||
public OutgoingTextMessage(Recipients recipients, String message, int subscriptionId) {
|
||||
this.recipients = recipients;
|
||||
this.message = message;
|
||||
this.subscriptionId = subscriptionId;
|
||||
}
|
||||
|
||||
protected OutgoingTextMessage(OutgoingTextMessage base, String body) {
|
||||
this.recipients = base.getRecipients();
|
||||
this.message = body;
|
||||
this.recipients = base.getRecipients();
|
||||
this.subscriptionId = base.getSubscriptionId();
|
||||
this.message = body;
|
||||
}
|
||||
|
||||
public int getSubscriptionId() {
|
||||
return subscriptionId;
|
||||
}
|
||||
|
||||
public String getMessageBody() {
|
||||
@ -48,9 +55,9 @@ public class OutgoingTextMessage {
|
||||
} else if (record.isKeyExchange()) {
|
||||
return new OutgoingKeyExchangeMessage(record.getRecipients(), record.getBody().getBody());
|
||||
} else if (record.isEndSession()) {
|
||||
return new OutgoingEndSessionMessage(new OutgoingTextMessage(record.getRecipients(), record.getBody().getBody()));
|
||||
return new OutgoingEndSessionMessage(new OutgoingTextMessage(record.getRecipients(), record.getBody().getBody(), -1));
|
||||
} else {
|
||||
return new OutgoingTextMessage(record.getRecipients(), record.getBody().getBody());
|
||||
return new OutgoingTextMessage(record.getRecipients(), record.getBody().getBody(), record.getSubscriptionId());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,23 @@
|
||||
package org.thoughtcrime.securesms.util.dualsim;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
public class SubscriptionInfoCompat {
|
||||
|
||||
private final int subscriptionId;
|
||||
private final @Nullable CharSequence displayName;
|
||||
|
||||
public SubscriptionInfoCompat(int subscriptionId, @Nullable CharSequence displayName) {
|
||||
this.subscriptionId = subscriptionId;
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public @NonNull CharSequence getDisplayName() {
|
||||
return displayName != null ? displayName : "";
|
||||
}
|
||||
|
||||
public int getSubscriptionId() {
|
||||
return subscriptionId;
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package org.thoughtcrime.securesms.util.dualsim;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.SubscriptionManager;
|
||||
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class SubscriptionManagerCompat {
|
||||
|
||||
private final Context context;
|
||||
|
||||
public SubscriptionManagerCompat(Context context) {
|
||||
this.context = context.getApplicationContext();
|
||||
}
|
||||
|
||||
public Optional<SubscriptionInfoCompat> getActiveSubscriptionInfo(int subscriptionId) {
|
||||
if (Build.VERSION.SDK_INT < 22) {
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
SubscriptionInfo subscriptionInfo = SubscriptionManager.from(context).getActiveSubscriptionInfo(subscriptionId);
|
||||
|
||||
if (subscriptionInfo != null) {
|
||||
return Optional.of(new SubscriptionInfoCompat(subscriptionId, subscriptionInfo.getDisplayName()));
|
||||
} else {
|
||||
return Optional.absent();
|
||||
}
|
||||
}
|
||||
|
||||
public @NonNull List<SubscriptionInfoCompat> getActiveSubscriptionInfoList() {
|
||||
if (Build.VERSION.SDK_INT < 22) {
|
||||
return new LinkedList<>();
|
||||
}
|
||||
|
||||
List<SubscriptionInfo> subscriptionInfos = SubscriptionManager.from(context).getActiveSubscriptionInfoList();
|
||||
|
||||
if (subscriptionInfos == null || subscriptionInfos.isEmpty()) {
|
||||
return new LinkedList<>();
|
||||
}
|
||||
|
||||
List<SubscriptionInfoCompat> compatList = new LinkedList<>();
|
||||
|
||||
for (SubscriptionInfo subscriptionInfo : subscriptionInfos) {
|
||||
compatList.add(new SubscriptionInfoCompat(subscriptionInfo.getSubscriptionId(),
|
||||
subscriptionInfo.getDisplayName()));
|
||||
}
|
||||
|
||||
return compatList;
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user