mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Compare commits
1 Commits
limit-in-m
...
recently-o
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1cda4fb1e |
@@ -5,8 +5,7 @@ import org.briarproject.bramble.api.contact.PendingContactId;
|
|||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.event.ConnectionClosedEvent;
|
import org.briarproject.bramble.api.plugin.event.ConnectionClosedEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent;
|
import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.ContactConnectedEvent;
|
import org.briarproject.bramble.api.plugin.event.ConnectionStatusChangedEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent;
|
|
||||||
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionClosedEvent;
|
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionClosedEvent;
|
||||||
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionOpenedEvent;
|
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionOpenedEvent;
|
||||||
|
|
||||||
@@ -21,15 +20,15 @@ public interface ConnectionRegistry {
|
|||||||
/**
|
/**
|
||||||
* Registers a connection with the given contact over the given transport.
|
* Registers a connection with the given contact over the given transport.
|
||||||
* Broadcasts {@link ConnectionOpenedEvent}. Also broadcasts
|
* Broadcasts {@link ConnectionOpenedEvent}. Also broadcasts
|
||||||
* {@link ContactConnectedEvent} if this is the only connection with the
|
* {@link ConnectionStatusChangedEvent} if this is the only connection with
|
||||||
* contact.
|
* the contact.
|
||||||
*/
|
*/
|
||||||
void registerConnection(ContactId c, TransportId t, boolean incoming);
|
void registerConnection(ContactId c, TransportId t, boolean incoming);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unregisters a connection with the given contact over the given transport.
|
* Unregisters a connection with the given contact over the given transport.
|
||||||
* Broadcasts {@link ConnectionClosedEvent}. Also broadcasts
|
* Broadcasts {@link ConnectionClosedEvent}. Also broadcasts
|
||||||
* {@link ContactDisconnectedEvent} if this is the only connection with
|
* {@link ConnectionStatusChangedEvent} if this is the only connection with
|
||||||
* the contact.
|
* the contact.
|
||||||
*/
|
*/
|
||||||
void unregisterConnection(ContactId c, TransportId t, boolean incoming);
|
void unregisterConnection(ContactId c, TransportId t, boolean incoming);
|
||||||
@@ -45,9 +44,9 @@ public interface ConnectionRegistry {
|
|||||||
boolean isConnected(ContactId c, TransportId t);
|
boolean isConnected(ContactId c, TransportId t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given contact is connected via any transport.
|
* Returns the connection status of the given contact via all transports.
|
||||||
*/
|
*/
|
||||||
boolean isConnected(ContactId c);
|
ConnectionStatus getConnectionStatus(ContactId c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a connection with the given pending contact. Broadcasts
|
* Registers a connection with the given pending contact. Broadcasts
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.briarproject.bramble.api.plugin;
|
||||||
|
|
||||||
|
public enum ConnectionStatus {
|
||||||
|
CONNECTED, RECENTLY_CONNECTED, DISCONNECTED
|
||||||
|
}
|
||||||
@@ -3,24 +3,31 @@ package org.briarproject.bramble.api.plugin.event;
|
|||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.ConnectionStatus;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event that is broadcast when a contact connects that was not previously
|
* An event that is broadcast when a contact's connection status changes.
|
||||||
* connected via any transport.
|
|
||||||
*/
|
*/
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class ContactConnectedEvent extends Event {
|
public class ConnectionStatusChangedEvent extends Event {
|
||||||
|
|
||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
|
private final ConnectionStatus status;
|
||||||
|
|
||||||
public ContactConnectedEvent(ContactId contactId) {
|
public ConnectionStatusChangedEvent(ContactId contactId,
|
||||||
|
ConnectionStatus status) {
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContactId getContactId() {
|
public ContactId getContactId() {
|
||||||
return contactId;
|
return contactId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ConnectionStatus getConnectionStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package org.briarproject.bramble.api.plugin.event;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
|
||||||
import org.briarproject.bramble.api.event.Event;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An event that is broadcast when a contact disconnects and is no longer
|
|
||||||
* connected via any transport.
|
|
||||||
*/
|
|
||||||
@Immutable
|
|
||||||
@NotNullByDefault
|
|
||||||
public class ContactDisconnectedEvent extends Event {
|
|
||||||
|
|
||||||
private final ContactId contactId;
|
|
||||||
|
|
||||||
public ContactDisconnectedEvent(ContactId contactId) {
|
|
||||||
this.contactId = contactId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContactId getContactId() {
|
|
||||||
return contactId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,30 +6,41 @@ import org.briarproject.bramble.api.contact.PendingContactId;
|
|||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
||||||
|
import org.briarproject.bramble.api.plugin.ConnectionStatus;
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
import org.briarproject.bramble.api.plugin.event.ConnectionClosedEvent;
|
import org.briarproject.bramble.api.plugin.event.ConnectionClosedEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent;
|
import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.ContactConnectedEvent;
|
import org.briarproject.bramble.api.plugin.event.ConnectionStatusChangedEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent;
|
|
||||||
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionClosedEvent;
|
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionClosedEvent;
|
||||||
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionOpenedEvent;
|
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionOpenedEvent;
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
import org.briarproject.bramble.api.system.Scheduler;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.concurrent.GuardedBy;
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
|
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||||
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.briarproject.bramble.api.plugin.ConnectionStatus.CONNECTED;
|
||||||
|
import static org.briarproject.bramble.api.plugin.ConnectionStatus.DISCONNECTED;
|
||||||
|
import static org.briarproject.bramble.api.plugin.ConnectionStatus.RECENTLY_CONNECTED;
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -38,22 +49,30 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
getLogger(ConnectionRegistryImpl.class.getName());
|
getLogger(ConnectionRegistryImpl.class.getName());
|
||||||
|
|
||||||
|
private static final long RECENTLY_CONNECTED_MS = MINUTES.toMillis(1);
|
||||||
|
private static final long EXPIRY_INTERVAL_MS = SECONDS.toMillis(10);
|
||||||
|
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
|
private final Clock clock;
|
||||||
|
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
private final Map<TransportId, Multiset<ContactId>> contactConnections;
|
private final Map<TransportId, Multiset<ContactId>> contactConnections;
|
||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
private final Multiset<ContactId> contactCounts;
|
private final Map<ContactId, Counter> contactCounts;
|
||||||
@GuardedBy("lock")
|
@GuardedBy("lock")
|
||||||
private final Set<PendingContactId> connectedPendingContacts;
|
private final Set<PendingContactId> connectedPendingContacts;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ConnectionRegistryImpl(EventBus eventBus) {
|
ConnectionRegistryImpl(EventBus eventBus, Clock clock,
|
||||||
|
@Scheduler ScheduledExecutorService scheduler) {
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
|
this.clock = clock;
|
||||||
contactConnections = new HashMap<>();
|
contactConnections = new HashMap<>();
|
||||||
contactCounts = new Multiset<>();
|
contactCounts = new HashMap<>();
|
||||||
connectedPendingContacts = new HashSet<>();
|
connectedPendingContacts = new HashSet<>();
|
||||||
|
scheduler.scheduleWithFixedDelay(this::expireRecentConnections,
|
||||||
|
EXPIRY_INTERVAL_MS, EXPIRY_INTERVAL_MS, MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -71,12 +90,22 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
|
|||||||
contactConnections.put(t, m);
|
contactConnections.put(t, m);
|
||||||
}
|
}
|
||||||
m.add(c);
|
m.add(c);
|
||||||
if (contactCounts.add(c) == 1) firstConnection = true;
|
|
||||||
|
Counter counter = contactCounts.get(c);
|
||||||
|
if (counter == null) {
|
||||||
|
counter = new Counter();
|
||||||
|
contactCounts.put(c, counter);
|
||||||
|
}
|
||||||
|
if (counter.connections == 0) {
|
||||||
|
counter.disconnectedTime = 0;
|
||||||
|
firstConnection = true;
|
||||||
|
}
|
||||||
|
counter.connections++;
|
||||||
}
|
}
|
||||||
eventBus.broadcast(new ConnectionOpenedEvent(c, t, incoming));
|
eventBus.broadcast(new ConnectionOpenedEvent(c, t, incoming));
|
||||||
if (firstConnection) {
|
if (firstConnection) {
|
||||||
LOG.info("Contact connected");
|
LOG.info("Contact connected");
|
||||||
eventBus.broadcast(new ContactConnectedEvent(c));
|
eventBus.broadcast(new ConnectionStatusChangedEvent(c, CONNECTED));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,12 +122,22 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
|
|||||||
if (m == null || !m.contains(c))
|
if (m == null || !m.contains(c))
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
m.remove(c);
|
m.remove(c);
|
||||||
if (contactCounts.remove(c) == 0) lastConnection = true;
|
|
||||||
|
Counter counter = contactCounts.get(c);
|
||||||
|
if (counter == null || counter.connections == 0) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
counter.connections--;
|
||||||
|
if (counter.connections == 0) {
|
||||||
|
counter.disconnectedTime = clock.currentTimeMillis();
|
||||||
|
lastConnection = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
eventBus.broadcast(new ConnectionClosedEvent(c, t, incoming));
|
eventBus.broadcast(new ConnectionClosedEvent(c, t, incoming));
|
||||||
if (lastConnection) {
|
if (lastConnection) {
|
||||||
LOG.info("Contact disconnected");
|
LOG.info("Contact disconnected");
|
||||||
eventBus.broadcast(new ContactDisconnectedEvent(c));
|
eventBus.broadcast(
|
||||||
|
new ConnectionStatusChangedEvent(c, RECENTLY_CONNECTED));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +145,7 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
|
|||||||
public Collection<ContactId> getConnectedContacts(TransportId t) {
|
public Collection<ContactId> getConnectedContacts(TransportId t) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
Multiset<ContactId> m = contactConnections.get(t);
|
Multiset<ContactId> m = contactConnections.get(t);
|
||||||
if (m == null) return Collections.emptyList();
|
if (m == null) return emptyList();
|
||||||
List<ContactId> ids = new ArrayList<>(m.keySet());
|
List<ContactId> ids = new ArrayList<>(m.keySet());
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(ids.size() + " contacts connected: " + t);
|
LOG.info(ids.size() + " contacts connected: " + t);
|
||||||
@@ -123,9 +162,11 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isConnected(ContactId c) {
|
public ConnectionStatus getConnectionStatus(ContactId c) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
return contactCounts.contains(c);
|
Counter counter = contactCounts.get(c);
|
||||||
|
if (counter == null) return DISCONNECTED;
|
||||||
|
return counter.connections > 0 ? CONNECTED : RECENTLY_CONNECTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,4 +188,36 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
|
|||||||
}
|
}
|
||||||
eventBus.broadcast(new RendezvousConnectionClosedEvent(p, success));
|
eventBus.broadcast(new RendezvousConnectionClosedEvent(p, success));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Scheduler
|
||||||
|
private void expireRecentConnections() {
|
||||||
|
long now = clock.currentTimeMillis();
|
||||||
|
List<ContactId> disconnected = new ArrayList<>();
|
||||||
|
synchronized (lock) {
|
||||||
|
Iterator<Entry<ContactId, Counter>> it =
|
||||||
|
contactCounts.entrySet().iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Entry<ContactId, Counter> e = it.next();
|
||||||
|
if (e.getValue().isExpired(now)) {
|
||||||
|
disconnected.add(e.getKey());
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (ContactId c : disconnected) {
|
||||||
|
eventBus.broadcast(
|
||||||
|
new ConnectionStatusChangedEvent(c, DISCONNECTED));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Counter {
|
||||||
|
|
||||||
|
private int connections = 0;
|
||||||
|
private long disconnectedTime = 0;
|
||||||
|
|
||||||
|
private boolean isExpired(long now) {
|
||||||
|
return connections == 0 &&
|
||||||
|
now - disconnectedTime > RECENTLY_CONNECTED_MS;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,18 +7,20 @@ import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
|||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
import org.briarproject.bramble.api.plugin.event.ConnectionClosedEvent;
|
import org.briarproject.bramble.api.plugin.event.ConnectionClosedEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent;
|
import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.ContactConnectedEvent;
|
import org.briarproject.bramble.api.plugin.event.ConnectionStatusChangedEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent;
|
|
||||||
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionClosedEvent;
|
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionClosedEvent;
|
||||||
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionOpenedEvent;
|
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionOpenedEvent;
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
@@ -30,6 +32,9 @@ import static org.junit.Assert.fail;
|
|||||||
public class ConnectionRegistryImplTest extends BrambleMockTestCase {
|
public class ConnectionRegistryImplTest extends BrambleMockTestCase {
|
||||||
|
|
||||||
private final EventBus eventBus = context.mock(EventBus.class);
|
private final EventBus eventBus = context.mock(EventBus.class);
|
||||||
|
private final Clock clock = context.mock(Clock.class);
|
||||||
|
private final ScheduledExecutorService scheduler =
|
||||||
|
context.mock(ScheduledExecutorService.class);
|
||||||
|
|
||||||
private final ContactId contactId = getContactId();
|
private final ContactId contactId = getContactId();
|
||||||
private final ContactId contactId1 = getContactId();
|
private final ContactId contactId1 = getContactId();
|
||||||
@@ -40,17 +45,25 @@ public class ConnectionRegistryImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRegisterAndUnregister() {
|
public void testRegisterAndUnregister() {
|
||||||
ConnectionRegistry c = new ConnectionRegistryImpl(eventBus);
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(scheduler).scheduleWithFixedDelay(with(any(Runnable.class)),
|
||||||
|
with(10_000L), with(10_000L), with(MILLISECONDS));
|
||||||
|
}});
|
||||||
|
|
||||||
|
ConnectionRegistry c = new ConnectionRegistryImpl(eventBus, clock,
|
||||||
|
scheduler);
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
|
||||||
// The registry should be empty
|
// The registry should be empty
|
||||||
assertEquals(emptyList(), c.getConnectedContacts(transportId));
|
assertEquals(emptyList(), c.getConnectedContacts(transportId));
|
||||||
assertEquals(emptyList(), c.getConnectedContacts(transportId1));
|
assertEquals(emptyList(), c.getConnectedContacts(transportId1));
|
||||||
|
|
||||||
// Check that a registered connection shows up - this should
|
// Check that a registered connection shows up - this should
|
||||||
// broadcast a ConnectionOpenedEvent and a ContactConnectedEvent
|
// broadcast a ConnectionOpenedEvent and a ConnectionStatusChangedEvent
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(eventBus).broadcast(with(any(ConnectionOpenedEvent.class)));
|
oneOf(eventBus).broadcast(with(any(ConnectionOpenedEvent.class)));
|
||||||
oneOf(eventBus).broadcast(with(any(ContactConnectedEvent.class)));
|
oneOf(eventBus).broadcast(with(any(
|
||||||
|
ConnectionStatusChangedEvent.class)));
|
||||||
}});
|
}});
|
||||||
c.registerConnection(contactId, transportId, true);
|
c.registerConnection(contactId, transportId, true);
|
||||||
assertEquals(singletonList(contactId),
|
assertEquals(singletonList(contactId),
|
||||||
@@ -81,11 +94,13 @@ public class ConnectionRegistryImplTest extends BrambleMockTestCase {
|
|||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
|
|
||||||
// Unregister the other connection - this should broadcast a
|
// Unregister the other connection - this should broadcast a
|
||||||
// ConnectionClosedEvent and a ContactDisconnectedEvent
|
// ConnectionClosedEvent and a ConnectionStatusChangedEvent
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(System.currentTimeMillis()));
|
||||||
oneOf(eventBus).broadcast(with(any(ConnectionClosedEvent.class)));
|
oneOf(eventBus).broadcast(with(any(ConnectionClosedEvent.class)));
|
||||||
oneOf(eventBus).broadcast(with(any(
|
oneOf(eventBus).broadcast(with(any(
|
||||||
ContactDisconnectedEvent.class)));
|
ConnectionStatusChangedEvent.class)));
|
||||||
}});
|
}});
|
||||||
c.unregisterConnection(contactId, transportId, true);
|
c.unregisterConnection(contactId, transportId, true);
|
||||||
assertEquals(emptyList(), c.getConnectedContacts(transportId));
|
assertEquals(emptyList(), c.getConnectedContacts(transportId));
|
||||||
@@ -102,12 +117,12 @@ public class ConnectionRegistryImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
// Register both contacts with one transport, one contact with both -
|
// Register both contacts with one transport, one contact with both -
|
||||||
// this should broadcast three ConnectionOpenedEvents and two
|
// this should broadcast three ConnectionOpenedEvents and two
|
||||||
// ContactConnectedEvents
|
// ConnectionStatusChangedEvents
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
exactly(3).of(eventBus).broadcast(with(any(
|
exactly(3).of(eventBus).broadcast(with(any(
|
||||||
ConnectionOpenedEvent.class)));
|
ConnectionOpenedEvent.class)));
|
||||||
exactly(2).of(eventBus).broadcast(with(any(
|
exactly(2).of(eventBus).broadcast(with(any(
|
||||||
ContactConnectedEvent.class)));
|
ConnectionStatusChangedEvent.class)));
|
||||||
}});
|
}});
|
||||||
c.registerConnection(contactId, transportId, true);
|
c.registerConnection(contactId, transportId, true);
|
||||||
c.registerConnection(contactId1, transportId, true);
|
c.registerConnection(contactId1, transportId, true);
|
||||||
@@ -122,7 +137,14 @@ public class ConnectionRegistryImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRegisterAndUnregisterPendingContacts() {
|
public void testRegisterAndUnregisterPendingContacts() {
|
||||||
ConnectionRegistry c = new ConnectionRegistryImpl(eventBus);
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(scheduler).scheduleWithFixedDelay(with(any(Runnable.class)),
|
||||||
|
with(10_000L), with(10_000L), with(MILLISECONDS));
|
||||||
|
}});
|
||||||
|
|
||||||
|
ConnectionRegistry c = new ConnectionRegistryImpl(eventBus, clock,
|
||||||
|
scheduler);
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(eventBus).broadcast(with(any(
|
oneOf(eventBus).broadcast(with(any(
|
||||||
|
|||||||
@@ -2,35 +2,38 @@ package org.briarproject.briar.android.contact;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.ConnectionStatus;
|
||||||
|
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.plugin.ConnectionStatus.DISCONNECTED;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class ContactItem {
|
public class ContactItem {
|
||||||
|
|
||||||
private final Contact contact;
|
private final Contact contact;
|
||||||
private boolean connected;
|
private ConnectionStatus status;
|
||||||
|
|
||||||
public ContactItem(Contact contact) {
|
public ContactItem(Contact contact) {
|
||||||
this(contact, false);
|
this(contact, DISCONNECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContactItem(Contact contact, boolean connected) {
|
public ContactItem(Contact contact, ConnectionStatus status) {
|
||||||
this.contact = contact;
|
this.contact = contact;
|
||||||
this.connected = connected;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Contact getContact() {
|
public Contact getContact() {
|
||||||
return contact;
|
return contact;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isConnected() {
|
ConnectionStatus getConnectionStatus() {
|
||||||
return connected;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setConnected(boolean connected) {
|
void setConnectionStatus(ConnectionStatus status) {
|
||||||
this.connected = connected;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.ConnectionStatus;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.contact.BaseContactListAdapter.OnContactClickListener;
|
import org.briarproject.briar.android.contact.BaseContactListAdapter.OnContactClickListener;
|
||||||
|
|
||||||
@@ -16,6 +17,8 @@ import androidx.annotation.UiThread;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import im.delight.android.identicons.IdenticonDrawable;
|
import im.delight.android.identicons.IdenticonDrawable;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.plugin.ConnectionStatus.CONNECTED;
|
||||||
|
import static org.briarproject.bramble.api.plugin.ConnectionStatus.RECENTLY_CONNECTED;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
|
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@@ -27,7 +30,7 @@ public class ContactItemViewHolder<I extends ContactItem>
|
|||||||
protected final ImageView avatar;
|
protected final ImageView avatar;
|
||||||
protected final TextView name;
|
protected final TextView name;
|
||||||
@Nullable
|
@Nullable
|
||||||
protected final ImageView bulb;
|
private final ImageView bulb;
|
||||||
|
|
||||||
public ContactItemViewHolder(View v) {
|
public ContactItemViewHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
@@ -47,10 +50,13 @@ public class ContactItemViewHolder<I extends ContactItem>
|
|||||||
|
|
||||||
if (bulb != null) {
|
if (bulb != null) {
|
||||||
// online/offline
|
// online/offline
|
||||||
if (item.isConnected()) {
|
ConnectionStatus status = item.getConnectionStatus();
|
||||||
bulb.setImageResource(R.drawable.contact_connected);
|
if (status == CONNECTED) {
|
||||||
|
bulb.setImageResource(R.drawable.ic_connected);
|
||||||
|
} else if (status == RECENTLY_CONNECTED) {
|
||||||
|
bulb.setImageResource(R.drawable.ic_recently_connected);
|
||||||
} else {
|
} else {
|
||||||
bulb.setImageResource(R.drawable.contact_disconnected);
|
bulb.setImageResource(R.drawable.ic_disconnected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public class ContactListAdapter extends
|
|||||||
if (c1.getTimestamp() != c2.getTimestamp()) {
|
if (c1.getTimestamp() != c2.getTimestamp()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return c1.isConnected() == c2.isConnected();
|
return c1.getConnectionStatus() == c2.getConnectionStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ import org.briarproject.bramble.api.event.EventListener;
|
|||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
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.ConnectionStatus;
|
||||||
import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent;
|
import org.briarproject.bramble.api.plugin.event.ConnectionStatusChangedEvent;
|
||||||
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.contact.BaseContactListAdapter.OnContactClickListener;
|
import org.briarproject.briar.android.contact.BaseContactListAdapter.OnContactClickListener;
|
||||||
@@ -53,7 +53,6 @@ import javax.inject.Inject;
|
|||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
import androidx.core.app.ActivityOptionsCompat;
|
import androidx.core.app.ActivityOptionsCompat;
|
||||||
import androidx.core.util.Pair;
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import io.github.kobakei.materialfabspeeddial.FabSpeedDial;
|
import io.github.kobakei.materialfabspeeddial.FabSpeedDial;
|
||||||
import io.github.kobakei.materialfabspeeddial.FabSpeedDial.OnMenuItemClickListener;
|
import io.github.kobakei.materialfabspeeddial.FabSpeedDial.OnMenuItemClickListener;
|
||||||
@@ -137,26 +136,15 @@ public class ContactListFragment extends BaseFragment implements EventListener,
|
|||||||
ContactId contactId = item.getContact().getId();
|
ContactId contactId = item.getContact().getId();
|
||||||
i.putExtra(CONTACT_ID, contactId.getInt());
|
i.putExtra(CONTACT_ID, contactId.getInt());
|
||||||
|
|
||||||
|
Bundle options = null;
|
||||||
|
// work-around for android bug #224270
|
||||||
if (SDK_INT >= 23 && !isSamsung7()) {
|
if (SDK_INT >= 23 && !isSamsung7()) {
|
||||||
ContactListItemViewHolder holder =
|
options = makeTransitionOptions(view);
|
||||||
(ContactListItemViewHolder) list
|
}
|
||||||
.getRecyclerView()
|
if (options == null) {
|
||||||
.findViewHolderForAdapterPosition(
|
|
||||||
adapter.findItemPosition(item));
|
|
||||||
Pair<View, String> avatar =
|
|
||||||
Pair.create(holder.avatar,
|
|
||||||
getTransitionName(holder.avatar));
|
|
||||||
Pair<View, String> bulb =
|
|
||||||
Pair.create(holder.bulb,
|
|
||||||
getTransitionName(holder.bulb));
|
|
||||||
ActivityOptionsCompat options =
|
|
||||||
makeSceneTransitionAnimation(getActivity(),
|
|
||||||
avatar, bulb);
|
|
||||||
ActivityCompat.startActivity(getActivity(), i,
|
|
||||||
options.toBundle());
|
|
||||||
} else {
|
|
||||||
// work-around for android bug #224270
|
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
|
} else {
|
||||||
|
ActivityCompat.startActivity(getActivity(), i, options);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
adapter = new ContactListAdapter(requireContext(),
|
adapter = new ContactListAdapter(requireContext(),
|
||||||
@@ -171,6 +159,15 @@ public class ContactListFragment extends BaseFragment implements EventListener,
|
|||||||
return contentView;
|
return contentView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Bundle makeTransitionOptions(View view) {
|
||||||
|
View avatar = view.findViewById(R.id.avatarView);
|
||||||
|
String name = requireNonNull(getTransitionName(avatar));
|
||||||
|
ActivityOptionsCompat options = makeSceneTransitionAnimation(
|
||||||
|
requireActivity(), view, name);
|
||||||
|
return options.toBundle();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMenuItemClick(FloatingActionButton fab, @Nullable TextView v,
|
public void onMenuItemClick(FloatingActionButton fab, @Nullable TextView v,
|
||||||
int itemId) {
|
int itemId) {
|
||||||
@@ -232,9 +229,9 @@ public class ContactListFragment extends BaseFragment implements EventListener,
|
|||||||
ContactId id = c.getId();
|
ContactId id = c.getId();
|
||||||
GroupCount count =
|
GroupCount count =
|
||||||
conversationManager.getGroupCount(id);
|
conversationManager.getGroupCount(id);
|
||||||
boolean connected =
|
ConnectionStatus status = connectionRegistry
|
||||||
connectionRegistry.isConnected(c.getId());
|
.getConnectionStatus(c.getId());
|
||||||
contacts.add(new ContactListItem(c, connected, count));
|
contacts.add(new ContactListItem(c, status, count));
|
||||||
} catch (NoSuchContactException e) {
|
} catch (NoSuchContactException e) {
|
||||||
// Continue
|
// Continue
|
||||||
}
|
}
|
||||||
@@ -265,10 +262,9 @@ public class ContactListFragment extends BaseFragment implements EventListener,
|
|||||||
if (e instanceof ContactAddedEvent) {
|
if (e instanceof ContactAddedEvent) {
|
||||||
LOG.info("Contact added, reloading");
|
LOG.info("Contact added, reloading");
|
||||||
loadContacts();
|
loadContacts();
|
||||||
} else if (e instanceof ContactConnectedEvent) {
|
} else if (e instanceof ConnectionStatusChangedEvent) {
|
||||||
setConnected(((ContactConnectedEvent) e).getContactId(), true);
|
ConnectionStatusChangedEvent c = (ConnectionStatusChangedEvent) e;
|
||||||
} else if (e instanceof ContactDisconnectedEvent) {
|
setConnectionStatus(c.getContactId(), c.getConnectionStatus());
|
||||||
setConnected(((ContactDisconnectedEvent) e).getContactId(), false);
|
|
||||||
} else if (e instanceof ContactRemovedEvent) {
|
} else if (e instanceof ContactRemovedEvent) {
|
||||||
LOG.info("Contact removed, removing item");
|
LOG.info("Contact removed, removing item");
|
||||||
removeItem(((ContactRemovedEvent) e).getContactId());
|
removeItem(((ContactRemovedEvent) e).getContactId());
|
||||||
@@ -304,12 +300,12 @@ public class ContactListFragment extends BaseFragment implements EventListener,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void setConnected(ContactId c, boolean connected) {
|
private void setConnectionStatus(ContactId c, ConnectionStatus status) {
|
||||||
adapter.incrementRevision();
|
adapter.incrementRevision();
|
||||||
int position = adapter.findItemPosition(c);
|
int position = adapter.findItemPosition(c);
|
||||||
ContactListItem item = adapter.getItemAt(position);
|
ContactListItem item = adapter.getItemAt(position);
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
item.setConnected(connected);
|
item.setConnectionStatus(status);
|
||||||
adapter.updateItemAt(position, item);
|
adapter.updateItemAt(position, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.briar.android.contact;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.ConnectionStatus;
|
||||||
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
|
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
|
||||||
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
|
import org.briarproject.briar.api.conversation.ConversationMessageHeader;
|
||||||
|
|
||||||
@@ -15,9 +16,9 @@ public class ContactListItem extends ContactItem {
|
|||||||
private long timestamp;
|
private long timestamp;
|
||||||
private int unread;
|
private int unread;
|
||||||
|
|
||||||
public ContactListItem(Contact contact, boolean connected,
|
public ContactListItem(Contact contact, ConnectionStatus status,
|
||||||
GroupCount count) {
|
GroupCount count) {
|
||||||
super(contact, connected);
|
super(contact, status);
|
||||||
this.empty = count.getMsgCount() == 0;
|
this.empty = count.getMsgCount() == 0;
|
||||||
this.unread = count.getUnreadCount();
|
this.unread = count.getUnreadCount();
|
||||||
this.timestamp = count.getLatestMsgTime();
|
this.timestamp = count.getLatestMsgTime();
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import org.briarproject.bramble.api.contact.ContactId;
|
|||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.contact.BaseContactListAdapter.OnContactClickListener;
|
import org.briarproject.briar.android.contact.BaseContactListAdapter.OnContactClickListener;
|
||||||
import org.briarproject.briar.android.util.UiUtils;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@@ -15,8 +14,11 @@ import javax.annotation.Nullable;
|
|||||||
|
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
|
|
||||||
|
import static android.view.View.INVISIBLE;
|
||||||
|
import static android.view.View.VISIBLE;
|
||||||
import static androidx.core.view.ViewCompat.setTransitionName;
|
import static androidx.core.view.ViewCompat.setTransitionName;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.formatDate;
|
import static org.briarproject.briar.android.util.UiUtils.formatDate;
|
||||||
|
import static org.briarproject.briar.android.util.UiUtils.getAvatarTransitionName;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -39,10 +41,11 @@ class ContactListItemViewHolder extends ContactItemViewHolder<ContactListItem> {
|
|||||||
// unread count
|
// unread count
|
||||||
int unreadCount = item.getUnreadCount();
|
int unreadCount = item.getUnreadCount();
|
||||||
if (unreadCount > 0) {
|
if (unreadCount > 0) {
|
||||||
unread.setText(String.format(Locale.getDefault(), "%d", unreadCount));
|
unread.setText(String.format(Locale.getDefault(), "%d",
|
||||||
unread.setVisibility(View.VISIBLE);
|
unreadCount));
|
||||||
|
unread.setVisibility(VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
unread.setVisibility(View.INVISIBLE);
|
unread.setVisibility(INVISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// date of last message
|
// date of last message
|
||||||
@@ -54,8 +57,7 @@ class ContactListItemViewHolder extends ContactItemViewHolder<ContactListItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ContactId c = item.getContact().getId();
|
ContactId c = item.getContact().getId();
|
||||||
setTransitionName(avatar, UiUtils.getAvatarTransitionName(c));
|
setTransitionName(avatar, getAvatarTransitionName(c));
|
||||||
setTransitionName(bulb, UiUtils.getBulbTransitionName(c));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ import org.briarproject.bramble.api.event.EventBus;
|
|||||||
import org.briarproject.bramble.api.event.EventListener;
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
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.ConnectionStatusChangedEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -18,6 +17,8 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.plugin.ConnectionStatus.CONNECTED;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class SharingControllerImpl implements SharingController, EventListener {
|
public class SharingControllerImpl implements SharingController, EventListener {
|
||||||
|
|
||||||
@@ -60,15 +61,14 @@ public class SharingControllerImpl implements SharingController, EventListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if (e instanceof ContactConnectedEvent) {
|
if (e instanceof ConnectionStatusChangedEvent) {
|
||||||
setConnected(((ContactConnectedEvent) e).getContactId());
|
ConnectionStatusChangedEvent c = (ConnectionStatusChangedEvent) e;
|
||||||
} else if (e instanceof ContactDisconnectedEvent) {
|
setConnectionStatus(c.getContactId());
|
||||||
setConnected(((ContactDisconnectedEvent) e).getContactId());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void setConnected(ContactId c) {
|
private void setConnectionStatus(ContactId c) {
|
||||||
if (listener == null) throw new IllegalStateException();
|
if (listener == null) throw new IllegalStateException();
|
||||||
if (contacts.contains(c)) {
|
if (contacts.contains(c)) {
|
||||||
int online = getOnlineCount();
|
int online = getOnlineCount();
|
||||||
@@ -95,7 +95,9 @@ public class SharingControllerImpl implements SharingController, EventListener {
|
|||||||
public int getOnlineCount() {
|
public int getOnlineCount() {
|
||||||
int online = 0;
|
int online = 0;
|
||||||
for (ContactId c : contacts) {
|
for (ContactId c : contacts) {
|
||||||
if (connectionRegistry.isConnected(c)) online++;
|
if (connectionRegistry.getConnectionStatus(c) == CONNECTED) {
|
||||||
|
online++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return online;
|
return online;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import android.view.Menu;
|
|||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
@@ -34,8 +33,8 @@ import org.briarproject.bramble.api.event.EventListener;
|
|||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
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.ConnectionStatus;
|
||||||
import org.briarproject.bramble.api.plugin.event.ContactDisconnectedEvent;
|
import org.briarproject.bramble.api.plugin.event.ConnectionStatusChangedEvent;
|
||||||
import org.briarproject.bramble.api.sync.ClientId;
|
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;
|
||||||
@@ -125,6 +124,8 @@ import static java.util.Objects.requireNonNull;
|
|||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.briarproject.bramble.api.plugin.ConnectionStatus.CONNECTED;
|
||||||
|
import static org.briarproject.bramble.api.plugin.ConnectionStatus.RECENTLY_CONNECTED;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
@@ -138,7 +139,6 @@ import static org.briarproject.briar.android.conversation.ImageActivity.ATTACHME
|
|||||||
import static org.briarproject.briar.android.conversation.ImageActivity.DATE;
|
import static org.briarproject.briar.android.conversation.ImageActivity.DATE;
|
||||||
import static org.briarproject.briar.android.conversation.ImageActivity.NAME;
|
import static org.briarproject.briar.android.conversation.ImageActivity.NAME;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.getAvatarTransitionName;
|
import static org.briarproject.briar.android.util.UiUtils.getAvatarTransitionName;
|
||||||
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;
|
||||||
@@ -198,8 +198,8 @@ public class ConversationActivity extends BriarActivity
|
|||||||
private ConversationAdapter adapter;
|
private ConversationAdapter adapter;
|
||||||
private Toolbar toolbar;
|
private Toolbar toolbar;
|
||||||
private CircleImageView toolbarAvatar;
|
private CircleImageView toolbarAvatar;
|
||||||
private ImageView toolbarStatus;
|
|
||||||
private TextView toolbarTitle;
|
private TextView toolbarTitle;
|
||||||
|
private TextView toolbarStatus;
|
||||||
private BriarRecyclerView list;
|
private BriarRecyclerView list;
|
||||||
private LinearLayoutManager layoutManager;
|
private LinearLayoutManager layoutManager;
|
||||||
private TextInputView textInputView;
|
private TextInputView textInputView;
|
||||||
@@ -237,8 +237,8 @@ public class ConversationActivity extends BriarActivity
|
|||||||
// Custom Toolbar
|
// Custom Toolbar
|
||||||
toolbar = requireNonNull(setUpCustomToolbar(true));
|
toolbar = requireNonNull(setUpCustomToolbar(true));
|
||||||
toolbarAvatar = toolbar.findViewById(R.id.contactAvatar);
|
toolbarAvatar = toolbar.findViewById(R.id.contactAvatar);
|
||||||
toolbarStatus = toolbar.findViewById(R.id.contactStatus);
|
|
||||||
toolbarTitle = toolbar.findViewById(R.id.contactName);
|
toolbarTitle = toolbar.findViewById(R.id.contactName);
|
||||||
|
toolbarStatus = toolbar.findViewById(R.id.contactStatus);
|
||||||
|
|
||||||
observeOnce(viewModel.getContactAuthorId(), this, authorId -> {
|
observeOnce(viewModel.getContactAuthorId(), this, authorId -> {
|
||||||
requireNonNull(authorId);
|
requireNonNull(authorId);
|
||||||
@@ -257,7 +257,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
this::onAddedPrivateMessage);
|
this::onAddedPrivateMessage);
|
||||||
|
|
||||||
setTransitionName(toolbarAvatar, getAvatarTransitionName(contactId));
|
setTransitionName(toolbarAvatar, getAvatarTransitionName(contactId));
|
||||||
setTransitionName(toolbarStatus, getBulbTransitionName(contactId));
|
|
||||||
|
|
||||||
visitor = new ConversationVisitor(this, this, this,
|
visitor = new ConversationVisitor(this, this, this,
|
||||||
viewModel.getContactDisplayName());
|
viewModel.getContactDisplayName());
|
||||||
@@ -499,14 +498,14 @@ public class ConversationActivity extends BriarActivity
|
|||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void displayContactOnlineStatus() {
|
private void displayContactOnlineStatus() {
|
||||||
if (connectionRegistry.isConnected(contactId)) {
|
ConnectionStatus status =
|
||||||
toolbarStatus.setImageDrawable(ContextCompat.getDrawable(
|
connectionRegistry.getConnectionStatus(contactId);
|
||||||
ConversationActivity.this, R.drawable.contact_online));
|
if (status == CONNECTED) {
|
||||||
toolbarStatus.setContentDescription(getString(R.string.online));
|
toolbarStatus.setText(R.string.online);
|
||||||
|
} else if (status == RECENTLY_CONNECTED) {
|
||||||
|
toolbarStatus.setText(R.string.recently_online);
|
||||||
} else {
|
} else {
|
||||||
toolbarStatus.setImageDrawable(ContextCompat.getDrawable(
|
toolbarStatus.setText(R.string.offline);
|
||||||
ConversationActivity.this, R.drawable.contact_offline));
|
|
||||||
toolbarStatus.setContentDescription(getString(R.string.offline));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -729,16 +728,10 @@ public class ConversationActivity extends BriarActivity
|
|||||||
LOG.info("Messages acked");
|
LOG.info("Messages acked");
|
||||||
markMessages(m.getMessageIds(), true, true);
|
markMessages(m.getMessageIds(), true, true);
|
||||||
}
|
}
|
||||||
} else if (e instanceof ContactConnectedEvent) {
|
} else if (e instanceof ConnectionStatusChangedEvent) {
|
||||||
ContactConnectedEvent c = (ContactConnectedEvent) e;
|
ConnectionStatusChangedEvent c = (ConnectionStatusChangedEvent) e;
|
||||||
if (c.getContactId().equals(contactId)) {
|
if (c.getContactId().equals(contactId)) {
|
||||||
LOG.info("Contact connected");
|
LOG.info("Connection status changed");
|
||||||
displayContactOnlineStatus();
|
|
||||||
}
|
|
||||||
} else if (e instanceof ContactDisconnectedEvent) {
|
|
||||||
ContactDisconnectedEvent c = (ContactDisconnectedEvent) e;
|
|
||||||
if (c.getContactId().equals(contactId)) {
|
|
||||||
LOG.info("Contact disconnected");
|
|
||||||
displayContactOnlineStatus();
|
displayContactOnlineStatus();
|
||||||
}
|
}
|
||||||
} else if (e instanceof ClientVersionUpdatedEvent) {
|
} else if (e instanceof ClientVersionUpdatedEvent) {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import org.briarproject.bramble.api.db.DbException;
|
|||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
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.ConnectionStatus;
|
||||||
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.contact.BaseContactListAdapter.OnContactClickListener;
|
import org.briarproject.briar.android.contact.BaseContactListAdapter.OnContactClickListener;
|
||||||
@@ -73,7 +74,8 @@ public class ContactChooserFragment extends BaseFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
|
public View onCreateView(LayoutInflater inflater,
|
||||||
|
@Nullable ViewGroup container,
|
||||||
@Nullable Bundle savedInstanceState) {
|
@Nullable Bundle savedInstanceState) {
|
||||||
|
|
||||||
View contentView = inflater.inflate(R.layout.list, container, false);
|
View contentView = inflater.inflate(R.layout.list, container, false);
|
||||||
@@ -127,9 +129,9 @@ public class ContactChooserFragment extends BaseFragment {
|
|||||||
ContactId id = c.getId();
|
ContactId id = c.getId();
|
||||||
GroupCount count =
|
GroupCount count =
|
||||||
conversationManager.getGroupCount(id);
|
conversationManager.getGroupCount(id);
|
||||||
boolean connected =
|
ConnectionStatus status = connectionRegistry
|
||||||
connectionRegistry.isConnected(c.getId());
|
.getConnectionStatus(c.getId());
|
||||||
contacts.add(new ContactListItem(c, connected, count));
|
contacts.add(new ContactListItem(c, status, count));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
displayContacts(contacts);
|
displayContacts(contacts);
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ public class GroupMemberListActivity extends BriarActivity
|
|||||||
supportFinishAfterTransition();
|
supportFinishAfterTransition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO ContactConnectedEvent and ContactDisconnectedEvent
|
// TODO ConnectionStatusChangedEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.db.DatabaseExecutor;
|
|||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
||||||
|
import org.briarproject.bramble.api.plugin.ConnectionStatus;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.briar.android.controller.DbControllerImpl;
|
import org.briarproject.briar.android.controller.DbControllerImpl;
|
||||||
import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
|
import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
|
||||||
@@ -19,6 +20,7 @@ import java.util.logging.Logger;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.api.plugin.ConnectionStatus.DISCONNECTED;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
class GroupMemberListControllerImpl extends DbControllerImpl
|
class GroupMemberListControllerImpl extends DbControllerImpl
|
||||||
@@ -50,10 +52,11 @@ class GroupMemberListControllerImpl extends DbControllerImpl
|
|||||||
privateGroupManager.getMembers(groupId);
|
privateGroupManager.getMembers(groupId);
|
||||||
for (GroupMember m : members) {
|
for (GroupMember m : members) {
|
||||||
ContactId c = m.getContactId();
|
ContactId c = m.getContactId();
|
||||||
boolean online = false;
|
ConnectionStatus status = DISCONNECTED;
|
||||||
if (c != null)
|
if (c != null) {
|
||||||
online = connectionRegistry.isConnected(c);
|
status = connectionRegistry.getConnectionStatus(c);
|
||||||
items.add(new MemberListItem(m, online));
|
}
|
||||||
|
items.add(new MemberListItem(m, status));
|
||||||
}
|
}
|
||||||
handler.onResult(items);
|
handler.onResult(items);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class MemberListAdapter extends
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean areContentsTheSame(MemberListItem m1, MemberListItem m2) {
|
public boolean areContentsTheSame(MemberListItem m1, MemberListItem m2) {
|
||||||
if (m1.isOnline() != m2.isOnline()) return false;
|
if (m1.getConnectionStatus() != m2.getConnectionStatus()) return false;
|
||||||
if (m1.getContactId() != m2.getContactId()) return false;
|
if (m1.getContactId() != m2.getContactId()) return false;
|
||||||
if (m1.getStatus() != m2.getStatus()) return false;
|
if (m1.getStatus() != m2.getStatus()) return false;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.identity.Author;
|
|||||||
import org.briarproject.bramble.api.identity.AuthorInfo;
|
import org.briarproject.bramble.api.identity.AuthorInfo;
|
||||||
import org.briarproject.bramble.api.identity.AuthorInfo.Status;
|
import org.briarproject.bramble.api.identity.AuthorInfo.Status;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.ConnectionStatus;
|
||||||
import org.briarproject.briar.api.privategroup.GroupMember;
|
import org.briarproject.briar.api.privategroup.GroupMember;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -15,11 +16,11 @@ import javax.annotation.concurrent.NotThreadSafe;
|
|||||||
class MemberListItem {
|
class MemberListItem {
|
||||||
|
|
||||||
private final GroupMember groupMember;
|
private final GroupMember groupMember;
|
||||||
private boolean online;
|
private ConnectionStatus status;
|
||||||
|
|
||||||
MemberListItem(GroupMember groupMember, boolean online) {
|
MemberListItem(GroupMember groupMember, ConnectionStatus status) {
|
||||||
this.groupMember = groupMember;
|
this.groupMember = groupMember;
|
||||||
this.online = online;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
Author getMember() {
|
Author getMember() {
|
||||||
@@ -43,12 +44,12 @@ class MemberListItem {
|
|||||||
return groupMember.getContactId();
|
return groupMember.getContactId();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isOnline() {
|
ConnectionStatus getConnectionStatus() {
|
||||||
return online;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setOnline(boolean online) {
|
void setConnectionStatus(ConnectionStatus status) {
|
||||||
this.online = online;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.ConnectionStatus;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.view.AuthorView;
|
import org.briarproject.briar.android.view.AuthorView;
|
||||||
|
|
||||||
@@ -14,6 +15,8 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
|
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
|
||||||
|
import static org.briarproject.bramble.api.plugin.ConnectionStatus.CONNECTED;
|
||||||
|
import static org.briarproject.bramble.api.plugin.ConnectionStatus.RECENTLY_CONNECTED;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
|
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@@ -38,10 +41,13 @@ class MemberListItemHolder extends RecyclerView.ViewHolder {
|
|||||||
// online status of visible contacts
|
// online status of visible contacts
|
||||||
if (item.getContactId() != null) {
|
if (item.getContactId() != null) {
|
||||||
bulb.setVisibility(VISIBLE);
|
bulb.setVisibility(VISIBLE);
|
||||||
if (item.isOnline()) {
|
ConnectionStatus status = item.getConnectionStatus();
|
||||||
bulb.setImageResource(R.drawable.contact_connected);
|
if (status == CONNECTED) {
|
||||||
|
bulb.setImageResource(R.drawable.ic_connected);
|
||||||
|
} else if (status == RECENTLY_CONNECTED) {
|
||||||
|
bulb.setImageResource(R.drawable.ic_recently_connected);
|
||||||
} else {
|
} else {
|
||||||
bulb.setImageResource(R.drawable.contact_disconnected);
|
bulb.setImageResource(R.drawable.ic_disconnected);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bulb.setVisibility(GONE);
|
bulb.setVisibility(GONE);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import org.briarproject.bramble.api.event.EventListener;
|
|||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
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.ConnectionStatus;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.bramble.api.sync.event.GroupRemovedEvent;
|
import org.briarproject.bramble.api.sync.event.GroupRemovedEvent;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
@@ -104,7 +105,7 @@ abstract class SharingStatusActivity extends BriarActivity
|
|||||||
supportFinishAfterTransition();
|
supportFinishAfterTransition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO ContactConnectedEvent and ContactDisconnectedEvent
|
// TODO ConnectionStatusChangedEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -134,8 +135,9 @@ abstract class SharingStatusActivity extends BriarActivity
|
|||||||
try {
|
try {
|
||||||
List<ContactItem> contactItems = new ArrayList<>();
|
List<ContactItem> contactItems = new ArrayList<>();
|
||||||
for (Contact c : getSharedWith()) {
|
for (Contact c : getSharedWith()) {
|
||||||
boolean online = connectionRegistry.isConnected(c.getId());
|
ConnectionStatus status =
|
||||||
ContactItem item = new ContactItem(c, online);
|
connectionRegistry.getConnectionStatus(c.getId());
|
||||||
|
ContactItem item = new ContactItem(c, status);
|
||||||
contactItems.add(item);
|
contactItems.add(item);
|
||||||
}
|
}
|
||||||
displaySharedWith(contactItems);
|
displaySharedWith(contactItems);
|
||||||
|
|||||||
@@ -238,10 +238,6 @@ public class UiUtils {
|
|||||||
return "avatar" + c.getInt();
|
return "avatar" + c.getInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getBulbTransitionName(ContactId c) {
|
|
||||||
return "bulb" + c.getInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static OnClickListener getGoToSettingsListener(Context context) {
|
public static OnClickListener getGoToSettingsListener(Context context) {
|
||||||
return (dialog, which) -> {
|
return (dialog, which) -> {
|
||||||
Intent i = new Intent();
|
Intent i = new Intent();
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportHeight="24"
|
|
||||||
android:viewportWidth="24">
|
|
||||||
|
|
||||||
<path
|
|
||||||
android:fillColor="#abffffff"
|
|
||||||
android:pathData="M12,2 C6.48,2,2,6.48,2,12 S6.48,22,12,22 S22,17.52,22,12 S17.52,2,12,2 Z M12,20
|
|
||||||
C7.58,20,4,16.42,4,12 S7.58,4,12,4 S20,7.58,20,12 S16.42,20,12,20 Z"/>
|
|
||||||
|
|
||||||
<path
|
|
||||||
android:fillColor="#95d220"
|
|
||||||
android:pathData="M10.8972,19.9503 C6.5514,19.3493,3.43091,15.2154,4.0625,10.896
|
|
||||||
C4.55452,7.53099,7.09451,4.8236,10.394,4.14714
|
|
||||||
C14.2569,3.35517,18.1698,5.54347,19.5236,9.25295
|
|
||||||
C20.0698,10.7495,20.1616,12.4612,19.777,13.9758
|
|
||||||
C19.5457,14.8864,18.8106,16.3388,18.2072,17.0771
|
|
||||||
C16.4904,19.1779,13.581,20.3215,10.8973,19.9503 Z"
|
|
||||||
android:strokeLineCap="round"
|
|
||||||
android:strokeLineJoin="round"
|
|
||||||
android:strokeWidth="0.76779664"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportHeight="24.0"
|
|
||||||
android:viewportWidth="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#abffffff"
|
|
||||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm0,18c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
|
|
||||||
</vector>
|
|
||||||
13
briar-android/src/main/res/drawable-night/ic_connected.xml
Normal file
13
briar-android/src/main/res/drawable-night/ic_connected.xml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:pathData="M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
|
||||||
|
android:strokeAlpha="1"
|
||||||
|
android:strokeWidth="1.5"
|
||||||
|
android:fillColor="#95d220"
|
||||||
|
android:strokeColor="#abffffff"
|
||||||
|
android:fillAlpha="1"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:pathData="M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
|
||||||
|
android:strokeAlpha="1"
|
||||||
|
android:strokeWidth="1.5"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#abffffff"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:fillAlpha="1"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:pathData="M12,12m-7,0a7,7 0,1 1,14 0a7,7 0,1 1,-14 0"
|
||||||
|
android:strokeAlpha="1"
|
||||||
|
android:strokeWidth="4.5"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#95d220"
|
||||||
|
android:fillAlpha="1"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
|
||||||
|
android:strokeAlpha="1"
|
||||||
|
android:strokeWidth="1.5"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#abffffff"
|
||||||
|
android:fillAlpha="1"/>
|
||||||
|
</vector>
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:alpha="0.56"
|
|
||||||
android:viewportHeight="24"
|
|
||||||
android:viewportWidth="24">
|
|
||||||
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="M12,2 C6.48,2,2,6.48,2,12 S6.48,22,12,22 S22,17.52,22,12 S17.52,2,12,2 Z M12,20
|
|
||||||
C7.58,20,4,16.42,4,12 S7.58,4,12,4 S20,7.58,20,12 S16.42,20,12,20 Z"/>
|
|
||||||
<path
|
|
||||||
android:pathData="M0,0 L24,0 L24,24 L0,24 Z"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#95d220"
|
|
||||||
android:pathData="M10.8972,19.9503 C6.5514,19.3493,3.43091,15.2154,4.0625,10.896
|
|
||||||
C4.55452,7.53099,7.09451,4.8236,10.394,4.14714
|
|
||||||
C14.2569,3.35517,18.1698,5.54347,19.5236,9.25295
|
|
||||||
C20.0698,10.7495,20.1616,12.4612,19.777,13.9758
|
|
||||||
C19.5457,14.8864,18.8106,16.3388,18.2072,17.0771
|
|
||||||
C16.4904,19.1779,13.581,20.3215,10.8973,19.9503 Z"
|
|
||||||
android:strokeLineCap="round"
|
|
||||||
android:strokeLineJoin="round"
|
|
||||||
android:strokeWidth="0.76779664"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:alpha="0.56"
|
|
||||||
android:viewportHeight="24.0"
|
|
||||||
android:viewportWidth="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm0,18c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
|
|
||||||
</vector>
|
|
||||||
13
briar-android/src/main/res/drawable/ic_connected.xml
Normal file
13
briar-android/src/main/res/drawable/ic_connected.xml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:pathData="M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
|
||||||
|
android:strokeAlpha="1"
|
||||||
|
android:strokeWidth="1.5"
|
||||||
|
android:fillColor="#95d220"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:fillAlpha="0.56"/>
|
||||||
|
</vector>
|
||||||
14
briar-android/src/main/res/drawable/ic_disconnected.xml
Normal file
14
briar-android/src/main/res/drawable/ic_disconnected.xml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:pathData="M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
|
||||||
|
android:strokeAlpha="1"
|
||||||
|
android:strokeWidth="1.5"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:fillAlpha="1"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:pathData="M12,12m-7,0a7,7 0,1 1,14 0a7,7 0,1 1,-14 0"
|
||||||
|
android:strokeAlpha="0.56"
|
||||||
|
android:strokeWidth="4.5"
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:strokeColor="#95d220"
|
||||||
|
android:fillAlpha="1"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
|
||||||
|
android:strokeAlpha="1"
|
||||||
|
android:strokeWidth="1.5"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#000000"
|
||||||
|
android:fillAlpha="1"/>
|
||||||
|
</vector>
|
||||||
@@ -18,27 +18,50 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<LinearLayout
|
<RelativeLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content">
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<include layout="@layout/contact_avatar_status" />
|
<de.hdodenhof.circleimageview.CircleImageView
|
||||||
|
android:id="@+id/contactAvatar"
|
||||||
|
style="@style/BriarAvatar"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_margin="4dp"
|
||||||
|
app:civ_border_color="@color/action_bar_text"
|
||||||
|
tools:src="@mipmap/ic_launcher_round" />
|
||||||
|
|
||||||
<com.vanniktech.emoji.EmojiTextView
|
<com.vanniktech.emoji.EmojiTextView
|
||||||
android:id="@+id/contactName"
|
android:id="@+id/contactName"
|
||||||
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse"
|
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
android:layout_marginStart="@dimen/margin_medium"
|
android:layout_marginStart="@dimen/margin_medium"
|
||||||
android:layout_marginLeft="@dimen/margin_medium"
|
android:layout_marginLeft="@dimen/margin_medium"
|
||||||
|
android:layout_toEndOf="@id/contactAvatar"
|
||||||
|
android:layout_toRightOf="@id/contactAvatar"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:textColor="@color/action_bar_text"
|
android:textColor="@color/action_bar_text"
|
||||||
tools:text="Contact Name of someone who chose a long name" />
|
tools:text="Contact Name of someone who chose a long name" />
|
||||||
|
|
||||||
</LinearLayout>
|
<TextView
|
||||||
|
android:id="@+id/contactStatus"
|
||||||
|
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Subtitle.Inverse"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/contactName"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_toEndOf="@id/contactAvatar"
|
||||||
|
android:layout_toRightOf="@id/contactAvatar"
|
||||||
|
android:textColor="@color/briar_text_secondary_inverse"
|
||||||
|
tools:text="Recently online" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
</androidx.appcompat.widget.Toolbar>
|
</androidx.appcompat.widget.Toolbar>
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="32dp"
|
|
||||||
android:layout_height="32dp"
|
|
||||||
tools:showIn="@layout/activity_conversation">
|
|
||||||
|
|
||||||
<de.hdodenhof.circleimageview.CircleImageView
|
|
||||||
android:id="@+id/contactAvatar"
|
|
||||||
style="@style/BriarAvatar"
|
|
||||||
android:layout_width="30dp"
|
|
||||||
android:layout_height="30dp"
|
|
||||||
app:civ_border_color="@color/action_bar_text"
|
|
||||||
tools:src="@mipmap/ic_launcher_round" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/contactStatus"
|
|
||||||
android:layout_width="15dp"
|
|
||||||
android:layout_height="15dp"
|
|
||||||
android:layout_gravity="bottom|end|right"
|
|
||||||
android:scaleType="fitCenter"
|
|
||||||
tools:ignore="ContentDescription"
|
|
||||||
tools:src="@drawable/contact_online" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
@@ -90,7 +90,7 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:ignore="ContentDescription"
|
tools:ignore="ContentDescription"
|
||||||
tools:src="@drawable/contact_connected" />
|
tools:src="@drawable/ic_recently_connected" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/divider"
|
android:id="@+id/divider"
|
||||||
|
|||||||
@@ -40,6 +40,6 @@
|
|||||||
android:layout_marginEnd="@dimen/listitem_horizontal_margin"
|
android:layout_marginEnd="@dimen/listitem_horizontal_margin"
|
||||||
android:layout_marginRight="@dimen/listitem_horizontal_margin"
|
android:layout_marginRight="@dimen/listitem_horizontal_margin"
|
||||||
tools:ignore="ContentDescription"
|
tools:ignore="ContentDescription"
|
||||||
tools:src="@drawable/contact_connected" />
|
tools:src="@drawable/ic_connected" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:ignore="ContentDescription"
|
tools:ignore="ContentDescription"
|
||||||
tools:src="@drawable/contact_connected" />
|
tools:src="@drawable/ic_connected" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/creatorView"
|
android:id="@+id/creatorView"
|
||||||
|
|||||||
@@ -110,6 +110,7 @@
|
|||||||
<string name="decline">Decline</string>
|
<string name="decline">Decline</string>
|
||||||
<string name="options">Options</string>
|
<string name="options">Options</string>
|
||||||
<string name="online">Online</string>
|
<string name="online">Online</string>
|
||||||
|
<string name="recently_online">Recently online</string>
|
||||||
<string name="offline">Offline</string>
|
<string name="offline">Offline</string>
|
||||||
<string name="send">Send</string>
|
<string name="send">Send</string>
|
||||||
<string name="allow">Allow</string>
|
<string name="allow">Allow</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user