Signal-Android/app/src/main/java/org/thoughtcrime/securesms/profiles/ProfileName.java

164 lines
4.8 KiB
Java

package org.thoughtcrime.securesms.profiles;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.util.StringUtil;
import org.thoughtcrime.securesms.util.cjkv.CJKVUtil;
import org.whispersystems.signalservice.api.crypto.ProfileCipher;
import java.util.Objects;
public final class ProfileName implements Parcelable {
public static final ProfileName EMPTY = new ProfileName("", "");
public static final int MAX_PART_LENGTH = (ProfileCipher.NAME_PADDED_LENGTH - 1) / 2;
private final String givenName;
private final String familyName;
private final String joinedName;
private ProfileName(@Nullable String givenName, @Nullable String familyName) {
this.givenName = givenName == null ? "" : givenName;
this.familyName = familyName == null ? "" : familyName;
this.joinedName = getJoinedName(this.givenName, this.familyName);
}
private ProfileName(Parcel in) {
this(in.readString(), in.readString());
}
public @NonNull String getGivenName() {
return givenName;
}
public @NonNull String getFamilyName() {
return familyName;
}
@VisibleForTesting
boolean isProfileNameCJKV() {
return isCJKV(givenName, familyName);
}
public boolean isEmpty() {
return joinedName.isEmpty();
}
public boolean isGivenNameEmpty() {
return givenName.isEmpty();
}
public @NonNull String serialize() {
if (isGivenNameEmpty()) {
return "";
} else if (familyName.isEmpty()) {
return givenName;
} else {
return String.format("%s\0%s", givenName, familyName);
}
}
@Override
public @NonNull String toString() {
return joinedName;
}
/**
* Deserializes a profile name, trims if exceeds the limits.
*/
public static @NonNull ProfileName fromSerialized(@Nullable String profileName) {
if (profileName == null || profileName.isEmpty()) {
return EMPTY;
}
String[] parts = profileName.split("\0");
if (parts.length == 0) {
return EMPTY;
} else if (parts.length == 1) {
return fromParts(parts[0], "");
} else {
return fromParts(parts[0], parts[1]);
}
}
/**
* Creates a profile name, trimming chars until it fits the limits.
*/
public static @NonNull ProfileName fromParts(@Nullable String givenName, @Nullable String familyName) {
givenName = givenName == null ? "" : givenName;
familyName = familyName == null ? "" : familyName;
givenName = StringUtil.trimToFit(givenName.trim(), ProfileName.MAX_PART_LENGTH);
familyName = StringUtil.trimToFit(familyName.trim(), ProfileName.MAX_PART_LENGTH);
return new ProfileName(givenName, familyName);
}
private static @NonNull String getJoinedName(@NonNull String givenName, @NonNull String familyName) {
if (givenName.isEmpty() && familyName.isEmpty()) return "";
else if (givenName.isEmpty()) return familyName;
else if (familyName.isEmpty()) return givenName;
else if (isCJKV(givenName, familyName)) return String.format("%s %s",
familyName,
givenName);
else return String.format("%s %s",
givenName,
familyName);
}
private static boolean isCJKV(@NonNull String givenName, @NonNull String familyName) {
if (givenName.isEmpty() && familyName.isEmpty()) {
return false;
} else {
return Stream.of(givenName, familyName)
.filterNot(String::isEmpty)
.reduce(true, (a, s) -> a && CJKVUtil.isCJKV(s));
}
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(givenName);
dest.writeString(familyName);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProfileName that = (ProfileName) o;
return Objects.equals(givenName, that.givenName) &&
Objects.equals(familyName, that.familyName);
}
@Override
public int hashCode() {
return Objects.hash(givenName, familyName);
}
public static final Creator<ProfileName> CREATOR = new Creator<ProfileName>() {
@Override
public ProfileName createFromParcel(Parcel in) {
return new ProfileName(in);
}
@Override
public ProfileName[] newArray(int size) {
return new ProfileName[size];
}
};
}