2011-12-20 19:20:44 +01:00
|
|
|
package org.thoughtcrime.securesms.recipients;
|
|
|
|
|
2017-08-22 03:32:38 +02:00
|
|
|
import android.content.Context;
|
2017-10-16 22:11:42 +02:00
|
|
|
import android.graphics.drawable.Drawable;
|
2012-09-12 03:23:19 +02:00
|
|
|
import android.net.Uri;
|
2017-11-26 19:45:39 +01:00
|
|
|
import android.text.TextUtils;
|
2011-12-20 19:20:44 +01:00
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
import androidx.annotation.AnyThread;
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import androidx.annotation.Nullable;
|
|
|
|
import androidx.annotation.WorkerThread;
|
2017-11-20 23:48:39 +01:00
|
|
|
|
2017-11-26 19:45:39 +01:00
|
|
|
import org.thoughtcrime.securesms.R;
|
2015-06-30 18:16:05 +02:00
|
|
|
import org.thoughtcrime.securesms.color.MaterialColor;
|
2015-06-30 00:33:36 +02:00
|
|
|
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
2015-06-23 19:15:33 +02:00
|
|
|
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
2017-10-16 22:11:42 +02:00
|
|
|
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
|
2017-11-26 19:45:39 +01:00
|
|
|
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
|
|
|
|
import org.thoughtcrime.securesms.contacts.avatars.GroupRecordContactPhoto;
|
|
|
|
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
|
|
|
|
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
|
|
|
|
import org.thoughtcrime.securesms.contacts.avatars.SystemContactPhoto;
|
2017-10-16 22:11:42 +02:00
|
|
|
import org.thoughtcrime.securesms.contacts.avatars.TransparentContactPhoto;
|
2019-08-07 20:22:51 +02:00
|
|
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
2019-09-26 16:12:51 +02:00
|
|
|
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
2019-08-07 20:22:51 +02:00
|
|
|
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
2017-08-22 19:44:04 +02:00
|
|
|
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
|
2018-05-22 11:13:10 +02:00
|
|
|
import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode;
|
2017-08-22 03:37:39 +02:00
|
|
|
import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
|
2019-08-07 20:22:51 +02:00
|
|
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
2020-03-26 15:00:17 +01:00
|
|
|
import org.thoughtcrime.securesms.groups.GroupId;
|
2019-09-07 05:40:06 +02:00
|
|
|
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
|
|
|
import org.thoughtcrime.securesms.logging.Log;
|
2018-08-16 18:47:43 +02:00
|
|
|
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
2019-08-07 20:22:51 +02:00
|
|
|
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
|
|
|
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
2019-12-20 21:12:22 +01:00
|
|
|
import org.thoughtcrime.securesms.profiles.ProfileName;
|
2019-10-09 18:57:36 +02:00
|
|
|
import org.thoughtcrime.securesms.util.FeatureFlags;
|
2017-08-01 17:56:00 +02:00
|
|
|
import org.thoughtcrime.securesms.util.Util;
|
2017-08-08 00:31:12 +02:00
|
|
|
import org.whispersystems.libsignal.util.guava.Optional;
|
2019-09-25 14:49:32 +02:00
|
|
|
import org.whispersystems.libsignal.util.guava.Preconditions;
|
2019-09-07 05:40:06 +02:00
|
|
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
|
|
|
import org.whispersystems.signalservice.api.util.UuidUtil;
|
2012-12-24 17:40:37 +01:00
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
import java.util.ArrayList;
|
2015-06-12 22:54:47 +02:00
|
|
|
import java.util.Collections;
|
2017-08-01 17:56:00 +02:00
|
|
|
import java.util.LinkedList;
|
|
|
|
import java.util.List;
|
2019-08-07 20:22:51 +02:00
|
|
|
import java.util.Objects;
|
2019-09-07 05:40:06 +02:00
|
|
|
import java.util.UUID;
|
2019-08-07 20:22:51 +02:00
|
|
|
|
2019-11-12 15:18:57 +01:00
|
|
|
import static org.thoughtcrime.securesms.database.RecipientDatabase.InsightsBannerTier;
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public class Recipient {
|
|
|
|
|
2019-10-09 04:14:52 +02:00
|
|
|
public static final Recipient UNKNOWN = new Recipient(RecipientId.UNKNOWN, new RecipientDetails());
|
|
|
|
|
2020-02-19 23:08:34 +01:00
|
|
|
private static final FallbackPhotoProvider DEFAULT_FALLBACK_PHOTO_PROVIDER = new FallbackPhotoProvider();
|
|
|
|
private static final String TAG = Log.tag(Recipient.class);
|
2019-09-07 05:40:06 +02:00
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
private final RecipientId id;
|
|
|
|
private final boolean resolving;
|
2019-09-07 05:40:06 +02:00
|
|
|
private final UUID uuid;
|
2019-10-29 01:16:11 +01:00
|
|
|
private final String username;
|
2019-09-07 05:40:06 +02:00
|
|
|
private final String e164;
|
|
|
|
private final String email;
|
2020-03-26 15:00:17 +01:00
|
|
|
private final GroupId groupId;
|
2019-08-07 20:22:51 +02:00
|
|
|
private final List<Recipient> participants;
|
|
|
|
private final Optional<Long> groupAvatarId;
|
|
|
|
private final boolean localNumber;
|
|
|
|
private final boolean blocked;
|
|
|
|
private final long muteUntil;
|
|
|
|
private final VibrateState messageVibrate;
|
|
|
|
private final VibrateState callVibrate;
|
|
|
|
private final Uri messageRingtone;
|
|
|
|
private final Uri callRingtone;
|
|
|
|
private final MaterialColor color;
|
|
|
|
private final Optional<Integer> defaultSubscriptionId;
|
|
|
|
private final int expireMessages;
|
|
|
|
private final RegisteredState registered;
|
|
|
|
private final byte[] profileKey;
|
2020-02-11 00:40:22 +01:00
|
|
|
private final byte[] profileKeyCredential;
|
2019-08-07 20:22:51 +02:00
|
|
|
private final String name;
|
|
|
|
private final Uri systemContactPhoto;
|
|
|
|
private final String customLabel;
|
|
|
|
private final Uri contactUri;
|
2019-12-20 21:12:22 +01:00
|
|
|
private final ProfileName profileName;
|
2019-08-07 20:22:51 +02:00
|
|
|
private final String profileAvatar;
|
|
|
|
private final boolean profileSharing;
|
|
|
|
private final String notificationChannel;
|
|
|
|
private final UnidentifiedAccessMode unidentifiedAccessMode;
|
|
|
|
private final boolean forceSmsSelection;
|
2020-02-14 21:47:31 +01:00
|
|
|
private final Capability uuidCapability;
|
2020-02-14 17:00:32 +01:00
|
|
|
private final Capability groupsV2Capability;
|
2019-11-12 15:18:57 +01:00
|
|
|
private final InsightsBannerTier insightsBannerTier;
|
2020-03-18 21:31:45 +01:00
|
|
|
private final byte[] storageId;
|
2019-09-26 16:12:51 +02:00
|
|
|
private final byte[] identityKey;
|
|
|
|
private final VerifiedStatus identityStatus;
|
2019-08-07 20:22:51 +02:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a {@link LiveRecipient}, which contains a {@link Recipient} that may or may not be
|
|
|
|
* populated with data. However, you can observe the value that's returned to be notified when the
|
|
|
|
* {@link Recipient} changes.
|
|
|
|
*/
|
|
|
|
@AnyThread
|
|
|
|
public static @NonNull LiveRecipient live(@NonNull RecipientId id) {
|
2019-09-25 15:51:41 +02:00
|
|
|
Preconditions.checkNotNull(id, "ID cannot be null.");
|
2019-08-07 20:22:51 +02:00
|
|
|
return ApplicationDependencies.getRecipientCache().getLive(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a fully-populated {@link Recipient}. May hit the disk, and therefore should be
|
|
|
|
* called on a background thread.
|
|
|
|
*/
|
|
|
|
@WorkerThread
|
|
|
|
public static @NonNull Recipient resolved(@NonNull RecipientId id) {
|
2019-09-25 15:51:41 +02:00
|
|
|
Preconditions.checkNotNull(id, "ID cannot be null.");
|
2019-08-07 20:22:51 +02:00
|
|
|
return live(id).resolve();
|
|
|
|
}
|
|
|
|
|
2019-10-29 01:16:11 +01:00
|
|
|
/**
|
|
|
|
* Returns a fully-populated {@link Recipient} and associates it with the provided username.
|
|
|
|
*/
|
|
|
|
@WorkerThread
|
|
|
|
public static @NonNull Recipient externalUsername(@NonNull Context context, @NonNull UUID uuid, @NonNull String username) {
|
|
|
|
Recipient recipient = externalPush(context, uuid, null);
|
|
|
|
DatabaseFactory.getRecipientDatabase(context).setUsername(recipient.getId(), username);
|
|
|
|
return recipient;
|
|
|
|
}
|
|
|
|
|
2019-09-07 05:40:06 +02:00
|
|
|
/**
|
|
|
|
* Returns a fully-populated {@link Recipient} based off of a {@link SignalServiceAddress},
|
|
|
|
* creating one in the database if necessary. Convenience overload of
|
|
|
|
* {@link #externalPush(Context, UUID, String)}
|
|
|
|
*/
|
|
|
|
@WorkerThread
|
|
|
|
public static @NonNull Recipient externalPush(@NonNull Context context, @NonNull SignalServiceAddress signalServiceAddress) {
|
|
|
|
return externalPush(context, signalServiceAddress.getUuid().orNull(), signalServiceAddress.getNumber().orNull());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a fully-populated {@link Recipient} based off of a UUID and phone number, creating one
|
|
|
|
* in the database if necessary. We want both piece of information so we're able to associate them
|
|
|
|
* both together, depending on which are available.
|
|
|
|
*
|
|
|
|
* In particular, while we'll eventually get the UUID of a user created via a phone number
|
|
|
|
* (through a directory sync), the only way we can store the phone number is by retrieving it from
|
|
|
|
* sent messages and whatnot. So we should store it when available.
|
|
|
|
*/
|
|
|
|
@WorkerThread
|
|
|
|
public static @NonNull Recipient externalPush(@NonNull Context context, @Nullable UUID uuid, @Nullable String e164) {
|
|
|
|
RecipientDatabase db = DatabaseFactory.getRecipientDatabase(context);
|
|
|
|
Optional<RecipientId> uuidUser = uuid != null ? db.getByUuid(uuid) : Optional.absent();
|
|
|
|
Optional<RecipientId> e164User = e164 != null ? db.getByE164(e164) : Optional.absent();
|
|
|
|
|
|
|
|
if (uuidUser.isPresent()) {
|
|
|
|
Recipient recipient = resolved(uuidUser.get());
|
|
|
|
|
|
|
|
if (e164 != null && !recipient.getE164().isPresent() && !e164User.isPresent()) {
|
|
|
|
db.setPhoneNumber(recipient.getId(), e164);
|
|
|
|
}
|
|
|
|
|
|
|
|
return resolved(recipient.getId());
|
|
|
|
} else if (e164User.isPresent()) {
|
|
|
|
Recipient recipient = resolved(e164User.get());
|
|
|
|
|
|
|
|
if (uuid != null && !recipient.getUuid().isPresent()) {
|
|
|
|
db.markRegistered(recipient.getId(), uuid);
|
|
|
|
} else if (!recipient.isRegistered()) {
|
|
|
|
db.markRegistered(recipient.getId());
|
|
|
|
|
2019-12-19 23:41:21 +01:00
|
|
|
if (FeatureFlags.uuids()) {
|
2019-12-04 17:19:03 +01:00
|
|
|
Log.i(TAG, "No UUID! Scheduling a fetch.");
|
|
|
|
ApplicationDependencies.getJobManager().add(new DirectoryRefreshJob(recipient, false));
|
|
|
|
}
|
2019-09-07 05:40:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return resolved(recipient.getId());
|
|
|
|
} else if (uuid != null) {
|
2019-12-19 23:41:21 +01:00
|
|
|
if (FeatureFlags.uuids() || e164 != null) {
|
2019-11-05 23:51:04 +01:00
|
|
|
RecipientId id = db.getOrInsertFromUuid(uuid);
|
|
|
|
db.markRegistered(id, uuid);
|
2019-09-07 05:40:06 +02:00
|
|
|
|
2019-11-05 23:51:04 +01:00
|
|
|
if (e164 != null) {
|
|
|
|
db.setPhoneNumber(id, e164);
|
|
|
|
}
|
2019-09-07 05:40:06 +02:00
|
|
|
|
2019-11-05 23:51:04 +01:00
|
|
|
return resolved(id);
|
|
|
|
} else {
|
|
|
|
throw new UuidRecipientError();
|
|
|
|
}
|
2019-09-07 05:40:06 +02:00
|
|
|
} else if (e164 != null) {
|
|
|
|
Recipient recipient = resolved(db.getOrInsertFromE164(e164));
|
|
|
|
|
|
|
|
if (!recipient.isRegistered()) {
|
|
|
|
db.markRegistered(recipient.getId());
|
|
|
|
|
2019-12-19 23:41:21 +01:00
|
|
|
if (FeatureFlags.uuids()) {
|
2019-12-04 17:19:03 +01:00
|
|
|
Log.i(TAG, "No UUID! Scheduling a fetch.");
|
|
|
|
ApplicationDependencies.getJobManager().add(new DirectoryRefreshJob(recipient, false));
|
|
|
|
}
|
2019-09-07 05:40:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return resolved(recipient.getId());
|
|
|
|
} else {
|
|
|
|
throw new AssertionError("You must provide either a UUID or phone number!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-25 17:04:45 +01:00
|
|
|
/**
|
|
|
|
* A safety wrapper around {@link #external(Context, String)} for when you know you're using an
|
|
|
|
* identifier for a system contact, and therefore always want to prevent interpreting it as a
|
|
|
|
* UUID. This will crash if given a UUID.
|
|
|
|
*
|
|
|
|
* (This may seem strange, but apparently some devices are returning valid UUIDs for contacts)
|
|
|
|
*/
|
|
|
|
@WorkerThread
|
|
|
|
public static @NonNull Recipient externalContact(@NonNull Context context, @NonNull String identifier) {
|
2020-01-18 00:32:26 +01:00
|
|
|
RecipientDatabase db = DatabaseFactory.getRecipientDatabase(context);
|
|
|
|
RecipientId id = null;
|
|
|
|
|
2019-11-25 17:04:45 +01:00
|
|
|
if (UuidUtil.isUuid(identifier)) {
|
|
|
|
throw new UuidRecipientError();
|
2020-01-18 00:32:26 +01:00
|
|
|
} else if (NumberUtil.isValidEmail(identifier)) {
|
|
|
|
id = db.getOrInsertFromEmail(identifier);
|
2019-11-25 17:04:45 +01:00
|
|
|
} else {
|
2020-01-18 00:32:26 +01:00
|
|
|
id = db.getOrInsertFromE164(identifier);
|
2019-11-25 17:04:45 +01:00
|
|
|
}
|
2020-01-18 00:32:26 +01:00
|
|
|
|
|
|
|
return Recipient.resolved(id);
|
2019-11-25 17:04:45 +01:00
|
|
|
}
|
|
|
|
|
2020-02-21 19:52:27 +01:00
|
|
|
/**
|
|
|
|
* A version of {@link #external(Context, String)} that should be used when you know the
|
|
|
|
* identifier is a groupId.
|
|
|
|
*/
|
|
|
|
@WorkerThread
|
2020-03-26 15:00:17 +01:00
|
|
|
public static @NonNull Recipient externalGroup(@NonNull Context context, @NonNull GroupId groupId) {
|
2020-02-21 19:52:27 +01:00
|
|
|
return Recipient.resolved(DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId));
|
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
/**
|
|
|
|
* Returns a fully-populated {@link Recipient} based off of a string identifier, creating one in
|
2019-09-07 05:40:06 +02:00
|
|
|
* the database if necessary. The identifier may be a uuid, phone number, email,
|
|
|
|
* or serialized groupId.
|
|
|
|
*
|
|
|
|
* If the identifier is a UUID of a Signal user, prefer using
|
|
|
|
* {@link #externalPush(Context, UUID, String)} or its overload, as this will let us associate
|
|
|
|
* the phone number with the recipient.
|
2019-08-07 20:22:51 +02:00
|
|
|
*/
|
|
|
|
@WorkerThread
|
2019-09-07 05:40:06 +02:00
|
|
|
public static @NonNull Recipient external(@NonNull Context context, @NonNull String identifier) {
|
|
|
|
Preconditions.checkNotNull(identifier, "Identifier cannot be null!");
|
2019-09-25 14:49:32 +02:00
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
RecipientDatabase db = DatabaseFactory.getRecipientDatabase(context);
|
|
|
|
RecipientId id = null;
|
|
|
|
|
2019-09-07 05:40:06 +02:00
|
|
|
if (UuidUtil.isUuid(identifier)) {
|
2019-11-05 23:51:04 +01:00
|
|
|
UUID uuid = UuidUtil.parseOrThrow(identifier);
|
|
|
|
|
2019-12-19 23:41:21 +01:00
|
|
|
if (FeatureFlags.uuids()) {
|
2019-11-05 23:51:04 +01:00
|
|
|
id = db.getOrInsertFromUuid(uuid);
|
|
|
|
} else {
|
|
|
|
Optional<RecipientId> possibleId = db.getByUuid(uuid);
|
|
|
|
|
|
|
|
if (possibleId.isPresent()) {
|
|
|
|
id = possibleId.get();
|
|
|
|
} else {
|
|
|
|
throw new UuidRecipientError();
|
|
|
|
}
|
|
|
|
}
|
2020-03-26 15:00:17 +01:00
|
|
|
} else if (GroupId.isEncodedGroup(identifier)) {
|
2020-04-20 17:01:31 +02:00
|
|
|
id = db.getOrInsertFromGroupId(GroupId.parseOrThrow(identifier));
|
2019-09-07 05:40:06 +02:00
|
|
|
} else if (NumberUtil.isValidEmail(identifier)) {
|
|
|
|
id = db.getOrInsertFromEmail(identifier);
|
2019-08-07 20:22:51 +02:00
|
|
|
} else {
|
2019-09-07 05:40:06 +02:00
|
|
|
String e164 = PhoneNumberFormatter.get(context).format(identifier);
|
2019-08-07 20:22:51 +02:00
|
|
|
id = db.getOrInsertFromE164(e164);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Recipient.resolved(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static @NonNull Recipient self() {
|
|
|
|
return ApplicationDependencies.getRecipientCache().getSelf();
|
|
|
|
}
|
|
|
|
|
|
|
|
Recipient(@NonNull RecipientId id) {
|
|
|
|
this.id = id;
|
|
|
|
this.resolving = true;
|
2019-09-07 05:40:06 +02:00
|
|
|
this.uuid = null;
|
2019-10-29 01:16:11 +01:00
|
|
|
this.username = null;
|
2019-09-07 05:40:06 +02:00
|
|
|
this.e164 = null;
|
|
|
|
this.email = null;
|
|
|
|
this.groupId = null;
|
2019-08-07 20:22:51 +02:00
|
|
|
this.participants = Collections.emptyList();
|
|
|
|
this.groupAvatarId = Optional.absent();
|
|
|
|
this.localNumber = false;
|
|
|
|
this.blocked = false;
|
|
|
|
this.muteUntil = 0;
|
|
|
|
this.messageVibrate = VibrateState.DEFAULT;
|
|
|
|
this.callVibrate = VibrateState.DEFAULT;
|
|
|
|
this.messageRingtone = null;
|
|
|
|
this.callRingtone = null;
|
|
|
|
this.color = null;
|
2019-11-12 15:18:57 +01:00
|
|
|
this.insightsBannerTier = InsightsBannerTier.TIER_TWO;
|
2019-08-07 20:22:51 +02:00
|
|
|
this.defaultSubscriptionId = Optional.absent();
|
|
|
|
this.expireMessages = 0;
|
|
|
|
this.registered = RegisteredState.UNKNOWN;
|
|
|
|
this.profileKey = null;
|
2020-02-11 00:40:22 +01:00
|
|
|
this.profileKeyCredential = null;
|
2019-08-07 20:22:51 +02:00
|
|
|
this.name = null;
|
|
|
|
this.systemContactPhoto = null;
|
|
|
|
this.customLabel = null;
|
|
|
|
this.contactUri = null;
|
2019-12-20 21:12:22 +01:00
|
|
|
this.profileName = ProfileName.EMPTY;
|
2019-08-07 20:22:51 +02:00
|
|
|
this.profileAvatar = null;
|
|
|
|
this.profileSharing = false;
|
|
|
|
this.notificationChannel = null;
|
|
|
|
this.unidentifiedAccessMode = UnidentifiedAccessMode.DISABLED;
|
|
|
|
this.forceSmsSelection = false;
|
2020-02-14 21:47:31 +01:00
|
|
|
this.uuidCapability = Capability.UNKNOWN;
|
2020-02-14 17:00:32 +01:00
|
|
|
this.groupsV2Capability = Capability.UNKNOWN;
|
2020-03-18 21:31:45 +01:00
|
|
|
this.storageId = null;
|
2019-09-26 16:12:51 +02:00
|
|
|
this.identityKey = null;
|
|
|
|
this.identityStatus = VerifiedStatus.DEFAULT;
|
2019-08-07 20:22:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Recipient(@NonNull RecipientId id, @NonNull RecipientDetails details) {
|
|
|
|
this.id = id;
|
|
|
|
this.resolving = false;
|
2019-09-07 05:40:06 +02:00
|
|
|
this.uuid = details.uuid;
|
2019-10-29 01:16:11 +01:00
|
|
|
this.username = details.username;
|
2019-09-07 05:40:06 +02:00
|
|
|
this.e164 = details.e164;
|
|
|
|
this.email = details.email;
|
|
|
|
this.groupId = details.groupId;
|
2019-08-07 20:22:51 +02:00
|
|
|
this.participants = details.participants;
|
2018-05-22 11:13:10 +02:00
|
|
|
this.groupAvatarId = details.groupAvatarId;
|
2019-08-07 20:22:51 +02:00
|
|
|
this.localNumber = details.isLocalNumber;
|
2018-05-22 11:13:10 +02:00
|
|
|
this.blocked = details.blocked;
|
2019-08-07 20:22:51 +02:00
|
|
|
this.muteUntil = details.mutedUntil;
|
2018-05-22 11:13:10 +02:00
|
|
|
this.messageVibrate = details.messageVibrateState;
|
|
|
|
this.callVibrate = details.callVibrateState;
|
2019-08-07 20:22:51 +02:00
|
|
|
this.messageRingtone = details.messageRingtone;
|
|
|
|
this.callRingtone = details.callRingtone;
|
|
|
|
this.color = details.color;
|
2019-11-12 15:18:57 +01:00
|
|
|
this.insightsBannerTier = details.insightsBannerTier;
|
2018-05-22 11:13:10 +02:00
|
|
|
this.defaultSubscriptionId = details.defaultSubscriptionId;
|
2019-08-07 20:22:51 +02:00
|
|
|
this.expireMessages = details.expireMessages;
|
2018-05-22 11:13:10 +02:00
|
|
|
this.registered = details.registered;
|
|
|
|
this.profileKey = details.profileKey;
|
2020-02-11 00:40:22 +01:00
|
|
|
this.profileKeyCredential = details.profileKeyCredential;
|
2019-08-07 20:22:51 +02:00
|
|
|
this.name = details.name;
|
|
|
|
this.systemContactPhoto = details.systemContactPhoto;
|
|
|
|
this.customLabel = details.customLabel;
|
|
|
|
this.contactUri = details.contactUri;
|
2018-05-22 11:13:10 +02:00
|
|
|
this.profileName = details.profileName;
|
|
|
|
this.profileAvatar = details.profileAvatar;
|
|
|
|
this.profileSharing = details.profileSharing;
|
2019-08-07 20:22:51 +02:00
|
|
|
this.notificationChannel = details.notificationChannel;
|
2018-05-22 11:13:10 +02:00
|
|
|
this.unidentifiedAccessMode = details.unidentifiedAccessMode;
|
2019-04-12 21:22:38 +02:00
|
|
|
this.forceSmsSelection = details.forceSmsSelection;
|
2020-02-14 21:47:31 +01:00
|
|
|
this.uuidCapability = details.uuidCapability;
|
2020-02-14 17:00:32 +01:00
|
|
|
this.groupsV2Capability = details.groupsV2Capability;
|
2020-03-18 21:31:45 +01:00
|
|
|
this.storageId = details.storageId;
|
2019-09-26 16:12:51 +02:00
|
|
|
this.identityKey = details.identityKey;
|
|
|
|
this.identityStatus = details.identityStatus;
|
2011-12-20 19:20:44 +01:00
|
|
|
}
|
2012-09-12 03:23:19 +02:00
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public @NonNull RecipientId getId() {
|
|
|
|
return id;
|
2019-01-14 08:30:54 +01:00
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public boolean isLocalNumber() {
|
|
|
|
return localNumber;
|
2011-12-20 19:20:44 +01:00
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public @Nullable Uri getContactUri() {
|
|
|
|
return contactUri;
|
2017-11-26 19:45:39 +01:00
|
|
|
}
|
|
|
|
|
2019-10-09 18:57:36 +02:00
|
|
|
public @Nullable String getName(@NonNull Context context) {
|
2020-03-27 15:28:48 +01:00
|
|
|
if (this.name == null && groupId != null && groupId.isMms()) {
|
2017-08-01 17:56:00 +02:00
|
|
|
List<String> names = new LinkedList<>();
|
|
|
|
|
|
|
|
for (Recipient recipient : participants) {
|
2019-10-31 17:20:55 +01:00
|
|
|
names.add(recipient.toShortString(context));
|
2017-08-01 17:56:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return Util.join(names, ", ");
|
|
|
|
}
|
|
|
|
|
2013-01-07 00:46:26 +01:00
|
|
|
return this.name;
|
2011-12-20 19:20:44 +01:00
|
|
|
}
|
|
|
|
|
2019-10-31 17:20:55 +01:00
|
|
|
/**
|
|
|
|
* TODO [UUID] -- Remove once UUID Feature Flag is removed
|
|
|
|
*/
|
|
|
|
@Deprecated
|
|
|
|
public @NonNull String toShortString(@NonNull Context context) {
|
2019-12-19 23:41:21 +01:00
|
|
|
if (FeatureFlags.profileDisplay()) return getDisplayName(context);
|
|
|
|
else return Optional.fromNullable(getName(context)).or(getSmsAddress()).or("");
|
2019-10-31 17:20:55 +01:00
|
|
|
}
|
|
|
|
|
2019-10-09 18:57:36 +02:00
|
|
|
public @NonNull String getDisplayName(@NonNull Context context) {
|
|
|
|
return Util.getFirstNonEmpty(getName(context),
|
2019-12-20 21:12:22 +01:00
|
|
|
getProfileName().toString(),
|
2019-10-29 01:16:11 +01:00
|
|
|
getDisplayUsername(),
|
2019-10-09 18:57:36 +02:00
|
|
|
e164,
|
|
|
|
email,
|
|
|
|
context.getString(R.string.Recipient_unknown));
|
|
|
|
}
|
2019-08-27 00:09:01 +02:00
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public @NonNull MaterialColor getColor() {
|
2020-04-03 18:59:06 +02:00
|
|
|
if (isGroupInternal()) {
|
|
|
|
return MaterialColor.GROUP;
|
|
|
|
} else if (color != null) {
|
|
|
|
return color;
|
|
|
|
} else if (name != null) {
|
|
|
|
Log.i(TAG, "Saving color for " + id);
|
|
|
|
MaterialColor color = ContactColors.generateFor(name);
|
|
|
|
DatabaseFactory.getRecipientDatabase(ApplicationDependencies.getApplication()).setColor(id, color);
|
|
|
|
return color;
|
|
|
|
} else {
|
|
|
|
return ContactColors.UNKNOWN_COLOR;
|
|
|
|
}
|
2015-06-30 00:33:36 +02:00
|
|
|
}
|
|
|
|
|
2019-09-07 05:40:06 +02:00
|
|
|
public @NonNull Optional<UUID> getUuid() {
|
|
|
|
return Optional.fromNullable(uuid);
|
|
|
|
}
|
|
|
|
|
2019-10-29 01:16:11 +01:00
|
|
|
public @NonNull Optional<String> getUsername() {
|
2019-12-19 23:41:21 +01:00
|
|
|
if (FeatureFlags.usernames()) {
|
2019-10-29 01:16:11 +01:00
|
|
|
return Optional.fromNullable(username);
|
|
|
|
} else {
|
|
|
|
return Optional.absent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-07 05:40:06 +02:00
|
|
|
public @NonNull Optional<String> getE164() {
|
|
|
|
return Optional.fromNullable(e164);
|
|
|
|
}
|
|
|
|
|
|
|
|
public @NonNull Optional<String> getEmail() {
|
|
|
|
return Optional.fromNullable(email);
|
|
|
|
}
|
|
|
|
|
2020-03-26 15:00:17 +01:00
|
|
|
public @NonNull Optional<GroupId> getGroupId() {
|
2019-09-07 05:40:06 +02:00
|
|
|
return Optional.fromNullable(groupId);
|
|
|
|
}
|
|
|
|
|
|
|
|
public @NonNull Optional<String> getSmsAddress() {
|
|
|
|
return Optional.fromNullable(e164).or(Optional.fromNullable(email));
|
|
|
|
}
|
|
|
|
|
2020-04-09 23:45:48 +02:00
|
|
|
public @NonNull UUID requireUuid() {
|
|
|
|
UUID resolved = resolving ? resolve().uuid : uuid;
|
|
|
|
|
|
|
|
if (resolved == null) {
|
|
|
|
throw new MissingAddressError();
|
|
|
|
}
|
|
|
|
|
|
|
|
return resolved;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-07 05:40:06 +02:00
|
|
|
public @NonNull String requireE164() {
|
|
|
|
String resolved = resolving ? resolve().e164 : e164;
|
|
|
|
|
|
|
|
if (resolved == null) {
|
|
|
|
throw new MissingAddressError();
|
|
|
|
}
|
|
|
|
|
|
|
|
return resolved;
|
|
|
|
}
|
|
|
|
|
|
|
|
public @NonNull String requireEmail() {
|
|
|
|
String resolved = resolving ? resolve().email : email;
|
|
|
|
|
|
|
|
if (resolved == null) {
|
|
|
|
throw new MissingAddressError();
|
|
|
|
}
|
|
|
|
|
|
|
|
return resolved;
|
|
|
|
}
|
|
|
|
|
|
|
|
public @NonNull String requireSmsAddress() {
|
|
|
|
Recipient recipient = resolving ? resolve() : this;
|
|
|
|
|
|
|
|
if (recipient.getE164().isPresent()) {
|
|
|
|
return recipient.getE164().get();
|
|
|
|
} else if (recipient.getEmail().isPresent()) {
|
|
|
|
return recipient.getEmail().get();
|
2019-08-07 20:22:51 +02:00
|
|
|
} else {
|
2019-09-07 05:40:06 +02:00
|
|
|
throw new MissingAddressError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean hasSmsAddress() {
|
|
|
|
return getE164().or(getEmail()).isPresent();
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean hasE164() {
|
|
|
|
return getE164().isPresent();
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean hasUuid() {
|
|
|
|
return getUuid().isPresent();
|
|
|
|
}
|
|
|
|
|
2020-03-26 15:00:17 +01:00
|
|
|
public @NonNull GroupId requireGroupId() {
|
|
|
|
GroupId resolved = resolving ? resolve().groupId : groupId;
|
2019-09-07 05:40:06 +02:00
|
|
|
|
|
|
|
if (resolved == null) {
|
|
|
|
throw new MissingAddressError();
|
|
|
|
}
|
|
|
|
|
|
|
|
return resolved;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean hasServiceIdentifier() {
|
|
|
|
return uuid != null || e164 != null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return A string identifier able to be used with the Signal service. Prefers UUID, and if not
|
|
|
|
* available, will return an E164 number.
|
|
|
|
*/
|
|
|
|
public @NonNull String requireServiceId() {
|
|
|
|
Recipient resolved = resolving ? resolve() : this;
|
|
|
|
|
|
|
|
if (resolved.getUuid().isPresent()) {
|
|
|
|
return resolved.getUuid().get().toString();
|
|
|
|
} else {
|
|
|
|
return getE164().get();
|
2015-06-30 00:33:36 +02:00
|
|
|
}
|
2011-12-20 19:20:44 +01:00
|
|
|
}
|
2012-09-12 03:23:19 +02:00
|
|
|
|
2019-09-07 05:40:06 +02:00
|
|
|
/**
|
|
|
|
* @return A single string to represent the recipient, in order of precedence:
|
|
|
|
*
|
|
|
|
* Group ID > UUID > Phone > Email
|
|
|
|
*/
|
|
|
|
public @NonNull String requireStringId() {
|
|
|
|
Recipient resolved = resolving ? resolve() : this;
|
|
|
|
|
|
|
|
if (resolved.isGroup()) {
|
2020-03-26 15:00:17 +01:00
|
|
|
return resolved.requireGroupId().toString();
|
2019-09-07 05:40:06 +02:00
|
|
|
} else if (resolved.getUuid().isPresent()) {
|
|
|
|
return resolved.getUuid().get().toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
return requireSmsAddress();
|
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public Optional<Integer> getDefaultSubscriptionId() {
|
2017-08-22 19:44:04 +02:00
|
|
|
return defaultSubscriptionId;
|
|
|
|
}
|
|
|
|
|
2019-12-20 21:12:22 +01:00
|
|
|
public @NonNull ProfileName getProfileName() {
|
2017-08-16 04:23:42 +02:00
|
|
|
return profileName;
|
|
|
|
}
|
|
|
|
|
2019-10-31 17:20:55 +01:00
|
|
|
public @Nullable String getCustomLabel() {
|
2019-12-19 23:41:21 +01:00
|
|
|
if (FeatureFlags.profileDisplay()) throw new AssertionError("This method should never be called if PROFILE_DISPLAY is enabled.");
|
2019-10-31 17:20:55 +01:00
|
|
|
return customLabel;
|
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public @Nullable String getProfileAvatar() {
|
2017-08-22 19:44:04 +02:00
|
|
|
return profileAvatar;
|
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public boolean isProfileSharing() {
|
2017-08-22 19:44:04 +02:00
|
|
|
return profileSharing;
|
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public boolean isGroup() {
|
2019-09-07 05:40:06 +02:00
|
|
|
return resolve().groupId != null;
|
2017-08-01 17:56:00 +02:00
|
|
|
}
|
|
|
|
|
2019-10-08 23:08:25 +02:00
|
|
|
private boolean isGroupInternal() {
|
2019-09-07 05:40:06 +02:00
|
|
|
return groupId != null;
|
2019-10-08 23:08:25 +02:00
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public boolean isMmsGroup() {
|
2020-03-26 15:00:17 +01:00
|
|
|
GroupId groupId = resolve().groupId;
|
2020-03-27 15:28:48 +01:00
|
|
|
return groupId != null && groupId.isMms();
|
2017-11-20 23:48:39 +01:00
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public boolean isPushGroup() {
|
2020-03-26 15:00:17 +01:00
|
|
|
GroupId groupId = resolve().groupId;
|
2020-03-27 15:28:48 +01:00
|
|
|
return groupId != null && groupId.isPush();
|
2013-01-07 00:46:26 +01:00
|
|
|
}
|
|
|
|
|
2020-04-09 23:02:13 +02:00
|
|
|
public boolean isPushV2Group() {
|
|
|
|
GroupId groupId = resolve().groupId;
|
|
|
|
return groupId != null && groupId.isV2();
|
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public @NonNull List<Recipient> getParticipants() {
|
|
|
|
return new ArrayList<>(participants);
|
2012-12-24 17:40:37 +01:00
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public @NonNull Drawable getFallbackContactPhotoDrawable(Context context, boolean inverted) {
|
2020-02-19 23:08:34 +01:00
|
|
|
return getFallbackContactPhotoDrawable(context, inverted, DEFAULT_FALLBACK_PHOTO_PROVIDER);
|
2017-10-16 22:11:42 +02:00
|
|
|
}
|
|
|
|
|
2020-02-19 23:08:34 +01:00
|
|
|
public @NonNull Drawable getFallbackContactPhotoDrawable(Context context, boolean inverted, @Nullable FallbackPhotoProvider fallbackPhotoProvider) {
|
|
|
|
return getFallbackContactPhoto(Util.firstNonNull(fallbackPhotoProvider, DEFAULT_FALLBACK_PHOTO_PROVIDER)).asDrawable(context, getColor().toAvatarColor(context), inverted);
|
|
|
|
}
|
|
|
|
|
|
|
|
public @NonNull Drawable getSmallFallbackContactPhotoDrawable(Context context, boolean inverted, @Nullable FallbackPhotoProvider fallbackPhotoProvider) {
|
|
|
|
return getFallbackContactPhoto(Util.firstNonNull(fallbackPhotoProvider, DEFAULT_FALLBACK_PHOTO_PROVIDER)).asSmallDrawable(context, getColor().toAvatarColor(context), inverted);
|
2019-10-07 20:43:36 +02:00
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public @NonNull FallbackContactPhoto getFallbackContactPhoto() {
|
2020-02-19 23:08:34 +01:00
|
|
|
return getFallbackContactPhoto(DEFAULT_FALLBACK_PHOTO_PROVIDER);
|
|
|
|
}
|
|
|
|
|
|
|
|
public @NonNull FallbackContactPhoto getFallbackContactPhoto(@NonNull FallbackPhotoProvider fallbackPhotoProvider) {
|
|
|
|
if (localNumber) return fallbackPhotoProvider.getPhotoForLocalNumber();
|
|
|
|
if (isResolving()) return fallbackPhotoProvider.getPhotoForResolvingRecipient();
|
|
|
|
else if (isGroupInternal()) return fallbackPhotoProvider.getPhotoForGroup();
|
|
|
|
else if (isGroup()) return fallbackPhotoProvider.getPhotoForGroup();
|
|
|
|
else if (!TextUtils.isEmpty(name)) return fallbackPhotoProvider.getPhotoForRecipientWithName(name);
|
|
|
|
else return fallbackPhotoProvider.getPhotoForRecipientWithoutName();
|
2017-10-16 22:11:42 +02:00
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public @Nullable ContactPhoto getContactPhoto() {
|
2019-10-08 23:08:25 +02:00
|
|
|
if (localNumber) return null;
|
2019-09-07 05:40:06 +02:00
|
|
|
else if (isGroupInternal() && groupAvatarId.isPresent()) return new GroupRecordContactPhoto(groupId, groupAvatarId.get());
|
2020-03-25 23:43:02 +01:00
|
|
|
else if (profileAvatar != null) return new ProfileContactPhoto(this, profileAvatar);
|
2020-04-01 18:39:22 +02:00
|
|
|
else if (systemContactPhoto != null) return new SystemContactPhoto(id, systemContactPhoto, 0);
|
2019-10-08 23:08:25 +02:00
|
|
|
else return null;
|
2017-11-26 19:45:39 +01:00
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public @Nullable Uri getMessageRingtone() {
|
2018-02-16 20:10:35 +01:00
|
|
|
if (messageRingtone != null && messageRingtone.getScheme() != null && messageRingtone.getScheme().startsWith("file")) {
|
2017-12-19 20:01:55 +01:00
|
|
|
return null;
|
|
|
|
}
|
2017-12-19 23:42:00 +01:00
|
|
|
|
2018-02-16 20:10:35 +01:00
|
|
|
return messageRingtone;
|
2017-08-01 17:56:00 +02:00
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public @Nullable Uri getCallRingtone() {
|
2018-02-16 20:10:35 +01:00
|
|
|
if (callRingtone != null && callRingtone.getScheme() != null && callRingtone.getScheme().startsWith("file")) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return callRingtone;
|
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public boolean isMuted() {
|
|
|
|
return System.currentTimeMillis() <= muteUntil;
|
2017-08-01 17:56:00 +02:00
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public boolean isBlocked() {
|
2017-08-01 17:56:00 +02:00
|
|
|
return blocked;
|
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public @NonNull VibrateState getMessageVibrate() {
|
2018-02-16 20:10:35 +01:00
|
|
|
return messageVibrate;
|
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public @NonNull VibrateState getCallVibrate() {
|
2018-02-16 20:10:35 +01:00
|
|
|
return callVibrate;
|
2017-08-01 17:56:00 +02:00
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public int getExpireMessages() {
|
2017-08-01 17:56:00 +02:00
|
|
|
return expireMessages;
|
|
|
|
}
|
|
|
|
|
2019-11-12 15:18:57 +01:00
|
|
|
public boolean hasSeenFirstInviteReminder() {
|
|
|
|
return insightsBannerTier.seen(InsightsBannerTier.TIER_ONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean hasSeenSecondInviteReminder() {
|
|
|
|
return insightsBannerTier.seen(InsightsBannerTier.TIER_TWO);
|
2017-08-22 19:44:04 +02:00
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public @NonNull RegisteredState getRegistered() {
|
|
|
|
if (isPushGroup()) return RegisteredState.REGISTERED;
|
|
|
|
else if (isMmsGroup()) return RegisteredState.NOT_REGISTERED;
|
2017-08-22 20:51:01 +02:00
|
|
|
|
2017-08-22 19:44:04 +02:00
|
|
|
return registered;
|
|
|
|
}
|
|
|
|
|
2019-10-17 15:04:37 +02:00
|
|
|
public boolean isRegistered() {
|
|
|
|
return registered == RegisteredState.REGISTERED || isPushGroup();
|
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public @Nullable String getNotificationChannel() {
|
2018-08-31 02:59:15 +02:00
|
|
|
return !NotificationChannels.supported() ? null : notificationChannel;
|
2018-08-16 18:47:43 +02:00
|
|
|
}
|
|
|
|
|
2019-04-12 21:22:38 +02:00
|
|
|
public boolean isForceSmsSelection() {
|
|
|
|
return forceSmsSelection;
|
|
|
|
}
|
|
|
|
|
2019-09-07 05:40:06 +02:00
|
|
|
/**
|
|
|
|
* @return True if this recipient can support receiving UUID-only messages, otherwise false.
|
|
|
|
*/
|
|
|
|
public boolean isUuidSupported() {
|
2019-12-19 23:41:21 +01:00
|
|
|
if (FeatureFlags.usernames()) {
|
2019-10-29 01:16:11 +01:00
|
|
|
return true;
|
|
|
|
} else {
|
2020-02-14 21:47:31 +01:00
|
|
|
return FeatureFlags.uuids() && uuidCapability == Capability.SUPPORTED;
|
2019-10-29 01:16:11 +01:00
|
|
|
}
|
2019-09-07 05:40:06 +02:00
|
|
|
}
|
|
|
|
|
2020-02-14 17:00:32 +01:00
|
|
|
public Capability getGroupsV2Capability() {
|
|
|
|
return groupsV2Capability;
|
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public @Nullable byte[] getProfileKey() {
|
2017-08-22 19:44:04 +02:00
|
|
|
return profileKey;
|
|
|
|
}
|
|
|
|
|
2020-02-11 00:40:22 +01:00
|
|
|
public @Nullable byte[] getProfileKeyCredential() {
|
|
|
|
return profileKeyCredential;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean hasProfileKeyCredential() {
|
|
|
|
return profileKeyCredential != null;
|
|
|
|
}
|
|
|
|
|
2020-03-18 21:31:45 +01:00
|
|
|
public @Nullable byte[] getStorageServiceId() {
|
|
|
|
return storageId;
|
2019-09-26 16:12:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public @NonNull VerifiedStatus getIdentityVerifiedStatus() {
|
|
|
|
return identityStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
public @Nullable byte[] getIdentityKey() {
|
|
|
|
return identityKey;
|
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public @NonNull UnidentifiedAccessMode getUnidentifiedAccessMode() {
|
|
|
|
return unidentifiedAccessMode;
|
2017-08-22 19:44:04 +02:00
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public boolean isSystemContact() {
|
|
|
|
return contactUri != null;
|
2018-05-22 11:13:10 +02:00
|
|
|
}
|
|
|
|
|
2020-02-21 19:52:27 +01:00
|
|
|
/**
|
|
|
|
* If this recipient is missing crucial data, this will return a populated copy. Otherwise it
|
|
|
|
* returns itself.
|
|
|
|
*/
|
|
|
|
public @NonNull Recipient resolve() {
|
2019-08-07 20:22:51 +02:00
|
|
|
if (resolving) {
|
|
|
|
return live().resolve();
|
|
|
|
} else {
|
|
|
|
return this;
|
2018-05-22 11:13:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public boolean isResolving() {
|
|
|
|
return resolving;
|
2017-08-22 19:44:04 +02:00
|
|
|
}
|
|
|
|
|
2020-02-21 19:52:27 +01:00
|
|
|
/**
|
|
|
|
* Forces retrieving a fresh copy of the recipient, regardless of its state.
|
|
|
|
*/
|
|
|
|
public @NonNull Recipient fresh() {
|
|
|
|
return live().resolve();
|
|
|
|
}
|
|
|
|
|
2019-08-07 20:22:51 +02:00
|
|
|
public @NonNull LiveRecipient live() {
|
|
|
|
return ApplicationDependencies.getRecipientCache().getLive(id);
|
2017-08-22 19:44:04 +02:00
|
|
|
}
|
|
|
|
|
2019-10-29 01:16:11 +01:00
|
|
|
private @Nullable String getDisplayUsername() {
|
|
|
|
if (!TextUtils.isEmpty(username)) {
|
|
|
|
return "@" + username;
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-19 03:17:08 +01:00
|
|
|
@Override
|
|
|
|
public boolean equals(Object o) {
|
|
|
|
if (this == o) return true;
|
2019-08-07 20:22:51 +02:00
|
|
|
if (o == null || getClass() != o.getClass()) return false;
|
|
|
|
Recipient recipient = (Recipient) o;
|
|
|
|
return id.equals(recipient.id);
|
2014-01-19 03:17:08 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 17:00:32 +01:00
|
|
|
public enum Capability {
|
|
|
|
UNKNOWN(0),
|
|
|
|
SUPPORTED(1),
|
|
|
|
NOT_SUPPORTED(-1);
|
|
|
|
|
|
|
|
private final int value;
|
|
|
|
|
|
|
|
Capability(int value) {
|
|
|
|
this.value = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int serialize() {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Capability deserialize(int value) {
|
|
|
|
switch (value) {
|
|
|
|
case 1 : return SUPPORTED;
|
|
|
|
case -1 : return NOT_SUPPORTED;
|
|
|
|
default : return UNKNOWN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Capability fromBoolean(boolean supported) {
|
|
|
|
return supported ? SUPPORTED : NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-19 03:17:08 +01:00
|
|
|
@Override
|
|
|
|
public int hashCode() {
|
2019-08-07 20:22:51 +02:00
|
|
|
return Objects.hash(id);
|
2012-12-24 17:40:37 +01:00
|
|
|
}
|
2019-09-07 05:40:06 +02:00
|
|
|
|
2020-02-19 23:08:34 +01:00
|
|
|
public static class FallbackPhotoProvider {
|
|
|
|
public @NonNull FallbackContactPhoto getPhotoForLocalNumber() {
|
|
|
|
return new ResourceContactPhoto(R.drawable.ic_note_34, R.drawable.ic_note_24);
|
|
|
|
}
|
|
|
|
|
|
|
|
public @NonNull FallbackContactPhoto getPhotoForResolvingRecipient() {
|
|
|
|
return new TransparentContactPhoto();
|
|
|
|
}
|
|
|
|
|
|
|
|
public @NonNull FallbackContactPhoto getPhotoForGroup() {
|
|
|
|
return new ResourceContactPhoto(R.drawable.ic_group_outline_34, R.drawable.ic_group_outline_20, R.drawable.ic_group_outline_48);
|
|
|
|
}
|
|
|
|
|
|
|
|
public @NonNull FallbackContactPhoto getPhotoForRecipientWithName(String name) {
|
|
|
|
return new GeneratedContactPhoto(name, R.drawable.ic_profile_outline_40);
|
|
|
|
}
|
|
|
|
|
|
|
|
public @NonNull FallbackContactPhoto getPhotoForRecipientWithoutName() {
|
|
|
|
return new ResourceContactPhoto(R.drawable.ic_profile_outline_40, R.drawable.ic_profile_outline_20, R.drawable.ic_profile_outline_48);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-09-07 05:40:06 +02:00
|
|
|
private static class MissingAddressError extends AssertionError {
|
|
|
|
}
|
2019-11-05 23:51:04 +01:00
|
|
|
|
|
|
|
private static class UuidRecipientError extends AssertionError {
|
|
|
|
}
|
2011-12-20 19:20:44 +01:00
|
|
|
}
|