mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-20 14:49:53 +01:00
Merge branch 'client-versioning-events' into 'master'
Update image attachment UI when new client version is received from contact Closes #1638 See merge request briar/briar!1195
This commit is contained in:
@@ -0,0 +1,63 @@
|
|||||||
|
package org.briarproject.bramble.api.versioning;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.sync.ClientId;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
public class ClientVersion implements Comparable<ClientVersion> {
|
||||||
|
|
||||||
|
private final ClientMajorVersion majorVersion;
|
||||||
|
private final int minorVersion;
|
||||||
|
|
||||||
|
public ClientVersion(ClientMajorVersion majorVersion,
|
||||||
|
int minorVersion) {
|
||||||
|
this.majorVersion = majorVersion;
|
||||||
|
this.minorVersion = minorVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientVersion(ClientId clientId, int majorVersion,
|
||||||
|
int minorVersion) {
|
||||||
|
this(new ClientMajorVersion(clientId, majorVersion), minorVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientMajorVersion getClientMajorVersion() {
|
||||||
|
return majorVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientId getClientId() {
|
||||||
|
return majorVersion.getClientId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMajorVersion() {
|
||||||
|
return majorVersion.getMajorVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMinorVersion() {
|
||||||
|
return minorVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o instanceof ClientVersion) {
|
||||||
|
ClientVersion cv = (ClientVersion) o;
|
||||||
|
return majorVersion.equals(cv.majorVersion)
|
||||||
|
&& minorVersion == cv.minorVersion;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return majorVersion.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(ClientVersion cv) {
|
||||||
|
int compare = majorVersion.compareTo(cv.majorVersion);
|
||||||
|
if (compare != 0) return compare;
|
||||||
|
return minorVersion - cv.minorVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package org.briarproject.bramble.api.versioning.event;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.event.Event;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.versioning.ClientVersion;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event that is broadcast when we receive a client versioning update from
|
||||||
|
* a contact.
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
public class ClientVersionUpdatedEvent extends Event {
|
||||||
|
|
||||||
|
private final ContactId contactId;
|
||||||
|
private final ClientVersion clientVersion;
|
||||||
|
|
||||||
|
public ClientVersionUpdatedEvent(ContactId contactId,
|
||||||
|
ClientVersion clientVersion) {
|
||||||
|
this.contactId = contactId;
|
||||||
|
this.clientVersion = clientVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContactId getContactId() {
|
||||||
|
return contactId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientVersion getClientVersion() {
|
||||||
|
return clientVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,7 +26,9 @@ import org.briarproject.bramble.api.sync.MessageId;
|
|||||||
import org.briarproject.bramble.api.sync.validation.IncomingMessageHook;
|
import org.briarproject.bramble.api.sync.validation.IncomingMessageHook;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.versioning.ClientMajorVersion;
|
import org.briarproject.bramble.api.versioning.ClientMajorVersion;
|
||||||
|
import org.briarproject.bramble.api.versioning.ClientVersion;
|
||||||
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
|
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
|
||||||
|
import org.briarproject.bramble.api.versioning.event.ClientVersionUpdatedEvent;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -80,9 +82,9 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
|
|||||||
@Override
|
@Override
|
||||||
public void registerClient(ClientId clientId, int majorVersion,
|
public void registerClient(ClientId clientId, int majorVersion,
|
||||||
int minorVersion, ClientVersioningHook hook) {
|
int minorVersion, ClientVersioningHook hook) {
|
||||||
ClientMajorVersion cv = new ClientMajorVersion(clientId, majorVersion);
|
ClientMajorVersion cmv = new ClientMajorVersion(clientId, majorVersion);
|
||||||
clients.add(new ClientVersion(cv, minorVersion));
|
clients.add(new ClientVersion(cmv, minorVersion));
|
||||||
hooks.put(cv, hook);
|
hooks.put(cmv, hook);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -96,9 +98,9 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
|
|||||||
Update remoteUpdate = loadUpdate(txn, latest.remote.messageId);
|
Update remoteUpdate = loadUpdate(txn, latest.remote.messageId);
|
||||||
Map<ClientMajorVersion, Visibility> visibilities =
|
Map<ClientMajorVersion, Visibility> visibilities =
|
||||||
getVisibilities(localUpdate.states, remoteUpdate.states);
|
getVisibilities(localUpdate.states, remoteUpdate.states);
|
||||||
ClientMajorVersion cv =
|
ClientMajorVersion key =
|
||||||
new ClientMajorVersion(clientId, majorVersion);
|
new ClientMajorVersion(clientId, majorVersion);
|
||||||
Visibility v = visibilities.get(cv);
|
Visibility v = visibilities.get(key);
|
||||||
return v == null ? INVISIBLE : v;
|
return v == null ? INVISIBLE : v;
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new DbException(e);
|
throw new DbException(e);
|
||||||
@@ -112,10 +114,11 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
|
|||||||
LatestUpdates latest = findLatestUpdates(txn, contactId);
|
LatestUpdates latest = findLatestUpdates(txn, contactId);
|
||||||
if (latest == null || latest.remote == null) return -1;
|
if (latest == null || latest.remote == null) return -1;
|
||||||
Update remoteUpdate = loadUpdate(txn, latest.remote.messageId);
|
Update remoteUpdate = loadUpdate(txn, latest.remote.messageId);
|
||||||
ClientMajorVersion cv =
|
ClientMajorVersion key =
|
||||||
new ClientMajorVersion(clientId, majorVersion);
|
new ClientMajorVersion(clientId, majorVersion);
|
||||||
for (ClientState remote : remoteUpdate.states) {
|
for (ClientState remote : remoteUpdate.states) {
|
||||||
if (remote.majorVersion.equals(cv)) return remote.minorVersion;
|
if (remote.clientVersion.getClientMajorVersion().equals(key))
|
||||||
|
return remote.clientVersion.getMinorVersion();
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
@@ -226,9 +229,21 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
|
|||||||
Map<ClientMajorVersion, Visibility> after =
|
Map<ClientMajorVersion, Visibility> after =
|
||||||
getVisibilities(newLocalStates, newRemoteStates);
|
getVisibilities(newLocalStates, newRemoteStates);
|
||||||
// Call hooks for any visibilities that have changed
|
// Call hooks for any visibilities that have changed
|
||||||
|
ContactId c = getContactId(txn, m.getGroupId());
|
||||||
if (!before.equals(after)) {
|
if (!before.equals(after)) {
|
||||||
Contact c = getContact(txn, m.getGroupId());
|
Contact contact = db.getContact(txn, c);
|
||||||
callVisibilityHooks(txn, c, before, after);
|
callVisibilityHooks(txn, contact, before, after);
|
||||||
|
}
|
||||||
|
// Broadcast events for any new client versions
|
||||||
|
Set<ClientVersion> oldRemoteVersions = new HashSet<>();
|
||||||
|
for (ClientState cs : oldRemoteStates) {
|
||||||
|
oldRemoteVersions.add(cs.clientVersion);
|
||||||
|
}
|
||||||
|
for (ClientState cs : newRemoteStates) {
|
||||||
|
if (!oldRemoteVersions.contains(cs.clientVersion)) {
|
||||||
|
txn.attach(new ClientVersionUpdatedEvent(c,
|
||||||
|
cs.clientVersion));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new InvalidMessageException(e);
|
throw new InvalidMessageException(e);
|
||||||
@@ -256,8 +271,8 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BdfList encodeClientVersion(ClientVersion cv) {
|
private BdfList encodeClientVersion(ClientVersion cv) {
|
||||||
return BdfList.of(cv.majorVersion.getClientId().getString(),
|
return BdfList.of(cv.getClientId().getString(), cv.getMajorVersion(),
|
||||||
cv.majorVersion.getMajorVersion(), cv.minorVersion);
|
cv.getMinorVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -298,8 +313,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
|
|||||||
ClientId clientId = new ClientId(cv.getString(0));
|
ClientId clientId = new ClientId(cv.getString(0));
|
||||||
int majorVersion = cv.getLong(1).intValue();
|
int majorVersion = cv.getLong(1).intValue();
|
||||||
int minorVersion = cv.getLong(2).intValue();
|
int minorVersion = cv.getLong(2).intValue();
|
||||||
parsed.add(new ClientVersion(clientId, majorVersion,
|
parsed.add(new ClientVersion(clientId, majorVersion, minorVersion));
|
||||||
minorVersion));
|
|
||||||
}
|
}
|
||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
@@ -418,13 +432,15 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
|
|||||||
private List<ClientState> updateStatesFromLocalVersions(
|
private List<ClientState> updateStatesFromLocalVersions(
|
||||||
List<ClientState> oldStates, List<ClientVersion> newVersions) {
|
List<ClientState> oldStates, List<ClientVersion> newVersions) {
|
||||||
Map<ClientMajorVersion, ClientState> oldMap = new HashMap<>();
|
Map<ClientMajorVersion, ClientState> oldMap = new HashMap<>();
|
||||||
for (ClientState cs : oldStates) oldMap.put(cs.majorVersion, cs);
|
for (ClientState cs : oldStates) {
|
||||||
|
oldMap.put(cs.clientVersion.getClientMajorVersion(), cs);
|
||||||
|
}
|
||||||
List<ClientState> newStates = new ArrayList<>(newVersions.size());
|
List<ClientState> newStates = new ArrayList<>(newVersions.size());
|
||||||
for (ClientVersion newVersion : newVersions) {
|
for (ClientVersion newVersion : newVersions) {
|
||||||
ClientState oldState = oldMap.get(newVersion.majorVersion);
|
ClientMajorVersion key = newVersion.getClientMajorVersion();
|
||||||
|
ClientState oldState = oldMap.get(key);
|
||||||
boolean active = oldState != null && oldState.active;
|
boolean active = oldState != null && oldState.active;
|
||||||
newStates.add(new ClientState(newVersion.majorVersion,
|
newStates.add(new ClientState(newVersion, active));
|
||||||
newVersion.minorVersion, active));
|
|
||||||
}
|
}
|
||||||
return newStates;
|
return newStates;
|
||||||
}
|
}
|
||||||
@@ -451,21 +467,25 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BdfList encodeClientState(ClientState cs) {
|
private BdfList encodeClientState(ClientState cs) {
|
||||||
return BdfList.of(cs.majorVersion.getClientId().getString(),
|
ClientVersion cv = cs.clientVersion;
|
||||||
cs.majorVersion.getMajorVersion(), cs.minorVersion, cs.active);
|
return BdfList.of(cv.getClientId().getString(), cv.getMajorVersion(),
|
||||||
|
cv.getMinorVersion(), cs.active);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<ClientMajorVersion, Visibility> getVisibilities(
|
private Map<ClientMajorVersion, Visibility> getVisibilities(
|
||||||
List<ClientState> localStates, List<ClientState> remoteStates) {
|
List<ClientState> localStates, List<ClientState> remoteStates) {
|
||||||
Map<ClientMajorVersion, ClientState> remoteMap = new HashMap<>();
|
Map<ClientMajorVersion, ClientState> remoteMap = new HashMap<>();
|
||||||
for (ClientState cs : remoteStates) remoteMap.put(cs.majorVersion, cs);
|
for (ClientState cs : remoteStates) {
|
||||||
|
remoteMap.put(cs.clientVersion.getClientMajorVersion(), cs);
|
||||||
|
}
|
||||||
Map<ClientMajorVersion, Visibility> visibilities = new HashMap<>();
|
Map<ClientMajorVersion, Visibility> visibilities = new HashMap<>();
|
||||||
for (ClientState local : localStates) {
|
for (ClientState local : localStates) {
|
||||||
ClientState remote = remoteMap.get(local.majorVersion);
|
ClientMajorVersion key =
|
||||||
if (remote == null) visibilities.put(local.majorVersion, INVISIBLE);
|
local.clientVersion.getClientMajorVersion();
|
||||||
else if (remote.active)
|
ClientState remote = remoteMap.get(key);
|
||||||
visibilities.put(local.majorVersion, SHARED);
|
if (remote == null) visibilities.put(key, INVISIBLE);
|
||||||
else visibilities.put(local.majorVersion, VISIBLE);
|
else if (remote.active) visibilities.put(key, SHARED);
|
||||||
|
else visibilities.put(key, VISIBLE);
|
||||||
}
|
}
|
||||||
return visibilities;
|
return visibilities;
|
||||||
}
|
}
|
||||||
@@ -486,9 +506,9 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void callVisibilityHook(Transaction txn, ClientMajorVersion cv,
|
private void callVisibilityHook(Transaction txn, ClientMajorVersion cmv,
|
||||||
Contact c, Visibility v) throws DbException {
|
Contact c, Visibility v) throws DbException {
|
||||||
ClientVersioningHook hook = hooks.get(cv);
|
ClientVersioningHook hook = hooks.get(cmv);
|
||||||
if (hook != null) hook.onClientVisibilityChanging(txn, c, v);
|
if (hook != null) hook.onClientVisibilityChanging(txn, c, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,18 +516,17 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
|
|||||||
List<ClientVersion> versions) throws DbException {
|
List<ClientVersion> versions) throws DbException {
|
||||||
List<ClientState> states = new ArrayList<>(versions.size());
|
List<ClientState> states = new ArrayList<>(versions.size());
|
||||||
for (ClientVersion cv : versions) {
|
for (ClientVersion cv : versions) {
|
||||||
states.add(new ClientState(cv.majorVersion, cv.minorVersion,
|
states.add(new ClientState(cv, false));
|
||||||
false));
|
|
||||||
}
|
}
|
||||||
storeUpdate(txn, g, states, 1);
|
storeUpdate(txn, g, states, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Contact getContact(Transaction txn, GroupId g) throws DbException {
|
private ContactId getContactId(Transaction txn, GroupId g)
|
||||||
|
throws DbException {
|
||||||
try {
|
try {
|
||||||
BdfDictionary meta =
|
BdfDictionary meta =
|
||||||
clientHelper.getGroupMetadataAsDictionary(txn, g);
|
clientHelper.getGroupMetadataAsDictionary(txn, g);
|
||||||
int id = meta.getLong(GROUP_KEY_CONTACT_ID).intValue();
|
return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue());
|
||||||
return db.getContact(txn, new ContactId(id));
|
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new DbException(e);
|
throw new DbException(e);
|
||||||
}
|
}
|
||||||
@@ -516,13 +535,16 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
|
|||||||
private List<ClientState> updateStatesFromRemoteStates(
|
private List<ClientState> updateStatesFromRemoteStates(
|
||||||
List<ClientState> oldLocalStates, List<ClientState> remoteStates) {
|
List<ClientState> oldLocalStates, List<ClientState> remoteStates) {
|
||||||
Set<ClientMajorVersion> remoteSet = new HashSet<>();
|
Set<ClientMajorVersion> remoteSet = new HashSet<>();
|
||||||
for (ClientState cs : remoteStates) remoteSet.add(cs.majorVersion);
|
for (ClientState cs : remoteStates) {
|
||||||
|
remoteSet.add(cs.clientVersion.getClientMajorVersion());
|
||||||
|
}
|
||||||
List<ClientState> newLocalStates =
|
List<ClientState> newLocalStates =
|
||||||
new ArrayList<>(oldLocalStates.size());
|
new ArrayList<>(oldLocalStates.size());
|
||||||
for (ClientState oldState : oldLocalStates) {
|
for (ClientState oldState : oldLocalStates) {
|
||||||
boolean active = remoteSet.contains(oldState.majorVersion);
|
ClientMajorVersion cmv =
|
||||||
newLocalStates.add(new ClientState(oldState.majorVersion,
|
oldState.clientVersion.getClientMajorVersion();
|
||||||
oldState.minorVersion, active));
|
boolean active = remoteSet.contains(cmv);
|
||||||
|
newLocalStates.add(new ClientState(oldState.clientVersion, active));
|
||||||
}
|
}
|
||||||
return newLocalStates;
|
return newLocalStates;
|
||||||
}
|
}
|
||||||
@@ -561,61 +583,19 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ClientVersion implements Comparable<ClientVersion> {
|
|
||||||
|
|
||||||
private final ClientMajorVersion majorVersion;
|
|
||||||
private final int minorVersion;
|
|
||||||
|
|
||||||
private ClientVersion(ClientMajorVersion majorVersion,
|
|
||||||
int minorVersion) {
|
|
||||||
this.majorVersion = majorVersion;
|
|
||||||
this.minorVersion = minorVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ClientVersion(ClientId clientId, int majorVersion,
|
|
||||||
int minorVersion) {
|
|
||||||
this(new ClientMajorVersion(clientId, majorVersion), minorVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (o instanceof ClientVersion) {
|
|
||||||
ClientVersion cv = (ClientVersion) o;
|
|
||||||
return majorVersion.equals(cv.majorVersion)
|
|
||||||
&& minorVersion == cv.minorVersion;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return majorVersion.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(ClientVersion cv) {
|
|
||||||
int compare = majorVersion.compareTo(cv.majorVersion);
|
|
||||||
if (compare != 0) return compare;
|
|
||||||
return minorVersion - cv.minorVersion;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ClientState {
|
private static class ClientState {
|
||||||
|
|
||||||
private final ClientMajorVersion majorVersion;
|
private final ClientVersion clientVersion;
|
||||||
private final int minorVersion;
|
|
||||||
private final boolean active;
|
private final boolean active;
|
||||||
|
|
||||||
private ClientState(ClientMajorVersion majorVersion, int minorVersion,
|
private ClientState(ClientVersion clientVersion, boolean active) {
|
||||||
boolean active) {
|
this.clientVersion = clientVersion;
|
||||||
this.majorVersion = majorVersion;
|
|
||||||
this.minorVersion = minorVersion;
|
|
||||||
this.active = active;
|
this.active = active;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClientState(ClientId clientId, int majorVersion,
|
private ClientState(ClientId clientId, int majorVersion,
|
||||||
int minorVersion, boolean active) {
|
int minorVersion, boolean active) {
|
||||||
this(new ClientMajorVersion(clientId, majorVersion), minorVersion,
|
this(new ClientVersion(clientId, majorVersion, minorVersion),
|
||||||
active);
|
active);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,8 +603,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
|
|||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (o instanceof ClientState) {
|
if (o instanceof ClientState) {
|
||||||
ClientState cs = (ClientState) o;
|
ClientState cs = (ClientState) o;
|
||||||
return majorVersion.equals(cs.majorVersion)
|
return clientVersion.equals(cs.clientVersion)
|
||||||
&& minorVersion == cs.minorVersion
|
|
||||||
&& active == cs.active;
|
&& active == cs.active;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -632,7 +611,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return majorVersion.hashCode();
|
return clientVersion.hashCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
|
|||||||
private final ClientId clientId = getClientId();
|
private final ClientId clientId = getClientId();
|
||||||
private final long now = System.currentTimeMillis();
|
private final long now = System.currentTimeMillis();
|
||||||
private final Transaction txn = new Transaction(null, false);
|
private final Transaction txn = new Transaction(null, false);
|
||||||
|
private final BdfDictionary groupMeta = BdfDictionary.of(
|
||||||
|
new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt()));
|
||||||
|
|
||||||
private ClientVersioningManagerImpl createInstance() {
|
private ClientVersioningManagerImpl createInstance() {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -107,8 +109,6 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void expectAddingContact() throws Exception {
|
private void expectAddingContact() throws Exception {
|
||||||
BdfDictionary groupMeta = BdfDictionary.of(
|
|
||||||
new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt()));
|
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
BdfList localUpdateBody = BdfList.of(new BdfList(), 1L);
|
BdfList localUpdateBody = BdfList.of(new BdfList(), 1L);
|
||||||
Message localUpdate = getMessage(contactGroup.getId());
|
Message localUpdate = getMessage(contactGroup.getId());
|
||||||
@@ -459,6 +459,10 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
|
|||||||
// Delete the old remote update
|
// Delete the old remote update
|
||||||
oneOf(db).deleteMessage(txn, oldRemoteUpdateId);
|
oneOf(db).deleteMessage(txn, oldRemoteUpdateId);
|
||||||
oneOf(db).deleteMessageMetadata(txn, oldRemoteUpdateId);
|
oneOf(db).deleteMessageMetadata(txn, oldRemoteUpdateId);
|
||||||
|
// Get contact ID
|
||||||
|
oneOf(clientHelper).getGroupMetadataAsDictionary(txn,
|
||||||
|
contactGroup.getId());
|
||||||
|
will(returnValue(groupMeta));
|
||||||
// No states or visibilities have changed
|
// No states or visibilities have changed
|
||||||
}});
|
}});
|
||||||
|
|
||||||
@@ -488,6 +492,10 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
|
|||||||
// Load the latest local update
|
// Load the latest local update
|
||||||
oneOf(clientHelper).getMessageAsList(txn, oldLocalUpdateId);
|
oneOf(clientHelper).getMessageAsList(txn, oldLocalUpdateId);
|
||||||
will(returnValue(oldLocalUpdateBody));
|
will(returnValue(oldLocalUpdateBody));
|
||||||
|
// Get client ID
|
||||||
|
oneOf(clientHelper).getGroupMetadataAsDictionary(txn,
|
||||||
|
contactGroup.getId());
|
||||||
|
will(returnValue(groupMeta));
|
||||||
// No states or visibilities have changed
|
// No states or visibilities have changed
|
||||||
}});
|
}});
|
||||||
|
|
||||||
|
|||||||
@@ -46,9 +46,11 @@ import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|||||||
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
||||||
import org.briarproject.bramble.api.plugin.event.ContactConnectedEvent;
|
import org.briarproject.bramble.api.plugin.event.ContactConnectedEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent;
|
import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent;
|
||||||
|
import org.briarproject.bramble.api.sync.ClientId;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
|
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
|
||||||
import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
|
import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
|
||||||
|
import org.briarproject.bramble.api.versioning.event.ClientVersionUpdatedEvent;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.activity.BriarActivity;
|
import org.briarproject.briar.android.activity.BriarActivity;
|
||||||
@@ -99,7 +101,6 @@ import javax.inject.Inject;
|
|||||||
import de.hdodenhof.circleimageview.CircleImageView;
|
import de.hdodenhof.circleimageview.CircleImageView;
|
||||||
import im.delight.android.identicons.IdenticonDrawable;
|
import im.delight.android.identicons.IdenticonDrawable;
|
||||||
import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt;
|
import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt;
|
||||||
import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.PromptStateChangeListener;
|
|
||||||
|
|
||||||
import static android.arch.lifecycle.Lifecycle.State.STARTED;
|
import static android.arch.lifecycle.Lifecycle.State.STARTED;
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
@@ -130,8 +131,6 @@ import static org.briarproject.briar.android.util.UiUtils.getBulbTransitionName;
|
|||||||
import static org.briarproject.briar.android.util.UiUtils.observeOnce;
|
import static org.briarproject.briar.android.util.UiUtils.observeOnce;
|
||||||
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE;
|
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE;
|
||||||
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH;
|
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH;
|
||||||
import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_DISMISSED;
|
|
||||||
import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_FINISHED;
|
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -263,11 +262,15 @@ public class ConversationActivity extends BriarActivity
|
|||||||
ImagePreview imagePreview = findViewById(R.id.imagePreview);
|
ImagePreview imagePreview = findViewById(R.id.imagePreview);
|
||||||
sendController = new TextAttachmentController(textInputView,
|
sendController = new TextAttachmentController(textInputView,
|
||||||
imagePreview, this, viewModel);
|
imagePreview, this, viewModel);
|
||||||
observeOnce(viewModel.hasImageSupport(), this, hasSupport -> {
|
viewModel.hasImageSupport().observe(this, new Observer<Boolean>() {
|
||||||
if (hasSupport != null && hasSupport) {
|
@Override
|
||||||
// TODO: remove cast when removing feature flag
|
public void onChanged(@Nullable Boolean hasSupport) {
|
||||||
((TextAttachmentController) sendController)
|
if (hasSupport != null && hasSupport) {
|
||||||
.setImagesSupported();
|
// TODO: remove cast when removing feature flag
|
||||||
|
((TextAttachmentController) sendController)
|
||||||
|
.setImagesSupported();
|
||||||
|
viewModel.hasImageSupport().removeObserver(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -649,6 +652,15 @@ public class ConversationActivity extends BriarActivity
|
|||||||
LOG.info("Contact disconnected");
|
LOG.info("Contact disconnected");
|
||||||
displayContactOnlineStatus();
|
displayContactOnlineStatus();
|
||||||
}
|
}
|
||||||
|
} else if (e instanceof ClientVersionUpdatedEvent) {
|
||||||
|
ClientVersionUpdatedEvent c = (ClientVersionUpdatedEvent) e;
|
||||||
|
if (c.getContactId().equals(contactId)) {
|
||||||
|
ClientId clientId = c.getClientVersion().getClientId();
|
||||||
|
if (clientId.equals(MessagingManager.CLIENT_ID)) {
|
||||||
|
LOG.info("Contact's messaging client was updated");
|
||||||
|
viewModel.recheckFeaturesAndOnboarding(contactId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -829,9 +841,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
|
|
||||||
private void showImageOnboarding() {
|
private void showImageOnboarding() {
|
||||||
// TODO: remove cast when removing feature flag
|
// TODO: remove cast when removing feature flag
|
||||||
((TextAttachmentController) sendController)
|
((TextAttachmentController) sendController).showImageOnboarding(this);
|
||||||
.showImageOnboarding(this, () ->
|
|
||||||
viewModel.onImageOnboardingSeen());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showIntroductionOnboarding(@Nullable Boolean show) {
|
private void showIntroductionOnboarding(@Nullable Boolean show) {
|
||||||
@@ -865,11 +875,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PromptStateChangeListener listener = (prompt, state) -> {
|
|
||||||
if (state == STATE_DISMISSED || state == STATE_FINISHED) {
|
|
||||||
viewModel.onIntroductionOnboardingSeen();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
new MaterialTapTargetPrompt.Builder(ConversationActivity.this,
|
new MaterialTapTargetPrompt.Builder(ConversationActivity.this,
|
||||||
R.style.OnboardingDialogTheme).setTarget(target)
|
R.style.OnboardingDialogTheme).setTarget(target)
|
||||||
.setPrimaryText(R.string.introduction_onboarding_title)
|
.setPrimaryText(R.string.introduction_onboarding_title)
|
||||||
@@ -877,7 +882,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
.setIcon(R.drawable.ic_more_vert_accent)
|
.setIcon(R.drawable.ic_more_vert_accent)
|
||||||
.setBackgroundColour(
|
.setBackgroundColour(
|
||||||
ContextCompat.getColor(this, R.color.briar_primary))
|
ContextCompat.getColor(this, R.color.briar_primary))
|
||||||
.setPromptStateChangeListener(listener)
|
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -231,47 +231,24 @@ public class ConversationViewModel extends AndroidViewModel
|
|||||||
boolean introductionSupported = contacts.size() > 1;
|
boolean introductionSupported = contacts.size() > 1;
|
||||||
showIntroductionAction.postValue(introductionSupported);
|
showIntroductionAction.postValue(introductionSupported);
|
||||||
|
|
||||||
|
// we only show one onboarding dialog at a time
|
||||||
Settings settings = settingsManager.getSettings(SETTINGS_NAMESPACE);
|
Settings settings = settingsManager.getSettings(SETTINGS_NAMESPACE);
|
||||||
if (imagesSupported &&
|
if (imagesSupported &&
|
||||||
settings.getBoolean(SHOW_ONBOARDING_IMAGE, true)) {
|
settings.getBoolean(SHOW_ONBOARDING_IMAGE, true)) {
|
||||||
// check if we should show onboarding, only if images are supported
|
onOnboardingShown(SHOW_ONBOARDING_IMAGE);
|
||||||
showImageOnboarding.postEvent(true);
|
showImageOnboarding.postEvent(true);
|
||||||
// allow observer to stop listening for changes
|
} else if (introductionSupported &&
|
||||||
showIntroductionOnboarding.postEvent(false);
|
settings.getBoolean(SHOW_ONBOARDING_INTRODUCTION, true)) {
|
||||||
} else {
|
onOnboardingShown(SHOW_ONBOARDING_INTRODUCTION);
|
||||||
// allow observer to stop listening for changes
|
showIntroductionOnboarding.postEvent(true);
|
||||||
showImageOnboarding.postEvent(false);
|
|
||||||
// we only show one onboarding dialog at a time
|
|
||||||
if (introductionSupported &&
|
|
||||||
settings.getBoolean(SHOW_ONBOARDING_INTRODUCTION, true)) {
|
|
||||||
showIntroductionOnboarding.postEvent(true);
|
|
||||||
} else {
|
|
||||||
// allow observer to stop listening for changes
|
|
||||||
showIntroductionOnboarding.postEvent(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@DatabaseExecutor
|
||||||
void onImageOnboardingSeen() {
|
private void onOnboardingShown(String key) throws DbException {
|
||||||
onOnboardingSeen(SHOW_ONBOARDING_IMAGE);
|
Settings settings = new Settings();
|
||||||
}
|
settings.putBoolean(key, false);
|
||||||
|
settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE);
|
||||||
@UiThread
|
|
||||||
void onIntroductionOnboardingSeen() {
|
|
||||||
onOnboardingSeen(SHOW_ONBOARDING_INTRODUCTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onOnboardingSeen(String key) {
|
|
||||||
dbExecutor.execute(() -> {
|
|
||||||
try {
|
|
||||||
Settings settings = new Settings();
|
|
||||||
settings.putBoolean(key, false);
|
|
||||||
settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE);
|
|
||||||
} catch (DbException e) {
|
|
||||||
logException(LOG, WARNING, e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createMessage(GroupId groupId, @Nullable String text,
|
private void createMessage(GroupId groupId, @Nullable String text,
|
||||||
@@ -352,4 +329,14 @@ public class ConversationViewModel extends AndroidViewModel
|
|||||||
return addedHeader;
|
return addedHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
void recheckFeaturesAndOnboarding(ContactId contactId) {
|
||||||
|
dbExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
checkFeaturesAndOnboarding(contactId);
|
||||||
|
} catch (DbException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import java.util.Collection;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt;
|
import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt;
|
||||||
import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.PromptStateChangeListener;
|
|
||||||
|
|
||||||
import static android.arch.lifecycle.Lifecycle.State.DESTROYED;
|
import static android.arch.lifecycle.Lifecycle.State.DESTROYED;
|
||||||
import static android.content.Intent.ACTION_GET_CONTENT;
|
import static android.content.Intent.ACTION_GET_CONTENT;
|
||||||
@@ -44,8 +43,6 @@ import static android.widget.Toast.LENGTH_LONG;
|
|||||||
import static org.briarproject.briar.android.util.UiUtils.resolveColorAttribute;
|
import static org.briarproject.briar.android.util.UiUtils.resolveColorAttribute;
|
||||||
import static org.briarproject.briar.api.messaging.MessagingConstants.IMAGE_MIME_TYPES;
|
import static org.briarproject.briar.api.messaging.MessagingConstants.IMAGE_MIME_TYPES;
|
||||||
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE;
|
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE;
|
||||||
import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_DISMISSED;
|
|
||||||
import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_FINISHED;
|
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -269,13 +266,7 @@ public class TextAttachmentController extends TextSendController
|
|||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showImageOnboarding(Activity activity,
|
public void showImageOnboarding(Activity activity) {
|
||||||
Runnable onOnboardingSeen) {
|
|
||||||
PromptStateChangeListener listener = (prompt, state) -> {
|
|
||||||
if (state == STATE_DISMISSED || state == STATE_FINISHED) {
|
|
||||||
onOnboardingSeen.run();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
int color = resolveColorAttribute(activity, R.attr.colorControlNormal);
|
int color = resolveColorAttribute(activity, R.attr.colorControlNormal);
|
||||||
new MaterialTapTargetPrompt.Builder(activity,
|
new MaterialTapTargetPrompt.Builder(activity,
|
||||||
R.style.OnboardingDialogTheme).setTarget(sendButton)
|
R.style.OnboardingDialogTheme).setTarget(sendButton)
|
||||||
@@ -284,7 +275,6 @@ public class TextAttachmentController extends TextSendController
|
|||||||
.setBackgroundColour(getColor(activity, R.color.briar_primary))
|
.setBackgroundColour(getColor(activity, R.color.briar_primary))
|
||||||
.setIcon(R.drawable.ic_image)
|
.setIcon(R.drawable.ic_image)
|
||||||
.setIconDrawableColourFilter(color)
|
.setIconDrawableColourFilter(color)
|
||||||
.setPromptStateChangeListener(listener)
|
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user