mirror of
https://github.com/oxen-io/session-android.git
synced 2025-04-16 10:31:28 +00:00
Convert vCard attachments to Shared Contacts.
When you share a vCard from an external app (like the Contacts app) into Signal, we'll now convert it to a pretty Shared Contact message and allow you to choose which fields of the contact you wish to send.
This commit is contained in:
parent
e6c16cf28d
commit
ca260a92e3
@ -120,6 +120,10 @@ dependencies {
|
|||||||
compile 'com.codewaves.stickyheadergrid:stickyheadergrid:0.9.4'
|
compile 'com.codewaves.stickyheadergrid:stickyheadergrid:0.9.4'
|
||||||
compile 'com.github.dmytrodanylyk.circular-progress-button:library:1.1.3-S2'
|
compile 'com.github.dmytrodanylyk.circular-progress-button:library:1.1.3-S2'
|
||||||
compile 'net.zetetic:android-database-sqlcipher:3.5.9'
|
compile 'net.zetetic:android-database-sqlcipher:3.5.9'
|
||||||
|
compile ('com.googlecode.ez-vcard:ez-vcard:0.9.11') {
|
||||||
|
exclude group: 'com.fasterxml.jackson.core'
|
||||||
|
exclude group: 'org.freemarker'
|
||||||
|
}
|
||||||
|
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
testCompile 'org.assertj:assertj-core:1.7.1'
|
testCompile 'org.assertj:assertj-core:1.7.1'
|
||||||
@ -306,6 +310,7 @@ android {
|
|||||||
'proguard-klinker.pro',
|
'proguard-klinker.pro',
|
||||||
'proguard-retrolambda.pro',
|
'proguard-retrolambda.pro',
|
||||||
'proguard-okhttp.pro',
|
'proguard-okhttp.pro',
|
||||||
|
'proguard-ez-vcard.pro',
|
||||||
'proguard.cfg'
|
'proguard.cfg'
|
||||||
testProguardFiles 'proguard-automation.pro',
|
testProguardFiles 'proguard-automation.pro',
|
||||||
'proguard.cfg'
|
'proguard.cfg'
|
||||||
|
1
proguard-ez-vcard.pro
Normal file
1
proguard-ez-vcard.pro
Normal file
@ -0,0 +1 @@
|
|||||||
|
-dontwarn ezvcard.io.html.HCardPage
|
@ -1391,12 +1391,16 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
private void setMedia(@Nullable Uri uri, @NonNull MediaType mediaType, int width, int height) {
|
private void setMedia(@Nullable Uri uri, @NonNull MediaType mediaType, int width, int height) {
|
||||||
if (uri == null) return;
|
if (uri == null) return;
|
||||||
attachmentManager.setMedia(glideRequests, uri, mediaType, getCurrentMediaConstraints(), width, height);
|
|
||||||
|
if (MediaType.VCARD.equals(mediaType) && isSecureText) {
|
||||||
|
openContactShareEditor(uri);
|
||||||
|
} else {
|
||||||
|
attachmentManager.setMedia(glideRequests, uri, mediaType, getCurrentMediaConstraints(), width, height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openContactShareEditor(Uri contactUri) {
|
private void openContactShareEditor(Uri contactUri) {
|
||||||
long id = ContactUtil.getContactIdFromUri(contactUri);
|
Intent intent = ContactShareEditActivity.getIntent(this, Collections.singletonList(contactUri));
|
||||||
Intent intent = ContactShareEditActivity.getIntent(this, Collections.singletonList(id));
|
|
||||||
startActivityForResult(intent, GET_CONTACT_DETAILS);
|
startActivityForResult(intent, GET_CONTACT_DETAILS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,8 +17,12 @@ import org.thoughtcrime.securesms.contactshare.Contact.Name;
|
|||||||
import org.thoughtcrime.securesms.contactshare.Contact.Phone;
|
import org.thoughtcrime.securesms.contactshare.Contact.Phone;
|
||||||
import org.thoughtcrime.securesms.contactshare.Contact.PostalAddress;
|
import org.thoughtcrime.securesms.contactshare.Contact.PostalAddress;
|
||||||
import org.thoughtcrime.securesms.database.Address;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
|
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||||
|
import org.thoughtcrime.securesms.providers.PersistentBlobProvider;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -26,6 +30,9 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import ezvcard.Ezvcard;
|
||||||
|
import ezvcard.VCard;
|
||||||
|
|
||||||
import static org.thoughtcrime.securesms.contactshare.Contact.*;
|
import static org.thoughtcrime.securesms.contactshare.Contact.*;
|
||||||
|
|
||||||
public class ContactRepository {
|
public class ContactRepository {
|
||||||
@ -45,11 +52,18 @@ public class ContactRepository {
|
|||||||
this.contactsDatabase = contactsDatabase;
|
this.contactsDatabase = contactsDatabase;
|
||||||
}
|
}
|
||||||
|
|
||||||
void getContacts(@NonNull List<Long> contactIds, @NonNull ValueCallback<List<Contact>> callback) {
|
void getContacts(@NonNull List<Uri> contactUris, @NonNull ValueCallback<List<Contact>> callback) {
|
||||||
executor.execute(() -> {
|
executor.execute(() -> {
|
||||||
List<Contact> contacts = new ArrayList<>(contactIds.size());
|
List<Contact> contacts = new ArrayList<>(contactUris.size());
|
||||||
for (long id : contactIds) {
|
for (Uri contactUri : contactUris) {
|
||||||
Contact contact = getContact(id);
|
Contact contact;
|
||||||
|
|
||||||
|
if (ContactsContract.AUTHORITY.equals(contactUri.getAuthority())) {
|
||||||
|
contact = getContactFromSystemContacts(ContactUtil.getContactIdFromUri(contactUri));
|
||||||
|
} else {
|
||||||
|
contact = getContactFromVcard(contactUri);
|
||||||
|
}
|
||||||
|
|
||||||
if (contact != null) {
|
if (contact != null) {
|
||||||
contacts.add(contact);
|
contacts.add(contact);
|
||||||
}
|
}
|
||||||
@ -59,7 +73,7 @@ public class ContactRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
private @Nullable Contact getContact(long contactId) {
|
private @Nullable Contact getContactFromSystemContacts(long contactId) {
|
||||||
Name name = getName(contactId);
|
Name name = getName(contactId);
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
Log.w(TAG, "Couldn't find a name associated with the provided contact ID.");
|
Log.w(TAG, "Couldn't find a name associated with the provided contact ID.");
|
||||||
@ -73,6 +87,79 @@ public class ContactRepository {
|
|||||||
return new Contact(name, null, phoneNumbers, getEmails(contactId), getPostalAddresses(contactId), avatar);
|
return new Contact(name, null, phoneNumbers, getEmails(contactId), getPostalAddresses(contactId), avatar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
private @Nullable Contact getContactFromVcard(@NonNull Uri uri) {
|
||||||
|
Contact contact = null;
|
||||||
|
|
||||||
|
try (InputStream stream = PartAuthority.getAttachmentStream(context, uri)) {
|
||||||
|
VCard vcard = Ezvcard.parse(stream).first();
|
||||||
|
|
||||||
|
ezvcard.property.StructuredName vName = vcard.getStructuredName();
|
||||||
|
List<ezvcard.property.Telephone> vPhones = vcard.getTelephoneNumbers();
|
||||||
|
List<ezvcard.property.Email> vEmails = vcard.getEmails();
|
||||||
|
List<ezvcard.property.Address> vPostalAddresses = vcard.getAddresses();
|
||||||
|
|
||||||
|
String organization = vcard.getOrganization() != null && !vcard.getOrganization().getValues().isEmpty() ? vcard.getOrganization().getValues().get(0) : null;
|
||||||
|
String displayName = vcard.getFormattedName() != null ? vcard.getFormattedName().getValue() : null;
|
||||||
|
|
||||||
|
if (displayName == null && vName != null) {
|
||||||
|
displayName = vName.getGiven();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayName == null && vcard.getOrganization() != null) {
|
||||||
|
displayName = organization;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayName == null) {
|
||||||
|
throw new IOException("No valid name.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Name name = new Name(displayName,
|
||||||
|
vName != null ? vName.getGiven() : null,
|
||||||
|
vName != null ? vName.getFamily() : null,
|
||||||
|
vName != null && !vName.getPrefixes().isEmpty() ? vName.getPrefixes().get(0) : null,
|
||||||
|
vName != null && !vName.getSuffixes().isEmpty() ? vName.getSuffixes().get(0) : null,
|
||||||
|
null);
|
||||||
|
|
||||||
|
|
||||||
|
List<Phone> phoneNumbers = new ArrayList<>(vPhones.size());
|
||||||
|
for (ezvcard.property.Telephone vEmail : vPhones) {
|
||||||
|
String label = !vEmail.getTypes().isEmpty() ? getCleanedVcardType(vEmail.getTypes().get(0).getValue()) : null;
|
||||||
|
phoneNumbers.add(new Phone(vEmail.getText(), phoneTypeFromVcardType(label), label));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Email> emails = new ArrayList<>(vEmails.size());
|
||||||
|
for (ezvcard.property.Email vEmail : vEmails) {
|
||||||
|
String label = !vEmail.getTypes().isEmpty() ? getCleanedVcardType(vEmail.getTypes().get(0).getValue()) : null;
|
||||||
|
emails.add(new Email(vEmail.getValue(), emailTypeFromVcardType(label), label));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<PostalAddress> postalAddresses = new ArrayList<>(vPostalAddresses.size());
|
||||||
|
for (ezvcard.property.Address vPostalAddress : vPostalAddresses) {
|
||||||
|
String label = !vPostalAddress.getTypes().isEmpty() ? getCleanedVcardType(vPostalAddress.getTypes().get(0).getValue()) : null;
|
||||||
|
postalAddresses.add(new PostalAddress(postalAddressTypeFromVcardType(label),
|
||||||
|
label,
|
||||||
|
vPostalAddress.getStreetAddress(),
|
||||||
|
vPostalAddress.getPoBox(),
|
||||||
|
null,
|
||||||
|
vPostalAddress.getLocality(),
|
||||||
|
vPostalAddress.getRegion(),
|
||||||
|
vPostalAddress.getPostalCode(),
|
||||||
|
vPostalAddress.getCountry()));
|
||||||
|
}
|
||||||
|
|
||||||
|
contact = new Contact(name, organization, phoneNumbers, emails, postalAddresses, null);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, "Failed to parse the vcard.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PersistentBlobProvider.AUTHORITY.equals(uri.getAuthority())) {
|
||||||
|
PersistentBlobProvider.getInstance(context).delete(context, uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
return contact;
|
||||||
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
private @Nullable Name getName(long contactId) {
|
private @Nullable Name getName(long contactId) {
|
||||||
try (Cursor cursor = contactsDatabase.getNameDetails(contactId)) {
|
try (Cursor cursor = contactsDatabase.getNameDetails(contactId)) {
|
||||||
@ -225,6 +312,13 @@ public class ContactRepository {
|
|||||||
return Phone.Type.CUSTOM;
|
return Phone.Type.CUSTOM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Phone.Type phoneTypeFromVcardType(@Nullable String type) {
|
||||||
|
if ("home".equalsIgnoreCase(type)) return Phone.Type.HOME;
|
||||||
|
else if ("cell".equalsIgnoreCase(type)) return Phone.Type.MOBILE;
|
||||||
|
else if ("work".equalsIgnoreCase(type)) return Phone.Type.WORK;
|
||||||
|
else return Phone.Type.CUSTOM;
|
||||||
|
}
|
||||||
|
|
||||||
private Email.Type emailTypeFromContactType(int type) {
|
private Email.Type emailTypeFromContactType(int type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ContactsContract.CommonDataKinds.Email.TYPE_HOME:
|
case ContactsContract.CommonDataKinds.Email.TYPE_HOME:
|
||||||
@ -237,6 +331,13 @@ public class ContactRepository {
|
|||||||
return Email.Type.CUSTOM;
|
return Email.Type.CUSTOM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Email.Type emailTypeFromVcardType(@Nullable String type) {
|
||||||
|
if ("home".equalsIgnoreCase(type)) return Email.Type.HOME;
|
||||||
|
else if ("cell".equalsIgnoreCase(type)) return Email.Type.MOBILE;
|
||||||
|
else if ("work".equalsIgnoreCase(type)) return Email.Type.WORK;
|
||||||
|
else return Email.Type.CUSTOM;
|
||||||
|
}
|
||||||
|
|
||||||
private PostalAddress.Type postalAddressTypeFromContactType(int type) {
|
private PostalAddress.Type postalAddressTypeFromContactType(int type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME:
|
case ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME:
|
||||||
@ -247,6 +348,22 @@ public class ContactRepository {
|
|||||||
return PostalAddress.Type.CUSTOM;
|
return PostalAddress.Type.CUSTOM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PostalAddress.Type postalAddressTypeFromVcardType(@Nullable String type) {
|
||||||
|
if ("home".equalsIgnoreCase(type)) return PostalAddress.Type.HOME;
|
||||||
|
else if ("work".equalsIgnoreCase(type)) return PostalAddress.Type.WORK;
|
||||||
|
else return PostalAddress.Type.CUSTOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getCleanedVcardType(@Nullable String type) {
|
||||||
|
if (TextUtils.isEmpty(type)) return "";
|
||||||
|
|
||||||
|
if (type.startsWith("x-") && type.length() > 2) {
|
||||||
|
return type.substring(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
interface ValueCallback<T> {
|
interface ValueCallback<T> {
|
||||||
void onComplete(@NonNull T value);
|
void onComplete(@NonNull T value);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import android.app.Activity;
|
|||||||
import android.arch.lifecycle.ViewModelProviders;
|
import android.arch.lifecycle.ViewModelProviders;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
@ -30,20 +31,20 @@ import static org.thoughtcrime.securesms.contactshare.ContactShareEditViewModel.
|
|||||||
|
|
||||||
public class ContactShareEditActivity extends PassphraseRequiredActionBarActivity implements ContactShareEditAdapter.EventListener {
|
public class ContactShareEditActivity extends PassphraseRequiredActionBarActivity implements ContactShareEditAdapter.EventListener {
|
||||||
|
|
||||||
public static final String KEY_CONTACTS = "contacts";
|
public static final String KEY_CONTACTS = "contacts";
|
||||||
private static final String KEY_CONTACT_IDS = "ids";
|
private static final String KEY_CONTACT_URIS = "contact_uris";
|
||||||
private static final int CODE_NAME_EDIT = 55;
|
private static final int CODE_NAME_EDIT = 55;
|
||||||
|
|
||||||
private final DynamicTheme dynamicTheme = new DynamicTheme();
|
private final DynamicTheme dynamicTheme = new DynamicTheme();
|
||||||
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||||
|
|
||||||
private ContactShareEditViewModel viewModel;
|
private ContactShareEditViewModel viewModel;
|
||||||
|
|
||||||
public static Intent getIntent(@NonNull Context context, @NonNull List<Long> contactIds) {
|
public static Intent getIntent(@NonNull Context context, @NonNull List<Uri> contactUris) {
|
||||||
ArrayList<String> serializedIds = new ArrayList<>(Stream.of(contactIds).map(String::valueOf).toList());
|
ArrayList<Uri> contactUriList = new ArrayList<>(contactUris);
|
||||||
|
|
||||||
Intent intent = new Intent(context, ContactShareEditActivity.class);
|
Intent intent = new Intent(context, ContactShareEditActivity.class);
|
||||||
intent.putStringArrayListExtra(KEY_CONTACT_IDS, serializedIds);
|
intent.putParcelableArrayListExtra(KEY_CONTACT_URIS, contactUriList);
|
||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,13 +62,11 @@ public class ContactShareEditActivity extends PassphraseRequiredActionBarActivit
|
|||||||
throw new IllegalStateException("You must supply extras to this activity. Please use the #getIntent() method.");
|
throw new IllegalStateException("You must supply extras to this activity. Please use the #getIntent() method.");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> serializedIds = getIntent().getStringArrayListExtra(KEY_CONTACT_IDS);
|
List<Uri> contactUris = getIntent().getParcelableArrayListExtra(KEY_CONTACT_URIS);
|
||||||
if (serializedIds == null) {
|
if (contactUris == null) {
|
||||||
throw new IllegalStateException("You must supply contact ID's to this activity. Please use the #getIntent() method.");
|
throw new IllegalStateException("You must supply contact Uri's to this activity. Please use the #getIntent() method.");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Long> contactIds = Stream.of(serializedIds).map(Long::parseLong).toList();
|
|
||||||
|
|
||||||
View sendButton = findViewById(R.id.contact_share_edit_send);
|
View sendButton = findViewById(R.id.contact_share_edit_send);
|
||||||
sendButton.setOnClickListener(v -> onSendClicked(viewModel.getFinalizedContacts()));
|
sendButton.setOnClickListener(v -> onSendClicked(viewModel.getFinalizedContacts()));
|
||||||
|
|
||||||
@ -82,7 +81,7 @@ public class ContactShareEditActivity extends PassphraseRequiredActionBarActivit
|
|||||||
AsyncTask.THREAD_POOL_EXECUTOR,
|
AsyncTask.THREAD_POOL_EXECUTOR,
|
||||||
DatabaseFactory.getContactsDatabase(this));
|
DatabaseFactory.getContactsDatabase(this));
|
||||||
|
|
||||||
viewModel = ViewModelProviders.of(this, new Factory(contactIds, contactRepository)).get(ContactShareEditViewModel.class);
|
viewModel = ViewModelProviders.of(this, new Factory(contactUris, contactRepository)).get(ContactShareEditViewModel.class);
|
||||||
viewModel.getContacts().observe(this, contacts -> {
|
viewModel.getContacts().observe(this, contacts -> {
|
||||||
contactAdapter.setContacts(contacts);
|
contactAdapter.setContacts(contacts);
|
||||||
contactList.post(() -> contactList.scrollToPosition(0));
|
contactList.post(() -> contactList.scrollToPosition(0));
|
||||||
|
@ -4,6 +4,7 @@ import android.arch.lifecycle.LiveData;
|
|||||||
import android.arch.lifecycle.MutableLiveData;
|
import android.arch.lifecycle.MutableLiveData;
|
||||||
import android.arch.lifecycle.ViewModel;
|
import android.arch.lifecycle.ViewModel;
|
||||||
import android.arch.lifecycle.ViewModelProvider;
|
import android.arch.lifecycle.ViewModelProvider;
|
||||||
|
import android.net.Uri;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
@ -20,14 +21,14 @@ class ContactShareEditViewModel extends ViewModel {
|
|||||||
private final SingleLiveEvent<Event> events;
|
private final SingleLiveEvent<Event> events;
|
||||||
private final ContactRepository repo;
|
private final ContactRepository repo;
|
||||||
|
|
||||||
ContactShareEditViewModel(@NonNull List<Long> contactIds,
|
ContactShareEditViewModel(@NonNull List<Uri> contactUris,
|
||||||
@NonNull ContactRepository contactRepository)
|
@NonNull ContactRepository contactRepository)
|
||||||
{
|
{
|
||||||
contacts = new MutableLiveData<>();
|
contacts = new MutableLiveData<>();
|
||||||
events = new SingleLiveEvent<>();
|
events = new SingleLiveEvent<>();
|
||||||
repo = contactRepository;
|
repo = contactRepository;
|
||||||
|
|
||||||
repo.getContacts(contactIds, retrieved -> {
|
repo.getContacts(contactUris, retrieved -> {
|
||||||
if (retrieved.isEmpty()) {
|
if (retrieved.isEmpty()) {
|
||||||
events.postValue(Event.BAD_CONTACT);
|
events.postValue(Event.BAD_CONTACT);
|
||||||
} else {
|
} else {
|
||||||
@ -96,17 +97,17 @@ class ContactShareEditViewModel extends ViewModel {
|
|||||||
|
|
||||||
static class Factory extends ViewModelProvider.NewInstanceFactory {
|
static class Factory extends ViewModelProvider.NewInstanceFactory {
|
||||||
|
|
||||||
private final List<Long> contactIds;
|
private final List<Uri> contactUris;
|
||||||
private final ContactRepository contactRepository;
|
private final ContactRepository contactRepository;
|
||||||
|
|
||||||
Factory(@NonNull List<Long> contactIds, @NonNull ContactRepository contactRepository) {
|
Factory(@NonNull List<Uri> contactUris, @NonNull ContactRepository contactRepository) {
|
||||||
this.contactIds = contactIds;
|
this.contactUris = contactUris;
|
||||||
this.contactRepository = contactRepository;
|
this.contactRepository = contactRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
|
public @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
|
||||||
return modelClass.cast(new ContactShareEditViewModel(contactIds, contactRepository));
|
return modelClass.cast(new ContactShareEditViewModel(contactUris, contactRepository));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -508,7 +508,7 @@ public class AttachmentManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum MediaType {
|
public enum MediaType {
|
||||||
IMAGE, GIF, AUDIO, VIDEO, DOCUMENT;
|
IMAGE, GIF, AUDIO, VIDEO, DOCUMENT, VCARD;
|
||||||
|
|
||||||
public @NonNull Slide createSlide(@NonNull Context context,
|
public @NonNull Slide createSlide(@NonNull Context context,
|
||||||
@NonNull Uri uri,
|
@NonNull Uri uri,
|
||||||
@ -527,6 +527,7 @@ public class AttachmentManager {
|
|||||||
case GIF: return new GifSlide(context, uri, dataSize, width, height);
|
case GIF: return new GifSlide(context, uri, dataSize, width, height);
|
||||||
case AUDIO: return new AudioSlide(context, uri, dataSize, false);
|
case AUDIO: return new AudioSlide(context, uri, dataSize, false);
|
||||||
case VIDEO: return new VideoSlide(context, uri, dataSize);
|
case VIDEO: return new VideoSlide(context, uri, dataSize);
|
||||||
|
case VCARD:
|
||||||
case DOCUMENT: return new DocumentSlide(context, uri, mimeType, dataSize, fileName);
|
case DOCUMENT: return new DocumentSlide(context, uri, mimeType, dataSize, fileName);
|
||||||
default: throw new AssertionError("unrecognized enum");
|
default: throw new AssertionError("unrecognized enum");
|
||||||
}
|
}
|
||||||
@ -538,6 +539,7 @@ public class AttachmentManager {
|
|||||||
if (MediaUtil.isImageType(mimeType)) return IMAGE;
|
if (MediaUtil.isImageType(mimeType)) return IMAGE;
|
||||||
if (MediaUtil.isAudioType(mimeType)) return AUDIO;
|
if (MediaUtil.isAudioType(mimeType)) return AUDIO;
|
||||||
if (MediaUtil.isVideoType(mimeType)) return VIDEO;
|
if (MediaUtil.isVideoType(mimeType)) return VIDEO;
|
||||||
|
if (MediaUtil.isVcard(mimeType)) return VCARD;
|
||||||
|
|
||||||
return DOCUMENT;
|
return DOCUMENT;
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ public class MediaUtil {
|
|||||||
public static final String AUDIO_AAC = "audio/aac";
|
public static final String AUDIO_AAC = "audio/aac";
|
||||||
public static final String AUDIO_UNSPECIFIED = "audio/*";
|
public static final String AUDIO_UNSPECIFIED = "audio/*";
|
||||||
public static final String VIDEO_UNSPECIFIED = "video/*";
|
public static final String VIDEO_UNSPECIFIED = "video/*";
|
||||||
|
public static final String VCARD = "text/x-vcard";
|
||||||
|
|
||||||
|
|
||||||
public static Slide getSlideForAttachment(Context context, Attachment attachment) {
|
public static Slide getSlideForAttachment(Context context, Attachment attachment) {
|
||||||
@ -196,6 +197,10 @@ public class MediaUtil {
|
|||||||
return !TextUtils.isEmpty(contentType) && contentType.trim().startsWith("video/");
|
return !TextUtils.isEmpty(contentType) && contentType.trim().startsWith("video/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isVcard(String contentType) {
|
||||||
|
return !TextUtils.isEmpty(contentType) && contentType.trim().equals(VCARD);
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isGif(String contentType) {
|
public static boolean isGif(String contentType) {
|
||||||
return !TextUtils.isEmpty(contentType) && contentType.trim().equals("image/gif");
|
return !TextUtils.isEmpty(contentType) && contentType.trim().equals("image/gif");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user