Refactor ContactsCursorLoader to implement factory pattern.
Utilization of the factory pattern will enable us to more easily change what contacts we present to the user for a specific screen in the future instead of continuing to modify and potentially introduce bugs to this screen.
This commit is contained in:
parent
e068fde8f2
commit
243b4b9414
4 changed files with 297 additions and 184 deletions
|
@ -58,6 +58,7 @@ import com.pnikosis.materialishprogress.ProgressWheel;
|
|||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.components.RecyclerViewFastScroller;
|
||||
import org.thoughtcrime.securesms.components.emoji.WarningTextView;
|
||||
import org.thoughtcrime.securesms.contacts.AbstractContactsCursorLoader;
|
||||
import org.thoughtcrime.securesms.contacts.ContactChip;
|
||||
import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter;
|
||||
import org.thoughtcrime.securesms.contacts.ContactSelectionListItem;
|
||||
|
@ -130,6 +131,7 @@ public final class ContactSelectionListFragment extends LoggingFragment
|
|||
private HorizontalScrollView chipGroupScrollContainer;
|
||||
private WarningTextView groupLimit;
|
||||
private OnSelectionLimitReachedListener onSelectionLimitReachedListener;
|
||||
private AbstractContactsCursorLoaderFactoryProvider cursorFactoryProvider;
|
||||
|
||||
|
||||
@Nullable private FixedViewsAdapter headerAdapter;
|
||||
|
@ -162,6 +164,14 @@ public final class ContactSelectionListFragment extends LoggingFragment
|
|||
if (context instanceof OnSelectionLimitReachedListener) {
|
||||
onSelectionLimitReachedListener = (OnSelectionLimitReachedListener) context;
|
||||
}
|
||||
|
||||
if (context instanceof AbstractContactsCursorLoaderFactoryProvider) {
|
||||
cursorFactoryProvider = (AbstractContactsCursorLoaderFactoryProvider) context;
|
||||
}
|
||||
|
||||
if (getParentFragment() instanceof AbstractContactsCursorLoaderFactoryProvider) {
|
||||
cursorFactoryProvider = (AbstractContactsCursorLoaderFactoryProvider) context;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -388,9 +398,14 @@ public final class ContactSelectionListFragment extends LoggingFragment
|
|||
@Override
|
||||
public @NonNull Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
FragmentActivity activity = requireActivity();
|
||||
return new ContactsCursorLoader(activity,
|
||||
activity.getIntent().getIntExtra(DISPLAY_MODE, DisplayMode.FLAG_ALL),
|
||||
cursorFilter, activity.getIntent().getBooleanExtra(RECENTS, false));
|
||||
int displayMode = activity.getIntent().getIntExtra(DISPLAY_MODE, DisplayMode.FLAG_ALL);
|
||||
boolean displayRecents = activity.getIntent().getBooleanExtra(RECENTS, false);
|
||||
|
||||
if (cursorFactoryProvider != null) {
|
||||
return cursorFactoryProvider.get().create();
|
||||
} else {
|
||||
return new ContactsCursorLoader.Factory(activity, displayMode, cursorFilter, displayRecents).create();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -696,4 +711,8 @@ public final class ContactSelectionListFragment extends LoggingFragment
|
|||
public interface ScrollCallback {
|
||||
void onBeginScroll();
|
||||
}
|
||||
|
||||
public interface AbstractContactsCursorLoaderFactoryProvider {
|
||||
@NonNull AbstractContactsCursorLoader.Factory get();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
package org.thoughtcrime.securesms.contacts;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.MergeCursor;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.loader.content.CursorLoader;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class AbstractContactsCursorLoader extends CursorLoader {
|
||||
|
||||
private final String filter;
|
||||
|
||||
protected AbstractContactsCursorLoader(@NonNull Context context, @Nullable String filter) {
|
||||
super(context);
|
||||
|
||||
this.filter = sanitizeFilter(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Cursor loadInBackground() {
|
||||
List<Cursor> cursorList = TextUtils.isEmpty(filter) ? getUnfilteredResults()
|
||||
: getFilteredResults();
|
||||
if (cursorList.size() > 0) {
|
||||
return new MergeCursor(cursorList.toArray(new Cursor[0]));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected final String getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
protected abstract List<Cursor> getUnfilteredResults();
|
||||
|
||||
protected abstract List<Cursor> getFilteredResults();
|
||||
|
||||
private static @NonNull String sanitizeFilter(@Nullable String filter) {
|
||||
if (filter == null) {
|
||||
return "";
|
||||
} else if (filter.startsWith("@")) {
|
||||
return filter.substring(1);
|
||||
} else {
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
|
||||
public interface Factory {
|
||||
@NonNull AbstractContactsCursorLoader create();
|
||||
}
|
||||
}
|
|
@ -20,13 +20,8 @@ import android.Manifest;
|
|||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.database.MergeCursor;
|
||||
import android.provider.ContactsContract;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.loader.content.CursorLoader;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
@ -37,7 +32,6 @@ import org.thoughtcrime.securesms.database.ThreadDatabase;
|
|||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
|
@ -51,7 +45,7 @@ import java.util.List;
|
|||
*
|
||||
* @author Jake McGinty
|
||||
*/
|
||||
public class ContactsCursorLoader extends CursorLoader {
|
||||
public class ContactsCursorLoader extends AbstractContactsCursorLoader {
|
||||
|
||||
private static final String TAG = ContactsCursorLoader.class.getSimpleName();
|
||||
|
||||
|
@ -67,57 +61,27 @@ public class ContactsCursorLoader extends CursorLoader {
|
|||
public static final int FLAG_ALL = FLAG_PUSH | FLAG_SMS | FLAG_ACTIVE_GROUPS | FLAG_INACTIVE_GROUPS | FLAG_SELF;
|
||||
}
|
||||
|
||||
private static final String[] CONTACT_PROJECTION = new String[]{ContactRepository.ID_COLUMN,
|
||||
ContactRepository.NAME_COLUMN,
|
||||
ContactRepository.NUMBER_COLUMN,
|
||||
ContactRepository.NUMBER_TYPE_COLUMN,
|
||||
ContactRepository.LABEL_COLUMN,
|
||||
ContactRepository.CONTACT_TYPE_COLUMN,
|
||||
ContactRepository.ABOUT_COLUMN};
|
||||
|
||||
private static final int RECENT_CONVERSATION_MAX = 25;
|
||||
|
||||
private final String filter;
|
||||
private final int mode;
|
||||
private final boolean recents;
|
||||
|
||||
private final ContactRepository contactRepository;
|
||||
|
||||
public ContactsCursorLoader(@NonNull Context context, int mode, String filter, boolean recents)
|
||||
private ContactsCursorLoader(@NonNull Context context, int mode, String filter, boolean recents)
|
||||
{
|
||||
super(context);
|
||||
super(context, filter);
|
||||
|
||||
if (flagSet(mode, DisplayMode.FLAG_INACTIVE_GROUPS) && !flagSet(mode, DisplayMode.FLAG_ACTIVE_GROUPS)) {
|
||||
throw new AssertionError("Inactive group flag set, but the active group flag isn't!");
|
||||
}
|
||||
|
||||
this.filter = sanitizeFilter(filter);
|
||||
this.mode = mode;
|
||||
this.recents = recents;
|
||||
this.contactRepository = new ContactRepository(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor loadInBackground() {
|
||||
List<Cursor> cursorList = TextUtils.isEmpty(filter) ? getUnfilteredResults()
|
||||
: getFilteredResults();
|
||||
if (cursorList.size() > 0) {
|
||||
return new MergeCursor(cursorList.toArray(new Cursor[0]));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static @NonNull String sanitizeFilter(@Nullable String filter) {
|
||||
if (filter == null) {
|
||||
return "";
|
||||
} else if (filter.startsWith("@")) {
|
||||
return filter.substring(1);
|
||||
} else {
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
|
||||
private List<Cursor> getUnfilteredResults() {
|
||||
protected final List<Cursor> getUnfilteredResults() {
|
||||
ArrayList<Cursor> cursorList = new ArrayList<>();
|
||||
|
||||
if (groupsOnly(mode)) {
|
||||
|
@ -131,7 +95,7 @@ public class ContactsCursorLoader extends CursorLoader {
|
|||
return cursorList;
|
||||
}
|
||||
|
||||
private List<Cursor> getFilteredResults() {
|
||||
protected final List<Cursor> getFilteredResults() {
|
||||
ArrayList<Cursor> cursorList = new ArrayList<>();
|
||||
|
||||
addContactsSection(cursorList);
|
||||
|
@ -153,7 +117,7 @@ public class ContactsCursorLoader extends CursorLoader {
|
|||
Cursor recentConversations = getRecentConversationsCursor();
|
||||
|
||||
if (recentConversations.getCount() > 0) {
|
||||
cursorList.add(getRecentsHeaderCursor());
|
||||
cursorList.add(ContactsCursorRows.forRecentsHeader(getContext()));
|
||||
cursorList.add(recentConversations);
|
||||
}
|
||||
}
|
||||
|
@ -162,7 +126,7 @@ public class ContactsCursorLoader extends CursorLoader {
|
|||
List<Cursor> contacts = getContactsCursors();
|
||||
|
||||
if (!isCursorListEmpty(contacts)) {
|
||||
cursorList.add(getContactsHeaderCursor());
|
||||
cursorList.add(ContactsCursorRows.forContactsHeader(getContext()));
|
||||
cursorList.addAll(contacts);
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +139,7 @@ public class ContactsCursorLoader extends CursorLoader {
|
|||
Cursor groups = getRecentConversationsCursor(true);
|
||||
|
||||
if (groups.getCount() > 0) {
|
||||
cursorList.add(getRecentsHeaderCursor());
|
||||
cursorList.add(ContactsCursorRows.forRecentsHeader(getContext()));
|
||||
cursorList.add(groups);
|
||||
}
|
||||
}
|
||||
|
@ -188,89 +152,28 @@ public class ContactsCursorLoader extends CursorLoader {
|
|||
Cursor groups = getGroupsCursor();
|
||||
|
||||
if (groups.getCount() > 0) {
|
||||
cursorList.add(getGroupsHeaderCursor());
|
||||
cursorList.add(ContactsCursorRows.forGroupsHeader(getContext()));
|
||||
cursorList.add(groups);
|
||||
}
|
||||
}
|
||||
|
||||
private void addNewNumberSection(@NonNull List<Cursor> cursorList) {
|
||||
if (FeatureFlags.usernames() && NumberUtil.isVisuallyValidNumberOrEmail(filter)) {
|
||||
cursorList.add(getPhoneNumberSearchHeaderCursor());
|
||||
if (FeatureFlags.usernames() && NumberUtil.isVisuallyValidNumberOrEmail(getFilter())) {
|
||||
cursorList.add(ContactsCursorRows.forPhoneNumberSearchHeader(getContext()));
|
||||
cursorList.add(getNewNumberCursor());
|
||||
} else if (!FeatureFlags.usernames() && NumberUtil.isValidSmsOrEmail(filter)){
|
||||
cursorList.add(getPhoneNumberSearchHeaderCursor());
|
||||
} else if (!FeatureFlags.usernames() && NumberUtil.isValidSmsOrEmail(getFilter())) {
|
||||
cursorList.add(ContactsCursorRows.forPhoneNumberSearchHeader(getContext()));
|
||||
cursorList.add(getNewNumberCursor());
|
||||
}
|
||||
}
|
||||
|
||||
private void addUsernameSearchSection(@NonNull List<Cursor> cursorList) {
|
||||
if (FeatureFlags.usernames() && UsernameUtil.isValidUsernameForSearch(filter)) {
|
||||
cursorList.add(getUsernameSearchHeaderCursor());
|
||||
if (FeatureFlags.usernames() && UsernameUtil.isValidUsernameForSearch(getFilter())) {
|
||||
cursorList.add(ContactsCursorRows.forUsernameSearchHeader(getContext()));
|
||||
cursorList.add(getUsernameSearchCursor());
|
||||
}
|
||||
}
|
||||
|
||||
private Cursor getRecentsHeaderCursor() {
|
||||
MatrixCursor recentsHeader = new MatrixCursor(CONTACT_PROJECTION);
|
||||
recentsHeader.addRow(new Object[]{ null,
|
||||
getContext().getString(R.string.ContactsCursorLoader_recent_chats),
|
||||
"",
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE,
|
||||
"",
|
||||
ContactRepository.DIVIDER_TYPE,
|
||||
"" });
|
||||
return recentsHeader;
|
||||
}
|
||||
|
||||
private Cursor getContactsHeaderCursor() {
|
||||
MatrixCursor contactsHeader = new MatrixCursor(CONTACT_PROJECTION, 1);
|
||||
contactsHeader.addRow(new Object[] { null,
|
||||
getContext().getString(R.string.ContactsCursorLoader_contacts),
|
||||
"",
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE,
|
||||
"",
|
||||
ContactRepository.DIVIDER_TYPE,
|
||||
"" });
|
||||
return contactsHeader;
|
||||
}
|
||||
|
||||
private Cursor getGroupsHeaderCursor() {
|
||||
MatrixCursor groupHeader = new MatrixCursor(CONTACT_PROJECTION, 1);
|
||||
groupHeader.addRow(new Object[]{ null,
|
||||
getContext().getString(R.string.ContactsCursorLoader_groups),
|
||||
"",
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE,
|
||||
"",
|
||||
ContactRepository.DIVIDER_TYPE,
|
||||
"" });
|
||||
return groupHeader;
|
||||
}
|
||||
|
||||
private Cursor getPhoneNumberSearchHeaderCursor() {
|
||||
MatrixCursor contactsHeader = new MatrixCursor(CONTACT_PROJECTION, 1);
|
||||
contactsHeader.addRow(new Object[] { null,
|
||||
getContext().getString(R.string.ContactsCursorLoader_phone_number_search),
|
||||
"",
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE,
|
||||
"",
|
||||
ContactRepository.DIVIDER_TYPE,
|
||||
"" });
|
||||
return contactsHeader;
|
||||
}
|
||||
|
||||
private Cursor getUsernameSearchHeaderCursor() {
|
||||
MatrixCursor contactsHeader = new MatrixCursor(CONTACT_PROJECTION, 1);
|
||||
contactsHeader.addRow(new Object[] { null,
|
||||
getContext().getString(R.string.ContactsCursorLoader_username_search),
|
||||
"",
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE,
|
||||
"",
|
||||
ContactRepository.DIVIDER_TYPE,
|
||||
"" });
|
||||
return contactsHeader;
|
||||
}
|
||||
|
||||
|
||||
private Cursor getRecentConversationsCursor() {
|
||||
return getRecentConversationsCursor(false);
|
||||
}
|
||||
|
@ -278,21 +181,12 @@ public class ContactsCursorLoader extends CursorLoader {
|
|||
private Cursor getRecentConversationsCursor(boolean groupsOnly) {
|
||||
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(getContext());
|
||||
|
||||
MatrixCursor recentConversations = new MatrixCursor(CONTACT_PROJECTION, RECENT_CONVERSATION_MAX);
|
||||
MatrixCursor recentConversations = ContactsCursorRows.createMatrixCursor(RECENT_CONVERSATION_MAX);
|
||||
try (Cursor rawConversations = threadDatabase.getRecentConversationList(RECENT_CONVERSATION_MAX, flagSet(mode, DisplayMode.FLAG_INACTIVE_GROUPS), groupsOnly, hideGroupsV1(mode), !smsEnabled(mode))) {
|
||||
ThreadDatabase.Reader reader = threadDatabase.readerFor(rawConversations);
|
||||
ThreadRecord threadRecord;
|
||||
while ((threadRecord = reader.getNext()) != null) {
|
||||
Recipient recipient = threadRecord.getRecipient();
|
||||
String stringId = recipient.isGroup() ? recipient.requireGroupId().toString() : recipient.getE164().transform(PhoneNumberFormatter::prettyPrint).or(recipient.getEmail()).or("");
|
||||
|
||||
recentConversations.addRow(new Object[] { recipient.getId().serialize(),
|
||||
recipient.getDisplayName(getContext()),
|
||||
stringId,
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE,
|
||||
"",
|
||||
ContactRepository.RECENT_TYPE | (recipient.isRegistered() && !recipient.isForceSmsSelection() ? ContactRepository.PUSH_TYPE : 0),
|
||||
recipient.getCombinedAboutAndEmoji() });
|
||||
recentConversations.addRow(ContactsCursorRows.forRecipient(getContext(), threadRecord.getRecipient()));
|
||||
}
|
||||
}
|
||||
return recentConversations;
|
||||
|
@ -306,56 +200,34 @@ public class ContactsCursorLoader extends CursorLoader {
|
|||
}
|
||||
|
||||
if (pushEnabled(mode)) {
|
||||
cursorList.add(contactRepository.querySignalContacts(filter, selfEnabled(mode)));
|
||||
cursorList.add(contactRepository.querySignalContacts(getFilter(), selfEnabled(mode)));
|
||||
}
|
||||
|
||||
if (pushEnabled(mode) && smsEnabled(mode)) {
|
||||
cursorList.add(contactRepository.queryNonSignalContacts(filter));
|
||||
cursorList.add(contactRepository.queryNonSignalContacts(getFilter()));
|
||||
} else if (smsEnabled(mode)) {
|
||||
cursorList.add(filterNonPushContacts(contactRepository.queryNonSignalContacts(filter)));
|
||||
cursorList.add(filterNonPushContacts(contactRepository.queryNonSignalContacts(getFilter())));
|
||||
}
|
||||
return cursorList;
|
||||
}
|
||||
|
||||
private Cursor getGroupsCursor() {
|
||||
MatrixCursor groupContacts = new MatrixCursor(CONTACT_PROJECTION);
|
||||
try (GroupDatabase.Reader reader = DatabaseFactory.getGroupDatabase(getContext()).getGroupsFilteredByTitle(filter, flagSet(mode, DisplayMode.FLAG_INACTIVE_GROUPS), hideGroupsV1(mode))) {
|
||||
MatrixCursor groupContacts = ContactsCursorRows.createMatrixCursor();
|
||||
try (GroupDatabase.Reader reader = DatabaseFactory.getGroupDatabase(getContext()).getGroupsFilteredByTitle(getFilter(), flagSet(mode, DisplayMode.FLAG_INACTIVE_GROUPS), hideGroupsV1(mode))) {
|
||||
GroupDatabase.GroupRecord groupRecord;
|
||||
while ((groupRecord = reader.getNext()) != null) {
|
||||
groupContacts.addRow(new Object[] { groupRecord.getRecipientId().serialize(),
|
||||
groupRecord.getTitle(),
|
||||
groupRecord.getId(),
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM,
|
||||
"",
|
||||
ContactRepository.NORMAL_TYPE,
|
||||
"" });
|
||||
groupContacts.addRow(ContactsCursorRows.forGroup(groupRecord));
|
||||
}
|
||||
}
|
||||
return groupContacts;
|
||||
}
|
||||
|
||||
private Cursor getNewNumberCursor() {
|
||||
MatrixCursor newNumberCursor = new MatrixCursor(CONTACT_PROJECTION, 1);
|
||||
newNumberCursor.addRow(new Object[] { null,
|
||||
getUnknownContactTitle(),
|
||||
filter,
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM,
|
||||
"\u21e2",
|
||||
ContactRepository.NEW_PHONE_TYPE,
|
||||
"" });
|
||||
return newNumberCursor;
|
||||
return ContactsCursorRows.forNewNumber(getUnknownContactTitle(), getFilter());
|
||||
}
|
||||
|
||||
private Cursor getUsernameSearchCursor() {
|
||||
MatrixCursor cursor = new MatrixCursor(CONTACT_PROJECTION, 1);
|
||||
cursor.addRow(new Object[] { null,
|
||||
getUnknownContactTitle(),
|
||||
filter,
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM,
|
||||
"\u21e2",
|
||||
ContactRepository.NEW_USERNAME_TYPE,
|
||||
"" });
|
||||
return cursor;
|
||||
return ContactsCursorRows.forUsernameSearch(getUnknownContactTitle(), getFilter());
|
||||
}
|
||||
|
||||
private String getUnknownContactTitle() {
|
||||
|
@ -371,19 +243,13 @@ public class ContactsCursorLoader extends CursorLoader {
|
|||
private @NonNull Cursor filterNonPushContacts(@NonNull Cursor cursor) {
|
||||
try {
|
||||
final long startMillis = System.currentTimeMillis();
|
||||
final MatrixCursor matrix = new MatrixCursor(CONTACT_PROJECTION);
|
||||
final MatrixCursor matrix = ContactsCursorRows.createMatrixCursor();
|
||||
while (cursor.moveToNext()) {
|
||||
final RecipientId id = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ContactRepository.ID_COLUMN)));
|
||||
final Recipient recipient = Recipient.resolved(id);
|
||||
|
||||
if (recipient.resolve().getRegistered() != RecipientDatabase.RegisteredState.REGISTERED) {
|
||||
matrix.addRow(new Object[]{cursor.getLong(cursor.getColumnIndexOrThrow(ContactRepository.ID_COLUMN)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(ContactRepository.NAME_COLUMN)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(ContactRepository.NUMBER_COLUMN)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(ContactRepository.NUMBER_TYPE_COLUMN)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(ContactRepository.LABEL_COLUMN)),
|
||||
ContactRepository.NORMAL_TYPE,
|
||||
"" });
|
||||
matrix.addRow(ContactsCursorRows.forNonPushContact(cursor));
|
||||
}
|
||||
}
|
||||
Log.i(TAG, "filterNonPushContacts() -> " + (System.currentTimeMillis() - startMillis) + "ms");
|
||||
|
@ -440,4 +306,24 @@ public class ContactsCursorLoader extends CursorLoader {
|
|||
private static boolean flagSet(int mode, int flag) {
|
||||
return (mode & flag) > 0;
|
||||
}
|
||||
|
||||
public static class Factory implements AbstractContactsCursorLoader.Factory {
|
||||
|
||||
private final Context context;
|
||||
private final int displayMode;
|
||||
private final String cursorFilter;
|
||||
private final boolean displayRecents;
|
||||
|
||||
public Factory(Context context, int displayMode, String cursorFilter, boolean displayRecents) {
|
||||
this.context = context;
|
||||
this.displayMode = displayMode;
|
||||
this.cursorFilter = cursorFilter;
|
||||
this.displayRecents = displayRecents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull AbstractContactsCursorLoader create() {
|
||||
return new ContactsCursorLoader(context, displayMode, cursorFilter, displayRecents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
package org.thoughtcrime.securesms.contacts;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.provider.ContactsContract;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
/**
|
||||
* Helper utility for generating cursors and cursor rows for subclasses of {@link AbstractContactsCursorLoader}.
|
||||
*/
|
||||
public final class ContactsCursorRows {
|
||||
|
||||
private static final String[] CONTACT_PROJECTION = new String[]{ContactRepository.ID_COLUMN,
|
||||
ContactRepository.NAME_COLUMN,
|
||||
ContactRepository.NUMBER_COLUMN,
|
||||
ContactRepository.NUMBER_TYPE_COLUMN,
|
||||
ContactRepository.LABEL_COLUMN,
|
||||
ContactRepository.CONTACT_TYPE_COLUMN,
|
||||
ContactRepository.ABOUT_COLUMN};
|
||||
|
||||
/**
|
||||
* Create a {@link MatrixCursor} with the proper projection for a subclass of {@link AbstractContactsCursorLoader}
|
||||
*/
|
||||
public static @NonNull MatrixCursor createMatrixCursor() {
|
||||
return new MatrixCursor(CONTACT_PROJECTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MatrixCursor} with the proper projection for a subclass of {@link AbstractContactsCursorLoader}
|
||||
*
|
||||
* @param initialCapacity The initial capacity to hand to the {@link MatrixCursor}
|
||||
*/
|
||||
public static @NonNull MatrixCursor createMatrixCursor(int initialCapacity) {
|
||||
return new MatrixCursor(CONTACT_PROJECTION, initialCapacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a row for a contacts cursor based off the given recipient.
|
||||
*/
|
||||
public static @NonNull Object[] forRecipient(@NonNull Context context, @NonNull Recipient recipient) {
|
||||
String stringId = recipient.isGroup() ? recipient.requireGroupId().toString()
|
||||
: recipient.getE164().transform(PhoneNumberFormatter::prettyPrint).or(recipient.getEmail()).or("");
|
||||
|
||||
return new Object[]{recipient.getId().serialize(),
|
||||
recipient.getDisplayName(context),
|
||||
stringId,
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE,
|
||||
"",
|
||||
ContactRepository.RECENT_TYPE | (recipient.isRegistered() && !recipient.isForceSmsSelection() ? ContactRepository.PUSH_TYPE : 0),
|
||||
recipient.getCombinedAboutAndEmoji()};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a row for a contacts cursor based off the given system contact.
|
||||
*/
|
||||
public static @NonNull Object[] forNonPushContact(@NonNull Cursor systemContactCursor) {
|
||||
return new Object[]{systemContactCursor.getLong(systemContactCursor.getColumnIndexOrThrow(ContactRepository.ID_COLUMN)),
|
||||
systemContactCursor.getString(systemContactCursor.getColumnIndexOrThrow(ContactRepository.NAME_COLUMN)),
|
||||
systemContactCursor.getString(systemContactCursor.getColumnIndexOrThrow(ContactRepository.NUMBER_COLUMN)),
|
||||
systemContactCursor.getString(systemContactCursor.getColumnIndexOrThrow(ContactRepository.NUMBER_TYPE_COLUMN)),
|
||||
systemContactCursor.getString(systemContactCursor.getColumnIndexOrThrow(ContactRepository.LABEL_COLUMN)),
|
||||
ContactRepository.NORMAL_TYPE,
|
||||
""};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a row for a contacts cursor based off the given group record.
|
||||
*/
|
||||
public static @NonNull Object[] forGroup(@NonNull GroupDatabase.GroupRecord groupRecord) {
|
||||
return new Object[]{groupRecord.getRecipientId().serialize(),
|
||||
groupRecord.getTitle(),
|
||||
groupRecord.getId(),
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM,
|
||||
"",
|
||||
ContactRepository.NORMAL_TYPE,
|
||||
""};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a row for a contacts cursor for a new number the user is entering or has entered.
|
||||
*/
|
||||
public static @NonNull MatrixCursor forNewNumber(@NonNull String unknownContactTitle, @NonNull String filter) {
|
||||
MatrixCursor matrixCursor = createMatrixCursor(1);
|
||||
|
||||
matrixCursor.addRow(new Object[]{null,
|
||||
unknownContactTitle,
|
||||
filter,
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM,
|
||||
"\u21e2",
|
||||
ContactRepository.NEW_PHONE_TYPE,
|
||||
""});
|
||||
|
||||
return matrixCursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a row for a contacts cursor for a username the user is entering or has entered.
|
||||
*/
|
||||
public static @NonNull MatrixCursor forUsernameSearch(@NonNull String unknownContactTitle, @NonNull String filter) {
|
||||
MatrixCursor matrixCursor = createMatrixCursor(1);
|
||||
|
||||
matrixCursor.addRow(new Object[]{null,
|
||||
unknownContactTitle,
|
||||
filter,
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM,
|
||||
"\u21e2",
|
||||
ContactRepository.NEW_USERNAME_TYPE,
|
||||
""});
|
||||
|
||||
return matrixCursor;
|
||||
}
|
||||
|
||||
public static @NonNull MatrixCursor forUsernameSearchHeader(@NonNull Context context) {
|
||||
return forHeader(context.getString(R.string.ContactsCursorLoader_username_search));
|
||||
}
|
||||
|
||||
public static @NonNull MatrixCursor forPhoneNumberSearchHeader(@NonNull Context context) {
|
||||
return forHeader(context.getString(R.string.ContactsCursorLoader_phone_number_search));
|
||||
}
|
||||
|
||||
public static @NonNull MatrixCursor forGroupsHeader(@NonNull Context context) {
|
||||
return forHeader(context.getString(R.string.ContactsCursorLoader_groups));
|
||||
}
|
||||
|
||||
public static @NonNull MatrixCursor forRecentsHeader(@NonNull Context context) {
|
||||
return forHeader(context.getString(R.string.ContactsCursorLoader_recent_chats));
|
||||
}
|
||||
|
||||
public static @NonNull MatrixCursor forContactsHeader(@NonNull Context context) {
|
||||
return forHeader(context.getString(R.string.ContactsCursorLoader_contacts));
|
||||
}
|
||||
|
||||
public static @NonNull MatrixCursor forHeader(@NonNull String name) {
|
||||
MatrixCursor matrixCursor = createMatrixCursor(1);
|
||||
|
||||
matrixCursor.addRow(new Object[]{null,
|
||||
name,
|
||||
"",
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE,
|
||||
"",
|
||||
ContactRepository.DIVIDER_TYPE,
|
||||
""});
|
||||
|
||||
return matrixCursor;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue