mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 00:59:49 +01:00
Added ability to share contacts.
The "contact" option in the attachments tray now brings you through an optimized contact sharing flow, allowing you to select specific fields to share. The contact is then presented as a special message type, allowing you to interact with the card to add the contact to your system contacts, invite them to signal, initiate a signal message, etc.
This commit is contained in:
@@ -86,6 +86,7 @@ import org.thoughtcrime.securesms.components.camera.QuickAttachmentDrawer;
|
||||
import org.thoughtcrime.securesms.components.camera.QuickAttachmentDrawer.AttachmentDrawerListener;
|
||||
import org.thoughtcrime.securesms.components.camera.QuickAttachmentDrawer.DrawerState;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiDrawer;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiStrings;
|
||||
import org.thoughtcrime.securesms.components.identity.UntrustedSendDialog;
|
||||
import org.thoughtcrime.securesms.components.identity.UnverifiedBannerView;
|
||||
import org.thoughtcrime.securesms.components.identity.UnverifiedSendDialog;
|
||||
@@ -96,6 +97,9 @@ import org.thoughtcrime.securesms.components.reminder.ReminderView;
|
||||
import org.thoughtcrime.securesms.components.reminder.UnauthorizedReminder;
|
||||
import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
||||
import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData;
|
||||
import org.thoughtcrime.securesms.contactshare.Contact;
|
||||
import org.thoughtcrime.securesms.contactshare.ContactShareEditActivity;
|
||||
import org.thoughtcrime.securesms.contactshare.ContactUtil;
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
|
||||
import org.thoughtcrime.securesms.crypto.SecurityEvent;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
@@ -142,12 +146,12 @@ import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.scribbles.ScribbleActivity;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.thoughtcrime.securesms.service.WebRtcCallService;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||
import org.thoughtcrime.securesms.util.CharacterCalculator.CharacterState;
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions;
|
||||
import org.thoughtcrime.securesms.util.Dialogs;
|
||||
import org.thoughtcrime.securesms.util.DirectoryHelper;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
@@ -170,6 +174,7 @@ import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import java.io.IOException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@@ -206,16 +211,17 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
public static final String TIMING_EXTRA = "timing";
|
||||
public static final String LAST_SEEN_EXTRA = "last_seen";
|
||||
|
||||
private static final int PICK_GALLERY = 1;
|
||||
private static final int PICK_DOCUMENT = 2;
|
||||
private static final int PICK_AUDIO = 3;
|
||||
private static final int PICK_CONTACT_INFO = 4;
|
||||
private static final int GROUP_EDIT = 5;
|
||||
private static final int TAKE_PHOTO = 6;
|
||||
private static final int ADD_CONTACT = 7;
|
||||
private static final int PICK_LOCATION = 8;
|
||||
private static final int PICK_GIF = 9;
|
||||
private static final int SMS_DEFAULT = 10;
|
||||
private static final int PICK_GALLERY = 1;
|
||||
private static final int PICK_DOCUMENT = 2;
|
||||
private static final int PICK_AUDIO = 3;
|
||||
private static final int PICK_CONTACT = 4;
|
||||
private static final int GET_CONTACT_DETAILS = 5;
|
||||
private static final int GROUP_EDIT = 6;
|
||||
private static final int TAKE_PHOTO = 7;
|
||||
private static final int ADD_CONTACT = 8;
|
||||
private static final int PICK_LOCATION = 9;
|
||||
private static final int PICK_GIF = 10;
|
||||
private static final int SMS_DEFAULT = 11;
|
||||
|
||||
private GlideRequests glideRequests;
|
||||
protected ComposeText composeText;
|
||||
@@ -419,8 +425,15 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
case PICK_AUDIO:
|
||||
setMedia(data.getData(), MediaType.AUDIO);
|
||||
break;
|
||||
case PICK_CONTACT_INFO:
|
||||
addAttachmentContactInfo(data.getData());
|
||||
case PICK_CONTACT:
|
||||
if (isSecureText && !isSmsForced()) {
|
||||
openContactShareEditor(data.getData());
|
||||
} else {
|
||||
addAttachmentContactInfo(data.getData());
|
||||
}
|
||||
break;
|
||||
case GET_CONTACT_DETAILS:
|
||||
sendSharedContact(data.getParcelableArrayListExtra(ContactShareEditActivity.KEY_CONTACTS));
|
||||
break;
|
||||
case GROUP_EDIT:
|
||||
recipient = Recipient.from(this, data.getParcelableExtra(GroupCreateActivity.GROUP_ADDRESS_EXTRA), true);
|
||||
@@ -770,7 +783,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
.setType(GroupContext.Type.QUIT)
|
||||
.build();
|
||||
|
||||
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(getRecipient(), context, null, System.currentTimeMillis(), 0, null);
|
||||
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(getRecipient(), context, null, System.currentTimeMillis(), 0, null, Collections.emptyList());
|
||||
MessageSender.send(self, outgoingMessage, threadId, false, null);
|
||||
DatabaseFactory.getGroupDatabase(self).remove(groupId, Address.fromSerialized(TextSecurePreferences.getLocalNumber(self)));
|
||||
initializeEnabledCheck();
|
||||
@@ -826,23 +839,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
if (recipient == null) return;
|
||||
|
||||
if (isSecureText) {
|
||||
Permissions.with(ConversationActivity.this)
|
||||
.request(Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA)
|
||||
.ifNecessary()
|
||||
.withRationaleDialog(getString(R.string.ConversationActivity_to_call_s_signal_needs_access_to_your_microphone_and_camera, recipient.toShortString()),
|
||||
R.drawable.ic_mic_white_48dp, R.drawable.ic_videocam_white_48dp)
|
||||
.withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_needs_the_microphone_and_camera_permissions_in_order_to_call_s, recipient.toShortString()))
|
||||
.onAllGranted(() -> {
|
||||
Intent intent = new Intent(this, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_OUTGOING_CALL);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, recipient.getAddress());
|
||||
startService(intent);
|
||||
|
||||
Intent activityIntent = new Intent(this, WebRtcCallActivity.class);
|
||||
activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(activityIntent);
|
||||
})
|
||||
.execute();
|
||||
CommunicationActions.startVoiceCall(this, recipient);
|
||||
} else {
|
||||
try {
|
||||
Intent dialIntent = new Intent(Intent.ACTION_DIAL,
|
||||
@@ -1378,7 +1375,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
case AttachmentTypeSelector.ADD_SOUND:
|
||||
AttachmentManager.selectAudio(this, PICK_AUDIO); break;
|
||||
case AttachmentTypeSelector.ADD_CONTACT_INFO:
|
||||
AttachmentManager.selectContactInfo(this, PICK_CONTACT_INFO); break;
|
||||
AttachmentManager.selectContactInfo(this, PICK_CONTACT); break;
|
||||
case AttachmentTypeSelector.ADD_LOCATION:
|
||||
AttachmentManager.selectLocation(this, PICK_LOCATION); break;
|
||||
case AttachmentTypeSelector.TAKE_PHOTO:
|
||||
@@ -1397,6 +1394,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
attachmentManager.setMedia(glideRequests, uri, mediaType, getCurrentMediaConstraints(), width, height);
|
||||
}
|
||||
|
||||
private void openContactShareEditor(Uri contactUri) {
|
||||
long id = ContactUtil.getContactIdFromUri(contactUri);
|
||||
Intent intent = ContactShareEditActivity.getIntent(this, Collections.singletonList(id));
|
||||
startActivityForResult(intent, GET_CONTACT_DETAILS);
|
||||
}
|
||||
|
||||
private void addAttachmentContactInfo(Uri contactUri) {
|
||||
ContactAccessor contactDataList = ContactAccessor.getInstance();
|
||||
ContactData contactData = contactDataList.getContactData(this, contactUri);
|
||||
@@ -1405,6 +1408,14 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
else if (contactData.numbers.size() > 1) selectContactInfo(contactData);
|
||||
}
|
||||
|
||||
private void sendSharedContact(List<Contact> contacts) {
|
||||
int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().or(-1);
|
||||
long expiresIn = recipient.getExpireMessages() * 1000L;
|
||||
boolean initiating = threadId == -1;
|
||||
|
||||
sendMediaMessage(isSmsForced(), "", attachmentManager.buildSlideDeck(), contacts, expiresIn, subscriptionId, initiating);
|
||||
}
|
||||
|
||||
private void selectContactInfo(ContactData contactData) {
|
||||
final CharSequence[] numbers = new CharSequence[contactData.numbers.size()];
|
||||
final CharSequence[] numberItems = new CharSequence[contactData.numbers.size()];
|
||||
@@ -1572,6 +1583,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
return getRecipient() != null && getRecipient().isPushGroupRecipient();
|
||||
}
|
||||
|
||||
private boolean isSmsForced() {
|
||||
return sendButton.isManualSelection() && sendButton.getSelectedTransport().isSms();
|
||||
}
|
||||
|
||||
protected Recipient getRecipient() {
|
||||
return this.recipient;
|
||||
}
|
||||
@@ -1682,11 +1697,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
throws InvalidMessageException
|
||||
{
|
||||
Log.w(TAG, "Sending media message...");
|
||||
sendMediaMessage(forceSms, getMessage(), attachmentManager.buildSlideDeck(), expiresIn, subscriptionId, initiating);
|
||||
sendMediaMessage(forceSms, getMessage(), attachmentManager.buildSlideDeck(), Collections.emptyList(), expiresIn, subscriptionId, initiating);
|
||||
}
|
||||
|
||||
private ListenableFuture<Void> sendMediaMessage(final boolean forceSms, String body, SlideDeck slideDeck, final long expiresIn, final int subscriptionId, final boolean initiating) {
|
||||
OutgoingMediaMessage outgoingMessageCandidate = new OutgoingMediaMessage(recipient, slideDeck, body, System.currentTimeMillis(), subscriptionId, expiresIn, distributionType, inputPanel.getQuote().orNull());
|
||||
private ListenableFuture<Void> sendMediaMessage(final boolean forceSms, String body, SlideDeck slideDeck, List<Contact> contacts, final long expiresIn, final int subscriptionId, final boolean initiating) {
|
||||
OutgoingMediaMessage outgoingMessageCandidate = new OutgoingMediaMessage(recipient, slideDeck, body, System.currentTimeMillis(), subscriptionId, expiresIn, distributionType, inputPanel.getQuote().orNull(), contacts);
|
||||
|
||||
final SettableFuture<Void> future = new SettableFuture<>();
|
||||
final Context context = getApplicationContext();
|
||||
@@ -1871,7 +1886,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
SlideDeck slideDeck = new SlideDeck();
|
||||
slideDeck.addSlide(audioSlide);
|
||||
|
||||
sendMediaMessage(forceSms, "", slideDeck, expiresIn, subscriptionId, initiating).addListener(new AssertedSuccessListener<Void>() {
|
||||
sendMediaMessage(forceSms, "", slideDeck, Collections.emptyList(), expiresIn, subscriptionId, initiating).addListener(new AssertedSuccessListener<Void>() {
|
||||
@Override
|
||||
public void onSuccess(Void nothing) {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@@ -2072,11 +2087,28 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
author = messageRecord.getIndividualRecipient();
|
||||
}
|
||||
|
||||
inputPanel.setQuote(GlideApp.with(this),
|
||||
messageRecord.getDateSent(),
|
||||
author,
|
||||
messageRecord.getBody(),
|
||||
messageRecord.isMms() ? ((MmsMessageRecord)messageRecord).getSlideDeck() : new SlideDeck());
|
||||
if (messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getSharedContacts().isEmpty()) {
|
||||
Contact contact = ((MmsMessageRecord) messageRecord).getSharedContacts().get(0);
|
||||
String displayName = ContactUtil.getDisplayName(contact);
|
||||
String body = getString(R.string.ConversationActivity_quoted_contact_message, EmojiStrings.BUST_IN_SILHOUETTE, displayName);
|
||||
SlideDeck slideDeck = new SlideDeck();
|
||||
|
||||
if (contact.getAvatarAttachment() != null) {
|
||||
slideDeck.addSlide(MediaUtil.getSlideForAttachment(this, contact.getAvatarAttachment()));
|
||||
}
|
||||
|
||||
inputPanel.setQuote(GlideApp.with(this),
|
||||
messageRecord.getDateSent(),
|
||||
author,
|
||||
body,
|
||||
slideDeck);
|
||||
} else {
|
||||
inputPanel.setQuote(GlideApp.with(this),
|
||||
messageRecord.getDateSent(),
|
||||
author,
|
||||
messageRecord.getBody(),
|
||||
messageRecord.isMms() ? ((MmsMessageRecord) messageRecord).getSlideDeck() : new SlideDeck());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user