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:
Moxie Marlinspike
2016-02-05 16:10:33 -08:00
parent c1106d98dd
commit 6da86e482d
53 changed files with 727 additions and 281 deletions

View File

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