Move capabilities into a single column.
This commit is contained in:
parent
ead64d92a5
commit
3357475fc4
9 changed files with 276 additions and 60 deletions
|
@ -31,6 +31,7 @@ import org.thoughtcrime.securesms.groups.v2.ProfileKeySet;
|
|||
import org.thoughtcrime.securesms.groups.v2.processing.GroupsV2StateProcessor;
|
||||
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
|
||||
import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob;
|
||||
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
||||
import org.thoughtcrime.securesms.profiles.ProfileName;
|
||||
|
@ -40,6 +41,7 @@ import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
|||
import org.thoughtcrime.securesms.storage.StorageSyncHelper.RecordUpdate;
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncModels;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.Bitmask;
|
||||
import org.thoughtcrime.securesms.util.CursorUtil;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||
|
@ -114,8 +116,7 @@ public class RecipientDatabase extends Database {
|
|||
private static final String LAST_PROFILE_FETCH = "last_profile_fetch";
|
||||
private static final String UNIDENTIFIED_ACCESS_MODE = "unidentified_access_mode";
|
||||
private static final String FORCE_SMS_SELECTION = "force_sms_selection";
|
||||
private static final String UUID_CAPABILITY = "uuid_supported";
|
||||
private static final String GROUPS_V2_CAPABILITY = "gv2_capability";
|
||||
private static final String CAPABILITIES = "capabilities";
|
||||
private static final String STORAGE_SERVICE_ID = "storage_service_key";
|
||||
private static final String DIRTY = "dirty";
|
||||
private static final String PROFILE_GIVEN_NAME = "signal_profile_name";
|
||||
|
@ -129,6 +130,11 @@ public class RecipientDatabase extends Database {
|
|||
private static final String IDENTITY_STATUS = "identity_status";
|
||||
private static final String IDENTITY_KEY = "identity_key";
|
||||
|
||||
private static final class Capabilities {
|
||||
static final int BIT_LENGTH = 2;
|
||||
static final int GROUPS_V2 = 0;
|
||||
}
|
||||
|
||||
private static final String[] RECIPIENT_PROJECTION = new String[] {
|
||||
ID, UUID, USERNAME, PHONE, EMAIL, GROUP_ID, GROUP_TYPE,
|
||||
BLOCKED, MESSAGE_RINGTONE, CALL_RINGTONE, MESSAGE_VIBRATE, CALL_VIBRATE, MUTE_UNTIL, COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, MESSAGE_EXPIRATION_TIME, REGISTERED,
|
||||
|
@ -138,7 +144,7 @@ public class RecipientDatabase extends Database {
|
|||
NOTIFICATION_CHANNEL,
|
||||
UNIDENTIFIED_ACCESS_MODE,
|
||||
FORCE_SMS_SELECTION,
|
||||
UUID_CAPABILITY, GROUPS_V2_CAPABILITY,
|
||||
CAPABILITIES,
|
||||
STORAGE_SERVICE_ID, DIRTY,
|
||||
MENTION_SETTING
|
||||
};
|
||||
|
@ -329,12 +335,11 @@ public class RecipientDatabase extends Database {
|
|||
LAST_PROFILE_FETCH + " INTEGER DEFAULT 0, " +
|
||||
UNIDENTIFIED_ACCESS_MODE + " INTEGER DEFAULT 0, " +
|
||||
FORCE_SMS_SELECTION + " INTEGER DEFAULT 0, " +
|
||||
UUID_CAPABILITY + " INTEGER DEFAULT " + Recipient.Capability.UNKNOWN.serialize() + ", " +
|
||||
GROUPS_V2_CAPABILITY + " INTEGER DEFAULT " + Recipient.Capability.UNKNOWN.serialize() + ", " +
|
||||
STORAGE_SERVICE_ID + " TEXT UNIQUE DEFAULT NULL, " +
|
||||
DIRTY + " INTEGER DEFAULT " + DirtyState.CLEAN.getId() + ", " +
|
||||
MENTION_SETTING + " INTEGER DEFAULT " + MentionSetting.ALWAYS_NOTIFY.getId() + ", " +
|
||||
STORAGE_PROTO + " TEXT DEFAULT NULL);";
|
||||
STORAGE_PROTO + " TEXT DEFAULT NULL, " +
|
||||
CAPABILITIES + " INTEGER DEFAULT 0);";
|
||||
|
||||
private static final String INSIGHTS_INVITEE_LIST = "SELECT " + TABLE_NAME + "." + ID +
|
||||
" FROM " + TABLE_NAME +
|
||||
|
@ -503,6 +508,7 @@ public class RecipientDatabase extends Database {
|
|||
if (transactionSuccessful) {
|
||||
if (recipientNeedingRefresh != null) {
|
||||
Recipient.live(recipientNeedingRefresh).refresh();
|
||||
RetrieveProfileJob.enqueue(recipientNeedingRefresh);
|
||||
}
|
||||
|
||||
if (remapped != null) {
|
||||
|
@ -1173,8 +1179,7 @@ public class RecipientDatabase extends Database {
|
|||
String notificationChannel = CursorUtil.requireString(cursor, NOTIFICATION_CHANNEL);
|
||||
int unidentifiedAccessMode = CursorUtil.requireInt(cursor, UNIDENTIFIED_ACCESS_MODE);
|
||||
boolean forceSmsSelection = CursorUtil.requireBoolean(cursor, FORCE_SMS_SELECTION);
|
||||
int uuidCapabilityValue = CursorUtil.requireInt(cursor, UUID_CAPABILITY);
|
||||
int groupsV2CapabilityValue = CursorUtil.requireInt(cursor, GROUPS_V2_CAPABILITY);
|
||||
long capabilities = CursorUtil.requireLong(cursor, CAPABILITIES);
|
||||
String storageKeyRaw = CursorUtil.requireString(cursor, STORAGE_SERVICE_ID);
|
||||
int mentionSettingId = CursorUtil.requireInt(cursor, MENTION_SETTING);
|
||||
|
||||
|
@ -1240,8 +1245,7 @@ public class RecipientDatabase extends Database {
|
|||
notificationChannel,
|
||||
UnidentifiedAccessMode.fromMode(unidentifiedAccessMode),
|
||||
forceSmsSelection,
|
||||
Recipient.Capability.deserialize(uuidCapabilityValue),
|
||||
Recipient.Capability.deserialize(groupsV2CapabilityValue),
|
||||
capabilities,
|
||||
InsightsBannerTier.fromId(insightsBannerTier),
|
||||
storageKey,
|
||||
MentionSetting.fromId(mentionSettingId),
|
||||
|
@ -1404,9 +1408,13 @@ public class RecipientDatabase extends Database {
|
|||
}
|
||||
|
||||
public void setCapabilities(@NonNull RecipientId id, @NonNull SignalServiceProfile.Capabilities capabilities) {
|
||||
ContentValues values = new ContentValues(2);
|
||||
values.put(UUID_CAPABILITY, Recipient.Capability.fromBoolean(capabilities.isUuid()).serialize());
|
||||
values.put(GROUPS_V2_CAPABILITY, Recipient.Capability.fromBoolean(capabilities.isGv2()).serialize());
|
||||
long value = 0;
|
||||
|
||||
value = Bitmask.update(value, Capabilities.GROUPS_V2, Capabilities.BIT_LENGTH, Recipient.Capability.fromBoolean(capabilities.isGv2()).serialize());
|
||||
|
||||
ContentValues values = new ContentValues(1);
|
||||
values.put(CAPABILITIES, value);
|
||||
|
||||
if (update(id, values)) {
|
||||
Recipient.live(id).refresh();
|
||||
}
|
||||
|
@ -2372,7 +2380,7 @@ public class RecipientDatabase extends Database {
|
|||
uuidValues.put(SYSTEM_PHONE_LABEL, e164Settings.getSystemPhoneLabel());
|
||||
uuidValues.put(SYSTEM_CONTACT_URI, e164Settings.getSystemContactUri());
|
||||
uuidValues.put(PROFILE_SHARING, uuidSettings.isProfileSharing() || e164Settings.isProfileSharing());
|
||||
uuidValues.put(GROUPS_V2_CAPABILITY, uuidSettings.getGroupsV2Capability() != Recipient.Capability.UNKNOWN ? uuidSettings.getGroupsV2Capability().serialize() : e164Settings.getGroupsV2Capability().serialize());
|
||||
uuidValues.put(CAPABILITIES, Math.max(uuidSettings.getCapabilities(), e164Settings.getCapabilities()));
|
||||
uuidValues.put(MENTION_SETTING, uuidSettings.getMentionSetting() != MentionSetting.ALWAYS_NOTIFY ? uuidSettings.getMentionSetting().getId() : e164Settings.getMentionSetting().getId());
|
||||
if (uuidSettings.getProfileKey() != null) {
|
||||
updateProfileValuesForMerge(uuidValues, uuidSettings);
|
||||
|
@ -2589,7 +2597,7 @@ public class RecipientDatabase extends Database {
|
|||
private final String notificationChannel;
|
||||
private final UnidentifiedAccessMode unidentifiedAccessMode;
|
||||
private final boolean forceSmsSelection;
|
||||
private final Recipient.Capability uuidCapability;
|
||||
private final long capabilities;
|
||||
private final Recipient.Capability groupsV2Capability;
|
||||
private final InsightsBannerTier insightsBannerTier;
|
||||
private final byte[] storageId;
|
||||
|
@ -2627,8 +2635,7 @@ public class RecipientDatabase extends Database {
|
|||
@Nullable String notificationChannel,
|
||||
@NonNull UnidentifiedAccessMode unidentifiedAccessMode,
|
||||
boolean forceSmsSelection,
|
||||
Recipient.Capability uuidCapability,
|
||||
Recipient.Capability groupsV2Capability,
|
||||
long capabilities,
|
||||
@NonNull InsightsBannerTier insightsBannerTier,
|
||||
@Nullable byte[] storageId,
|
||||
@NonNull MentionSetting mentionSetting,
|
||||
|
@ -2665,8 +2672,8 @@ public class RecipientDatabase extends Database {
|
|||
this.notificationChannel = notificationChannel;
|
||||
this.unidentifiedAccessMode = unidentifiedAccessMode;
|
||||
this.forceSmsSelection = forceSmsSelection;
|
||||
this.uuidCapability = uuidCapability;
|
||||
this.groupsV2Capability = groupsV2Capability;
|
||||
this.capabilities = capabilities;
|
||||
this.groupsV2Capability = Recipient.Capability.deserialize((int) Bitmask.read(capabilities, Capabilities.GROUPS_V2, Capabilities.BIT_LENGTH));
|
||||
this.insightsBannerTier = insightsBannerTier;
|
||||
this.storageId = storageId;
|
||||
this.mentionSetting = mentionSetting;
|
||||
|
@ -2801,10 +2808,6 @@ public class RecipientDatabase extends Database {
|
|||
return forceSmsSelection;
|
||||
}
|
||||
|
||||
public Recipient.Capability getUuidCapability() {
|
||||
return uuidCapability;
|
||||
}
|
||||
|
||||
public Recipient.Capability getGroupsV2Capability() {
|
||||
return groupsV2Capability;
|
||||
}
|
||||
|
@ -2821,6 +2824,10 @@ public class RecipientDatabase extends Database {
|
|||
return syncExtras;
|
||||
}
|
||||
|
||||
long getCapabilities() {
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* A bundle of data that's only necessary when syncing to storage service, not for a
|
||||
* {@link Recipient}.
|
||||
|
|
|
@ -157,8 +157,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||
private static final int MENTION_CLEANUP = 76;
|
||||
private static final int MENTION_CLEANUP_V2 = 77;
|
||||
private static final int REACTION_CLEANUP = 78;
|
||||
private static final int CAPABILITIES_REFACTOR = 79;
|
||||
|
||||
private static final int DATABASE_VERSION = 78;
|
||||
private static final int DATABASE_VERSION = 79;
|
||||
private static final String DATABASE_NAME = "signal.db";
|
||||
|
||||
private final Context context;
|
||||
|
@ -1131,6 +1132,13 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||
db.update("sms", values, "remote_deleted = ?", new String[] { "1" });
|
||||
}
|
||||
|
||||
if (oldVersion < CAPABILITIES_REFACTOR) {
|
||||
db.execSQL("ALTER TABLE recipient ADD COLUMN capabilities INTEGER DEFAULT 0");
|
||||
|
||||
db.execSQL("UPDATE recipient SET capabilities = 1 WHERE gv2_capability = 1");
|
||||
db.execSQL("UPDATE recipient SET capabilities = 2 WHERE gv2_capability = -1");
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
|
|
|
@ -30,9 +30,7 @@ public final class LogSectionCapabilities implements LogSection {
|
|||
|
||||
AccountAttributes.Capabilities capabilities = AppCapabilities.getCapabilities(false);
|
||||
|
||||
return new StringBuilder().append("Local device UUID : ").append(capabilities.isUuid()).append("\n")
|
||||
.append("Global UUID : ").append(self.getUuidCapability()).append("\n")
|
||||
.append("Local device GV2 : ").append(capabilities.isGv2()).append("\n")
|
||||
return new StringBuilder().append("Local device GV2: ").append(capabilities.isGv2()).append("\n")
|
||||
.append("Global GV2 : ").append(self.getGroupsV2Capability()).append("\n");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,7 +97,6 @@ public class Recipient {
|
|||
private final String notificationChannel;
|
||||
private final UnidentifiedAccessMode unidentifiedAccessMode;
|
||||
private final boolean forceSmsSelection;
|
||||
private final Capability uuidCapability;
|
||||
private final Capability groupsV2Capability;
|
||||
private final InsightsBannerTier insightsBannerTier;
|
||||
private final byte[] storageId;
|
||||
|
@ -311,7 +310,6 @@ public class Recipient {
|
|||
this.notificationChannel = null;
|
||||
this.unidentifiedAccessMode = UnidentifiedAccessMode.DISABLED;
|
||||
this.forceSmsSelection = false;
|
||||
this.uuidCapability = Capability.UNKNOWN;
|
||||
this.groupsV2Capability = Capability.UNKNOWN;
|
||||
this.storageId = null;
|
||||
this.mentionSetting = MentionSetting.ALWAYS_NOTIFY;
|
||||
|
@ -353,7 +351,6 @@ public class Recipient {
|
|||
this.notificationChannel = details.notificationChannel;
|
||||
this.unidentifiedAccessMode = details.unidentifiedAccessMode;
|
||||
this.forceSmsSelection = details.forceSmsSelection;
|
||||
this.uuidCapability = details.uuidCapability;
|
||||
this.groupsV2Capability = details.groupsV2Capability;
|
||||
this.storageId = details.storageId;
|
||||
this.mentionSetting = details.mentionSetting;
|
||||
|
@ -740,25 +737,10 @@ public class Recipient {
|
|||
return forceSmsSelection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if this recipient can support receiving UUID-only messages, otherwise false.
|
||||
*/
|
||||
public boolean isUuidSupported() {
|
||||
if (FeatureFlags.usernames()) {
|
||||
return true;
|
||||
} else {
|
||||
return uuidCapability == Capability.SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
public Capability getGroupsV2Capability() {
|
||||
return groupsV2Capability;
|
||||
}
|
||||
|
||||
public Capability getUuidCapability() {
|
||||
return uuidCapability;
|
||||
}
|
||||
|
||||
public @Nullable byte[] getProfileKey() {
|
||||
return profileKey;
|
||||
}
|
||||
|
@ -825,7 +807,7 @@ public class Recipient {
|
|||
public enum Capability {
|
||||
UNKNOWN(0),
|
||||
SUPPORTED(1),
|
||||
NOT_SUPPORTED(-1);
|
||||
NOT_SUPPORTED(2);
|
||||
|
||||
private final int value;
|
||||
|
||||
|
@ -839,9 +821,10 @@ public class Recipient {
|
|||
|
||||
public static Capability deserialize(int value) {
|
||||
switch (value) {
|
||||
case 1 : return SUPPORTED;
|
||||
case -1 : return NOT_SUPPORTED;
|
||||
default : return UNKNOWN;
|
||||
case 0: return UNKNOWN;
|
||||
case 1: return SUPPORTED;
|
||||
case 2: return NOT_SUPPORTED;
|
||||
default: throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,6 @@ public class RecipientDetails {
|
|||
final String notificationChannel;
|
||||
final UnidentifiedAccessMode unidentifiedAccessMode;
|
||||
final boolean forceSmsSelection;
|
||||
final Recipient.Capability uuidCapability;
|
||||
final Recipient.Capability groupsV2Capability;
|
||||
final InsightsBannerTier insightsBannerTier;
|
||||
final byte[] storageId;
|
||||
|
@ -104,7 +103,6 @@ public class RecipientDetails {
|
|||
this.notificationChannel = settings.getNotificationChannel();
|
||||
this.unidentifiedAccessMode = settings.getUnidentifiedAccessMode();
|
||||
this.forceSmsSelection = settings.isForceSmsSelection();
|
||||
this.uuidCapability = settings.getUuidCapability();
|
||||
this.groupsV2Capability = settings.getGroupsV2Capability();
|
||||
this.insightsBannerTier = settings.getInsightsBannerTier();
|
||||
this.storageId = settings.getStorageId();
|
||||
|
@ -152,7 +150,6 @@ public class RecipientDetails {
|
|||
this.unidentifiedAccessMode = UnidentifiedAccessMode.UNKNOWN;
|
||||
this.forceSmsSelection = false;
|
||||
this.name = null;
|
||||
this.uuidCapability = Recipient.Capability.UNKNOWN;
|
||||
this.groupsV2Capability = Recipient.Capability.UNKNOWN;
|
||||
this.storageId = null;
|
||||
this.mentionSetting = MentionSetting.ALWAYS_NOTIFY;
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import org.whispersystems.libsignal.util.guava.Preconditions;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* A set of utilities to make working with Bitmasks easier.
|
||||
*/
|
||||
public final class Bitmask {
|
||||
|
||||
/**
|
||||
* Reads a bitmasked boolean from a long at the requested position.
|
||||
*/
|
||||
public static boolean read(long value, int position) {
|
||||
return read(value, position, 1) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a bitmasked value from a long at the requested position.
|
||||
*
|
||||
* @param value The value your are reading state from
|
||||
* @param position The position you'd like to read from
|
||||
* @param flagBitSize How many bits are in each flag
|
||||
* @return The value at the requested position
|
||||
*/
|
||||
public static long read(long value, int position, int flagBitSize) {
|
||||
Preconditions.checkArgument(flagBitSize >= 0, "Must have a positive bit size! size: " + flagBitSize);
|
||||
|
||||
int bitsToShift = position * flagBitSize;
|
||||
Preconditions.checkArgument(bitsToShift + flagBitSize <= 64 && position >= 0, String.format(Locale.US, "Your position is out of bounds! position: %d, flagBitSize: %d", position, flagBitSize));
|
||||
|
||||
long shifted = value >>> bitsToShift;
|
||||
long mask = twoToThe(flagBitSize) - 1;
|
||||
|
||||
return shifted & mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value at the specified position in a single-bit bitmasked long.
|
||||
*/
|
||||
public static long update(long existing, int position, boolean value) {
|
||||
return update(existing, position, 1, value ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the value in a bitmasked long.
|
||||
*
|
||||
* @param existing The existing state of the bitmask
|
||||
* @param position The position you'd like to update
|
||||
* @param flagBitSize How many bits are in each flag
|
||||
* @param value The value you'd like to set at the specified position
|
||||
* @return The updated bitmask
|
||||
*/
|
||||
public static long update(long existing, int position, int flagBitSize, long value) {
|
||||
Preconditions.checkArgument(flagBitSize >= 0, "Must have a positive bit size! size: " + flagBitSize);
|
||||
Preconditions.checkArgument(value >= 0, "Value must be positive! value: " + value);
|
||||
Preconditions.checkArgument(value < twoToThe(flagBitSize), String.format(Locale.US, "Value is larger than you can hold for the given bitsize! value: %d, flagBitSize: %d", value, flagBitSize));
|
||||
|
||||
int bitsToShift = position * flagBitSize;
|
||||
Preconditions.checkArgument(bitsToShift + flagBitSize <= 64 && position >= 0, String.format(Locale.US, "Your position is out of bounds! position: %d, flagBitSize: %d", position, flagBitSize));
|
||||
|
||||
long clearMask = ~((twoToThe(flagBitSize) - 1) << bitsToShift);
|
||||
long cleared = existing & clearMask;
|
||||
long shiftedValue = value << bitsToShift;
|
||||
|
||||
return cleared | shiftedValue;
|
||||
}
|
||||
|
||||
/** Simple method to do 2^n. Giving it a name just so it's clear what's happening. */
|
||||
private static long twoToThe(long n) {
|
||||
return 1 << n;
|
||||
}
|
||||
}
|
|
@ -30,6 +30,14 @@ public final class CursorUtil {
|
|||
return cursor.getBlob(cursor.getColumnIndexOrThrow(column));
|
||||
}
|
||||
|
||||
public static boolean requireMaskedBoolean(@NonNull Cursor cursor, @NonNull String column, int position) {
|
||||
return Bitmask.read(requireLong(cursor, column), position);
|
||||
}
|
||||
|
||||
public static int requireMaskedInt(@NonNull Cursor cursor, @NonNull String column, int position, int flagBitSize) {
|
||||
return Util.toIntExact(Bitmask.read(requireLong(cursor, column), position, flagBitSize));
|
||||
}
|
||||
|
||||
public static Optional<String> getString(@NonNull Cursor cursor, @NonNull String column) {
|
||||
if (cursor.getColumnIndex(column) < 0) {
|
||||
return Optional.absent();
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class BitmaskTest {
|
||||
|
||||
@Test
|
||||
public void read_singleBit() {
|
||||
assertFalse(Bitmask.read(0b00000000, 0));
|
||||
assertFalse(Bitmask.read(0b11111101, 1));
|
||||
assertFalse(Bitmask.read(0b11111011, 2));
|
||||
assertFalse(Bitmask.read(0b01111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111L, 63));
|
||||
|
||||
assertTrue(Bitmask.read(0b00000001, 0));
|
||||
assertTrue(Bitmask.read(0b00000010, 1));
|
||||
assertTrue(Bitmask.read(0b00000100, 2));
|
||||
assertTrue(Bitmask.read(0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L, 63));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void read_twoBits() {
|
||||
assertEquals(0, Bitmask.read(0b11111100, 0, 2));
|
||||
assertEquals(1, Bitmask.read(0b11111101, 0, 2));
|
||||
assertEquals(2, Bitmask.read(0b11111110, 0, 2));
|
||||
assertEquals(3, Bitmask.read(0b11111111, 0, 2));
|
||||
|
||||
assertEquals(0, Bitmask.read(0b11110011, 1, 2));
|
||||
assertEquals(1, Bitmask.read(0b11110111, 1, 2));
|
||||
assertEquals(2, Bitmask.read(0b11111011, 1, 2));
|
||||
assertEquals(3, Bitmask.read(0b11111111, 1, 2));
|
||||
|
||||
assertEquals(0, Bitmask.read(0b00000000, 2, 2));
|
||||
assertEquals(1, Bitmask.read(0b00010000, 2, 2));
|
||||
assertEquals(2, Bitmask.read(0b00100000, 2, 2));
|
||||
assertEquals(3, Bitmask.read(0b00110000, 2, 2));
|
||||
|
||||
assertEquals(0, Bitmask.read(0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L, 31, 2));
|
||||
assertEquals(1, Bitmask.read(0b01000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L, 31, 2));
|
||||
assertEquals(2, Bitmask.read(0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L, 31, 2));
|
||||
assertEquals(3, Bitmask.read(0b11000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L, 31, 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void read_fourBits() {
|
||||
assertEquals(0, Bitmask.read(0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L, 15, 4));
|
||||
assertEquals(4, Bitmask.read(0b01000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L, 15, 4));
|
||||
assertEquals(8, Bitmask.read(0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L, 15, 4));
|
||||
assertEquals(15, Bitmask.read(0b11110000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L, 15, 4));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void read_error_negativeIndex() {
|
||||
Bitmask.read(0b0000000, -1);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void read_error_indexTooLarge_singleBit() {
|
||||
Bitmask.read(0b0000000, 64);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void read_error_indexTooLarge_twoBits() {
|
||||
Bitmask.read(0b0000000, 32, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void update_singleBit() {
|
||||
assertEquals(0b00000001, Bitmask.update(0b00000000, 0, true));
|
||||
assertEquals(0b00000010, Bitmask.update(0b00000000, 1, true));
|
||||
assertEquals(0b00000100, Bitmask.update(0b00000000, 2, true));
|
||||
assertEquals(0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L,
|
||||
Bitmask.update(0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L, 63, true));
|
||||
|
||||
assertEquals(0b11111110, Bitmask.update(0b11111111, 0, false));
|
||||
assertEquals(0b11111101, Bitmask.update(0b11111111, 1, false));
|
||||
assertEquals(0b11111011, Bitmask.update(0b11111111, 2, false));
|
||||
assertEquals(0b01111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111L,
|
||||
Bitmask.update(0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111L, 63, false));
|
||||
|
||||
assertEquals(0b11111111, Bitmask.update(0b11111111, 0, true));
|
||||
assertEquals(0b11111111, Bitmask.update(0b11111111, 1, true));
|
||||
assertEquals(0b11111111, Bitmask.update(0b11111111, 2, true));
|
||||
assertEquals(0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111L,
|
||||
Bitmask.update(0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111L, 63, true));
|
||||
|
||||
assertEquals(0b00000000, Bitmask.update(0b00000000, 0, false));
|
||||
assertEquals(0b00000000, Bitmask.update(0b00000000, 1, false));
|
||||
assertEquals(0b00000000, Bitmask.update(0b00000000, 2, false));
|
||||
assertEquals(0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L,
|
||||
Bitmask.update(0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L, 63, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void update_twoBits() {
|
||||
assertEquals(0b00000000, Bitmask.update(0b00000000, 0, 2, 0));
|
||||
assertEquals(0b00000001, Bitmask.update(0b00000000, 0, 2, 1));
|
||||
assertEquals(0b00000010, Bitmask.update(0b00000000, 0, 2, 2));
|
||||
assertEquals(0b00000011, Bitmask.update(0b00000000, 0, 2, 3));
|
||||
|
||||
assertEquals(0b00000000, Bitmask.update(0b00000000, 1, 2, 0));
|
||||
assertEquals(0b00000100, Bitmask.update(0b00000000, 1, 2, 1));
|
||||
assertEquals(0b00001000, Bitmask.update(0b00000000, 1, 2, 2));
|
||||
assertEquals(0b00001100, Bitmask.update(0b00000000, 1, 2, 3));
|
||||
|
||||
assertEquals(0b11111100, Bitmask.update(0b11111111, 0, 2, 0));
|
||||
assertEquals(0b11111101, Bitmask.update(0b11111111, 0, 2, 1));
|
||||
assertEquals(0b11111110, Bitmask.update(0b11111111, 0, 2, 2));
|
||||
assertEquals(0b11111111, Bitmask.update(0b11111111, 0, 2, 3));
|
||||
|
||||
assertEquals(0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L,
|
||||
Bitmask.update(0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L, 31, 2, 0));
|
||||
assertEquals(0b01000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L,
|
||||
Bitmask.update(0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L, 31, 2, 1));
|
||||
assertEquals(0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L,
|
||||
Bitmask.update(0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L, 31, 2, 2));
|
||||
assertEquals(0b11000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L,
|
||||
Bitmask.update(0b00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000L, 31, 2, 3));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void update_error_negativeIndex() {
|
||||
Bitmask.update(0b0000000, -1, true);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void update_error_indexTooLarge_singleBit() {
|
||||
Bitmask.update(0b0000000, 64, true);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void update_error_indexTooLarge_twoBits() {
|
||||
Bitmask.update(0b0000000, 32, 2, 0);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void update_error_negativeValue() {
|
||||
Bitmask.update(0b0000000, 0, 2, -1);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void update_error_valueTooLarge() {
|
||||
Bitmask.update(0b0000000, 0, 2, 4);
|
||||
}
|
||||
}
|
|
@ -91,9 +91,6 @@ public class SignalServiceProfile {
|
|||
}
|
||||
|
||||
public static class Capabilities {
|
||||
@JsonProperty
|
||||
private boolean uuid;
|
||||
|
||||
@JsonProperty
|
||||
private boolean gv2;
|
||||
|
||||
|
@ -103,10 +100,6 @@ public class SignalServiceProfile {
|
|||
@JsonCreator
|
||||
public Capabilities() {}
|
||||
|
||||
public boolean isUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public boolean isGv2() {
|
||||
return gv2;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue