Unused code cleanup.

This commit is contained in:
Anton Chekulaev
2020-12-02 23:01:04 +11:00
parent 12804a30c0
commit 5e3cb706c4
55 changed files with 45 additions and 5681 deletions

View File

@@ -1,227 +0,0 @@
package org.thoughtcrime.securesms.contactshare;
import android.content.Context;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import com.annimon.stream.Stream;
import network.loki.messenger.R;
import org.thoughtcrime.securesms.contactshare.Contact.Phone;
import org.thoughtcrime.securesms.mms.GlideRequests;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import static org.thoughtcrime.securesms.contactshare.Contact.*;
class ContactFieldAdapter extends RecyclerView.Adapter<ContactFieldAdapter.ContactFieldViewHolder> {
private final Locale locale;
private final boolean selectable;
private final List<Field> fields;
private final GlideRequests glideRequests;
public ContactFieldAdapter(@NonNull Locale locale, @NonNull GlideRequests glideRequests, boolean selectable) {
this.locale = locale;
this.glideRequests = glideRequests;
this.selectable = selectable;
this.fields = new ArrayList<>();
}
@Override
public @NonNull ContactFieldViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ContactFieldViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_selectable_contact_field, parent, false));
}
@Override
public void onBindViewHolder(@NonNull ContactFieldViewHolder holder, int position) {
holder.bind(fields.get(position), glideRequests, selectable);
}
@Override
public void onViewRecycled(@NonNull ContactFieldViewHolder holder) {
holder.recycle();
}
@Override
public int getItemCount() {
return fields.size();
}
void setFields(@NonNull Context context,
@Nullable Avatar avatar,
@NonNull List<Phone> phoneNumbers,
@NonNull List<Email> emails,
@NonNull List<PostalAddress> postalAddresses)
{
fields.clear();
if (avatar != null) {
fields.add(new Field(avatar));
}
fields.addAll(Stream.of(phoneNumbers).map(phone -> new Field(context, phone, locale)).toList());
fields.addAll(Stream.of(emails).map(email -> new Field(context, email)).toList());
fields.addAll(Stream.of(postalAddresses).map(address -> new Field(context, address)).toList());
notifyDataSetChanged();
}
static class ContactFieldViewHolder extends RecyclerView.ViewHolder {
private final TextView value;
private final TextView label;
private final ImageView icon;
private final ImageView avatar;
private final CheckBox checkBox;
ContactFieldViewHolder(View itemView) {
super(itemView);
value = itemView.findViewById(R.id.contact_field_value);
label = itemView.findViewById(R.id.contact_field_label);
icon = itemView.findViewById(R.id.contact_field_icon);
avatar = itemView.findViewById(R.id.contact_field_avatar);
checkBox = itemView.findViewById(R.id.contact_field_checkbox);
}
void bind(@NonNull Field field, @NonNull GlideRequests glideRequests, boolean selectable) {
value.setMaxLines(field.maxLines);
value.setText(field.value);
label.setText(field.label);
icon.setImageResource(field.iconResId);
if (field.iconUri != null) {
avatar.setVisibility(View.VISIBLE);
glideRequests.load(field.iconUri).circleCrop().into(avatar);
} else {
avatar.setVisibility(View.GONE);
}
if (selectable) {
checkBox.setVisibility(View.VISIBLE);
checkBox.setOnCheckedChangeListener(null);
checkBox.setChecked(field.isSelected());
checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> field.setSelected(isChecked));
} else {
checkBox.setVisibility(View.GONE);
checkBox.setOnCheckedChangeListener(null);
}
}
void recycle() {
checkBox.setOnCheckedChangeListener(null);
}
}
static class Field {
final String value;
final String label;
final int iconResId;
final int maxLines;
final Selectable selectable;
@Nullable
final Uri iconUri;
Field(@NonNull Context context, @NonNull Phone phoneNumber, @NonNull Locale locale) {
this.value = ContactUtil.getPrettyPhoneNumber(phoneNumber, locale);
this.iconResId = R.drawable.ic_call_white_24dp;
this.iconUri = null;
this.maxLines = 1;
this.selectable = phoneNumber;
switch (phoneNumber.getType()) {
case HOME:
label = context.getString(R.string.ContactShareEditActivity_type_home);
break;
case MOBILE:
label = context.getString(R.string.ContactShareEditActivity_type_mobile);
break;
case WORK:
label = context.getString(R.string.ContactShareEditActivity_type_work);
break;
case CUSTOM:
label = phoneNumber.getLabel() != null ? phoneNumber.getLabel() : "";
break;
default:
label = "";
}
}
Field(@NonNull Context context, @NonNull Email email) {
this.value = email.getEmail();
this.iconResId = R.drawable.baseline_email_white_24;
this.iconUri = null;
this.maxLines = 1;
this.selectable = email;
switch (email.getType()) {
case HOME:
label = context.getString(R.string.ContactShareEditActivity_type_home);
break;
case MOBILE:
label = context.getString(R.string.ContactShareEditActivity_type_mobile);
break;
case WORK:
label = context.getString(R.string.ContactShareEditActivity_type_work);
break;
case CUSTOM:
label = email.getLabel() != null ? email.getLabel() : "";
break;
default:
label = "";
}
}
Field(@NonNull Context context, @NonNull PostalAddress postalAddress) {
this.value = postalAddress.toString();
this.iconResId = R.drawable.ic_location_on_white_24dp;
this.iconUri = null;
this.maxLines = 3;
this.selectable = postalAddress;
switch (postalAddress.getType()) {
case HOME:
label = context.getString(R.string.ContactShareEditActivity_type_home);
break;
case WORK:
label = context.getString(R.string.ContactShareEditActivity_type_work);
break;
case CUSTOM:
label = postalAddress.getLabel() != null ? postalAddress.getLabel() : context.getString(R.string.ContactShareEditActivity_type_missing);
break;
default:
label = context.getString(R.string.ContactShareEditActivity_type_missing);
}
}
Field(@NonNull Avatar avatar) {
this.value = "";
this.iconResId = R.drawable.baseline_account_circle_white_24;
this.iconUri = avatar.getAttachment() != null ? avatar.getAttachment().getDataUri() : null;
this.maxLines = 1;
this.selectable = avatar;
this.label = "";
}
void setSelected(boolean selected) {
selectable.setSelected(selected);
}
boolean isSelected() {
return selectable.isSelected();
}
}
}

View File

@@ -1,138 +0,0 @@
package org.thoughtcrime.securesms.contactshare;
import androidx.lifecycle.ViewModelProviders;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import android.widget.TextView;
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity;
import network.loki.messenger.R;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import static org.thoughtcrime.securesms.contactshare.Contact.*;
public class ContactNameEditActivity extends PassphraseRequiredActionBarActivity {
public static final String KEY_NAME = "name";
public static final String KEY_CONTACT_INDEX = "contact_index";
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
private TextView displayNameView;
private ContactNameEditViewModel viewModel;
static Intent getIntent(@NonNull Context context, @NonNull Name name, int contactPosition) {
Intent intent = new Intent(context, ContactNameEditActivity.class);
intent.putExtra(KEY_NAME, name);
intent.putExtra(KEY_CONTACT_INDEX, contactPosition);
return intent;
}
@Override
protected void onPreCreate() {
dynamicTheme.onCreate(this);
dynamicLanguage.onCreate(this);
}
@Override
protected void onCreate(Bundle savedInstanceState, boolean ready) {
super.onCreate(savedInstanceState, ready);
if (getIntent() == null) {
throw new IllegalStateException("You must supply extras to this activity. Please use the #getIntent() method.");
}
Name name = getIntent().getParcelableExtra(KEY_NAME);
if (name == null) {
throw new IllegalStateException("You must supply a name to this activity. Please use the #getIntent() method.");
}
setContentView(R.layout.activity_contact_name_edit);
initializeToolbar();
initializeViews(name);
viewModel = ViewModelProviders.of(this).get(ContactNameEditViewModel.class);
viewModel.setName(name);
viewModel.getDisplayName().observe(this, displayNameView::setText);
}
@Override
protected void onResume() {
super.onResume();
dynamicTheme.onResume(this);
dynamicLanguage.onResume(this);
}
private void initializeToolbar() {
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setTitle("");
toolbar.setNavigationIcon(R.drawable.ic_check_white_24dp);
toolbar.setNavigationOnClickListener(v -> {
Intent resultIntent = new Intent();
resultIntent.putExtra(KEY_NAME, viewModel.getName());
resultIntent.putExtra(KEY_CONTACT_INDEX, getIntent().getIntExtra(KEY_CONTACT_INDEX, -1));
setResult(RESULT_OK, resultIntent);
finish();
});
}
private void initializeViews(@NonNull Name name) {
displayNameView = findViewById(R.id.name_edit_display_name);
TextView givenName = findViewById(R.id.name_edit_given_name);
TextView familyName = findViewById(R.id.name_edit_family_name);
TextView middleName = findViewById(R.id.name_edit_middle_name);
TextView prefix = findViewById(R.id.name_edit_prefix);
TextView suffix = findViewById(R.id.name_edit_suffix);
givenName.setText(name.getGivenName());
familyName.setText(name.getFamilyName());
middleName.setText(name.getMiddleName());
prefix.setText(name.getPrefix());
suffix.setText(name.getSuffix());
givenName.addTextChangedListener(new SimpleTextWatcher() {
@Override
public void onTextChanged(String text) {
viewModel.updateGivenName(text);
}
});
familyName.addTextChangedListener(new SimpleTextWatcher() {
@Override
public void onTextChanged(String text) {
viewModel.updateFamilyName(text);
}
});
middleName.addTextChangedListener(new SimpleTextWatcher() {
@Override
public void onTextChanged(String text) {
viewModel.updateMiddleName(text);
}
});
prefix.addTextChangedListener(new SimpleTextWatcher() {
@Override
public void onTextChanged(String text) {
viewModel.updatePrefix(text);
}
});
suffix.addTextChangedListener(new SimpleTextWatcher() {
@Override
public void onTextChanged(String text) {
viewModel.updateSuffix(text);
}
});
}
}

View File

@@ -1,132 +0,0 @@
package org.thoughtcrime.securesms.contactshare;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import static org.thoughtcrime.securesms.contactshare.Contact.*;
public class ContactNameEditViewModel extends ViewModel {
private final MutableLiveData<String> displayName;
private String givenName;
private String familyName;
private String middleName;
private String prefix;
private String suffix;
public ContactNameEditViewModel() {
this.displayName = new MutableLiveData<>();
}
void setName(@NonNull Name name) {
givenName = name.getGivenName();
familyName = name.getFamilyName();
middleName = name.getMiddleName();
prefix = name.getPrefix();
suffix = name.getSuffix();
displayName.postValue(buildDisplayName());
}
Name getName() {
return new Name(displayName.getValue(), givenName, familyName, prefix, suffix, middleName);
}
LiveData<String> getDisplayName() {
return displayName;
}
void updateGivenName(@NonNull String givenName) {
this.givenName = givenName;
displayName.postValue(buildDisplayName());
}
void updateFamilyName(@NonNull String familyName) {
this.familyName = familyName;
displayName.postValue(buildDisplayName());
}
void updatePrefix(@NonNull String prefix) {
this.prefix = prefix;
displayName.postValue(buildDisplayName());
}
void updateSuffix(@NonNull String suffix) {
this.suffix = suffix;
displayName.postValue(buildDisplayName());
}
void updateMiddleName(@NonNull String middleName) {
this.middleName = middleName;
displayName.postValue(buildDisplayName());
}
private String buildDisplayName() {
boolean isCJKV = isCJKV(givenName) && isCJKV(middleName) && isCJKV(familyName) && isCJKV(prefix) && isCJKV(suffix);
if (isCJKV) {
return joinString(familyName, givenName, prefix, suffix, middleName);
}
return joinString(prefix, givenName, middleName, familyName, suffix);
}
private String joinString(String... values) {
StringBuilder builder = new StringBuilder();
for (String value : values) {
if (!TextUtils.isEmpty(value)) {
builder.append(value).append(' ');
}
}
return builder.toString().trim();
}
private boolean isCJKV(@Nullable String value) {
if (TextUtils.isEmpty(value)) {
return true;
}
for (int offset = 0; offset < value.length(); ) {
int codepoint = Character.codePointAt(value, offset);
if (!isCodepointCJKV(codepoint)) {
return false;
}
offset += Character.charCount(codepoint);
}
return true;
}
private boolean isCodepointCJKV(int codepoint) {
if (codepoint == (int)' ') return true;
Character.UnicodeBlock block = Character.UnicodeBlock.of(codepoint);
return Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS.equals(block) ||
Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A.equals(block) ||
Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B.equals(block) ||
Character.UnicodeBlock.CJK_COMPATIBILITY.equals(block) ||
Character.UnicodeBlock.CJK_COMPATIBILITY_FORMS.equals(block) ||
Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS.equals(block) ||
Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT.equals(block) ||
Character.UnicodeBlock.CJK_RADICALS_SUPPLEMENT.equals(block) ||
Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION.equals(block) ||
Character.UnicodeBlock.ENCLOSED_CJK_LETTERS_AND_MONTHS.equals(block) ||
Character.UnicodeBlock.KANGXI_RADICALS.equals(block) ||
Character.UnicodeBlock.IDEOGRAPHIC_DESCRIPTION_CHARACTERS.equals(block) ||
Character.UnicodeBlock.HIRAGANA.equals(block) ||
Character.UnicodeBlock.KATAKANA.equals(block) ||
Character.UnicodeBlock.KATAKANA_PHONETIC_EXTENSIONS.equals(block) ||
Character.UnicodeBlock.HANGUL_JAMO.equals(block) ||
Character.UnicodeBlock.HANGUL_COMPATIBILITY_JAMO.equals(block) ||
Character.UnicodeBlock.HANGUL_SYLLABLES.equals(block) ||
Character.isIdeographic(codepoint);
}
}

View File

@@ -1,389 +0,0 @@
package org.thoughtcrime.securesms.contactshare;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import android.text.TextUtils;
import org.thoughtcrime.securesms.contacts.ContactsDatabase;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
import org.thoughtcrime.securesms.contactshare.Contact.Email;
import org.thoughtcrime.securesms.contactshare.Contact.Name;
import org.thoughtcrime.securesms.contactshare.Contact.Phone;
import org.thoughtcrime.securesms.contactshare.Contact.PostalAddress;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.recipients.Recipient;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import ezvcard.Ezvcard;
import ezvcard.VCard;
import static org.thoughtcrime.securesms.contactshare.Contact.*;
public class ContactRepository {
private static final String TAG = ContactRepository.class.getSimpleName();
private final Context context;
private final Executor executor;
private final ContactsDatabase contactsDatabase;
ContactRepository(@NonNull Context context,
@NonNull Executor executor,
@NonNull ContactsDatabase contactsDatabase)
{
this.context = context.getApplicationContext();
this.executor = executor;
this.contactsDatabase = contactsDatabase;
}
void getContacts(@NonNull List<Uri> contactUris, @NonNull ValueCallback<List<Contact>> callback) {
executor.execute(() -> {
List<Contact> contacts = new ArrayList<>(contactUris.size());
for (Uri contactUri : contactUris) {
Contact contact;
if (ContactsContract.AUTHORITY.equals(contactUri.getAuthority())) {
contact = getContactFromSystemContacts(ContactUtil.getContactIdFromUri(contactUri));
} else {
contact = getContactFromVcard(contactUri);
}
if (contact != null) {
contacts.add(contact);
}
}
callback.onComplete(contacts);
});
}
@WorkerThread
private @Nullable Contact getContactFromSystemContacts(long contactId) {
Name name = getName(contactId);
if (name == null) {
Log.w(TAG, "Couldn't find a name associated with the provided contact ID.");
return null;
}
List<Phone> phoneNumbers = getPhoneNumbers(contactId);
AvatarInfo avatarInfo = getAvatarInfo(contactId, phoneNumbers);
Avatar avatar = avatarInfo != null ? new Avatar(avatarInfo.uri, avatarInfo.isProfile) : null;
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 (BlobProvider.AUTHORITY.equals(uri.getAuthority())) {
BlobProvider.getInstance().delete(context, uri);
}
return contact;
}
@WorkerThread
private @Nullable Name getName(long contactId) {
try (Cursor cursor = contactsDatabase.getNameDetails(contactId)) {
if (cursor != null && cursor.moveToFirst()) {
String cursorDisplayName = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME));
String cursorGivenName = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
String cursorFamilyName = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME));
String cursorPrefix = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.PREFIX));
String cursorSuffix = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.SUFFIX));
String cursorMiddleName = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME));
Name name = new Name(cursorDisplayName, cursorGivenName, cursorFamilyName, cursorPrefix, cursorSuffix, cursorMiddleName);
if (!name.isEmpty()) {
return name;
}
}
}
String org = contactsDatabase.getOrganizationName(contactId);
if (!TextUtils.isEmpty(org)) {
return new Name(org, org, null, null, null, null);
}
return null;
}
@WorkerThread
private @NonNull List<Phone> getPhoneNumbers(long contactId) {
Map<String, Phone> numberMap = new HashMap<>();
try (Cursor cursor = contactsDatabase.getPhoneDetails(contactId)) {
while (cursor != null && cursor.moveToNext()) {
String cursorNumber = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER));
int cursorType = cursor.getInt(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.TYPE));
String cursorLabel = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.LABEL));
String number = ContactUtil.getNormalizedPhoneNumber(context, cursorNumber);
Phone existing = numberMap.get(number);
Phone candidate = new Phone(number, phoneTypeFromContactType(cursorType), cursorLabel);
if (existing == null || (existing.getType() == Phone.Type.CUSTOM && existing.getLabel() == null)) {
numberMap.put(number, candidate);
}
}
}
List<Phone> numbers = new ArrayList<>(numberMap.size());
numbers.addAll(numberMap.values());
return numbers;
}
@WorkerThread
private @NonNull List<Email> getEmails(long contactId) {
List<Email> emails = new LinkedList<>();
try (Cursor cursor = contactsDatabase.getEmailDetails(contactId)) {
while (cursor != null && cursor.moveToNext()) {
String cursorEmail = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.ADDRESS));
int cursorType = cursor.getInt(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.TYPE));
String cursorLabel = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Email.LABEL));
emails.add(new Email(cursorEmail, emailTypeFromContactType(cursorType), cursorLabel));
}
}
return emails;
}
@WorkerThread
private @NonNull List<PostalAddress> getPostalAddresses(long contactId) {
List<PostalAddress> postalAddresses = new LinkedList<>();
try (Cursor cursor = contactsDatabase.getPostalAddressDetails(contactId)) {
while (cursor != null && cursor.moveToNext()) {
int cursorType = cursor.getInt(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.TYPE));
String cursorLabel = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.LABEL));
String cursorStreet = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.STREET));
String cursorPoBox = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.POBOX));
String cursorNeighborhood = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.NEIGHBORHOOD));
String cursorCity = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.CITY));
String cursorRegion = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.REGION));
String cursorPostal = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE));
String cursorCountry = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY));
postalAddresses.add(new PostalAddress(postalAddressTypeFromContactType(cursorType),
cursorLabel,
cursorStreet,
cursorPoBox,
cursorNeighborhood,
cursorCity,
cursorRegion,
cursorPostal,
cursorCountry));
}
}
return postalAddresses;
}
@WorkerThread
private @Nullable AvatarInfo getAvatarInfo(long contactId, List<Phone> phoneNumbers) {
AvatarInfo systemAvatar = getSystemAvatarInfo(contactId);
if (systemAvatar != null) {
return systemAvatar;
}
for (Phone phoneNumber : phoneNumbers) {
AvatarInfo recipientAvatar = getRecipientAvatarInfo(Address.fromExternal(context, phoneNumber.getNumber()));
if (recipientAvatar != null) {
return recipientAvatar;
}
}
return null;
}
@WorkerThread
private @Nullable AvatarInfo getSystemAvatarInfo(long contactId) {
Uri uri = contactsDatabase.getAvatarUri(contactId);
if (uri != null) {
return new AvatarInfo(uri, false);
}
return null;
}
@WorkerThread
private @Nullable AvatarInfo getRecipientAvatarInfo(@NonNull Address address) {
Recipient recipient = Recipient.from(context, address, false);
ContactPhoto contactPhoto = recipient.getContactPhoto();
if (contactPhoto != null) {
Uri avatarUri = contactPhoto.getUri(context);
if (avatarUri != null) {
return new AvatarInfo(avatarUri, contactPhoto.isProfilePhoto());
}
}
return null;
}
private Phone.Type phoneTypeFromContactType(int type) {
switch (type) {
case ContactsContract.CommonDataKinds.Phone.TYPE_HOME:
return Phone.Type.HOME;
case ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE:
return Phone.Type.MOBILE;
case ContactsContract.CommonDataKinds.Phone.TYPE_WORK:
return Phone.Type.WORK;
}
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) {
switch (type) {
case ContactsContract.CommonDataKinds.Email.TYPE_HOME:
return Email.Type.HOME;
case ContactsContract.CommonDataKinds.Email.TYPE_MOBILE:
return Email.Type.MOBILE;
case ContactsContract.CommonDataKinds.Email.TYPE_WORK:
return Email.Type.WORK;
}
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) {
switch (type) {
case ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME:
return PostalAddress.Type.HOME;
case ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK:
return PostalAddress.Type.WORK;
}
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> {
void onComplete(@NonNull T value);
}
private static class AvatarInfo {
private final Uri uri;
private final boolean isProfile;
private AvatarInfo(Uri uri, boolean isProfile) {
this.uri = uri;
this.isProfile = isProfile;
}
public Uri getUri() {
return uri;
}
public boolean isProfile() {
return isProfile;
}
}
}

View File

@@ -1,140 +0,0 @@
package org.thoughtcrime.securesms.contactshare;
import android.app.Activity;
import androidx.lifecycle.ViewModelProviders;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.widget.Toast;
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity;
import network.loki.messenger.R;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import java.util.ArrayList;
import java.util.List;
import static org.thoughtcrime.securesms.contactshare.Contact.*;
import static org.thoughtcrime.securesms.contactshare.ContactShareEditViewModel.*;
public class ContactShareEditActivity extends PassphraseRequiredActionBarActivity implements ContactShareEditAdapter.EventListener {
public static final String KEY_CONTACTS = "contacts";
private static final String KEY_CONTACT_URIS = "contact_uris";
private static final int CODE_NAME_EDIT = 55;
private final DynamicTheme dynamicTheme = new DynamicTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
private ContactShareEditViewModel viewModel;
public static Intent getIntent(@NonNull Context context, @NonNull List<Uri> contactUris) {
ArrayList<Uri> contactUriList = new ArrayList<>(contactUris);
Intent intent = new Intent(context, ContactShareEditActivity.class);
intent.putParcelableArrayListExtra(KEY_CONTACT_URIS, contactUriList);
return intent;
}
@Override
protected void onPreCreate() {
dynamicTheme.onCreate(this);
dynamicLanguage.onCreate(this);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState, boolean ready) {
setContentView(R.layout.activity_contact_share_edit);
if (getIntent() == null) {
throw new IllegalStateException("You must supply extras to this activity. Please use the #getIntent() method.");
}
List<Uri> contactUris = getIntent().getParcelableArrayListExtra(KEY_CONTACT_URIS);
if (contactUris == null) {
throw new IllegalStateException("You must supply contact Uri's to this activity. Please use the #getIntent() method.");
}
View sendButton = findViewById(R.id.contact_share_edit_send);
sendButton.setOnClickListener(v -> onSendClicked(viewModel.getFinalizedContacts()));
RecyclerView contactList = findViewById(R.id.contact_share_edit_list);
contactList.setLayoutManager(new LinearLayoutManager(this));
contactList.getLayoutManager().setAutoMeasureEnabled(true);
ContactShareEditAdapter contactAdapter = new ContactShareEditAdapter(GlideApp.with(this), dynamicLanguage.getCurrentLocale(), this);
contactList.setAdapter(contactAdapter);
ContactRepository contactRepository = new ContactRepository(this,
AsyncTask.THREAD_POOL_EXECUTOR,
DatabaseFactory.getContactsDatabase(this));
viewModel = ViewModelProviders.of(this, new Factory(contactUris, contactRepository)).get(ContactShareEditViewModel.class);
viewModel.getContacts().observe(this, contacts -> {
contactAdapter.setContacts(contacts);
contactList.post(() -> contactList.scrollToPosition(0));
});
viewModel.getEvents().observe(this, this::presentEvent);
}
@Override
protected void onResume() {
super.onResume();
dynamicTheme.onResume(this);
dynamicTheme.onResume(this);
}
private void presentEvent(@Nullable Event event) {
if (event == null) {
return;
}
if (event == Event.BAD_CONTACT) {
Toast.makeText(this, R.string.ContactShareEditActivity_invalid_contact, Toast.LENGTH_SHORT).show();
finish();
}
}
private void onSendClicked(List<Contact> contacts) {
Intent intent = new Intent();
ArrayList<Contact> contactArrayList = new ArrayList<>(contacts.size());
contactArrayList.addAll(contacts);
intent.putExtra(KEY_CONTACTS, contactArrayList);
setResult(Activity.RESULT_OK, intent);
finish();
}
@Override
public void onNameEditClicked(int position, @NonNull Name name) {
startActivityForResult(ContactNameEditActivity.getIntent(this, name, position), CODE_NAME_EDIT);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode != CODE_NAME_EDIT || resultCode != RESULT_OK || data == null) {
return;
}
int position = data.getIntExtra(ContactNameEditActivity.KEY_CONTACT_INDEX, -1);
Name name = data.getParcelableExtra(ContactNameEditActivity.KEY_NAME);
if (name != null) {
viewModel.updateContactName(position, name);
}
}
}

View File

@@ -1,95 +0,0 @@
package org.thoughtcrime.securesms.contactshare;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import network.loki.messenger.R;
import org.thoughtcrime.securesms.mms.GlideRequests;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import static org.thoughtcrime.securesms.contactshare.Contact.*;
public class ContactShareEditAdapter extends RecyclerView.Adapter<ContactShareEditAdapter.ContactEditViewHolder> {
private final GlideRequests glideRequests;
private final Locale locale;
private final EventListener eventListener;
private final List<Contact> contacts;
ContactShareEditAdapter(@NonNull GlideRequests glideRequests, @NonNull Locale locale, @NonNull EventListener eventListener) {
this.glideRequests = glideRequests;
this.locale = locale;
this.eventListener = eventListener;
this.contacts = new ArrayList<>();
}
@Override
public @NonNull ContactEditViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ContactEditViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_editable_contact, parent, false),
locale,
glideRequests);
}
@Override
public void onBindViewHolder(@NonNull ContactEditViewHolder holder, int position) {
holder.bind(position, contacts.get(position), eventListener);
}
@Override
public int getItemCount() {
return contacts.size();
}
void setContacts(@Nullable List<Contact> contacts) {
this.contacts.clear();
if (contacts != null) {
this.contacts.addAll(contacts);
}
notifyDataSetChanged();
}
static class ContactEditViewHolder extends RecyclerView.ViewHolder {
private final TextView name;
private final View nameEditButton;
private final ContactFieldAdapter fieldAdapter;
ContactEditViewHolder(View itemView, @NonNull Locale locale, @NonNull GlideRequests glideRequests) {
super(itemView);
this.name = itemView.findViewById(R.id.editable_contact_name);
this.nameEditButton = itemView.findViewById(R.id.editable_contact_name_edit_button);
this.fieldAdapter = new ContactFieldAdapter(locale, glideRequests, true);
RecyclerView fields = itemView.findViewById(R.id.editable_contact_fields);
fields.setLayoutManager(new LinearLayoutManager(itemView.getContext()));
fields.getLayoutManager().setAutoMeasureEnabled(true);
fields.setAdapter(fieldAdapter);
}
void bind(int position, @NonNull Contact contact, @NonNull EventListener eventListener) {
Context context = itemView.getContext();
name.setText(ContactUtil.getDisplayName(contact));
nameEditButton.setOnClickListener(v -> eventListener.onNameEditClicked(position, contact.getName()));
fieldAdapter.setFields(context, contact.getAvatar(), contact.getPhoneNumbers(), contact.getEmails(), contact.getPostalAddresses());
}
}
interface EventListener {
void onNameEditClicked(int position, @NonNull Name name);
}
}

View File

@@ -1,113 +0,0 @@
package org.thoughtcrime.securesms.contactshare;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import android.net.Uri;
import androidx.annotation.NonNull;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.contactshare.Contact.Name;
import org.thoughtcrime.securesms.util.SingleLiveEvent;
import java.util.ArrayList;
import java.util.List;
class ContactShareEditViewModel extends ViewModel {
private final MutableLiveData<List<Contact>> contacts;
private final SingleLiveEvent<Event> events;
private final ContactRepository repo;
ContactShareEditViewModel(@NonNull List<Uri> contactUris,
@NonNull ContactRepository contactRepository)
{
contacts = new MutableLiveData<>();
events = new SingleLiveEvent<>();
repo = contactRepository;
repo.getContacts(contactUris, retrieved -> {
if (retrieved.isEmpty()) {
events.postValue(Event.BAD_CONTACT);
} else {
contacts.postValue(retrieved);
}
});
}
@NonNull LiveData<List<Contact>> getContacts() {
return contacts;
}
@NonNull List<Contact> getFinalizedContacts() {
List<Contact> currentContacts = getCurrentContacts();
List<Contact> trimmedContacts = new ArrayList<>(currentContacts.size());
for (Contact contact : currentContacts) {
Contact trimmed = new Contact(contact.getName(),
contact.getOrganization(),
trimSelectables(contact.getPhoneNumbers()),
trimSelectables(contact.getEmails()),
trimSelectables(contact.getPostalAddresses()),
contact.getAvatar() != null && contact.getAvatar().isSelected() ? contact.getAvatar() : null);
trimmedContacts.add(trimmed);
}
return trimmedContacts;
}
@NonNull LiveData<Event> getEvents() {
return events;
}
void updateContactName(int contactPosition, @NonNull Name name) {
if (name.isEmpty()) {
events.postValue(Event.BAD_CONTACT);
return;
}
List<Contact> currentContacts = getCurrentContacts();
Contact original = currentContacts.remove(contactPosition);
currentContacts.add(new Contact(name,
original.getOrganization(),
original.getPhoneNumbers(),
original.getEmails(),
original.getPostalAddresses(),
original.getAvatar()));
contacts.postValue(currentContacts);
}
private <E extends Selectable> List<E> trimSelectables(List<E> selectables) {
return Stream.of(selectables).filter(Selectable::isSelected).toList();
}
@NonNull
private List<Contact> getCurrentContacts() {
List<Contact> currentContacts = contacts.getValue();
return currentContacts != null ? currentContacts : new ArrayList<>();
}
enum Event {
BAD_CONTACT
}
static class Factory extends ViewModelProvider.NewInstanceFactory {
private final List<Uri> contactUris;
private final ContactRepository contactRepository;
Factory(@NonNull List<Uri> contactUris, @NonNull ContactRepository contactRepository) {
this.contactUris = contactUris;
this.contactRepository = contactRepository;
}
@Override
public @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return modelClass.cast(new ContactShareEditViewModel(contactUris, contactRepository));
}
}
}

View File

@@ -34,16 +34,6 @@ import network.loki.messenger.R;
public final class ContactUtil {
private static final String TAG = ContactUtil.class.getSimpleName();
public static long getContactIdFromUri(@NonNull Uri uri) {
try {
return Long.parseLong(uri.getLastPathSegment());
} catch (NumberFormatException e) {
return -1;
}
}
public static @NonNull CharSequence getStringSummary(@NonNull Context context, @NonNull Contact contact) {
String contactName = ContactUtil.getDisplayName(contact);
@@ -69,159 +59,4 @@ public final class ContactUtil {
return "";
}
public static @NonNull String getDisplayNumber(@NonNull Contact contact, @NonNull Locale locale) {
Phone displayNumber = getPrimaryNumber(contact);
if (displayNumber != null) {
return ContactUtil.getPrettyPhoneNumber(displayNumber, locale);
} else if (contact.getEmails().size() > 0) {
return contact.getEmails().get(0).getEmail();
} else {
return "";
}
}
private static @Nullable Phone getPrimaryNumber(@NonNull Contact contact) {
if (contact.getPhoneNumbers().size() == 0) {
return null;
}
List<Phone> mobileNumbers = Stream.of(contact.getPhoneNumbers()).filter(number -> number.getType() == Phone.Type.MOBILE).toList();
if (mobileNumbers.size() > 0) {
return mobileNumbers.get(0);
}
return contact.getPhoneNumbers().get(0);
}
public static @NonNull String getPrettyPhoneNumber(@NonNull Phone phoneNumber, @NonNull Locale fallbackLocale) {
return getPrettyPhoneNumber(phoneNumber.getNumber(), fallbackLocale);
}
private static @NonNull String getPrettyPhoneNumber(@NonNull String phoneNumber, @NonNull Locale fallbackLocale) {
return phoneNumber;
}
public static @NonNull String getNormalizedPhoneNumber(@NonNull Context context, @NonNull String number) {
Address address = Address.fromExternal(context, number);
return address.serialize();
}
@MainThread
public static void selectRecipientThroughDialog(@NonNull Context context, @NonNull List<Recipient> choices, @NonNull Locale locale, @NonNull RecipientSelectedCallback callback) {
if (choices.size() > 1) {
CharSequence[] values = new CharSequence[choices.size()];
for (int i = 0; i < values.length; i++) {
values[i] = getPrettyPhoneNumber(choices.get(i).getAddress().toPhoneString(), locale);
}
new AlertDialog.Builder(context)
.setItems(values, ((dialog, which) -> callback.onSelected(choices.get(which))))
.create()
.show();
} else {
callback.onSelected(choices.get(0));
}
}
public static List<Recipient> getRecipients(@NonNull Context context, @NonNull Contact contact) {
return Stream.of(contact.getPhoneNumbers()).map(phone -> Recipient.from(context, Address.fromExternal(context, phone.getNumber()), true)).toList();
}
@WorkerThread
public static @NonNull Intent buildAddToContactsIntent(@NonNull Context context, @NonNull Contact contact) {
Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
if (!TextUtils.isEmpty(contact.getName().getDisplayName())) {
intent.putExtra(ContactsContract.Intents.Insert.NAME, contact.getName().getDisplayName());
}
if (!TextUtils.isEmpty(contact.getOrganization())) {
intent.putExtra(ContactsContract.Intents.Insert.COMPANY, contact.getOrganization());
}
if (contact.getPhoneNumbers().size() > 0) {
intent.putExtra(ContactsContract.Intents.Insert.PHONE, contact.getPhoneNumbers().get(0).getNumber());
intent.putExtra(ContactsContract.Intents.Insert.PHONE_TYPE, getSystemType(contact.getPhoneNumbers().get(0).getType()));
}
if (contact.getPhoneNumbers().size() > 1) {
intent.putExtra(ContactsContract.Intents.Insert.SECONDARY_PHONE, contact.getPhoneNumbers().get(1).getNumber());
intent.putExtra(ContactsContract.Intents.Insert.SECONDARY_PHONE_TYPE, getSystemType(contact.getPhoneNumbers().get(1).getType()));
}
if (contact.getPhoneNumbers().size() > 2) {
intent.putExtra(ContactsContract.Intents.Insert.TERTIARY_PHONE, contact.getPhoneNumbers().get(2).getNumber());
intent.putExtra(ContactsContract.Intents.Insert.TERTIARY_PHONE_TYPE, getSystemType(contact.getPhoneNumbers().get(2).getType()));
}
if (contact.getEmails().size() > 0) {
intent.putExtra(ContactsContract.Intents.Insert.EMAIL, contact.getEmails().get(0).getEmail());
intent.putExtra(ContactsContract.Intents.Insert.EMAIL_TYPE, getSystemType(contact.getEmails().get(0).getType()));
}
if (contact.getEmails().size() > 1) {
intent.putExtra(ContactsContract.Intents.Insert.SECONDARY_EMAIL, contact.getEmails().get(1).getEmail());
intent.putExtra(ContactsContract.Intents.Insert.SECONDARY_EMAIL_TYPE, getSystemType(contact.getEmails().get(1).getType()));
}
if (contact.getEmails().size() > 2) {
intent.putExtra(ContactsContract.Intents.Insert.TERTIARY_EMAIL, contact.getEmails().get(2).getEmail());
intent.putExtra(ContactsContract.Intents.Insert.TERTIARY_EMAIL_TYPE, getSystemType(contact.getEmails().get(2).getType()));
}
if (contact.getPostalAddresses().size() > 0) {
intent.putExtra(ContactsContract.Intents.Insert.POSTAL, contact.getPostalAddresses().get(0).toString());
intent.putExtra(ContactsContract.Intents.Insert.POSTAL_TYPE, getSystemType(contact.getPostalAddresses().get(0).getType()));
}
if (contact.getAvatarAttachment() != null && contact.getAvatarAttachment().getDataUri() != null) {
try {
ContentValues values = new ContentValues();
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
values.put(ContactsContract.CommonDataKinds.Photo.PHOTO, Util.readFully(PartAuthority.getAttachmentStream(context, contact.getAvatarAttachment().getDataUri())));
ArrayList<ContentValues> valuesArray = new ArrayList<>(1);
valuesArray.add(values);
intent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, valuesArray);
} catch (IOException e) {
Log.w(TAG, "Failed to read avatar into a byte array.", e);
}
}
return intent;
}
private static int getSystemType(Phone.Type type) {
switch (type) {
case HOME: return ContactsContract.CommonDataKinds.Phone.TYPE_HOME;
case MOBILE: return ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE;
case WORK: return ContactsContract.CommonDataKinds.Phone.TYPE_WORK;
default: return ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM;
}
}
private static int getSystemType(Email.Type type) {
switch (type) {
case HOME: return ContactsContract.CommonDataKinds.Email.TYPE_HOME;
case MOBILE: return ContactsContract.CommonDataKinds.Email.TYPE_MOBILE;
case WORK: return ContactsContract.CommonDataKinds.Email.TYPE_WORK;
default: return ContactsContract.CommonDataKinds.Email.TYPE_CUSTOM;
}
}
private static int getSystemType(PostalAddress.Type type) {
switch (type) {
case HOME: return ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME;
case WORK: return ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK;
default: return ContactsContract.CommonDataKinds.StructuredPostal.TYPE_CUSTOM;
}
}
public interface RecipientSelectedCallback {
void onSelected(@NonNull Recipient recipient);
}
}