mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 19:59:05 +01:00
Compare commits
86 Commits
release-1.
...
release-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39478a7914 | ||
|
|
112e71a9cb | ||
|
|
5650bef310 | ||
|
|
2a87171c49 | ||
|
|
15cb5409e7 | ||
|
|
fd07dc006d | ||
|
|
cc87c4e37d | ||
|
|
4a10e876f6 | ||
|
|
fad0057c4a | ||
|
|
5aabfcea9a | ||
|
|
f7d928c774 | ||
|
|
bd983d9796 | ||
|
|
de8d1b7d96 | ||
|
|
9155f62d0b | ||
|
|
86684e228a | ||
|
|
9615eff649 | ||
|
|
9381d46f51 | ||
|
|
e4a3a1ad40 | ||
|
|
905dc2a662 | ||
|
|
c2b7f85b8e | ||
|
|
ae81eb3737 | ||
|
|
60d949c342 | ||
|
|
1c90e64894 | ||
|
|
f0e2d5281f | ||
|
|
c7522dae1f | ||
|
|
097d14b9a1 | ||
|
|
0491c3cace | ||
|
|
cbae13feca | ||
|
|
b7c8859c82 | ||
|
|
2e120f752c | ||
|
|
031eac54c5 | ||
|
|
2c2596afdd | ||
|
|
d1be14effe | ||
|
|
b56e7ab07d | ||
|
|
089e9589ed | ||
|
|
660ba16a14 | ||
|
|
b101c4b636 | ||
|
|
fdfddd2667 | ||
|
|
296546544f | ||
|
|
ad579a6ba3 | ||
|
|
90e82357ba | ||
|
|
b3b40753d8 | ||
|
|
e60df3cece | ||
|
|
da3cb95151 | ||
|
|
c27885072f | ||
|
|
6557d564c9 | ||
|
|
53edcaf3e9 | ||
|
|
5122c961b4 | ||
|
|
f83b9244d4 | ||
|
|
81292967e0 | ||
|
|
b72f6b4fc3 | ||
|
|
488be49c93 | ||
|
|
90db45817a | ||
|
|
81863b9db6 | ||
|
|
da069adb57 | ||
|
|
46425b09fa | ||
|
|
41e1a436c9 | ||
|
|
989394d18b | ||
|
|
b6b3f9c292 | ||
|
|
a52547f73b | ||
|
|
24f823a3ce | ||
|
|
a045d7d306 | ||
|
|
a29d5efd93 | ||
|
|
37cd1cdddf | ||
|
|
4f495bb4d3 | ||
|
|
1a70200b65 | ||
|
|
6925dfcbdd | ||
|
|
7d479063a9 | ||
|
|
2309e73216 | ||
|
|
4b325f797b | ||
|
|
9be83c3cc7 | ||
|
|
86f650503b | ||
|
|
d430b4fd2d | ||
|
|
fcf7cf72ea | ||
|
|
b78dfea95f | ||
|
|
183fe08565 | ||
|
|
7e32697696 | ||
|
|
29758b174a | ||
|
|
61e18f104e | ||
|
|
ffeca8817f | ||
|
|
59fae2fa3c | ||
|
|
2d9345c018 | ||
|
|
817df9c75a | ||
|
|
745515457e | ||
|
|
ba5928218a | ||
|
|
74e4a9cbdf |
@@ -9,8 +9,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 26
|
targetSdkVersion 26
|
||||||
versionCode 10101
|
versionCode 10102
|
||||||
versionName "1.1.1"
|
versionName "1.1.2"
|
||||||
consumerProguardFiles 'proguard-rules.txt'
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
|
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package org.briarproject.bramble.api;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public interface Nameable {
|
||||||
|
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package org.briarproject.bramble.api;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An exception that indicates an unrecoverable version mismatch.
|
|
||||||
*/
|
|
||||||
public class UnsupportedVersionException extends IOException {
|
|
||||||
}
|
|
||||||
@@ -16,7 +16,6 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -49,14 +48,13 @@ public abstract class BdfMessageValidator implements MessageValidator {
|
|||||||
throw new InvalidMessageException(
|
throw new InvalidMessageException(
|
||||||
"Timestamp is too far in the future");
|
"Timestamp is too far in the future");
|
||||||
}
|
}
|
||||||
byte[] raw = m.getRaw();
|
byte[] body = m.getBody();
|
||||||
if (raw.length <= MESSAGE_HEADER_LENGTH) {
|
if (body.length == 0) {
|
||||||
throw new InvalidMessageException("Message is too short");
|
throw new InvalidMessageException("Message is too short");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
BdfList body = clientHelper.toList(raw, MESSAGE_HEADER_LENGTH,
|
BdfList bodyList = clientHelper.toList(body);
|
||||||
raw.length - MESSAGE_HEADER_LENGTH);
|
BdfMessageContext result = validateMessage(m, g, bodyList);
|
||||||
BdfMessageContext result = validateMessage(m, g, body);
|
|
||||||
Metadata meta = metadataEncoder.encode(result.getDictionary());
|
Metadata meta = metadataEncoder.encode(result.getDictionary());
|
||||||
return new MessageContext(meta, result.getDependencies());
|
return new MessageContext(meta, result.getDependencies());
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.api.identity;
|
package org.briarproject.bramble.api.identity;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Nameable;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
|
|
||||||
@@ -13,7 +14,7 @@ import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_K
|
|||||||
*/
|
*/
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class Author {
|
public class Author implements Nameable {
|
||||||
|
|
||||||
public enum Status {
|
public enum Status {
|
||||||
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES
|
NONE, ANONYMOUS, UNKNOWN, UNVERIFIED, VERIFIED, OURSELVES
|
||||||
|
|||||||
@@ -3,7 +3,13 @@ package org.briarproject.bramble.api.keyagreement;
|
|||||||
public interface KeyAgreementConstants {
|
public interface KeyAgreementConstants {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current version of the BQP protocol. Version number 89 is reserved.
|
* The version of the BQP protocol used in beta releases. This version
|
||||||
|
* number is reserved.
|
||||||
|
*/
|
||||||
|
byte BETA_PROTOCOL_VERSION = 89;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current version of the BQP protocol.
|
||||||
*/
|
*/
|
||||||
byte PROTOCOL_VERSION = 4;
|
byte PROTOCOL_VERSION = 4;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.briarproject.bramble.api.keyagreement;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when a QR code that has been scanned uses a protocol version that is
|
||||||
|
* not supported.
|
||||||
|
*/
|
||||||
|
public class UnsupportedVersionException extends IOException {
|
||||||
|
|
||||||
|
private final boolean tooOld;
|
||||||
|
|
||||||
|
public UnsupportedVersionException(boolean tooOld) {
|
||||||
|
this.tooOld = tooOld;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTooOld() {
|
||||||
|
return tooOld;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package org.briarproject.bramble.api.sync;
|
package org.briarproject.bramble.api.sync;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
||||||
|
|
||||||
public class Message {
|
public class Message {
|
||||||
@@ -13,17 +13,15 @@ public class Message {
|
|||||||
private final MessageId id;
|
private final MessageId id;
|
||||||
private final GroupId groupId;
|
private final GroupId groupId;
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
private final byte[] raw;
|
private final byte[] body;
|
||||||
|
|
||||||
public Message(MessageId id, GroupId groupId, long timestamp, byte[] raw) {
|
public Message(MessageId id, GroupId groupId, long timestamp, byte[] body) {
|
||||||
if (raw.length <= MESSAGE_HEADER_LENGTH)
|
if (body.length > MAX_MESSAGE_BODY_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
|
||||||
if (raw.length > MAX_MESSAGE_LENGTH)
|
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.raw = raw;
|
this.body = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,14 +49,14 @@ public class Message {
|
|||||||
* Returns the length of the raw message in bytes.
|
* Returns the length of the raw message in bytes.
|
||||||
*/
|
*/
|
||||||
public int getRawLength() {
|
public int getRawLength() {
|
||||||
return raw.length;
|
return MESSAGE_HEADER_LENGTH + body.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the raw message.
|
* Returns the message body.
|
||||||
*/
|
*/
|
||||||
public byte[] getRaw() {
|
public byte[] getBody() {
|
||||||
return raw;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ public interface MessageFactory {
|
|||||||
|
|
||||||
Message createMessage(byte[] raw);
|
Message createMessage(byte[] raw);
|
||||||
|
|
||||||
Message createMessage(MessageId m, byte[] raw);
|
byte[] getRawMessage(Message m);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package org.briarproject.bramble.test;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
|
||||||
|
public class ArrayClock implements Clock {
|
||||||
|
|
||||||
|
private final long[] times;
|
||||||
|
private int index = 0;
|
||||||
|
|
||||||
|
public ArrayClock(long... times) {
|
||||||
|
this.times = times;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long currentTimeMillis() {
|
||||||
|
return times[index++];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sleep(long milliseconds) throws InterruptedException {
|
||||||
|
Thread.sleep(milliseconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,7 +33,6 @@ import static org.briarproject.bramble.api.properties.TransportPropertyConstants
|
|||||||
import static org.briarproject.bramble.api.sync.ClientId.MAX_CLIENT_ID_LENGTH;
|
import static org.briarproject.bramble.api.sync.ClientId.MAX_CLIENT_ID_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
|
||||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
|
|
||||||
public class TestUtils {
|
public class TestUtils {
|
||||||
@@ -132,13 +131,13 @@ public class TestUtils {
|
|||||||
|
|
||||||
public static Message getMessage(GroupId groupId) {
|
public static Message getMessage(GroupId groupId) {
|
||||||
int bodyLength = 1 + random.nextInt(MAX_MESSAGE_BODY_LENGTH);
|
int bodyLength = 1 + random.nextInt(MAX_MESSAGE_BODY_LENGTH);
|
||||||
return getMessage(groupId, MESSAGE_HEADER_LENGTH + bodyLength);
|
return getMessage(groupId, bodyLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Message getMessage(GroupId groupId, int rawLength) {
|
public static Message getMessage(GroupId groupId, int bodyLength) {
|
||||||
MessageId id = new MessageId(getRandomId());
|
MessageId id = new MessageId(getRandomId());
|
||||||
byte[] raw = getRandomBytes(rawLength);
|
byte[] body = getRandomBytes(bodyLength);
|
||||||
return new Message(id, groupId, timestamp, raw);
|
return new Message(id, groupId, timestamp, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double getMedian(Collection<? extends Number> samples) {
|
public static double getMedian(Collection<? extends Number> samples) {
|
||||||
|
|||||||
@@ -159,7 +159,8 @@ class AccountManagerImpl implements AccountManager {
|
|||||||
@Override
|
@Override
|
||||||
public boolean createAccount(String name, String password) {
|
public boolean createAccount(String name, String password) {
|
||||||
synchronized (stateChangeLock) {
|
synchronized (stateChangeLock) {
|
||||||
// TODO don't allow creating another account if one already exists
|
if (hasDatabaseKey())
|
||||||
|
throw new AssertionError("Already have a database key");
|
||||||
LocalAuthor localAuthor = identityManager.createLocalAuthor(name);
|
LocalAuthor localAuthor = identityManager.createLocalAuthor(name);
|
||||||
identityManager.registerLocalAuthor(localAuthor);
|
identityManager.registerLocalAuthor(localAuthor);
|
||||||
SecretKey key = crypto.generateSecretKey();
|
SecretKey key = crypto.generateSecretKey();
|
||||||
@@ -182,6 +183,7 @@ class AccountManagerImpl implements AccountManager {
|
|||||||
LOG.info("Deleting account");
|
LOG.info("Deleting account");
|
||||||
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory());
|
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory());
|
||||||
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory());
|
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory());
|
||||||
|
databaseKey = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_N
|
|||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||||
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT;
|
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT;
|
||||||
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
|
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
|
||||||
import static org.briarproject.bramble.util.ValidationUtils.checkLength;
|
import static org.briarproject.bramble.util.ValidationUtils.checkLength;
|
||||||
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
|
import static org.briarproject.bramble.util.ValidationUtils.checkSize;
|
||||||
|
|
||||||
@@ -147,9 +146,7 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
@Override
|
@Override
|
||||||
public BdfList getMessageAsList(Transaction txn, MessageId m)
|
public BdfList getMessageAsList(Transaction txn, MessageId m)
|
||||||
throws DbException, FormatException {
|
throws DbException, FormatException {
|
||||||
byte[] raw = db.getMessage(txn, m).getRaw();
|
return toList(db.getMessage(txn, m).getBody());
|
||||||
return toList(raw, MESSAGE_HEADER_LENGTH,
|
|
||||||
raw.length - MESSAGE_HEADER_LENGTH);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -361,9 +358,7 @@ class ClientHelperImpl implements ClientHelper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BdfList toList(Message m) throws FormatException {
|
public BdfList toList(Message m) throws FormatException {
|
||||||
byte[] raw = m.getRaw();
|
return toList(m.getBody());
|
||||||
return toList(raw, MESSAGE_HEADER_LENGTH,
|
|
||||||
raw.length - MESSAGE_HEADER_LENGTH);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -421,7 +421,7 @@ interface Database<T> {
|
|||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<MessageId> getMessagesToOffer(T txn, ContactId c,
|
Collection<MessageId> getMessagesToOffer(T txn, ContactId c,
|
||||||
int maxMessages) throws DbException;
|
int maxMessages, int maxLatency) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the IDs of some messages that are eligible to be requested from
|
* Returns the IDs of some messages that are eligible to be requested from
|
||||||
@@ -438,8 +438,8 @@ interface Database<T> {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<MessageId> getMessagesToSend(T txn, ContactId c, int maxLength)
|
Collection<MessageId> getMessagesToSend(T txn, ContactId c, int maxLength,
|
||||||
throws DbException;
|
int maxLatency) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the IDs of any messages that need to be validated.
|
* Returns the IDs of any messages that need to be validated.
|
||||||
@@ -482,7 +482,7 @@ interface Database<T> {
|
|||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<MessageId> getRequestedMessagesToSend(T txn, ContactId c,
|
Collection<MessageId> getRequestedMessagesToSend(T txn, ContactId c,
|
||||||
int maxLength) throws DbException;
|
int maxLength, int maxLatency) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all settings in the given namespace.
|
* Returns all settings in the given namespace.
|
||||||
@@ -647,11 +647,11 @@ interface Database<T> {
|
|||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the transmission count and expiry time of the given message
|
* Updates the transmission count, expiry time and estimated time of arrival
|
||||||
* with respect to the given contact, using the latency of the transport
|
* of the given message with respect to the given contact, using the latency
|
||||||
* over which it was sent.
|
* of the transport over which it was sent.
|
||||||
*/
|
*/
|
||||||
void updateExpiryTime(T txn, ContactId c, MessageId m, int maxLatency)
|
void updateExpiryTimeAndEta(T txn, ContactId c, MessageId m, int maxLatency)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -313,11 +313,12 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsContact(txn, c))
|
if (!db.containsContact(txn, c))
|
||||||
throw new NoSuchContactException();
|
throw new NoSuchContactException();
|
||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, c, maxLength);
|
Collection<MessageId> ids =
|
||||||
|
db.getMessagesToSend(txn, c, maxLength, maxLatency);
|
||||||
List<Message> messages = new ArrayList<>(ids.size());
|
List<Message> messages = new ArrayList<>(ids.size());
|
||||||
for (MessageId m : ids) {
|
for (MessageId m : ids) {
|
||||||
messages.add(db.getMessage(txn, m));
|
messages.add(db.getMessage(txn, m));
|
||||||
db.updateExpiryTime(txn, c, m, maxLatency);
|
db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
|
||||||
}
|
}
|
||||||
if (ids.isEmpty()) return null;
|
if (ids.isEmpty()) return null;
|
||||||
db.lowerRequestedFlag(txn, c, ids);
|
db.lowerRequestedFlag(txn, c, ids);
|
||||||
@@ -333,9 +334,11 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsContact(txn, c))
|
if (!db.containsContact(txn, c))
|
||||||
throw new NoSuchContactException();
|
throw new NoSuchContactException();
|
||||||
Collection<MessageId> ids = db.getMessagesToOffer(txn, c, maxMessages);
|
Collection<MessageId> ids =
|
||||||
|
db.getMessagesToOffer(txn, c, maxMessages, maxLatency);
|
||||||
if (ids.isEmpty()) return null;
|
if (ids.isEmpty()) return null;
|
||||||
for (MessageId m : ids) db.updateExpiryTime(txn, c, m, maxLatency);
|
for (MessageId m : ids)
|
||||||
|
db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
|
||||||
return new Offer(ids);
|
return new Offer(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,12 +365,12 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
if (!db.containsContact(txn, c))
|
if (!db.containsContact(txn, c))
|
||||||
throw new NoSuchContactException();
|
throw new NoSuchContactException();
|
||||||
Collection<MessageId> ids = db.getRequestedMessagesToSend(txn, c,
|
Collection<MessageId> ids =
|
||||||
maxLength);
|
db.getRequestedMessagesToSend(txn, c, maxLength, maxLatency);
|
||||||
List<Message> messages = new ArrayList<>(ids.size());
|
List<Message> messages = new ArrayList<>(ids.size());
|
||||||
for (MessageId m : ids) {
|
for (MessageId m : ids) {
|
||||||
messages.add(db.getMessage(txn, m));
|
messages.add(db.getMessage(txn, m));
|
||||||
db.updateExpiryTime(txn, c, m, maxLatency);
|
db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
|
||||||
}
|
}
|
||||||
if (ids.isEmpty()) return null;
|
if (ids.isEmpty()) return null;
|
||||||
db.lowerRequestedFlag(txn, c, ids);
|
db.lowerRequestedFlag(txn, c, ids);
|
||||||
@@ -855,7 +858,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
if (!db.containsMessage(txn, m))
|
if (!db.containsMessage(txn, m))
|
||||||
throw new NoSuchMessageException();
|
throw new NoSuchMessageException();
|
||||||
if (db.getMessageState(txn, m) != DELIVERED)
|
if (db.getMessageState(txn, m) != DELIVERED)
|
||||||
throw new IllegalArgumentException("Shared undelivered message");
|
throw new IllegalArgumentException(
|
||||||
|
"Shared undelivered message");
|
||||||
db.setMessageShared(txn, m);
|
db.setMessageShared(txn, m);
|
||||||
transaction.attach(new MessageSharedEvent(m));
|
transaction.attach(new MessageSharedEvent(m));
|
||||||
}
|
}
|
||||||
@@ -881,7 +885,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
throw new NoSuchMessageException();
|
throw new NoSuchMessageException();
|
||||||
State dependentState = db.getMessageState(txn, dependent.getId());
|
State dependentState = db.getMessageState(txn, dependent.getId());
|
||||||
for (MessageId dependency : dependencies) {
|
for (MessageId dependency : dependencies) {
|
||||||
db.addMessageDependency(txn, dependent, dependency, dependentState);
|
db.addMessageDependency(txn, dependent, dependency,
|
||||||
|
dependentState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -913,7 +918,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
for (KeySet ks : keys) {
|
for (KeySet ks : keys) {
|
||||||
TransportId t = ks.getTransportKeys().getTransportId();
|
TransportId t = ks.getTransportKeys().getTransportId();
|
||||||
if (db.containsTransport(txn, t)) db.updateTransportKeys(txn, ks);
|
if (db.containsTransport(txn, t))
|
||||||
|
db.updateTransportKeys(txn, ks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
|
|||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
|
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
@@ -18,8 +19,9 @@ public class DatabaseModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
Database<Connection> provideDatabase(DatabaseConfig config, Clock clock) {
|
Database<Connection> provideDatabase(DatabaseConfig config,
|
||||||
return new H2Database(config, clock);
|
MessageFactory messageFactory, Clock clock) {
|
||||||
|
return new H2Database(config, messageFactory, clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
|
|||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.MigrationListener;
|
import org.briarproject.bramble.api.db.MigrationListener;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
|
|
||||||
@@ -36,9 +37,10 @@ class H2Database extends JdbcDatabase {
|
|||||||
private volatile SecretKey key = null;
|
private volatile SecretKey key = null;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
H2Database(DatabaseConfig config, Clock clock) {
|
H2Database(DatabaseConfig config, MessageFactory messageFactory,
|
||||||
|
Clock clock) {
|
||||||
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
||||||
clock);
|
messageFactory, clock);
|
||||||
this.config = config;
|
this.config = config;
|
||||||
File dir = config.getDatabaseDirectory();
|
File dir = config.getDatabaseDirectory();
|
||||||
String path = new File(dir, "db").getAbsolutePath();
|
String path = new File(dir, "db").getAbsolutePath();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
|
|||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.MigrationListener;
|
import org.briarproject.bramble.api.db.MigrationListener;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
|
|
||||||
@@ -37,9 +38,10 @@ class HyperSqlDatabase extends JdbcDatabase {
|
|||||||
private volatile SecretKey key = null;
|
private volatile SecretKey key = null;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
HyperSqlDatabase(DatabaseConfig config, Clock clock) {
|
HyperSqlDatabase(DatabaseConfig config, MessageFactory messageFactory,
|
||||||
|
Clock clock) {
|
||||||
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
||||||
clock);
|
messageFactory, clock);
|
||||||
this.config = config;
|
this.config = config;
|
||||||
File dir = config.getDatabaseDirectory();
|
File dir = config.getDatabaseDirectory();
|
||||||
String path = new File(dir, "db").getAbsolutePath();
|
String path = new File(dir, "db").getAbsolutePath();
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import org.briarproject.bramble.api.sync.Group;
|
|||||||
import org.briarproject.bramble.api.sync.Group.Visibility;
|
import org.briarproject.bramble.api.sync.Group.Visibility;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.api.sync.MessageStatus;
|
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||||
import org.briarproject.bramble.api.sync.ValidationManager.State;
|
import org.briarproject.bramble.api.sync.ValidationManager.State;
|
||||||
@@ -37,6 +38,7 @@ import java.sql.ResultSet;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -54,13 +56,13 @@ import java.util.logging.Logger;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static java.sql.Types.INTEGER;
|
import static java.sql.Types.INTEGER;
|
||||||
import static java.util.Collections.singletonList;
|
|
||||||
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 org.briarproject.bramble.api.db.Metadata.REMOVE;
|
import static org.briarproject.bramble.api.db.Metadata.REMOVE;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
||||||
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
|
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
|
||||||
|
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
|
||||||
@@ -77,7 +79,7 @@ import static org.briarproject.bramble.util.LogUtils.logException;
|
|||||||
abstract class JdbcDatabase implements Database<Connection> {
|
abstract class JdbcDatabase implements Database<Connection> {
|
||||||
|
|
||||||
// Package access for testing
|
// Package access for testing
|
||||||
static final int CODE_SCHEMA_VERSION = 39;
|
static final int CODE_SCHEMA_VERSION = 40;
|
||||||
|
|
||||||
// Rotation period offsets for incoming transport keys
|
// Rotation period offsets for incoming transport keys
|
||||||
private static final int OFFSET_PREV = -1;
|
private static final int OFFSET_PREV = -1;
|
||||||
@@ -217,6 +219,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " requested BOOLEAN NOT NULL,"
|
+ " requested BOOLEAN NOT NULL,"
|
||||||
+ " expiry BIGINT NOT NULL,"
|
+ " expiry BIGINT NOT NULL,"
|
||||||
+ " txCount INT NOT NULL,"
|
+ " txCount INT NOT NULL,"
|
||||||
|
+ " eta BIGINT NOT NULL,"
|
||||||
+ " PRIMARY KEY (messageId, contactId),"
|
+ " PRIMARY KEY (messageId, contactId),"
|
||||||
+ " FOREIGN KEY (messageId)"
|
+ " FOREIGN KEY (messageId)"
|
||||||
+ " REFERENCES messages (messageId)"
|
+ " REFERENCES messages (messageId)"
|
||||||
@@ -305,6 +308,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
// Different database libraries use different names for certain types
|
// Different database libraries use different names for certain types
|
||||||
private final String hashType, secretType, binaryType;
|
private final String hashType, secretType, binaryType;
|
||||||
private final String counterType, stringType;
|
private final String counterType, stringType;
|
||||||
|
private final MessageFactory messageFactory;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
|
|
||||||
// Locking: connectionsLock
|
// Locking: connectionsLock
|
||||||
@@ -320,12 +324,14 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
private final Condition connectionsChanged = connectionsLock.newCondition();
|
private final Condition connectionsChanged = connectionsLock.newCondition();
|
||||||
|
|
||||||
JdbcDatabase(String hashType, String secretType, String binaryType,
|
JdbcDatabase(String hashType, String secretType, String binaryType,
|
||||||
String counterType, String stringType, Clock clock) {
|
String counterType, String stringType,
|
||||||
|
MessageFactory messageFactory, Clock clock) {
|
||||||
this.hashType = hashType;
|
this.hashType = hashType;
|
||||||
this.secretType = secretType;
|
this.secretType = secretType;
|
||||||
this.binaryType = binaryType;
|
this.binaryType = binaryType;
|
||||||
this.counterType = counterType;
|
this.counterType = counterType;
|
||||||
this.stringType = stringType;
|
this.stringType = stringType;
|
||||||
|
this.messageFactory = messageFactory;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,7 +398,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
// Package access for testing
|
// Package access for testing
|
||||||
List<Migration<Connection>> getMigrations() {
|
List<Migration<Connection>> getMigrations() {
|
||||||
return singletonList(new Migration38_39());
|
return Arrays.asList(new Migration38_39(), new Migration39_40());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void storeSchemaVersion(Connection txn, int version)
|
private void storeSchemaVersion(Connection txn, int version)
|
||||||
@@ -727,7 +733,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
ps.setLong(3, m.getTimestamp());
|
ps.setLong(3, m.getTimestamp());
|
||||||
ps.setInt(4, state.getValue());
|
ps.setInt(4, state.getValue());
|
||||||
ps.setBoolean(5, messageShared);
|
ps.setBoolean(5, messageShared);
|
||||||
byte[] raw = m.getRaw();
|
byte[] raw = messageFactory.getRawMessage(m);
|
||||||
ps.setInt(6, raw.length);
|
ps.setInt(6, raw.length);
|
||||||
ps.setBytes(7, raw);
|
ps.setBytes(7, raw);
|
||||||
int affected = ps.executeUpdate();
|
int affected = ps.executeUpdate();
|
||||||
@@ -741,7 +747,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
boolean offered = removeOfferedMessage(txn, c, m.getId());
|
boolean offered = removeOfferedMessage(txn, c, m.getId());
|
||||||
boolean seen = offered || (sender != null && c.equals(sender));
|
boolean seen = offered || (sender != null && c.equals(sender));
|
||||||
addStatus(txn, m.getId(), c, m.getGroupId(), m.getTimestamp(),
|
addStatus(txn, m.getId(), c, m.getGroupId(), m.getTimestamp(),
|
||||||
m.getRawLength(), state, e.getValue(), messageShared,
|
raw.length, state, e.getValue(), messageShared,
|
||||||
false, seen);
|
false, seen);
|
||||||
}
|
}
|
||||||
// Update denormalised column in messageDependencies if dependency
|
// Update denormalised column in messageDependencies if dependency
|
||||||
@@ -800,8 +806,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
try {
|
try {
|
||||||
String sql = "INSERT INTO statuses (messageId, contactId, groupId,"
|
String sql = "INSERT INTO statuses (messageId, contactId, groupId,"
|
||||||
+ " timestamp, length, state, groupShared, messageShared,"
|
+ " timestamp, length, state, groupShared, messageShared,"
|
||||||
+ " deleted, ack, seen, requested, expiry, txCount)"
|
+ " deleted, ack, seen, requested, expiry, txCount, eta)"
|
||||||
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE, 0, 0)";
|
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE, 0, 0,"
|
||||||
|
+ " 0)";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setBytes(1, m.getBytes());
|
ps.setBytes(1, m.getBytes());
|
||||||
ps.setInt(2, c.getInt());
|
ps.setInt(2, c.getInt());
|
||||||
@@ -1501,7 +1508,10 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
rs.close();
|
rs.close();
|
||||||
ps.close();
|
ps.close();
|
||||||
if (raw == null) throw new MessageDeletedException();
|
if (raw == null) throw new MessageDeletedException();
|
||||||
return new Message(m, g, timestamp, raw);
|
if (raw.length < MESSAGE_HEADER_LENGTH) throw new AssertionError();
|
||||||
|
byte[] body = new byte[raw.length - MESSAGE_HEADER_LENGTH];
|
||||||
|
System.arraycopy(raw, MESSAGE_HEADER_LENGTH, body, 0, body.length);
|
||||||
|
return new Message(m, g, timestamp, body);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
tryToClose(rs);
|
tryToClose(rs);
|
||||||
tryToClose(ps);
|
tryToClose(ps);
|
||||||
@@ -1861,8 +1871,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<MessageId> getMessagesToOffer(Connection txn,
|
public Collection<MessageId> getMessagesToOffer(Connection txn,
|
||||||
ContactId c, int maxMessages) throws DbException {
|
ContactId c, int maxMessages, int maxLatency) throws DbException {
|
||||||
long now = clock.currentTimeMillis();
|
long now = clock.currentTimeMillis();
|
||||||
|
long eta = now + maxLatency;
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
@@ -1871,13 +1882,14 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
||||||
+ " AND deleted = FALSE"
|
+ " AND deleted = FALSE"
|
||||||
+ " AND seen = FALSE AND requested = FALSE"
|
+ " AND seen = FALSE AND requested = FALSE"
|
||||||
+ " AND expiry < ?"
|
+ " AND (expiry <= ? OR eta > ?)"
|
||||||
+ " ORDER BY timestamp LIMIT ?";
|
+ " ORDER BY timestamp LIMIT ?";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, c.getInt());
|
ps.setInt(1, c.getInt());
|
||||||
ps.setInt(2, DELIVERED.getValue());
|
ps.setInt(2, DELIVERED.getValue());
|
||||||
ps.setLong(3, now);
|
ps.setLong(3, now);
|
||||||
ps.setInt(4, maxMessages);
|
ps.setLong(4, eta);
|
||||||
|
ps.setInt(5, maxMessages);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
List<MessageId> ids = new ArrayList<>();
|
List<MessageId> ids = new ArrayList<>();
|
||||||
while (rs.next()) ids.add(new MessageId(rs.getBytes(1)));
|
while (rs.next()) ids.add(new MessageId(rs.getBytes(1)));
|
||||||
@@ -1918,8 +1930,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<MessageId> getMessagesToSend(Connection txn, ContactId c,
|
public Collection<MessageId> getMessagesToSend(Connection txn, ContactId c,
|
||||||
int maxLength) throws DbException {
|
int maxLength, int maxLatency) throws DbException {
|
||||||
long now = clock.currentTimeMillis();
|
long now = clock.currentTimeMillis();
|
||||||
|
long eta = now + maxLatency;
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
@@ -1928,12 +1941,13 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
||||||
+ " AND deleted = FALSE"
|
+ " AND deleted = FALSE"
|
||||||
+ " AND seen = FALSE"
|
+ " AND seen = FALSE"
|
||||||
+ " AND expiry < ?"
|
+ " AND (expiry <= ? OR eta > ?)"
|
||||||
+ " ORDER BY timestamp";
|
+ " ORDER BY timestamp";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, c.getInt());
|
ps.setInt(1, c.getInt());
|
||||||
ps.setInt(2, DELIVERED.getValue());
|
ps.setInt(2, DELIVERED.getValue());
|
||||||
ps.setLong(3, now);
|
ps.setLong(3, now);
|
||||||
|
ps.setLong(4, eta);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
List<MessageId> ids = new ArrayList<>();
|
List<MessageId> ids = new ArrayList<>();
|
||||||
int total = 0;
|
int total = 0;
|
||||||
@@ -2047,8 +2061,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<MessageId> getRequestedMessagesToSend(Connection txn,
|
public Collection<MessageId> getRequestedMessagesToSend(Connection txn,
|
||||||
ContactId c, int maxLength) throws DbException {
|
ContactId c, int maxLength, int maxLatency) throws DbException {
|
||||||
long now = clock.currentTimeMillis();
|
long now = clock.currentTimeMillis();
|
||||||
|
long eta = now + maxLatency;
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
@@ -2057,12 +2072,13 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
||||||
+ " AND deleted = FALSE"
|
+ " AND deleted = FALSE"
|
||||||
+ " AND seen = FALSE AND requested = TRUE"
|
+ " AND seen = FALSE AND requested = TRUE"
|
||||||
+ " AND expiry < ?"
|
+ " AND (expiry <= ? OR eta > ?)"
|
||||||
+ " ORDER BY timestamp";
|
+ " ORDER BY timestamp";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, c.getInt());
|
ps.setInt(1, c.getInt());
|
||||||
ps.setInt(2, DELIVERED.getValue());
|
ps.setInt(2, DELIVERED.getValue());
|
||||||
ps.setLong(3, now);
|
ps.setLong(3, now);
|
||||||
|
ps.setLong(4, eta);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
List<MessageId> ids = new ArrayList<>();
|
List<MessageId> ids = new ArrayList<>();
|
||||||
int total = 0;
|
int total = 0;
|
||||||
@@ -2873,7 +2889,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateExpiryTime(Connection txn, ContactId c, MessageId m,
|
public void updateExpiryTimeAndEta(Connection txn, ContactId c, MessageId m,
|
||||||
int maxLatency) throws DbException {
|
int maxLatency) throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
@@ -2889,13 +2905,16 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
if (rs.next()) throw new DbStateException();
|
if (rs.next()) throw new DbStateException();
|
||||||
rs.close();
|
rs.close();
|
||||||
ps.close();
|
ps.close();
|
||||||
sql = "UPDATE statuses SET expiry = ?, txCount = txCount + 1"
|
sql = "UPDATE statuses"
|
||||||
|
+ " SET expiry = ?, txCount = txCount + 1, eta = ?"
|
||||||
+ " WHERE messageId = ? AND contactId = ?";
|
+ " WHERE messageId = ? AND contactId = ?";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
long now = clock.currentTimeMillis();
|
long now = clock.currentTimeMillis();
|
||||||
|
long eta = now + maxLatency;
|
||||||
ps.setLong(1, calculateExpiry(now, maxLatency, txCount));
|
ps.setLong(1, calculateExpiry(now, maxLatency, txCount));
|
||||||
ps.setBytes(2, m.getBytes());
|
ps.setLong(2, eta);
|
||||||
ps.setInt(3, c.getInt());
|
ps.setBytes(3, m.getBytes());
|
||||||
|
ps.setInt(4, c.getInt());
|
||||||
int affected = ps.executeUpdate();
|
int affected = ps.executeUpdate();
|
||||||
if (affected != 1) throw new DbStateException();
|
if (affected != 1) throw new DbStateException();
|
||||||
ps.close();
|
ps.close();
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
|
class Migration39_40 implements Migration<Connection> {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(Migration39_40.class.getName());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStartVersion() {
|
||||||
|
return 39;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEndVersion() {
|
||||||
|
return 40;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void migrate(Connection txn) throws DbException {
|
||||||
|
Statement s = null;
|
||||||
|
try {
|
||||||
|
s = txn.createStatement();
|
||||||
|
s.execute("ALTER TABLE statuses"
|
||||||
|
+ " ADD eta BIGINT");
|
||||||
|
s.execute("UPDATE statuses SET eta = 0");
|
||||||
|
s.execute("ALTER TABLE statuses"
|
||||||
|
+ " ALTER COLUMN eta"
|
||||||
|
+ " SET NOT NULL");
|
||||||
|
} catch (SQLException e) {
|
||||||
|
tryToClose(s);
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryToClose(@Nullable Statement s) {
|
||||||
|
try {
|
||||||
|
if (s != null) s.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
package org.briarproject.bramble.keyagreement;
|
package org.briarproject.bramble.keyagreement;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.UnsupportedVersionException;
|
|
||||||
import org.briarproject.bramble.api.data.BdfList;
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
import org.briarproject.bramble.api.data.BdfReader;
|
import org.briarproject.bramble.api.data.BdfReader;
|
||||||
import org.briarproject.bramble.api.data.BdfReaderFactory;
|
import org.briarproject.bramble.api.data.BdfReaderFactory;
|
||||||
import org.briarproject.bramble.api.keyagreement.Payload;
|
import org.briarproject.bramble.api.keyagreement.Payload;
|
||||||
import org.briarproject.bramble.api.keyagreement.PayloadParser;
|
import org.briarproject.bramble.api.keyagreement.PayloadParser;
|
||||||
import org.briarproject.bramble.api.keyagreement.TransportDescriptor;
|
import org.briarproject.bramble.api.keyagreement.TransportDescriptor;
|
||||||
|
import org.briarproject.bramble.api.keyagreement.UnsupportedVersionException;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.BluetoothConstants;
|
import org.briarproject.bramble.api.plugin.BluetoothConstants;
|
||||||
import org.briarproject.bramble.api.plugin.LanTcpConstants;
|
import org.briarproject.bramble.api.plugin.LanTcpConstants;
|
||||||
@@ -21,6 +21,7 @@ import java.util.List;
|
|||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.BETA_PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
|
||||||
@@ -43,8 +44,11 @@ class PayloadParserImpl implements PayloadParser {
|
|||||||
// First byte: the protocol version
|
// First byte: the protocol version
|
||||||
int protocolVersion = in.read();
|
int protocolVersion = in.read();
|
||||||
if (protocolVersion == -1) throw new FormatException();
|
if (protocolVersion == -1) throw new FormatException();
|
||||||
if (protocolVersion != PROTOCOL_VERSION)
|
if (protocolVersion != PROTOCOL_VERSION) {
|
||||||
throw new UnsupportedVersionException();
|
boolean tooOld = protocolVersion < PROTOCOL_VERSION ||
|
||||||
|
protocolVersion == BETA_PROTOCOL_VERSION;
|
||||||
|
throw new UnsupportedVersionException(tooOld);
|
||||||
|
}
|
||||||
// The rest of the payload is a BDF list with one or more elements
|
// The rest of the payload is a BDF list with one or more elements
|
||||||
BdfReader r = bdfReaderFactory.createReader(in);
|
BdfReader r = bdfReaderFactory.createReader(in);
|
||||||
BdfList payload = r.readList();
|
BdfList payload = r.readList();
|
||||||
|
|||||||
@@ -39,11 +39,7 @@ class MessageFactoryImpl implements MessageFactory {
|
|||||||
if (body.length > MAX_MESSAGE_BODY_LENGTH)
|
if (body.length > MAX_MESSAGE_BODY_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
MessageId id = getMessageId(g, timestamp, body);
|
MessageId id = getMessageId(g, timestamp, body);
|
||||||
byte[] raw = new byte[MESSAGE_HEADER_LENGTH + body.length];
|
return new Message(id, g, timestamp, body);
|
||||||
System.arraycopy(g.getBytes(), 0, raw, 0, UniqueId.LENGTH);
|
|
||||||
ByteUtils.writeUint64(timestamp, raw, UniqueId.LENGTH);
|
|
||||||
System.arraycopy(body, 0, raw, MESSAGE_HEADER_LENGTH, body.length);
|
|
||||||
return new Message(id, g, timestamp, raw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private MessageId getMessageId(GroupId g, long timestamp, byte[] body) {
|
private MessageId getMessageId(GroupId g, long timestamp, byte[] body) {
|
||||||
@@ -69,18 +65,16 @@ class MessageFactoryImpl implements MessageFactory {
|
|||||||
byte[] body = new byte[raw.length - MESSAGE_HEADER_LENGTH];
|
byte[] body = new byte[raw.length - MESSAGE_HEADER_LENGTH];
|
||||||
System.arraycopy(raw, MESSAGE_HEADER_LENGTH, body, 0, body.length);
|
System.arraycopy(raw, MESSAGE_HEADER_LENGTH, body, 0, body.length);
|
||||||
MessageId id = getMessageId(g, timestamp, body);
|
MessageId id = getMessageId(g, timestamp, body);
|
||||||
return new Message(id, g, timestamp, raw);
|
return new Message(id, g, timestamp, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Message createMessage(MessageId m, byte[] raw) {
|
public byte[] getRawMessage(Message m) {
|
||||||
if (raw.length < MESSAGE_HEADER_LENGTH)
|
byte[] body = m.getBody();
|
||||||
throw new IllegalArgumentException();
|
byte[] raw = new byte[MESSAGE_HEADER_LENGTH + body.length];
|
||||||
if (raw.length > MAX_MESSAGE_LENGTH)
|
System.arraycopy(m.getGroupId().getBytes(), 0, raw, 0, UniqueId.LENGTH);
|
||||||
throw new IllegalArgumentException();
|
ByteUtils.writeUint64(m.getTimestamp(), raw, UniqueId.LENGTH);
|
||||||
byte[] groupId = new byte[UniqueId.LENGTH];
|
System.arraycopy(body, 0, raw, MESSAGE_HEADER_LENGTH, body.length);
|
||||||
System.arraycopy(raw, 0, groupId, 0, UniqueId.LENGTH);
|
return raw;
|
||||||
long timestamp = ByteUtils.readUint64(raw, UniqueId.LENGTH);
|
|
||||||
return new Message(m, new GroupId(groupId), timestamp, raw);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.bramble.sync;
|
|||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.record.RecordWriter;
|
import org.briarproject.bramble.api.record.RecordWriter;
|
||||||
import org.briarproject.bramble.api.record.RecordWriterFactory;
|
import org.briarproject.bramble.api.record.RecordWriterFactory;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.sync.SyncRecordWriter;
|
import org.briarproject.bramble.api.sync.SyncRecordWriter;
|
||||||
import org.briarproject.bramble.api.sync.SyncRecordWriterFactory;
|
import org.briarproject.bramble.api.sync.SyncRecordWriterFactory;
|
||||||
|
|
||||||
@@ -13,16 +14,19 @@ import javax.inject.Inject;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class SyncRecordWriterFactoryImpl implements SyncRecordWriterFactory {
|
class SyncRecordWriterFactoryImpl implements SyncRecordWriterFactory {
|
||||||
|
|
||||||
|
private final MessageFactory messageFactory;
|
||||||
private final RecordWriterFactory recordWriterFactory;
|
private final RecordWriterFactory recordWriterFactory;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
SyncRecordWriterFactoryImpl(RecordWriterFactory recordWriterFactory) {
|
SyncRecordWriterFactoryImpl(MessageFactory messageFactory,
|
||||||
|
RecordWriterFactory recordWriterFactory) {
|
||||||
|
this.messageFactory = messageFactory;
|
||||||
this.recordWriterFactory = recordWriterFactory;
|
this.recordWriterFactory = recordWriterFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SyncRecordWriter createRecordWriter(OutputStream out) {
|
public SyncRecordWriter createRecordWriter(OutputStream out) {
|
||||||
RecordWriter writer = recordWriterFactory.createRecordWriter(out);
|
RecordWriter writer = recordWriterFactory.createRecordWriter(out);
|
||||||
return new SyncRecordWriterImpl(writer);
|
return new SyncRecordWriterImpl(messageFactory, writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.record.Record;
|
|||||||
import org.briarproject.bramble.api.record.RecordWriter;
|
import org.briarproject.bramble.api.record.RecordWriter;
|
||||||
import org.briarproject.bramble.api.sync.Ack;
|
import org.briarproject.bramble.api.sync.Ack;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.api.sync.Offer;
|
import org.briarproject.bramble.api.sync.Offer;
|
||||||
import org.briarproject.bramble.api.sync.Request;
|
import org.briarproject.bramble.api.sync.Request;
|
||||||
@@ -25,10 +26,12 @@ import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class SyncRecordWriterImpl implements SyncRecordWriter {
|
class SyncRecordWriterImpl implements SyncRecordWriter {
|
||||||
|
|
||||||
|
private final MessageFactory messageFactory;
|
||||||
private final RecordWriter writer;
|
private final RecordWriter writer;
|
||||||
private final ByteArrayOutputStream payload = new ByteArrayOutputStream();
|
private final ByteArrayOutputStream payload = new ByteArrayOutputStream();
|
||||||
|
|
||||||
SyncRecordWriterImpl(RecordWriter writer) {
|
SyncRecordWriterImpl(MessageFactory messageFactory, RecordWriter writer) {
|
||||||
|
this.messageFactory = messageFactory;
|
||||||
this.writer = writer;
|
this.writer = writer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +49,8 @@ class SyncRecordWriterImpl implements SyncRecordWriter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeMessage(Message m) throws IOException {
|
public void writeMessage(Message m) throws IOException {
|
||||||
writer.writeRecord(new Record(PROTOCOL_VERSION, MESSAGE, m.getRaw()));
|
byte[] raw = messageFactory.getRawMessage(m);
|
||||||
|
writer.writeRecord(new Record(PROTOCOL_VERSION, MESSAGE, raw));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Bridge 131.252.210.150:8081 0E858AC201BF0F3FA3C462F64844CBFFC7297A42
|
|||||||
Bridge 67.205.189.122:8443 12D64D5D44E20169585E7378580C0D33A872AD98
|
Bridge 67.205.189.122:8443 12D64D5D44E20169585E7378580C0D33A872AD98
|
||||||
Bridge 45.32.148.146:8443 0CE016FB2462D8BF179AE71F7D702D09DEAC3F1D
|
Bridge 45.32.148.146:8443 0CE016FB2462D8BF179AE71F7D702D09DEAC3F1D
|
||||||
Bridge 148.251.90.59:7510 019F727CA6DCA6CA5C90B55E477B7D87981E75BC
|
Bridge 148.251.90.59:7510 019F727CA6DCA6CA5C90B55E477B7D87981E75BC
|
||||||
Bridge 195.91.239.8:9001 BA83F62551545655BBEBBFF353A45438D73FD45A
|
|
||||||
Bridge 45.55.1.74:8443 6F18FEFBB0CAECD5ABA755312FCCB34FC11A7AB8
|
Bridge 45.55.1.74:8443 6F18FEFBB0CAECD5ABA755312FCCB34FC11A7AB8
|
||||||
Bridge 97.107.131.168:65341 DCDA8A5F1E2C50A6756A58462E5CF4B6B2DFDE26
|
Bridge 85.229.131.78:444 50E433CCC5FEC11CC34CB4D92033561E065EA106
|
||||||
Bridge 85.229.131.78:444 50E433CCC5FEC11CC34CB4D92033561E065EA106
|
Bridge 178.62.62.193:8443 391B1F9B6A28A1C5FAE1872283985F975E5DB029
|
||||||
|
Bridge 45.76.29.92:8443 ECF1DD51A46FDEF2C50CED992EEEAE8DED18DA0C
|
||||||
@@ -16,10 +16,8 @@ import org.jmock.Expectations;
|
|||||||
import org.jmock.lib.legacy.ClassImposteriser;
|
import org.jmock.lib.legacy.ClassImposteriser;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertSame;
|
import static org.junit.Assert.assertSame;
|
||||||
|
|
||||||
@@ -58,8 +56,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
|
|||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
will(returnValue(timestamp - MAX_CLOCK_DIFFERENCE));
|
will(returnValue(timestamp - MAX_CLOCK_DIFFERENCE));
|
||||||
oneOf(clientHelper).toList(raw, MESSAGE_HEADER_LENGTH,
|
oneOf(clientHelper).toList(message.getBody());
|
||||||
raw.length - MESSAGE_HEADER_LENGTH);
|
|
||||||
will(returnValue(body));
|
will(returnValue(body));
|
||||||
oneOf(metadataEncoder).encode(dictionary);
|
oneOf(metadataEncoder).encode(dictionary);
|
||||||
will(returnValue(meta));
|
will(returnValue(meta));
|
||||||
@@ -84,18 +81,11 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
|
|||||||
|
|
||||||
@Test(expected = InvalidMessageException.class)
|
@Test(expected = InvalidMessageException.class)
|
||||||
public void testRejectsTooShortMessage() throws Exception {
|
public void testRejectsTooShortMessage() throws Exception {
|
||||||
byte[] invalidRaw = getRandomBytes(MESSAGE_HEADER_LENGTH);
|
Message invalidMessage = getMessage(groupId, 0);
|
||||||
// Use a mock message so the length of the raw message can be invalid
|
|
||||||
Message invalidMessage = context.mock(Message.class);
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
oneOf(invalidMessage).getTimestamp();
|
|
||||||
will(returnValue(timestamp));
|
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
will(returnValue(timestamp));
|
will(returnValue(timestamp));
|
||||||
oneOf(invalidMessage).getRaw();
|
|
||||||
will(returnValue(invalidRaw));
|
|
||||||
}});
|
}});
|
||||||
|
|
||||||
failIfSubclassIsCalled.validateMessage(invalidMessage, group);
|
failIfSubclassIsCalled.validateMessage(invalidMessage, group);
|
||||||
@@ -103,13 +93,12 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAcceptsMinLengthMessage() throws Exception {
|
public void testAcceptsMinLengthMessage() throws Exception {
|
||||||
Message shortMessage = getMessage(groupId, MESSAGE_HEADER_LENGTH + 1);
|
Message shortMessage = getMessage(groupId, 1);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
will(returnValue(timestamp));
|
will(returnValue(timestamp));
|
||||||
oneOf(clientHelper).toList(shortMessage.getRaw(),
|
oneOf(clientHelper).toList(shortMessage.getBody());
|
||||||
MESSAGE_HEADER_LENGTH, 1);
|
|
||||||
will(returnValue(body));
|
will(returnValue(body));
|
||||||
oneOf(metadataEncoder).encode(dictionary);
|
oneOf(metadataEncoder).encode(dictionary);
|
||||||
will(returnValue(meta));
|
will(returnValue(meta));
|
||||||
@@ -137,8 +126,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
|
|||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
will(returnValue(timestamp));
|
will(returnValue(timestamp));
|
||||||
oneOf(clientHelper).toList(raw, MESSAGE_HEADER_LENGTH,
|
oneOf(clientHelper).toList(message.getBody());
|
||||||
raw.length - MESSAGE_HEADER_LENGTH);
|
|
||||||
will(throwException(new FormatException()));
|
will(throwException(new FormatException()));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
@@ -150,8 +138,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
|
|||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(clock).currentTimeMillis();
|
oneOf(clock).currentTimeMillis();
|
||||||
will(returnValue(timestamp));
|
will(returnValue(timestamp));
|
||||||
oneOf(clientHelper).toList(raw, MESSAGE_HEADER_LENGTH,
|
oneOf(clientHelper).toList(message.getBody());
|
||||||
raw.length - MESSAGE_HEADER_LENGTH);
|
|
||||||
will(returnValue(body));
|
will(returnValue(body));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import java.util.HashSet;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static junit.framework.TestCase.assertTrue;
|
import static junit.framework.TestCase.assertTrue;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.test.ArrayClock;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@@ -74,24 +76,4 @@ public class ScryptKdfTest extends BrambleTestCase {
|
|||||||
PasswordBasedKdf kdf = new ScryptKdf(clock);
|
PasswordBasedKdf kdf = new ScryptKdf(clock);
|
||||||
assertEquals(256, kdf.chooseCostParameter());
|
assertEquals(256, kdf.chooseCostParameter());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ArrayClock implements Clock {
|
|
||||||
|
|
||||||
private final long[] times;
|
|
||||||
private int index = 0;
|
|
||||||
|
|
||||||
private ArrayClock(long... times) {
|
|
||||||
this.times = times;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long currentTimeMillis() {
|
|
||||||
return times[index++];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sleep(long milliseconds) throws InterruptedException {
|
|
||||||
Thread.sleep(milliseconds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -871,15 +871,15 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(database).containsContact(txn, contactId);
|
oneOf(database).containsContact(txn, contactId);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).getMessagesToSend(txn, contactId,
|
oneOf(database).getMessagesToSend(txn, contactId,
|
||||||
MAX_MESSAGE_LENGTH * 2);
|
MAX_MESSAGE_LENGTH * 2, maxLatency);
|
||||||
will(returnValue(ids));
|
will(returnValue(ids));
|
||||||
oneOf(database).getMessage(txn, messageId);
|
oneOf(database).getMessage(txn, messageId);
|
||||||
will(returnValue(message));
|
will(returnValue(message));
|
||||||
oneOf(database).updateExpiryTime(txn, contactId, messageId,
|
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
oneOf(database).getMessage(txn, messageId1);
|
oneOf(database).getMessage(txn, messageId1);
|
||||||
will(returnValue(message1));
|
will(returnValue(message1));
|
||||||
oneOf(database).updateExpiryTime(txn, contactId, messageId1,
|
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
oneOf(database).lowerRequestedFlag(txn, contactId, ids);
|
oneOf(database).lowerRequestedFlag(txn, contactId, ids);
|
||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
@@ -907,11 +907,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
oneOf(database).containsContact(txn, contactId);
|
oneOf(database).containsContact(txn, contactId);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).getMessagesToOffer(txn, contactId, 123);
|
oneOf(database).getMessagesToOffer(txn, contactId, 123, maxLatency);
|
||||||
will(returnValue(ids));
|
will(returnValue(ids));
|
||||||
oneOf(database).updateExpiryTime(txn, contactId, messageId,
|
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
oneOf(database).updateExpiryTime(txn, contactId, messageId1,
|
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
}});
|
}});
|
||||||
@@ -967,15 +967,15 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(database).containsContact(txn, contactId);
|
oneOf(database).containsContact(txn, contactId);
|
||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
oneOf(database).getRequestedMessagesToSend(txn, contactId,
|
oneOf(database).getRequestedMessagesToSend(txn, contactId,
|
||||||
MAX_MESSAGE_LENGTH * 2);
|
MAX_MESSAGE_LENGTH * 2, maxLatency);
|
||||||
will(returnValue(ids));
|
will(returnValue(ids));
|
||||||
oneOf(database).getMessage(txn, messageId);
|
oneOf(database).getMessage(txn, messageId);
|
||||||
will(returnValue(message));
|
will(returnValue(message));
|
||||||
oneOf(database).updateExpiryTime(txn, contactId, messageId,
|
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
oneOf(database).getMessage(txn, messageId1);
|
oneOf(database).getMessage(txn, messageId1);
|
||||||
will(returnValue(message1));
|
will(returnValue(message1));
|
||||||
oneOf(database).updateExpiryTime(txn, contactId, messageId1,
|
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1,
|
||||||
maxLatency);
|
maxLatency);
|
||||||
oneOf(database).lowerRequestedFlag(txn, contactId, ids);
|
oneOf(database).lowerRequestedFlag(txn, contactId, ids);
|
||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
|
|||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.settings.Settings;
|
import org.briarproject.bramble.api.settings.Settings;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.system.SystemClock;
|
import org.briarproject.bramble.system.SystemClock;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.briarproject.bramble.test.TestDatabaseConfig;
|
import org.briarproject.bramble.test.TestDatabaseConfig;
|
||||||
|
import org.briarproject.bramble.test.TestMessageFactory;
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
@@ -45,6 +47,7 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
protected final DatabaseConfig config =
|
protected final DatabaseConfig config =
|
||||||
new TestDatabaseConfig(testDir, 1024 * 1024);
|
new TestDatabaseConfig(testDir, 1024 * 1024);
|
||||||
|
protected final MessageFactory messageFactory = new TestMessageFactory();
|
||||||
protected final SecretKey key = getSecretKey();
|
protected final SecretKey key = getSecretKey();
|
||||||
protected final Clock clock = new SystemClock();
|
protected final Clock clock = new SystemClock();
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ package org.briarproject.bramble.db;
|
|||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.system.SystemClock;
|
import org.briarproject.bramble.system.SystemClock;
|
||||||
import org.briarproject.bramble.test.TestDatabaseConfig;
|
import org.briarproject.bramble.test.TestDatabaseConfig;
|
||||||
|
import org.briarproject.bramble.test.TestMessageFactory;
|
||||||
import org.briarproject.bramble.test.UTest;
|
import org.briarproject.bramble.test.UTest;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -30,7 +32,8 @@ public abstract class DatabasePerformanceComparisonTest
|
|||||||
private SecretKey databaseKey = getSecretKey();
|
private SecretKey databaseKey = getSecretKey();
|
||||||
|
|
||||||
abstract Database<Connection> createDatabase(boolean conditionA,
|
abstract Database<Connection> createDatabase(boolean conditionA,
|
||||||
DatabaseConfig databaseConfig, Clock clock);
|
DatabaseConfig databaseConfig, MessageFactory messageFactory,
|
||||||
|
Clock clock);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void benchmark(String name,
|
protected void benchmark(String name,
|
||||||
@@ -73,7 +76,8 @@ public abstract class DatabasePerformanceComparisonTest
|
|||||||
private Database<Connection> openDatabase(boolean conditionA)
|
private Database<Connection> openDatabase(boolean conditionA)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
Database<Connection> db = createDatabase(conditionA,
|
Database<Connection> db = createDatabase(conditionA,
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
new TestDatabaseConfig(testDir, MAX_SIZE),
|
||||||
|
new TestMessageFactory(), new SystemClock());
|
||||||
db.open(databaseKey, null);
|
db.open(databaseKey, null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,9 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
|
|||||||
*/
|
*/
|
||||||
private static final int STEADY_STATE_BLOCKS = 5;
|
private static final int STEADY_STATE_BLOCKS = 5;
|
||||||
|
|
||||||
|
// All our transports use a maximum latency of 30 seconds
|
||||||
|
private static final int MAX_LATENCY = 30 * 1000;
|
||||||
|
|
||||||
protected final File testDir = getTestDirectory();
|
protected final File testDir = getTestDirectory();
|
||||||
private final File resultsFile = new File(getTestName() + ".tsv");
|
private final File resultsFile = new File(getTestName() + ".tsv");
|
||||||
protected final Random random = new Random();
|
protected final Random random = new Random();
|
||||||
@@ -448,7 +451,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
|
|||||||
benchmark(name, db -> {
|
benchmark(name, db -> {
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
db.getMessagesToOffer(txn, pickRandom(contacts).getId(),
|
db.getMessagesToOffer(txn, pickRandom(contacts).getId(),
|
||||||
MAX_MESSAGE_IDS);
|
MAX_MESSAGE_IDS, MAX_LATENCY);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -470,7 +473,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
|
|||||||
benchmark(name, db -> {
|
benchmark(name, db -> {
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
db.getMessagesToSend(txn, pickRandom(contacts).getId(),
|
db.getMessagesToSend(txn, pickRandom(contacts).getId(),
|
||||||
MAX_MESSAGE_IDS);
|
MAX_MESSAGE_IDS, MAX_LATENCY);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -521,7 +524,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
|
|||||||
benchmark(name, db -> {
|
benchmark(name, db -> {
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
db.getRequestedMessagesToSend(txn, pickRandom(contacts).getId(),
|
db.getRequestedMessagesToSend(txn, pickRandom(contacts).getId(),
|
||||||
MAX_MESSAGE_IDS);
|
MAX_MESSAGE_IDS, MAX_LATENCY);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ package org.briarproject.bramble.db;
|
|||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.system.SystemClock;
|
import org.briarproject.bramble.system.SystemClock;
|
||||||
import org.briarproject.bramble.test.TestDatabaseConfig;
|
import org.briarproject.bramble.test.TestDatabaseConfig;
|
||||||
|
import org.briarproject.bramble.test.TestMessageFactory;
|
||||||
import org.briarproject.bramble.util.IoUtils;
|
import org.briarproject.bramble.util.IoUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -24,7 +26,7 @@ public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
|
|||||||
private SecretKey databaseKey = getSecretKey();
|
private SecretKey databaseKey = getSecretKey();
|
||||||
|
|
||||||
abstract Database<Connection> createDatabase(DatabaseConfig databaseConfig,
|
abstract Database<Connection> createDatabase(DatabaseConfig databaseConfig,
|
||||||
Clock clock);
|
MessageFactory messageFactory, Clock clock);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
protected abstract File getTraceFile();
|
protected abstract File getTraceFile();
|
||||||
@@ -46,7 +48,8 @@ public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
|
|||||||
|
|
||||||
private Database<Connection> openDatabase() throws DbException {
|
private Database<Connection> openDatabase() throws DbException {
|
||||||
Database<Connection> db = createDatabase(
|
Database<Connection> db = createDatabase(
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
new TestDatabaseConfig(testDir, MAX_SIZE),
|
||||||
|
new TestMessageFactory(), new SystemClock());
|
||||||
db.open(databaseKey, null);
|
db.open(databaseKey, null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.db;
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
|
||||||
@@ -13,7 +14,8 @@ public class H2DatabasePerformanceTest extends SingleDatabasePerformanceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected JdbcDatabase createDatabase(DatabaseConfig config, Clock clock) {
|
protected JdbcDatabase createDatabase(DatabaseConfig config,
|
||||||
return new H2Database(config, clock);
|
MessageFactory messageFactory, Clock clock) {
|
||||||
|
return new H2Database(config, messageFactory, clock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
package org.briarproject.bramble.db;
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
|
||||||
public class H2DatabaseTest extends JdbcDatabaseTest {
|
public class H2DatabaseTest extends JdbcDatabaseTest {
|
||||||
|
|
||||||
public H2DatabaseTest() throws Exception {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected JdbcDatabase createDatabase(DatabaseConfig config, Clock clock) {
|
protected JdbcDatabase createDatabase(DatabaseConfig config,
|
||||||
return new H2Database(config, clock);
|
MessageFactory messageFactory, Clock clock) {
|
||||||
|
return new H2Database(config, messageFactory, clock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.db;
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
|
||||||
@@ -14,8 +15,8 @@ public class H2DatabaseTraceTest extends DatabaseTraceTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
Database<Connection> createDatabase(DatabaseConfig databaseConfig,
|
Database<Connection> createDatabase(DatabaseConfig databaseConfig,
|
||||||
Clock clock) {
|
MessageFactory messageFactory, Clock clock) {
|
||||||
return new H2Database(databaseConfig, clock) {
|
return new H2Database(databaseConfig, messageFactory, clock) {
|
||||||
@Override
|
@Override
|
||||||
@Nonnull
|
@Nonnull
|
||||||
String getUrl() {
|
String getUrl() {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.db;
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
|
||||||
@@ -12,9 +13,11 @@ public class H2HyperSqlDatabasePerformanceComparisonTest
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
Database<Connection> createDatabase(boolean conditionA,
|
Database<Connection> createDatabase(boolean conditionA,
|
||||||
DatabaseConfig databaseConfig, Clock clock) {
|
DatabaseConfig databaseConfig, MessageFactory messageFactory,
|
||||||
if (conditionA) return new H2Database(databaseConfig, clock);
|
Clock clock) {
|
||||||
else return new HyperSqlDatabase(databaseConfig, clock);
|
if (conditionA)
|
||||||
|
return new H2Database(databaseConfig, messageFactory, clock);
|
||||||
|
else return new HyperSqlDatabase(databaseConfig, messageFactory, clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class H2MigrationTest extends DatabaseMigrationTest {
|
|||||||
@Override
|
@Override
|
||||||
Database<Connection> createDatabase(
|
Database<Connection> createDatabase(
|
||||||
List<Migration<Connection>> migrations) {
|
List<Migration<Connection>> migrations) {
|
||||||
return new H2Database(config, clock) {
|
return new H2Database(config, messageFactory, clock) {
|
||||||
@Override
|
@Override
|
||||||
List<Migration<Connection>> getMigrations() {
|
List<Migration<Connection>> getMigrations() {
|
||||||
return migrations;
|
return migrations;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.db;
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
|
||||||
@@ -17,8 +18,9 @@ public class H2SelfDatabasePerformanceComparisonTest
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
Database<Connection> createDatabase(boolean conditionA,
|
Database<Connection> createDatabase(boolean conditionA,
|
||||||
DatabaseConfig databaseConfig, Clock clock) {
|
DatabaseConfig databaseConfig, MessageFactory messageFactory,
|
||||||
return new H2Database(databaseConfig, clock);
|
Clock clock) {
|
||||||
|
return new H2Database(databaseConfig, messageFactory, clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.bramble.db;
|
|||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
|
||||||
@@ -19,11 +20,12 @@ public class H2SleepDatabasePerformanceComparisonTest
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
Database<Connection> createDatabase(boolean conditionA,
|
Database<Connection> createDatabase(boolean conditionA,
|
||||||
DatabaseConfig databaseConfig, Clock clock) {
|
DatabaseConfig databaseConfig, MessageFactory messageFactory,
|
||||||
|
Clock clock) {
|
||||||
if (conditionA) {
|
if (conditionA) {
|
||||||
return new H2Database(databaseConfig, clock);
|
return new H2Database(databaseConfig, messageFactory, clock);
|
||||||
} else {
|
} else {
|
||||||
return new H2Database(databaseConfig, clock) {
|
return new H2Database(databaseConfig, messageFactory, clock) {
|
||||||
@Override
|
@Override
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public void commitTransaction(Connection txn)
|
public void commitTransaction(Connection txn)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.db;
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
|
|
||||||
@@ -14,7 +15,8 @@ public class HyperSqlDatabasePerformanceTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected JdbcDatabase createDatabase(DatabaseConfig config, Clock clock) {
|
protected JdbcDatabase createDatabase(DatabaseConfig config,
|
||||||
return new HyperSqlDatabase(config, clock);
|
MessageFactory messageFactory, Clock clock) {
|
||||||
|
return new HyperSqlDatabase(config, messageFactory, clock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
package org.briarproject.bramble.db;
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
|
||||||
public class HyperSqlDatabaseTest extends JdbcDatabaseTest {
|
public class HyperSqlDatabaseTest extends JdbcDatabaseTest {
|
||||||
|
|
||||||
public HyperSqlDatabaseTest() throws Exception {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected JdbcDatabase createDatabase(DatabaseConfig config, Clock clock) {
|
protected JdbcDatabase createDatabase(DatabaseConfig config,
|
||||||
return new HyperSqlDatabase(config, clock);
|
MessageFactory messageFactory, Clock clock) {
|
||||||
|
return new HyperSqlDatabase(config, messageFactory ,clock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import java.util.List;
|
|||||||
public class HyperSqlMigrationTest extends DatabaseMigrationTest {
|
public class HyperSqlMigrationTest extends DatabaseMigrationTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Database<Connection> createDatabase(List<Migration<Connection>> migrations)
|
Database<Connection> createDatabase(
|
||||||
throws Exception {
|
List<Migration<Connection>> migrations) {
|
||||||
return new HyperSqlDatabase(config, clock) {
|
return new HyperSqlDatabase(config, messageFactory, clock) {
|
||||||
@Override
|
@Override
|
||||||
List<Migration<Connection>> getMigrations() {
|
List<Migration<Connection>> getMigrations() {
|
||||||
return migrations;
|
return migrations;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import org.briarproject.bramble.api.sync.ClientId;
|
|||||||
import org.briarproject.bramble.api.sync.Group;
|
import org.briarproject.bramble.api.sync.Group;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.api.sync.MessageStatus;
|
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||||
import org.briarproject.bramble.api.sync.ValidationManager.State;
|
import org.briarproject.bramble.api.sync.ValidationManager.State;
|
||||||
@@ -25,8 +26,10 @@ import org.briarproject.bramble.api.transport.KeySetId;
|
|||||||
import org.briarproject.bramble.api.transport.OutgoingKeys;
|
import org.briarproject.bramble.api.transport.OutgoingKeys;
|
||||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||||
import org.briarproject.bramble.system.SystemClock;
|
import org.briarproject.bramble.system.SystemClock;
|
||||||
|
import org.briarproject.bramble.test.ArrayClock;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.test.TestDatabaseConfig;
|
import org.briarproject.bramble.test.TestDatabaseConfig;
|
||||||
|
import org.briarproject.bramble.test.TestMessageFactory;
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -58,6 +61,7 @@ import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERE
|
|||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;
|
||||||
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
|
import static org.briarproject.bramble.api.sync.ValidationManager.State.UNKNOWN;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getClientId;
|
import static org.briarproject.bramble.test.TestUtils.getClientId;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getGroup;
|
import static org.briarproject.bramble.test.TestUtils.getGroup;
|
||||||
@@ -80,6 +84,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
private static final int ONE_MEGABYTE = 1024 * 1024;
|
private static final int ONE_MEGABYTE = 1024 * 1024;
|
||||||
private static final int MAX_SIZE = 5 * ONE_MEGABYTE;
|
private static final int MAX_SIZE = 5 * ONE_MEGABYTE;
|
||||||
|
// All our transports use a maximum latency of 30 seconds
|
||||||
|
private static final int MAX_LATENCY = 30 * 1000;
|
||||||
|
|
||||||
|
|
||||||
private final SecretKey key = getSecretKey();
|
private final SecretKey key = getSecretKey();
|
||||||
private final File testDir = getTestDirectory();
|
private final File testDir = getTestDirectory();
|
||||||
@@ -112,7 +119,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected abstract JdbcDatabase createDatabase(DatabaseConfig config,
|
protected abstract JdbcDatabase createDatabase(DatabaseConfig config,
|
||||||
Clock clock);
|
MessageFactory messageFactory, Clock clock);
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -144,8 +151,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
assertTrue(db.containsContact(txn, contactId));
|
assertTrue(db.containsContact(txn, contactId));
|
||||||
assertTrue(db.containsGroup(txn, groupId));
|
assertTrue(db.containsGroup(txn, groupId));
|
||||||
assertTrue(db.containsMessage(txn, messageId));
|
assertTrue(db.containsMessage(txn, messageId));
|
||||||
assertArrayEquals(message.getRaw(),
|
assertArrayEquals(message.getBody(),
|
||||||
db.getMessage(txn, messageId).getRaw());
|
db.getMessage(txn, messageId).getBody());
|
||||||
|
|
||||||
// Delete the records
|
// Delete the records
|
||||||
db.removeMessage(txn, messageId);
|
db.removeMessage(txn, messageId);
|
||||||
@@ -197,16 +204,16 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
// The contact has not seen the message, so it should be sendable
|
// The contact has not seen the message, so it should be sendable
|
||||||
Collection<MessageId> ids =
|
Collection<MessageId> ids =
|
||||||
db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
// Changing the status to seen = true should make the message unsendable
|
// Changing the status to seen = true should make the message unsendable
|
||||||
db.raiseSeenFlag(txn, contactId, messageId);
|
db.raiseSeenFlag(txn, contactId, messageId);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
@@ -228,30 +235,30 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
// The message has not been validated, so it should not be sendable
|
// The message has not been validated, so it should not be sendable
|
||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
ONE_MEGABYTE);
|
ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Marking the message delivered should make it sendable
|
// Marking the message delivered should make it sendable
|
||||||
db.setMessageState(txn, messageId, DELIVERED);
|
db.setMessageState(txn, messageId, DELIVERED);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
// Marking the message invalid should make it unsendable
|
// Marking the message invalid should make it unsendable
|
||||||
db.setMessageState(txn, messageId, INVALID);
|
db.setMessageState(txn, messageId, INVALID);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Marking the message pending should make it unsendable
|
// Marking the message pending should make it unsendable
|
||||||
db.setMessageState(txn, messageId, PENDING);
|
db.setMessageState(txn, messageId, PENDING);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
@@ -272,37 +279,37 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
// The group is invisible, so the message should not be sendable
|
// The group is invisible, so the message should not be sendable
|
||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
ONE_MEGABYTE);
|
ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Making the group visible should not make the message sendable
|
// Making the group visible should not make the message sendable
|
||||||
db.addGroupVisibility(txn, contactId, groupId, false);
|
db.addGroupVisibility(txn, contactId, groupId, false);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Sharing the group should make the message sendable
|
// Sharing the group should make the message sendable
|
||||||
db.setGroupVisibility(txn, contactId, groupId, true);
|
db.setGroupVisibility(txn, contactId, groupId, true);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
// Unsharing the group should make the message unsendable
|
// Unsharing the group should make the message unsendable
|
||||||
db.setGroupVisibility(txn, contactId, groupId, false);
|
db.setGroupVisibility(txn, contactId, groupId, false);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Making the group invisible should make the message unsendable
|
// Making the group invisible should make the message unsendable
|
||||||
db.removeGroupVisibility(txn, contactId, groupId);
|
db.removeGroupVisibility(txn, contactId, groupId);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
@@ -324,16 +331,16 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
// The message is not shared, so it should not be sendable
|
// The message is not shared, so it should not be sendable
|
||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
ONE_MEGABYTE);
|
ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Sharing the message should make it sendable
|
// Sharing the message should make it sendable
|
||||||
db.setMessageShared(txn, messageId);
|
db.setMessageShared(txn, messageId);
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
@@ -354,12 +361,13 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
db.addMessage(txn, message, DELIVERED, true, null);
|
db.addMessage(txn, message, DELIVERED, true, null);
|
||||||
|
|
||||||
// The message is sendable, but too large to send
|
// The message is sendable, but too large to send
|
||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
Collection<MessageId> ids =
|
||||||
message.getRawLength() - 1);
|
db.getMessagesToSend(txn, contactId, message.getRawLength() - 1,
|
||||||
|
MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// The message is just the right size to send
|
// The message is just the right size to send
|
||||||
ids = db.getMessagesToSend(txn, contactId, message.getRawLength());
|
ids = db.getMessagesToSend(txn, contactId, message.getRawLength(),
|
||||||
|
MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
@@ -422,19 +430,19 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
// Retrieve the message from the database and mark it as sent
|
// Retrieve the message from the database and mark it as sent
|
||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
ONE_MEGABYTE);
|
ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
db.updateExpiryTime(txn, contactId, messageId, Integer.MAX_VALUE);
|
db.updateExpiryTimeAndEta(txn, contactId, messageId, MAX_LATENCY);
|
||||||
|
|
||||||
// The message should no longer be sendable
|
// The message should no longer be sendable
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Pretend that the message was acked
|
// Pretend that the message was acked
|
||||||
db.raiseSeenFlag(txn, contactId, messageId);
|
db.raiseSeenFlag(txn, contactId, messageId);
|
||||||
|
|
||||||
// The message still should not be sendable
|
// The message still should not be sendable
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
@@ -1515,7 +1523,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
assertFalse(status.isSeen());
|
assertFalse(status.isSeen());
|
||||||
|
|
||||||
// Pretend the message was sent to the contact
|
// Pretend the message was sent to the contact
|
||||||
db.updateExpiryTime(txn, contactId, messageId, Integer.MAX_VALUE);
|
db.updateExpiryTimeAndEta(txn, contactId, messageId, Integer.MAX_VALUE);
|
||||||
|
|
||||||
// The message should be sent but not seen
|
// The message should be sent but not seen
|
||||||
status = db.getMessageStatus(txn, contactId, messageId);
|
status = db.getMessageStatus(txn, contactId, messageId);
|
||||||
@@ -1634,9 +1642,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
// The message should be sendable
|
// The message should be sendable
|
||||||
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
ONE_MEGABYTE);
|
ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertEquals(singletonList(messageId), ids);
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
// The message should be available
|
// The message should be available
|
||||||
@@ -1644,7 +1652,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
assertEquals(messageId, m.getId());
|
assertEquals(messageId, m.getId());
|
||||||
assertEquals(groupId, m.getGroupId());
|
assertEquals(groupId, m.getGroupId());
|
||||||
assertEquals(message.getTimestamp(), m.getTimestamp());
|
assertEquals(message.getTimestamp(), m.getTimestamp());
|
||||||
assertArrayEquals(message.getRaw(), m.getRaw());
|
assertArrayEquals(message.getBody(), m.getBody());
|
||||||
|
|
||||||
// Delete the message
|
// Delete the message
|
||||||
db.deleteMessage(txn, messageId);
|
db.deleteMessage(txn, messageId);
|
||||||
@@ -1653,9 +1661,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
assertTrue(db.containsVisibleMessage(txn, contactId, messageId));
|
assertTrue(db.containsVisibleMessage(txn, contactId, messageId));
|
||||||
|
|
||||||
// The message should not be sendable
|
// The message should not be sendable
|
||||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
ids = db.getMessagesToOffer(txn, contactId, 100);
|
ids = db.getMessagesToOffer(txn, contactId, 100, MAX_LATENCY);
|
||||||
assertTrue(ids.isEmpty());
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
// Requesting the message should throw an exception
|
// Requesting the message should throw an exception
|
||||||
@@ -1727,7 +1735,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testGetNextSendTime() throws Exception {
|
public void testGetNextSendTime() throws Exception {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
Database<Connection> db = open(false, new StoppedClock(now));
|
Database<Connection> db = open(false, new TestMessageFactory(),
|
||||||
|
new StoppedClock(now));
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
// Add a contact, a group and a message
|
// Add a contact, a group and a message
|
||||||
@@ -1758,12 +1767,12 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
// Update the message's expiry time as though we sent it - now the
|
// Update the message's expiry time as though we sent it - now the
|
||||||
// message should be sendable after one round-trip
|
// message should be sendable after one round-trip
|
||||||
db.updateExpiryTime(txn, contactId, messageId, 1000);
|
db.updateExpiryTimeAndEta(txn, contactId, messageId, 1000);
|
||||||
assertEquals(now + 2000, db.getNextSendTime(txn, contactId));
|
assertEquals(now + 2000, db.getNextSendTime(txn, contactId));
|
||||||
|
|
||||||
// Update the message's expiry time again - now it should be sendable
|
// Update the message's expiry time again - now it should be sendable
|
||||||
// after two round-trips
|
// after two round-trips
|
||||||
db.updateExpiryTime(txn, contactId, messageId, 1000);
|
db.updateExpiryTimeAndEta(txn, contactId, messageId, 1000);
|
||||||
assertEquals(now + 4000, db.getNextSendTime(txn, contactId));
|
assertEquals(now + 4000, db.getNextSendTime(txn, contactId));
|
||||||
|
|
||||||
// Delete the message - there should be no messages to send
|
// Delete the message - there should be no messages to send
|
||||||
@@ -1806,14 +1815,112 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Database<Connection> open(boolean resume) throws Exception {
|
@Test
|
||||||
return open(resume, new SystemClock());
|
public void testMessageRetransmission() throws Exception {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
long steps[] = {now, now, now + MAX_LATENCY * 2 - 1,
|
||||||
|
now + MAX_LATENCY * 2};
|
||||||
|
Database<Connection> db =
|
||||||
|
open(false, new TestMessageFactory(), new ArrayClock(steps));
|
||||||
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
|
// Add a contact, a shared group and a shared message
|
||||||
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
|
db.addGroup(txn, group);
|
||||||
|
db.addGroupVisibility(txn, contactId, groupId, true);
|
||||||
|
db.addMessage(txn, message, DELIVERED, true, null);
|
||||||
|
|
||||||
|
// Time: now
|
||||||
|
// Retrieve the message from the database
|
||||||
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
|
ONE_MEGABYTE, MAX_LATENCY);
|
||||||
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
|
// Time: now
|
||||||
|
// Mark the message as sent
|
||||||
|
db.updateExpiryTimeAndEta(txn, contactId, messageId, MAX_LATENCY);
|
||||||
|
|
||||||
|
// The message should expire after 2 * MAX_LATENCY
|
||||||
|
assertEquals(now + MAX_LATENCY * 2, db.getNextSendTime(txn, contactId));
|
||||||
|
|
||||||
|
// Time: now + MAX_LATENCY * 2 - 1
|
||||||
|
// The message should not yet be sendable
|
||||||
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
|
// Time: now + MAX_LATENCY * 2
|
||||||
|
// The message should have expired and should now be sendable
|
||||||
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Database<Connection> open(boolean resume, Clock clock)
|
|
||||||
throws Exception {
|
@Test
|
||||||
Database<Connection> db = createDatabase(
|
public void testFasterMessageRetransmission() throws Exception {
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), clock);
|
long now = System.currentTimeMillis();
|
||||||
|
long steps[] = {now, now, now, now, now + 1};
|
||||||
|
Database<Connection> db =
|
||||||
|
open(false, new TestMessageFactory(), new ArrayClock(steps));
|
||||||
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
|
// Add a contact, a shared group and a shared message
|
||||||
|
db.addLocalAuthor(txn, localAuthor);
|
||||||
|
assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(),
|
||||||
|
true, true));
|
||||||
|
db.addGroup(txn, group);
|
||||||
|
db.addGroupVisibility(txn, contactId, groupId, true);
|
||||||
|
db.addMessage(txn, message, DELIVERED, true, null);
|
||||||
|
|
||||||
|
// Time: now
|
||||||
|
// Retrieve the message from the database
|
||||||
|
Collection<MessageId> ids = db.getMessagesToSend(txn, contactId,
|
||||||
|
ONE_MEGABYTE, MAX_LATENCY);
|
||||||
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
|
// Time: now
|
||||||
|
// Mark the message as sent
|
||||||
|
db.updateExpiryTimeAndEta(txn, contactId, messageId, MAX_LATENCY);
|
||||||
|
|
||||||
|
// The message should expire after 2 * MAX_LATENCY
|
||||||
|
assertEquals(now + MAX_LATENCY * 2, db.getNextSendTime(txn, contactId));
|
||||||
|
|
||||||
|
// Time: now
|
||||||
|
// The message should not be sendable via the same transport
|
||||||
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
|
// Time: now
|
||||||
|
// The message should be sendable via a transport with a faster ETA
|
||||||
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE,
|
||||||
|
MAX_LATENCY - 1);
|
||||||
|
assertEquals(singletonList(messageId), ids);
|
||||||
|
|
||||||
|
// Time: now + 1
|
||||||
|
// The message should no longer be sendable via the faster transport,
|
||||||
|
// as the ETA is now equal
|
||||||
|
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE,
|
||||||
|
MAX_LATENCY - 1);
|
||||||
|
assertTrue(ids.isEmpty());
|
||||||
|
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Database<Connection> open(boolean resume) throws Exception {
|
||||||
|
return open(resume, new TestMessageFactory(), new SystemClock());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Database<Connection> open(boolean resume,
|
||||||
|
MessageFactory messageFactory, Clock clock) throws Exception {
|
||||||
|
Database<Connection> db =
|
||||||
|
createDatabase(new TestDatabaseConfig(testDir, MAX_SIZE),
|
||||||
|
messageFactory, clock);
|
||||||
if (!resume) TestUtils.deleteTestDirectory(testDir);
|
if (!resume) TestUtils.deleteTestDirectory(testDir);
|
||||||
db.open(key, null);
|
db.open(key, null);
|
||||||
return db;
|
return db;
|
||||||
@@ -1842,7 +1949,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
TestUtils.deleteTestDirectory(testDir);
|
deleteTestDirectory(testDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class StoppedClock implements Clock {
|
private static class StoppedClock implements Clock {
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ package org.briarproject.bramble.db;
|
|||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.system.SystemClock;
|
import org.briarproject.bramble.system.SystemClock;
|
||||||
import org.briarproject.bramble.test.TestDatabaseConfig;
|
import org.briarproject.bramble.test.TestDatabaseConfig;
|
||||||
|
import org.briarproject.bramble.test.TestMessageFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
@@ -21,7 +23,7 @@ public abstract class SingleDatabasePerformanceTest
|
|||||||
extends DatabasePerformanceTest {
|
extends DatabasePerformanceTest {
|
||||||
|
|
||||||
abstract Database<Connection> createDatabase(DatabaseConfig databaseConfig,
|
abstract Database<Connection> createDatabase(DatabaseConfig databaseConfig,
|
||||||
Clock clock);
|
MessageFactory messageFactory, Clock clock);
|
||||||
|
|
||||||
private SecretKey databaseKey = getSecretKey();
|
private SecretKey databaseKey = getSecretKey();
|
||||||
|
|
||||||
@@ -43,7 +45,8 @@ public abstract class SingleDatabasePerformanceTest
|
|||||||
|
|
||||||
private Database<Connection> openDatabase() throws DbException {
|
private Database<Connection> openDatabase() throws DbException {
|
||||||
Database<Connection> db = createDatabase(
|
Database<Connection> db = createDatabase(
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
new TestDatabaseConfig(testDir, MAX_SIZE),
|
||||||
|
new TestMessageFactory(), new SystemClock());
|
||||||
db.open(databaseKey, null);
|
db.open(databaseKey, null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,156 @@
|
|||||||
|
package org.briarproject.bramble.keyagreement;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Bytes;
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
|
import org.briarproject.bramble.api.data.BdfReader;
|
||||||
|
import org.briarproject.bramble.api.data.BdfReaderFactory;
|
||||||
|
import org.briarproject.bramble.api.keyagreement.Payload;
|
||||||
|
import org.briarproject.bramble.api.keyagreement.UnsupportedVersionException;
|
||||||
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
|
import org.jmock.Expectations;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.BETA_PROTOCOL_VERSION;
|
||||||
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
||||||
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
public class PayloadParserImplTest extends BrambleMockTestCase {
|
||||||
|
|
||||||
|
private final BdfReaderFactory bdfReaderFactory =
|
||||||
|
context.mock(BdfReaderFactory.class);
|
||||||
|
private final BdfReader bdfReader = context.mock(BdfReader.class);
|
||||||
|
|
||||||
|
private final PayloadParserImpl payloadParser =
|
||||||
|
new PayloadParserImpl(bdfReaderFactory);
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testThrowsFormatExceptionIfPayloadIsEmpty() throws Exception {
|
||||||
|
payloadParser.parse(new byte[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testThrowsUnsupportedVersionExceptionForOldVersion()
|
||||||
|
throws Exception {
|
||||||
|
try {
|
||||||
|
payloadParser.parse(new byte[] {PROTOCOL_VERSION - 1});
|
||||||
|
fail();
|
||||||
|
} catch (UnsupportedVersionException e) {
|
||||||
|
assertTrue(e.isTooOld());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testThrowsUnsupportedVersionExceptionForBetaVersion()
|
||||||
|
throws Exception {
|
||||||
|
try {
|
||||||
|
payloadParser.parse(new byte[] {BETA_PROTOCOL_VERSION});
|
||||||
|
fail();
|
||||||
|
} catch (UnsupportedVersionException e) {
|
||||||
|
assertTrue(e.isTooOld());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testThrowsUnsupportedVersionExceptionForNewVersion()
|
||||||
|
throws Exception {
|
||||||
|
try {
|
||||||
|
payloadParser.parse(new byte[] {PROTOCOL_VERSION + 1});
|
||||||
|
fail();
|
||||||
|
} catch (UnsupportedVersionException e) {
|
||||||
|
assertFalse(e.isTooOld());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testThrowsFormatExceptionForEmptyList() throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(bdfReaderFactory).createReader(
|
||||||
|
with(any(ByteArrayInputStream.class)));
|
||||||
|
will(returnValue(bdfReader));
|
||||||
|
oneOf(bdfReader).readList();
|
||||||
|
will(returnValue(new BdfList()));
|
||||||
|
}});
|
||||||
|
|
||||||
|
payloadParser.parse(new byte[] {PROTOCOL_VERSION});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testThrowsFormatExceptionForDataAfterList()
|
||||||
|
throws Exception {
|
||||||
|
byte[] commitment = getRandomBytes(COMMIT_LENGTH);
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(bdfReaderFactory).createReader(
|
||||||
|
with(any(ByteArrayInputStream.class)));
|
||||||
|
will(returnValue(bdfReader));
|
||||||
|
oneOf(bdfReader).readList();
|
||||||
|
will(returnValue(BdfList.of(new Bytes(commitment))));
|
||||||
|
oneOf(bdfReader).eof();
|
||||||
|
will(returnValue(false));
|
||||||
|
}});
|
||||||
|
|
||||||
|
payloadParser.parse(new byte[] {PROTOCOL_VERSION});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testThrowsFormatExceptionForShortCommitment()
|
||||||
|
throws Exception {
|
||||||
|
byte[] commitment = getRandomBytes(COMMIT_LENGTH - 1);
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(bdfReaderFactory).createReader(
|
||||||
|
with(any(ByteArrayInputStream.class)));
|
||||||
|
will(returnValue(bdfReader));
|
||||||
|
oneOf(bdfReader).readList();
|
||||||
|
will(returnValue(BdfList.of(new Bytes(commitment))));
|
||||||
|
oneOf(bdfReader).eof();
|
||||||
|
will(returnValue(true));
|
||||||
|
}});
|
||||||
|
|
||||||
|
payloadParser.parse(new byte[] {PROTOCOL_VERSION});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testThrowsFormatExceptionForLongCommitment()
|
||||||
|
throws Exception {
|
||||||
|
byte[] commitment = getRandomBytes(COMMIT_LENGTH + 1);
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(bdfReaderFactory).createReader(
|
||||||
|
with(any(ByteArrayInputStream.class)));
|
||||||
|
will(returnValue(bdfReader));
|
||||||
|
oneOf(bdfReader).readList();
|
||||||
|
will(returnValue(BdfList.of(new Bytes(commitment))));
|
||||||
|
oneOf(bdfReader).eof();
|
||||||
|
will(returnValue(true));
|
||||||
|
}});
|
||||||
|
|
||||||
|
payloadParser.parse(new byte[] {PROTOCOL_VERSION});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAcceptsPayloadWithNoDescriptors() throws Exception {
|
||||||
|
byte[] commitment = getRandomBytes(COMMIT_LENGTH);
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(bdfReaderFactory).createReader(
|
||||||
|
with(any(ByteArrayInputStream.class)));
|
||||||
|
will(returnValue(bdfReader));
|
||||||
|
oneOf(bdfReader).readList();
|
||||||
|
will(returnValue(BdfList.of(new Bytes(commitment))));
|
||||||
|
oneOf(bdfReader).eof();
|
||||||
|
will(returnValue(true));
|
||||||
|
}});
|
||||||
|
|
||||||
|
Payload p = payloadParser.parse(new byte[] {PROTOCOL_VERSION});
|
||||||
|
assertArrayEquals(commitment, p.getCommitment());
|
||||||
|
assertTrue(p.getTransportDescriptors().isEmpty());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -170,6 +170,6 @@ public class SyncIntegrationTest extends BrambleTestCase {
|
|||||||
m2.getGroupId().getBytes());
|
m2.getGroupId().getBytes());
|
||||||
assertEquals(m1.getTimestamp(), m2.getTimestamp());
|
assertEquals(m1.getTimestamp(), m2.getTimestamp());
|
||||||
assertEquals(m1.getRawLength(), m2.getRawLength());
|
assertEquals(m1.getRawLength(), m2.getRawLength());
|
||||||
assertArrayEquals(m1.getRaw(), m2.getRaw());
|
assertArrayEquals(m1.getBody(), m2.getBody());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package org.briarproject.bramble.test;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public class TestMessageFactory implements MessageFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message createMessage(GroupId g, long timestamp, byte[] body) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message createMessage(byte[] raw) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getRawMessage(Message m) {
|
||||||
|
byte[] body = m.getBody();
|
||||||
|
byte[] raw = new byte[MESSAGE_HEADER_LENGTH + body.length];
|
||||||
|
System.arraycopy(body, 0, raw, MESSAGE_HEADER_LENGTH, body.length);
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,7 +30,6 @@ public abstract class ValidatorTestCase extends BrambleMockTestCase {
|
|||||||
protected final Message message = getMessage(groupId);
|
protected final Message message = getMessage(groupId);
|
||||||
protected final MessageId messageId = message.getId();
|
protected final MessageId messageId = message.getId();
|
||||||
protected final long timestamp = message.getTimestamp();
|
protected final long timestamp = message.getTimestamp();
|
||||||
protected final byte[] raw = message.getRaw();
|
|
||||||
protected final Author author = getAuthor();
|
protected final Author author = getAuthor();
|
||||||
protected final BdfList authorList = BdfList.of(
|
protected final BdfList authorList = BdfList.of(
|
||||||
author.getFormatVersion(),
|
author.getFormatVersion(),
|
||||||
|
|||||||
@@ -10,9 +10,13 @@ import org.briarproject.bramble.api.system.ResourceProvider;
|
|||||||
import org.briarproject.bramble.test.BrambleJavaIntegrationTestComponent;
|
import org.briarproject.bramble.test.BrambleJavaIntegrationTestComponent;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.test.DaggerBrambleJavaIntegrationTestComponent;
|
import org.briarproject.bramble.test.DaggerBrambleJavaIntegrationTestComponent;
|
||||||
import org.junit.AfterClass;
|
import org.briarproject.bramble.util.OsUtils;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Parameterized;
|
||||||
|
import org.junit.runners.Parameterized.Parameters;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -29,13 +33,20 @@ import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
|||||||
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
|
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
|
||||||
import static org.briarproject.bramble.test.TestUtils.isOptionalTestEnabled;
|
import static org.briarproject.bramble.test.TestUtils.isOptionalTestEnabled;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.junit.Assume.assumeTrue;
|
import static org.junit.Assume.assumeTrue;
|
||||||
|
|
||||||
|
@RunWith(Parameterized.class)
|
||||||
public class BridgeTest extends BrambleTestCase {
|
public class BridgeTest extends BrambleTestCase {
|
||||||
|
|
||||||
private final static long TIMEOUT = SECONDS.toMillis(23);
|
@Parameters
|
||||||
|
public static Iterable<String> data() {
|
||||||
|
BrambleJavaIntegrationTestComponent component =
|
||||||
|
DaggerBrambleJavaIntegrationTestComponent.builder().build();
|
||||||
|
return component.getCircumventionProvider().getBridges();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static long TIMEOUT = SECONDS.toMillis(30);
|
||||||
|
|
||||||
private final static Logger LOG =
|
private final static Logger LOG =
|
||||||
Logger.getLogger(BridgeTest.class.getName());
|
Logger.getLogger(BridgeTest.class.getName());
|
||||||
@@ -53,17 +64,23 @@ public class BridgeTest extends BrambleTestCase {
|
|||||||
@Inject
|
@Inject
|
||||||
Clock clock;
|
Clock clock;
|
||||||
|
|
||||||
private List<String> bridges;
|
private final File torDir = getTestDirectory();
|
||||||
private LinuxTorPluginFactory factory;
|
private final String bridge;
|
||||||
private final static File torDir = getTestDirectory();
|
|
||||||
|
|
||||||
private volatile String currentBridge = null;
|
private LinuxTorPluginFactory factory;
|
||||||
|
|
||||||
|
public BridgeTest(String bridge) {
|
||||||
|
this.bridge = bridge;
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
// Skip this test unless it's explicitly enabled in the environment
|
// Skip this test unless it's explicitly enabled in the environment
|
||||||
assumeTrue(isOptionalTestEnabled(BridgeTest.class));
|
assumeTrue(isOptionalTestEnabled(BridgeTest.class));
|
||||||
|
|
||||||
|
// TODO: Remove this assumption when the plugin supports other platforms
|
||||||
|
assumeTrue(OsUtils.isLinux());
|
||||||
|
|
||||||
BrambleJavaIntegrationTestComponent component =
|
BrambleJavaIntegrationTestComponent component =
|
||||||
DaggerBrambleJavaIntegrationTestComponent.builder().build();
|
DaggerBrambleJavaIntegrationTestComponent.builder().build();
|
||||||
component.inject(this);
|
component.inject(this);
|
||||||
@@ -72,7 +89,6 @@ public class BridgeTest extends BrambleTestCase {
|
|||||||
LocationUtils locationUtils = () -> "US";
|
LocationUtils locationUtils = () -> "US";
|
||||||
SocketFactory torSocketFactory = SocketFactory.getDefault();
|
SocketFactory torSocketFactory = SocketFactory.getDefault();
|
||||||
|
|
||||||
bridges = circumventionProvider.getBridges();
|
|
||||||
CircumventionProvider bridgeProvider = new CircumventionProvider() {
|
CircumventionProvider bridgeProvider = new CircumventionProvider() {
|
||||||
@Override
|
@Override
|
||||||
public boolean isTorProbablyBlocked(String countryCode) {
|
public boolean isTorProbablyBlocked(String countryCode) {
|
||||||
@@ -86,7 +102,7 @@ public class BridgeTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getBridges() {
|
public List<String> getBridges() {
|
||||||
return singletonList(currentBridge);
|
return singletonList(bridge);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
factory = new LinuxTorPluginFactory(ioExecutor, networkManager,
|
factory = new LinuxTorPluginFactory(ioExecutor, networkManager,
|
||||||
@@ -94,25 +110,18 @@ public class BridgeTest extends BrambleTestCase {
|
|||||||
resourceProvider, bridgeProvider, clock, torDir);
|
resourceProvider, bridgeProvider, clock, torDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@After
|
||||||
public static void tearDown() {
|
public void tearDown() {
|
||||||
deleteTestDirectory(torDir);
|
deleteTestDirectory(torDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBridges() throws Exception {
|
public void testBridges() throws Exception {
|
||||||
assertTrue(bridges.size() > 0);
|
|
||||||
|
|
||||||
for (String bridge : bridges) testBridge(bridge);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void testBridge(String bridge) throws Exception {
|
|
||||||
DuplexPlugin duplexPlugin =
|
DuplexPlugin duplexPlugin =
|
||||||
factory.createPlugin(new TorPluginCallBack());
|
factory.createPlugin(new TorPluginCallBack());
|
||||||
assertNotNull(duplexPlugin);
|
assertNotNull(duplexPlugin);
|
||||||
LinuxTorPlugin plugin = (LinuxTorPlugin) duplexPlugin;
|
LinuxTorPlugin plugin = (LinuxTorPlugin) duplexPlugin;
|
||||||
|
|
||||||
currentBridge = bridge;
|
|
||||||
LOG.warning("Testing " + bridge);
|
LOG.warning("Testing " + bridge);
|
||||||
try {
|
try {
|
||||||
plugin.start();
|
plugin.start();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import org.briarproject.bramble.BrambleJavaModule;
|
|||||||
import org.briarproject.bramble.event.EventModule;
|
import org.briarproject.bramble.event.EventModule;
|
||||||
import org.briarproject.bramble.plugin.PluginModule;
|
import org.briarproject.bramble.plugin.PluginModule;
|
||||||
import org.briarproject.bramble.plugin.tor.BridgeTest;
|
import org.briarproject.bramble.plugin.tor.BridgeTest;
|
||||||
|
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
|
||||||
import org.briarproject.bramble.system.SystemModule;
|
import org.briarproject.bramble.system.SystemModule;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@@ -22,4 +23,5 @@ public interface BrambleJavaIntegrationTestComponent {
|
|||||||
|
|
||||||
void inject(BridgeTest init);
|
void inject(BridgeTest init);
|
||||||
|
|
||||||
|
CircumventionProvider getCircumventionProvider();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,65 +2,6 @@ apply plugin: 'com.android.application'
|
|||||||
apply plugin: 'witness'
|
apply plugin: 'witness'
|
||||||
apply from: 'witness.gradle'
|
apply from: 'witness.gradle'
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation project(path: ':briar-core', configuration: 'default')
|
|
||||||
implementation project(path: ':bramble-core', configuration: 'default')
|
|
||||||
implementation project(':bramble-android')
|
|
||||||
|
|
||||||
def supportVersion = '27.1.1'
|
|
||||||
implementation "com.android.support:support-v4:$supportVersion"
|
|
||||||
implementation("com.android.support:appcompat-v7:$supportVersion") {
|
|
||||||
exclude module: 'support-v4'
|
|
||||||
}
|
|
||||||
implementation("com.android.support:preference-v14:$supportVersion") {
|
|
||||||
exclude module: 'support-v4'
|
|
||||||
}
|
|
||||||
implementation("com.android.support:design:$supportVersion") {
|
|
||||||
exclude module: 'support-v4'
|
|
||||||
exclude module: 'recyclerview-v7'
|
|
||||||
}
|
|
||||||
implementation "com.android.support:cardview-v7:$supportVersion"
|
|
||||||
implementation "com.android.support:support-annotations:$supportVersion"
|
|
||||||
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
|
|
||||||
|
|
||||||
implementation('ch.acra:acra:4.9.1') {
|
|
||||||
exclude module: 'support-v4'
|
|
||||||
exclude module: 'support-annotations'
|
|
||||||
}
|
|
||||||
implementation 'info.guardianproject.panic:panic:0.5'
|
|
||||||
implementation 'info.guardianproject.trustedintents:trustedintents:0.2'
|
|
||||||
implementation 'de.hdodenhof:circleimageview:2.2.0'
|
|
||||||
implementation 'com.google.zxing:core:3.3.0'
|
|
||||||
implementation 'uk.co.samuelwall:material-tap-target-prompt:2.8.0'
|
|
||||||
implementation 'com.vanniktech:emoji-google:0.5.1'
|
|
||||||
|
|
||||||
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
|
|
||||||
|
|
||||||
compileOnly 'javax.annotation:jsr250-api:1.0'
|
|
||||||
|
|
||||||
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
|
||||||
testImplementation project(path: ':bramble-core', configuration: 'testOutput')
|
|
||||||
testImplementation 'org.robolectric:robolectric:3.8'
|
|
||||||
testImplementation 'org.robolectric:shadows-support-v4:3.3.2'
|
|
||||||
testImplementation 'org.mockito:mockito-core:2.13.0'
|
|
||||||
testImplementation 'junit:junit:4.12'
|
|
||||||
testImplementation "org.jmock:jmock:2.8.2"
|
|
||||||
testImplementation "org.jmock:jmock-junit4:2.8.2"
|
|
||||||
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
|
||||||
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
|
||||||
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
|
||||||
|
|
||||||
def espressoVersion = '3.0.2'
|
|
||||||
androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoVersion"
|
|
||||||
androidTestImplementation "com.android.support.test.espresso:espresso-contrib:$espressoVersion"
|
|
||||||
androidTestImplementation "com.android.support.test.espresso:espresso-intents:$espressoVersion"
|
|
||||||
androidTestImplementation "tools.fastlane:screengrab:1.1.0"
|
|
||||||
androidTestImplementation "com.android.support.test.uiautomator:uiautomator-v18:2.1.3"
|
|
||||||
androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.0.2"
|
|
||||||
androidTestCompileOnly 'javax.annotation:jsr250-api:1.0'
|
|
||||||
androidTestImplementation 'junit:junit:4.12'
|
|
||||||
}
|
|
||||||
|
|
||||||
def getStdout = { command, defaultValue ->
|
def getStdout = { command, defaultValue ->
|
||||||
def stdout = new ByteArrayOutputStream()
|
def stdout = new ByteArrayOutputStream()
|
||||||
try {
|
try {
|
||||||
@@ -81,15 +22,15 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 15
|
minSdkVersion 15
|
||||||
targetSdkVersion 26
|
targetSdkVersion 26
|
||||||
versionCode 10101
|
versionCode 10102
|
||||||
versionName "1.1.1"
|
versionName "1.1.2"
|
||||||
applicationId "org.briarproject.briar.android"
|
applicationId "org.briarproject.briar.android"
|
||||||
buildConfigField "String", "GitHash",
|
buildConfigField "String", "GitHash",
|
||||||
"\"${getStdout(['git', 'rev-parse', '--short=7', 'HEAD'], 'No commit hash')}\""
|
"\"${getStdout(['git', 'rev-parse', '--short=7', 'HEAD'], 'No commit hash')}\""
|
||||||
def now = (long) (System.currentTimeMillis() / 1000)
|
def now = (long) (System.currentTimeMillis() / 1000)
|
||||||
buildConfigField "Long", "BuildTimestamp",
|
buildConfigField "Long", "BuildTimestamp",
|
||||||
"${getStdout(['git', 'log', '-n', '1', '--format=%ct'], now)}000L"
|
"${getStdout(['git', 'log', '-n', '1', '--format=%ct'], now)}000L"
|
||||||
testInstrumentationRunner 'org.briarproject.briar.android.test.BriarTestRunner'
|
testInstrumentationRunner 'org.briarproject.briar.android.BriarTestRunner'
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@@ -144,6 +85,65 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(path: ':briar-core', configuration: 'default')
|
||||||
|
implementation project(path: ':bramble-core', configuration: 'default')
|
||||||
|
implementation project(':bramble-android')
|
||||||
|
|
||||||
|
def supportVersion = '27.1.1'
|
||||||
|
implementation "com.android.support:support-v4:$supportVersion"
|
||||||
|
implementation("com.android.support:appcompat-v7:$supportVersion") {
|
||||||
|
exclude module: 'support-v4'
|
||||||
|
}
|
||||||
|
implementation("com.android.support:preference-v14:$supportVersion") {
|
||||||
|
exclude module: 'support-v4'
|
||||||
|
}
|
||||||
|
implementation("com.android.support:design:$supportVersion") {
|
||||||
|
exclude module: 'support-v4'
|
||||||
|
exclude module: 'recyclerview-v7'
|
||||||
|
}
|
||||||
|
implementation "com.android.support:cardview-v7:$supportVersion"
|
||||||
|
implementation "com.android.support:support-annotations:$supportVersion"
|
||||||
|
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
|
||||||
|
|
||||||
|
implementation('ch.acra:acra:4.9.1') {
|
||||||
|
exclude module: 'support-v4'
|
||||||
|
exclude module: 'support-annotations'
|
||||||
|
}
|
||||||
|
implementation 'info.guardianproject.panic:panic:0.5'
|
||||||
|
implementation 'info.guardianproject.trustedintents:trustedintents:0.2'
|
||||||
|
implementation 'de.hdodenhof:circleimageview:2.2.0'
|
||||||
|
implementation 'com.google.zxing:core:3.3.0'
|
||||||
|
implementation 'uk.co.samuelwall:material-tap-target-prompt:2.8.0'
|
||||||
|
implementation 'com.vanniktech:emoji-google:0.5.1'
|
||||||
|
|
||||||
|
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
|
||||||
|
|
||||||
|
compileOnly 'javax.annotation:jsr250-api:1.0'
|
||||||
|
|
||||||
|
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
||||||
|
testImplementation project(path: ':bramble-core', configuration: 'testOutput')
|
||||||
|
testImplementation 'org.robolectric:robolectric:3.8'
|
||||||
|
testImplementation 'org.robolectric:shadows-support-v4:3.3.2'
|
||||||
|
testImplementation 'org.mockito:mockito-core:2.13.0'
|
||||||
|
testImplementation 'junit:junit:4.12'
|
||||||
|
testImplementation "org.jmock:jmock:2.8.2"
|
||||||
|
testImplementation "org.jmock:jmock-junit4:2.8.2"
|
||||||
|
testImplementation "org.jmock:jmock-legacy:2.8.2"
|
||||||
|
testImplementation "org.hamcrest:hamcrest-library:1.3"
|
||||||
|
testImplementation "org.hamcrest:hamcrest-core:1.3"
|
||||||
|
|
||||||
|
def espressoVersion = '3.0.2'
|
||||||
|
androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoVersion"
|
||||||
|
androidTestImplementation "com.android.support.test.espresso:espresso-contrib:$espressoVersion"
|
||||||
|
androidTestImplementation "com.android.support.test.espresso:espresso-intents:$espressoVersion"
|
||||||
|
androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.0.2"
|
||||||
|
androidTestCompileOnly 'javax.annotation:jsr250-api:1.0'
|
||||||
|
androidTestImplementation 'junit:junit:4.12'
|
||||||
|
androidTestScreenshotImplementation "tools.fastlane:screengrab:1.2.0"
|
||||||
|
androidTestScreenshotImplementation "com.android.support.test.uiautomator:uiautomator-v18:2.1.3"
|
||||||
|
}
|
||||||
|
|
||||||
task verifyTranslations {
|
task verifyTranslations {
|
||||||
doLast {
|
doLast {
|
||||||
def file = project.file("src/main/res/values/arrays.xml")
|
def file = project.file("src/main/res/values/arrays.xml")
|
||||||
@@ -153,8 +153,9 @@ task verifyTranslations {
|
|||||||
lc.children().each { value -> translations.add(value.text()) }
|
lc.children().each { value -> translations.add(value.text()) }
|
||||||
|
|
||||||
def folders = ["default", "en-US"]
|
def folders = ["default", "en-US"]
|
||||||
|
def exceptions = ["values-night", "values-v21", "values-ldrtl"]
|
||||||
project.file("src/main/res").eachDir { dir ->
|
project.file("src/main/res").eachDir { dir ->
|
||||||
if (dir.name.startsWith("values-") && !dir.name.endsWith("night") && !dir.name.endsWith("v21")) {
|
if (dir.name.startsWith("values-") && !exceptions.contains(dir.name)) {
|
||||||
folders.add(dir.name.substring(7).replace("-r", "-"))
|
folders.add(dir.name.substring(7).replace("-r", "-"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
app_package_name "org.briarproject.briar.android.screenshot.debug"
|
app_package_name "org.briarproject.briar.android.screenshot.debug"
|
||||||
locales ['en-US']
|
locales ['en-US']
|
||||||
use_tests_in_classes([
|
|
||||||
'org.briarproject.briar.android.login.SetupActivityScreenshotTest',
|
|
||||||
'org.briarproject.briar.android.settings.SettingsActivityScreenshotTest',
|
|
||||||
])
|
|
||||||
app_apk_path "build/outputs/apk/screenshot/debug/briar-android-screenshot-debug.apk"
|
app_apk_path "build/outputs/apk/screenshot/debug/briar-android-screenshot-debug.apk"
|
||||||
tests_apk_path "build/outputs/apk/androidTest/screenshot/debug/briar-android-screenshot-debug-androidTest.apk"
|
tests_apk_path "build/outputs/apk/androidTest/screenshot/debug/briar-android-screenshot-debug-androidTest.apk"
|
||||||
test_instrumentation_runner "org.briarproject.briar.android.test.BriarTestRunner"
|
test_instrumentation_runner "org.briarproject.briar.android.BriarTestRunner"
|
||||||
|
reinstall_app = true
|
||||||
|
exit_on_test_failure = true
|
||||||
@@ -4,4 +4,8 @@ adb shell am broadcast -a com.android.systemui.demo -e command enter
|
|||||||
adb shell am broadcast -a com.android.systemui.demo -e command notifications -e visible false
|
adb shell am broadcast -a com.android.systemui.demo -e command notifications -e visible false
|
||||||
adb shell am broadcast -a com.android.systemui.demo -e command battery -e level 100
|
adb shell am broadcast -a com.android.systemui.demo -e command battery -e level 100
|
||||||
adb shell am broadcast -a com.android.systemui.demo -e command network -e wifi show
|
adb shell am broadcast -a com.android.systemui.demo -e command network -e wifi show
|
||||||
adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm 1337
|
adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm 1337
|
||||||
|
|
||||||
|
# workaround for Android Pie hidden API Espresso bug
|
||||||
|
adb shell settings put global hidden_api_policy_pre_p_apps 1
|
||||||
|
adb shell settings put global hidden_api_policy_p_apps 1
|
||||||
|
|||||||
@@ -12,4 +12,4 @@
|
|||||||
-keep class junit.** { *; }
|
-keep class junit.** { *; }
|
||||||
-dontwarn junit.**
|
-dontwarn junit.**
|
||||||
|
|
||||||
-dontwarn org.briarproject.briar.android.BriarTestComponentApplication
|
-dontwarn org.briarproject.briar.android.**
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
package org.briarproject.briar.android.test;
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.test.runner.AndroidJUnitRunner;
|
import android.support.test.runner.AndroidJUnitRunner;
|
||||||
|
|
||||||
import org.briarproject.briar.android.BriarTestComponentApplication;
|
|
||||||
|
|
||||||
public class BriarTestRunner extends AndroidJUnitRunner {
|
public class BriarTestRunner extends AndroidJUnitRunner {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -13,8 +11,8 @@ public class BriarTestRunner extends AndroidJUnitRunner {
|
|||||||
Context context)
|
Context context)
|
||||||
throws InstantiationException, IllegalAccessException,
|
throws InstantiationException, IllegalAccessException,
|
||||||
ClassNotFoundException {
|
ClassNotFoundException {
|
||||||
return super.newApplication(cl, BriarTestComponentApplication.class.getName(),
|
return super.newApplication(cl,
|
||||||
context);
|
BriarTestComponentApplication.class.getName(), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.support.test.espresso.intent.rule.IntentsTestRule;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static android.support.test.InstrumentationRegistry.getTargetContext;
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
public abstract class UiTest {
|
||||||
|
|
||||||
|
protected final String USERNAME =
|
||||||
|
getTargetContext().getString(R.string.screenshot_alice);
|
||||||
|
protected static final String PASSWORD = "123456";
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected AccountManager accountManager;
|
||||||
|
@Inject
|
||||||
|
protected LifecycleManager lifecycleManager;
|
||||||
|
|
||||||
|
public UiTest() {
|
||||||
|
BriarTestComponentApplication app =
|
||||||
|
(BriarTestComponentApplication) getTargetContext()
|
||||||
|
.getApplicationContext();
|
||||||
|
inject((BriarUiTestComponent) app.getApplicationComponent());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void inject(BriarUiTestComponent component);
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
protected class CleanAccountTestRule<A extends Activity>
|
||||||
|
extends IntentsTestRule<A> {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final Runnable runnable;
|
||||||
|
|
||||||
|
public CleanAccountTestRule(Class<A> activityClass) {
|
||||||
|
super(activityClass);
|
||||||
|
this.runnable = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this if you need to run code before launching the activity.
|
||||||
|
* Note: You need to use {@link #launchActivity(Intent)} yourself
|
||||||
|
* to start the activity.
|
||||||
|
*/
|
||||||
|
public CleanAccountTestRule(Class<A> activityClass, Runnable runnable) {
|
||||||
|
super(activityClass, false, false);
|
||||||
|
this.runnable = runnable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void beforeActivityLaunched() {
|
||||||
|
super.beforeActivityLaunched();
|
||||||
|
accountManager.deleteAccount();
|
||||||
|
accountManager.createAccount(USERNAME, PASSWORD);
|
||||||
|
if (runnable != null) {
|
||||||
|
Intent serviceIntent =
|
||||||
|
new Intent(getTargetContext(), BriarService.class);
|
||||||
|
getTargetContext().startService(serviceIntent);
|
||||||
|
try {
|
||||||
|
lifecycleManager.waitForStartup();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.briarproject.briar.android.test;
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.support.test.espresso.PerformException;
|
import android.support.test.espresso.PerformException;
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
package org.briarproject.briar.android.test;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.support.test.espresso.intent.rule.IntentsTestRule;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.account.AccountManager;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
|
||||||
import org.briarproject.briar.android.BriarTestComponentApplication;
|
|
||||||
import org.briarproject.briar.android.BriarUiTestComponent;
|
|
||||||
import org.junit.ClassRule;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import tools.fastlane.screengrab.Screengrab;
|
|
||||||
import tools.fastlane.screengrab.UiAutomatorScreenshotStrategy;
|
|
||||||
import tools.fastlane.screengrab.locale.LocaleTestRule;
|
|
||||||
|
|
||||||
import static android.support.test.InstrumentationRegistry.getTargetContext;
|
|
||||||
import static tools.fastlane.screengrab.Screengrab.setDefaultScreenshotStrategy;
|
|
||||||
|
|
||||||
public abstract class ScreenshotTest {
|
|
||||||
|
|
||||||
@ClassRule
|
|
||||||
public static final LocaleTestRule localeTestRule = new LocaleTestRule();
|
|
||||||
|
|
||||||
protected static final String USERNAME = "Alice";
|
|
||||||
protected static final String PASSWORD = "123456";
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected AccountManager accountManager;
|
|
||||||
@Inject
|
|
||||||
protected LifecycleManager lifecycleManager;
|
|
||||||
|
|
||||||
public ScreenshotTest() {
|
|
||||||
super();
|
|
||||||
setDefaultScreenshotStrategy(new UiAutomatorScreenshotStrategy());
|
|
||||||
BriarTestComponentApplication app =
|
|
||||||
(BriarTestComponentApplication) getTargetContext()
|
|
||||||
.getApplicationContext();
|
|
||||||
inject((BriarUiTestComponent) app.getApplicationComponent());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void inject(BriarUiTestComponent component);
|
|
||||||
|
|
||||||
protected void screenshot(String name) {
|
|
||||||
try {
|
|
||||||
Screengrab.screenshot(name);
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
if (!e.getMessage().equals("Unable to capture screenshot."))
|
|
||||||
throw e;
|
|
||||||
// The tests should still pass when run from AndroidStudio
|
|
||||||
// without manually granting permissions like fastlane does.
|
|
||||||
Log.w("Screengrab", "Permission to write screenshot is missing.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected class CleanAccountTestRule<A extends Activity>
|
|
||||||
extends IntentsTestRule<A> {
|
|
||||||
|
|
||||||
public CleanAccountTestRule(Class<A> activityClass) {
|
|
||||||
super(activityClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void beforeActivityLaunched() {
|
|
||||||
super.beforeActivityLaunched();
|
|
||||||
accountManager.deleteAccount();
|
|
||||||
accountManager.createAccount(USERNAME, PASSWORD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.BrambleAndroidModule;
|
||||||
|
import org.briarproject.bramble.BrambleCoreModule;
|
||||||
|
import org.briarproject.bramble.account.BriarAccountModule;
|
||||||
|
import org.briarproject.briar.BriarCoreModule;
|
||||||
|
import org.briarproject.briar.android.navdrawer.NavDrawerActivityTest;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Component;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Component(modules = {
|
||||||
|
AppModule.class,
|
||||||
|
BriarCoreModule.class,
|
||||||
|
BrambleAndroidModule.class,
|
||||||
|
BriarAccountModule.class,
|
||||||
|
BrambleCoreModule.class
|
||||||
|
})
|
||||||
|
public interface BriarUiTestComponent extends AndroidComponent {
|
||||||
|
|
||||||
|
void inject(NavDrawerActivityTest test);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -6,8 +6,8 @@ import android.view.Gravity;
|
|||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.BriarUiTestComponent;
|
import org.briarproject.briar.android.BriarUiTestComponent;
|
||||||
|
import org.briarproject.briar.android.UiTest;
|
||||||
import org.briarproject.briar.android.settings.SettingsActivity;
|
import org.briarproject.briar.android.settings.SettingsActivity;
|
||||||
import org.briarproject.briar.android.test.ScreenshotTest;
|
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -23,7 +23,7 @@ import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
|||||||
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class NavDrawerActivityTest extends ScreenshotTest {
|
public class NavDrawerActivityTest extends UiTest {
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public CleanAccountTestRule<NavDrawerActivity> testRule =
|
public CleanAccountTestRule<NavDrawerActivity> testRule =
|
||||||
@@ -4,8 +4,7 @@ import org.briarproject.bramble.BrambleAndroidModule;
|
|||||||
import org.briarproject.bramble.BrambleCoreModule;
|
import org.briarproject.bramble.BrambleCoreModule;
|
||||||
import org.briarproject.bramble.account.BriarAccountModule;
|
import org.briarproject.bramble.account.BriarAccountModule;
|
||||||
import org.briarproject.briar.BriarCoreModule;
|
import org.briarproject.briar.BriarCoreModule;
|
||||||
import org.briarproject.briar.android.login.SetupActivityScreenshotTest;
|
import org.briarproject.briar.android.contact.ConversationActivityScreenshotTest;
|
||||||
import org.briarproject.briar.android.navdrawer.NavDrawerActivityTest;
|
|
||||||
import org.briarproject.briar.android.settings.SettingsActivityScreenshotTest;
|
import org.briarproject.briar.android.settings.SettingsActivityScreenshotTest;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@@ -22,8 +21,9 @@ import dagger.Component;
|
|||||||
})
|
})
|
||||||
public interface BriarUiTestComponent extends AndroidComponent {
|
public interface BriarUiTestComponent extends AndroidComponent {
|
||||||
|
|
||||||
void inject(SetupActivityScreenshotTest test);
|
void inject(SetupDataTest test);
|
||||||
void inject(NavDrawerActivityTest test);
|
|
||||||
|
void inject(ConversationActivityScreenshotTest test);
|
||||||
void inject(SettingsActivityScreenshotTest test);
|
void inject(SettingsActivityScreenshotTest test);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.plugin.ConnectionRegistry;
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
import org.briarproject.briar.api.test.TestDataCreator;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import tools.fastlane.screengrab.FalconScreenshotStrategy;
|
||||||
|
import tools.fastlane.screengrab.Screengrab;
|
||||||
|
import tools.fastlane.screengrab.locale.LocaleTestRule;
|
||||||
|
|
||||||
|
public abstract class ScreenshotTest extends UiTest {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static final LocaleTestRule localeTestRule = new LocaleTestRule();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected TestDataCreator testDataCreator;
|
||||||
|
@Inject
|
||||||
|
protected ConnectionRegistry connectionRegistry;
|
||||||
|
@Inject
|
||||||
|
protected Clock clock;
|
||||||
|
|
||||||
|
protected void screenshot(String name, Activity activity) {
|
||||||
|
try {
|
||||||
|
Screengrab.screenshot(name, new FalconScreenshotStrategy(activity));
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
if (!e.getMessage().equals("Unable to capture screenshot."))
|
||||||
|
throw e;
|
||||||
|
// The tests should still pass when run from AndroidStudio
|
||||||
|
// without manually granting permissions like fastlane does.
|
||||||
|
Log.w("Screengrab", "Permission to write screenshot is missing.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected long getMinutesAgo(int minutes) {
|
||||||
|
return clock.currentTimeMillis() - minutes * 60 * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package org.briarproject.briar.android.login;
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
import android.support.test.espresso.intent.rule.IntentsTestRule;
|
import android.support.test.espresso.intent.rule.IntentsTestRule;
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
@@ -6,9 +6,12 @@ import android.support.test.uiautomator.UiDevice;
|
|||||||
import android.support.test.uiautomator.UiObject;
|
import android.support.test.uiautomator.UiObject;
|
||||||
import android.support.test.uiautomator.UiSelector;
|
import android.support.test.uiautomator.UiSelector;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.BriarUiTestComponent;
|
import org.briarproject.briar.android.login.OpenDatabaseActivity;
|
||||||
import org.briarproject.briar.android.test.ScreenshotTest;
|
import org.briarproject.briar.android.login.SetupActivity;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -26,14 +29,14 @@ import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
|
|||||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||||
import static android.support.test.runner.lifecycle.Stage.PAUSED;
|
import static android.support.test.runner.lifecycle.Stage.PAUSED;
|
||||||
import static junit.framework.Assert.assertTrue;
|
import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID;
|
||||||
import static org.briarproject.briar.android.test.ViewActions.waitForActivity;
|
import static org.briarproject.briar.android.ViewActions.waitForActivity;
|
||||||
import static org.briarproject.briar.android.test.ViewActions.waitUntilMatches;
|
import static org.briarproject.briar.android.ViewActions.waitUntilMatches;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.needsDozeWhitelisting;
|
import static org.briarproject.briar.android.util.UiUtils.needsDozeWhitelisting;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class SetupActivityScreenshotTest extends ScreenshotTest {
|
public class SetupDataTest extends ScreenshotTest {
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public IntentsTestRule<SetupActivity> testRule =
|
public IntentsTestRule<SetupActivity> testRule =
|
||||||
@@ -61,7 +64,7 @@ public class SetupActivityScreenshotTest extends ScreenshotTest {
|
|||||||
onView(withId(R.id.nickname_entry))
|
onView(withId(R.id.nickname_entry))
|
||||||
.perform(waitUntilMatches(withText(USERNAME)));
|
.perform(waitUntilMatches(withText(USERNAME)));
|
||||||
|
|
||||||
screenshot("manual_create_account");
|
screenshot("manual_create_account", testRule.getActivity());
|
||||||
|
|
||||||
onView(withId(R.id.next))
|
onView(withId(R.id.next))
|
||||||
.check(matches(isDisplayed()))
|
.check(matches(isDisplayed()))
|
||||||
@@ -94,13 +97,54 @@ public class SetupActivityScreenshotTest extends ScreenshotTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// wait for OpenDatabaseActivity to show up
|
// wait for OpenDatabaseActivity to show up
|
||||||
onView(withId(R.id.progress))
|
|
||||||
.check(matches(isDisplayed()));
|
|
||||||
onView(isRoot())
|
onView(isRoot())
|
||||||
.perform(waitForActivity(testRule.getActivity(), PAUSED));
|
.perform(waitForActivity(testRule.getActivity(), PAUSED));
|
||||||
intended(hasComponent(OpenDatabaseActivity.class.getName()));
|
intended(hasComponent(OpenDatabaseActivity.class.getName()));
|
||||||
|
|
||||||
assertTrue(accountManager.hasDatabaseKey());
|
assertTrue(accountManager.hasDatabaseKey());
|
||||||
|
|
||||||
|
lifecycleManager.waitForStartup();
|
||||||
|
createTestData();
|
||||||
|
|
||||||
|
// close expiry warning
|
||||||
|
onView(withId(R.id.expiryWarning))
|
||||||
|
.perform(waitUntilMatches(isDisplayed()));
|
||||||
|
onView(withId(R.id.expiryWarningClose))
|
||||||
|
.check(matches(isDisplayed()));
|
||||||
|
onView(withId(R.id.expiryWarningClose))
|
||||||
|
.perform(click());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createTestData() {
|
||||||
|
try {
|
||||||
|
createTestDataExceptions();
|
||||||
|
} catch (DbException | FormatException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createTestDataExceptions()
|
||||||
|
throws DbException, FormatException {
|
||||||
|
String bobName =
|
||||||
|
getTargetContext().getString(R.string.screenshot_bob);
|
||||||
|
Contact bob = testDataCreator.addContact(bobName);
|
||||||
|
|
||||||
|
String bobHi = getTargetContext()
|
||||||
|
.getString(R.string.screenshot_message_1);
|
||||||
|
long bobTime = getMinutesAgo(2);
|
||||||
|
testDataCreator.addPrivateMessage(bob, bobHi, bobTime, true);
|
||||||
|
|
||||||
|
String aliceHi = getTargetContext()
|
||||||
|
.getString(R.string.screenshot_message_2);
|
||||||
|
long aliceTime = getMinutesAgo(1);
|
||||||
|
testDataCreator.addPrivateMessage(bob, aliceHi, aliceTime, false);
|
||||||
|
|
||||||
|
String bobHi2 = getTargetContext()
|
||||||
|
.getString(R.string.screenshot_message_3);
|
||||||
|
long bobTime2 = getMinutesAgo(0);
|
||||||
|
testDataCreator.addPrivateMessage(bob, bobHi2, bobTime2, true);
|
||||||
|
|
||||||
|
connectionRegistry.registerConnection(bob.getId(), ID, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package org.briarproject.briar.android.contact;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.support.test.rule.ActivityTestRule;
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.android.BriarUiTestComponent;
|
||||||
|
import org.briarproject.briar.android.ScreenshotTest;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static android.support.test.InstrumentationRegistry.getInstrumentation;
|
||||||
|
import static android.support.test.espresso.Espresso.onView;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||||
|
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||||
|
import static org.briarproject.briar.android.ViewActions.waitUntilMatches;
|
||||||
|
import static org.briarproject.briar.android.contact.ConversationActivity.CONTACT_ID;
|
||||||
|
import static org.hamcrest.Matchers.allOf;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class ConversationActivityScreenshotTest extends ScreenshotTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ActivityTestRule<ConversationActivity> testRule =
|
||||||
|
new ActivityTestRule<>(ConversationActivity.class, false, false);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void inject(BriarUiTestComponent component) {
|
||||||
|
component.inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void messaging() throws Exception {
|
||||||
|
Context targetContext = getInstrumentation().getTargetContext();
|
||||||
|
Intent intent = new Intent(targetContext, ConversationActivity.class);
|
||||||
|
intent.putExtra(CONTACT_ID, 1);
|
||||||
|
testRule.launchActivity(intent);
|
||||||
|
|
||||||
|
onView(withId(R.id.conversationView))
|
||||||
|
.perform(waitUntilMatches(allOf(
|
||||||
|
withText(R.string.screenshot_message_3),
|
||||||
|
isCompletelyDisplayed())
|
||||||
|
));
|
||||||
|
|
||||||
|
screenshot("manual_messaging", testRule.getActivity());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,14 +2,15 @@ package org.briarproject.briar.android.settings;
|
|||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.support.test.espresso.contrib.DrawerActions;
|
import android.support.test.espresso.contrib.DrawerActions;
|
||||||
|
import android.support.test.rule.ActivityTestRule;
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.BriarUiTestComponent;
|
import org.briarproject.briar.android.BriarUiTestComponent;
|
||||||
|
import org.briarproject.briar.android.ScreenshotTest;
|
||||||
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
||||||
import org.briarproject.briar.android.test.ScreenshotTest;
|
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -26,15 +27,15 @@ import static android.support.test.espresso.matcher.ViewMatchers.withChild;
|
|||||||
import static android.support.test.espresso.matcher.ViewMatchers.withClassName;
|
import static android.support.test.espresso.matcher.ViewMatchers.withClassName;
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||||
import static org.briarproject.briar.android.test.ViewActions.waitUntilMatches;
|
import static org.briarproject.briar.android.ViewActions.waitUntilMatches;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class SettingsActivityScreenshotTest extends ScreenshotTest {
|
public class SettingsActivityScreenshotTest extends ScreenshotTest {
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public CleanAccountTestRule<SettingsActivity> testRule =
|
public ActivityTestRule<SettingsActivity> testRule =
|
||||||
new CleanAccountTestRule<>(SettingsActivity.class);
|
new ActivityTestRule<>(SettingsActivity.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void inject(BriarUiTestComponent component) {
|
protected void inject(BriarUiTestComponent component) {
|
||||||
@@ -46,7 +47,7 @@ public class SettingsActivityScreenshotTest extends ScreenshotTest {
|
|||||||
onView(withText(R.string.settings_button))
|
onView(withText(R.string.settings_button))
|
||||||
.check(matches(isDisplayed()));
|
.check(matches(isDisplayed()));
|
||||||
|
|
||||||
screenshot("manual_dark_theme_settings");
|
screenshot("manual_dark_theme_settings", testRule.getActivity());
|
||||||
|
|
||||||
// switch to dark theme
|
// switch to dark theme
|
||||||
onView(withText(R.string.pref_theme_title))
|
onView(withText(R.string.pref_theme_title))
|
||||||
@@ -56,10 +57,20 @@ public class SettingsActivityScreenshotTest extends ScreenshotTest {
|
|||||||
.check(matches(isDisplayed()))
|
.check(matches(isDisplayed()))
|
||||||
.perform(click());
|
.perform(click());
|
||||||
|
|
||||||
// open nav drawer and remove expiry warning
|
openNavDrawer();
|
||||||
openNavDrawer(true);
|
|
||||||
|
|
||||||
screenshot("manual_dark_theme_nav_drawer");
|
screenshot("manual_dark_theme_nav_drawer", testRule.getActivity());
|
||||||
|
|
||||||
|
// switch to back to light theme
|
||||||
|
onView(withText(R.string.settings_button))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click());
|
||||||
|
onView(withText(R.string.pref_theme_title))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click());
|
||||||
|
onView(withText(R.string.pref_theme_light))
|
||||||
|
.check(matches(isDisplayed()))
|
||||||
|
.perform(click());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -83,12 +94,11 @@ public class SettingsActivityScreenshotTest extends ScreenshotTest {
|
|||||||
.check(matches(isDisplayed()))
|
.check(matches(isDisplayed()))
|
||||||
.check(matches(isEnabled()));
|
.check(matches(isEnabled()));
|
||||||
|
|
||||||
screenshot("manual_app_lock");
|
screenshot("manual_app_lock", testRule.getActivity());
|
||||||
|
|
||||||
// no more expiry warning to remove, because sharedprefs cached?
|
openNavDrawer();
|
||||||
openNavDrawer(false);
|
|
||||||
|
|
||||||
screenshot("manual_app_lock_nav_drawer");
|
screenshot("manual_app_lock_nav_drawer", testRule.getActivity());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -104,23 +114,15 @@ public class SettingsActivityScreenshotTest extends ScreenshotTest {
|
|||||||
.check(matches(isDisplayed()))
|
.check(matches(isDisplayed()))
|
||||||
.perform(waitUntilMatches(isEnabled()));
|
.perform(waitUntilMatches(isEnabled()));
|
||||||
|
|
||||||
screenshot("manual_tor_settings");
|
screenshot("manual_tor_settings", testRule.getActivity());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openNavDrawer(boolean expiry) {
|
private void openNavDrawer() {
|
||||||
// start main activity
|
// start main activity
|
||||||
Intent i =
|
Intent i =
|
||||||
new Intent(testRule.getActivity(), NavDrawerActivity.class);
|
new Intent(testRule.getActivity(), NavDrawerActivity.class);
|
||||||
testRule.getActivity().startActivity(i);
|
testRule.getActivity().startActivity(i);
|
||||||
|
|
||||||
// close expiry warning
|
|
||||||
if (expiry) {
|
|
||||||
onView(withId(R.id.expiryWarningClose))
|
|
||||||
.check(matches(isDisplayed()));
|
|
||||||
onView(withId(R.id.expiryWarningClose))
|
|
||||||
.perform(click());
|
|
||||||
}
|
|
||||||
|
|
||||||
// open navigation drawer
|
// open navigation drawer
|
||||||
onView(withId(R.id.drawer_layout))
|
onView(withId(R.id.drawer_layout))
|
||||||
.check(matches(isClosed(Gravity.START)))
|
.check(matches(isClosed(Gravity.START)))
|
||||||
@@ -13,9 +13,10 @@
|
|||||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||||
|
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
|
||||||
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
||||||
<uses-permission-sdk-23 android:name="android.permission.USE_BIOMETRIC" />
|
<uses-permission-sdk-23 android:name="android.permission.USE_BIOMETRIC" />
|
||||||
|
|
||||||
@@ -25,6 +26,7 @@
|
|||||||
android:icon="@mipmap/ic_launcher_round"
|
android:icon="@mipmap/ic_launcher_round"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:logo="@mipmap/ic_launcher_round"
|
android:logo="@mipmap/ic_launcher_round"
|
||||||
|
android:supportsRtl="true"
|
||||||
android:theme="@style/BriarTheme">
|
android:theme="@style/BriarTheme">
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
|
|||||||
@@ -41,13 +41,9 @@ import org.briarproject.briar.android.util.BriarNotificationBuilder;
|
|||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.blog.event.BlogPostAddedEvent;
|
import org.briarproject.briar.api.blog.event.BlogPostAddedEvent;
|
||||||
import org.briarproject.briar.api.forum.event.ForumPostReceivedEvent;
|
import org.briarproject.briar.api.forum.event.ForumPostReceivedEvent;
|
||||||
import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent;
|
|
||||||
import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent;
|
|
||||||
import org.briarproject.briar.api.introduction.event.IntroductionSucceededEvent;
|
import org.briarproject.briar.api.introduction.event.IntroductionSucceededEvent;
|
||||||
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
|
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
|
||||||
import org.briarproject.briar.api.privategroup.event.GroupMessageAddedEvent;
|
import org.briarproject.briar.api.privategroup.event.GroupMessageAddedEvent;
|
||||||
import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent;
|
|
||||||
import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent;
|
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
@@ -235,19 +231,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
} else if (e instanceof BlogPostAddedEvent) {
|
} else if (e instanceof BlogPostAddedEvent) {
|
||||||
BlogPostAddedEvent b = (BlogPostAddedEvent) e;
|
BlogPostAddedEvent b = (BlogPostAddedEvent) e;
|
||||||
showBlogPostNotification(b.getGroupId());
|
showBlogPostNotification(b.getGroupId());
|
||||||
} else if (e instanceof IntroductionRequestReceivedEvent) {
|
|
||||||
ContactId c = ((IntroductionRequestReceivedEvent) e).getContactId();
|
|
||||||
showContactNotification(c);
|
|
||||||
} else if (e instanceof IntroductionResponseReceivedEvent) {
|
|
||||||
ContactId c =
|
|
||||||
((IntroductionResponseReceivedEvent) e).getContactId();
|
|
||||||
showContactNotification(c);
|
|
||||||
} else if (e instanceof InvitationRequestReceivedEvent) {
|
|
||||||
ContactId c = ((InvitationRequestReceivedEvent) e).getContactId();
|
|
||||||
showContactNotification(c);
|
|
||||||
} else if (e instanceof InvitationResponseReceivedEvent) {
|
|
||||||
ContactId c = ((InvitationResponseReceivedEvent) e).getContactId();
|
|
||||||
showContactNotification(c);
|
|
||||||
} else if (e instanceof IntroductionSucceededEvent) {
|
} else if (e instanceof IntroductionSucceededEvent) {
|
||||||
showIntroductionNotification();
|
showIntroductionNotification();
|
||||||
}
|
}
|
||||||
@@ -327,9 +310,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
R.plurals.private_message_notification_text, contactTotal,
|
R.plurals.private_message_notification_text, contactTotal,
|
||||||
contactTotal));
|
contactTotal));
|
||||||
b.setNumber(contactTotal);
|
b.setNumber(contactTotal);
|
||||||
boolean showOnLockScreen =
|
b.setNotificationCategory(CATEGORY_MESSAGE);
|
||||||
settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
|
|
||||||
b.setLockscreenVisibility(CATEGORY_MESSAGE, showOnLockScreen);
|
|
||||||
if (mayAlertAgain) setAlertProperties(b);
|
if (mayAlertAgain) setAlertProperties(b);
|
||||||
setDeleteIntent(b, CONTACT_URI);
|
setDeleteIntent(b, CONTACT_URI);
|
||||||
Set<ContactId> contacts = contactCounts.keySet();
|
Set<ContactId> contacts = contactCounts.keySet();
|
||||||
@@ -431,9 +412,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
R.plurals.group_message_notification_text, groupTotal,
|
R.plurals.group_message_notification_text, groupTotal,
|
||||||
groupTotal));
|
groupTotal));
|
||||||
b.setNumber(groupTotal);
|
b.setNumber(groupTotal);
|
||||||
boolean showOnLockScreen =
|
b.setNotificationCategory(CATEGORY_SOCIAL);
|
||||||
settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
|
|
||||||
b.setLockscreenVisibility(CATEGORY_SOCIAL, showOnLockScreen);
|
|
||||||
if (mayAlertAgain) setAlertProperties(b);
|
if (mayAlertAgain) setAlertProperties(b);
|
||||||
setDeleteIntent(b, GROUP_URI);
|
setDeleteIntent(b, GROUP_URI);
|
||||||
Set<GroupId> groups = groupCounts.keySet();
|
Set<GroupId> groups = groupCounts.keySet();
|
||||||
@@ -504,9 +483,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
R.plurals.forum_post_notification_text, forumTotal,
|
R.plurals.forum_post_notification_text, forumTotal,
|
||||||
forumTotal));
|
forumTotal));
|
||||||
b.setNumber(forumTotal);
|
b.setNumber(forumTotal);
|
||||||
boolean showOnLockScreen =
|
b.setNotificationCategory(CATEGORY_SOCIAL);
|
||||||
settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
|
|
||||||
b.setLockscreenVisibility(CATEGORY_SOCIAL, showOnLockScreen);
|
|
||||||
if (mayAlertAgain) setAlertProperties(b);
|
if (mayAlertAgain) setAlertProperties(b);
|
||||||
setDeleteIntent(b, FORUM_URI);
|
setDeleteIntent(b, FORUM_URI);
|
||||||
Set<GroupId> forums = forumCounts.keySet();
|
Set<GroupId> forums = forumCounts.keySet();
|
||||||
@@ -575,9 +552,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
R.plurals.blog_post_notification_text, blogTotal,
|
R.plurals.blog_post_notification_text, blogTotal,
|
||||||
blogTotal));
|
blogTotal));
|
||||||
b.setNumber(blogTotal);
|
b.setNumber(blogTotal);
|
||||||
boolean showOnLockScreen =
|
b.setNotificationCategory(CATEGORY_SOCIAL);
|
||||||
settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
|
|
||||||
b.setLockscreenVisibility(CATEGORY_SOCIAL, showOnLockScreen);
|
|
||||||
if (mayAlertAgain) setAlertProperties(b);
|
if (mayAlertAgain) setAlertProperties(b);
|
||||||
setDeleteIntent(b, BLOG_URI);
|
setDeleteIntent(b, BLOG_URI);
|
||||||
// Touching the notification shows the combined blog feed
|
// Touching the notification shows the combined blog feed
|
||||||
@@ -618,9 +593,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
b.setContentText(appContext.getResources().getQuantityString(
|
b.setContentText(appContext.getResources().getQuantityString(
|
||||||
R.plurals.introduction_notification_text, introductionTotal,
|
R.plurals.introduction_notification_text, introductionTotal,
|
||||||
introductionTotal));
|
introductionTotal));
|
||||||
boolean showOnLockScreen =
|
b.setNotificationCategory(CATEGORY_MESSAGE);
|
||||||
settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
|
|
||||||
b.setLockscreenVisibility(CATEGORY_MESSAGE, showOnLockScreen);
|
|
||||||
setAlertProperties(b);
|
setAlertProperties(b);
|
||||||
setDeleteIntent(b, INTRODUCTION_URI);
|
setDeleteIntent(b, INTRODUCTION_URI);
|
||||||
// Touching the notification shows the contact list
|
// Touching the notification shows the contact list
|
||||||
|
|||||||
@@ -101,6 +101,8 @@ public class LockManagerImpl implements LockManager, Service, EventListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stopService() {
|
public void stopService() {
|
||||||
|
timeoutMinutes = timeoutNever;
|
||||||
|
if (alarmSet) alarmManager.cancel(lockIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
|
|||||||
@@ -68,6 +68,11 @@ public abstract class BaseActivity extends AppCompatActivity
|
|||||||
public void onCreate(@Nullable Bundle state) {
|
public void onCreate(@Nullable Bundle state) {
|
||||||
super.onCreate(state);
|
super.onCreate(state);
|
||||||
|
|
||||||
|
// WARNING: When removing this or making it possible to turn it off,
|
||||||
|
// we need a solution for the app lock feature.
|
||||||
|
// When the app is locked by a timeout and FLAG_SECURE is not
|
||||||
|
// set, the app content becomes visible briefly before the
|
||||||
|
// unlock screen is shown.
|
||||||
if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
|
if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
|
||||||
|
|
||||||
AndroidComponent applicationComponent =
|
AndroidComponent applicationComponent =
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ import org.briarproject.briar.android.controller.ActivityLifecycleController;
|
|||||||
import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
|
import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.blog.Blog;
|
import org.briarproject.briar.api.blog.Blog;
|
||||||
|
import org.briarproject.briar.api.blog.BlogInvitationResponse;
|
||||||
import org.briarproject.briar.api.blog.BlogManager;
|
import org.briarproject.briar.api.blog.BlogManager;
|
||||||
import org.briarproject.briar.api.blog.BlogSharingManager;
|
import org.briarproject.briar.api.blog.BlogSharingManager;
|
||||||
import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent;
|
import org.briarproject.briar.api.blog.event.BlogInvitationResponseReceivedEvent;
|
||||||
import org.briarproject.briar.api.blog.event.BlogPostAddedEvent;
|
import org.briarproject.briar.api.blog.event.BlogPostAddedEvent;
|
||||||
import org.briarproject.briar.api.sharing.InvitationResponse;
|
|
||||||
import org.briarproject.briar.api.sharing.event.ContactLeftShareableEvent;
|
import org.briarproject.briar.api.sharing.event.ContactLeftShareableEvent;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -107,7 +107,7 @@ class BlogControllerImpl extends BaseControllerImpl
|
|||||||
} else if (e instanceof BlogInvitationResponseReceivedEvent) {
|
} else if (e instanceof BlogInvitationResponseReceivedEvent) {
|
||||||
BlogInvitationResponseReceivedEvent b =
|
BlogInvitationResponseReceivedEvent b =
|
||||||
(BlogInvitationResponseReceivedEvent) e;
|
(BlogInvitationResponseReceivedEvent) e;
|
||||||
InvitationResponse r = b.getResponse();
|
BlogInvitationResponse r = b.getMessageHeader();
|
||||||
if (r.getShareableId().equals(groupId) && r.wasAccepted()) {
|
if (r.getShareableId().equals(groupId) && r.wasAccepted()) {
|
||||||
LOG.info("Blog invitation accepted");
|
LOG.info("Blog invitation accepted");
|
||||||
onBlogInvitationAccepted(b.getContactId());
|
onBlogInvitationAccepted(b.getContactId());
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.briar.android.contact;
|
package org.briarproject.briar.android.contact;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v4.app.ActivityOptionsCompat;
|
import android.support.v4.app.ActivityOptionsCompat;
|
||||||
@@ -36,19 +35,10 @@ import org.briarproject.briar.android.fragment.BaseFragment;
|
|||||||
import org.briarproject.briar.android.keyagreement.ContactExchangeActivity;
|
import org.briarproject.briar.android.keyagreement.ContactExchangeActivity;
|
||||||
import org.briarproject.briar.android.view.BriarRecyclerView;
|
import org.briarproject.briar.android.view.BriarRecyclerView;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.client.BaseMessageHeader;
|
|
||||||
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
|
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
|
||||||
import org.briarproject.briar.api.introduction.IntroductionRequest;
|
|
||||||
import org.briarproject.briar.api.introduction.IntroductionResponse;
|
|
||||||
import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent;
|
|
||||||
import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent;
|
|
||||||
import org.briarproject.briar.api.messaging.ConversationManager;
|
import org.briarproject.briar.api.messaging.ConversationManager;
|
||||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
||||||
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
|
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
|
||||||
import org.briarproject.briar.api.sharing.InvitationRequest;
|
|
||||||
import org.briarproject.briar.api.sharing.InvitationResponse;
|
|
||||||
import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent;
|
|
||||||
import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -57,6 +47,7 @@ import java.util.logging.Logger;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static android.support.v4.app.ActivityOptionsCompat.makeSceneTransitionAnimation;
|
import static android.support.v4.app.ActivityOptionsCompat.makeSceneTransitionAnimation;
|
||||||
import static android.support.v4.view.ViewCompat.getTransitionName;
|
import static android.support.v4.view.ViewCompat.getTransitionName;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
@@ -122,7 +113,7 @@ 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());
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 23) {
|
if (SDK_INT >= 23) {
|
||||||
ContactListItemViewHolder holder =
|
ContactListItemViewHolder holder =
|
||||||
(ContactListItemViewHolder) list
|
(ContactListItemViewHolder) list
|
||||||
.getRecyclerView()
|
.getRecyclerView()
|
||||||
@@ -256,41 +247,16 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
|
PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
|
||||||
PrivateMessageHeader h = p.getMessageHeader();
|
PrivateMessageHeader h = p.getMessageHeader();
|
||||||
updateItem(p.getContactId(), h);
|
updateItem(p.getContactId(), h);
|
||||||
} else if (e instanceof IntroductionRequestReceivedEvent) {
|
|
||||||
LOG.info("Introduction request received, updating item");
|
|
||||||
IntroductionRequestReceivedEvent m =
|
|
||||||
(IntroductionRequestReceivedEvent) e;
|
|
||||||
IntroductionRequest ir = m.getIntroductionRequest();
|
|
||||||
updateItem(m.getContactId(), ir);
|
|
||||||
} else if (e instanceof IntroductionResponseReceivedEvent) {
|
|
||||||
LOG.info("Introduction response received, updating item");
|
|
||||||
IntroductionResponseReceivedEvent m =
|
|
||||||
(IntroductionResponseReceivedEvent) e;
|
|
||||||
IntroductionResponse ir = m.getIntroductionResponse();
|
|
||||||
updateItem(m.getContactId(), ir);
|
|
||||||
} else if (e instanceof InvitationRequestReceivedEvent) {
|
|
||||||
LOG.info("Invitation Request received, update item");
|
|
||||||
InvitationRequestReceivedEvent m =
|
|
||||||
(InvitationRequestReceivedEvent) e;
|
|
||||||
InvitationRequest ir = m.getRequest();
|
|
||||||
updateItem(m.getContactId(), ir);
|
|
||||||
} else if (e instanceof InvitationResponseReceivedEvent) {
|
|
||||||
LOG.info("Invitation response received, updating item");
|
|
||||||
InvitationResponseReceivedEvent m =
|
|
||||||
(InvitationResponseReceivedEvent) e;
|
|
||||||
InvitationResponse ir = m.getResponse();
|
|
||||||
updateItem(m.getContactId(), ir);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateItem(ContactId c, BaseMessageHeader h) {
|
private void updateItem(ContactId c, PrivateMessageHeader h) {
|
||||||
runOnUiThreadUnlessDestroyed(() -> {
|
runOnUiThreadUnlessDestroyed(() -> {
|
||||||
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) {
|
||||||
ConversationItem i = ConversationItem.from(getContext(), h);
|
item.addMessage(h);
|
||||||
item.addMessage(i);
|
|
||||||
adapter.updateItemAt(position, item);
|
adapter.updateItemAt(position, item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,6 +3,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.briar.api.client.MessageTracker.GroupCount;
|
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
|
||||||
|
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
||||||
|
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
@@ -22,11 +23,10 @@ public class ContactListItem extends ContactItem {
|
|||||||
this.timestamp = count.getLatestMsgTime();
|
this.timestamp = count.getLatestMsgTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
void addMessage(ConversationItem message) {
|
void addMessage(PrivateMessageHeader h) {
|
||||||
empty = false;
|
empty = false;
|
||||||
if (message.getTime() > timestamp) timestamp = message.getTime();
|
if (h.getTimestamp() > timestamp) timestamp = h.getTimestamp();
|
||||||
if (!message.isRead())
|
if (!h.isRead()) unread++;
|
||||||
unread++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isEmpty() {
|
boolean isEmpty() {
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package org.briarproject.briar.android.contact;
|
package org.briarproject.briar.android.contact;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.MutableLiveData;
|
||||||
|
import android.arch.lifecycle.Observer;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
@@ -50,6 +53,7 @@ import org.briarproject.briar.android.activity.ActivityComponent;
|
|||||||
import org.briarproject.briar.android.activity.BriarActivity;
|
import org.briarproject.briar.android.activity.BriarActivity;
|
||||||
import org.briarproject.briar.android.blog.BlogActivity;
|
import org.briarproject.briar.android.blog.BlogActivity;
|
||||||
import org.briarproject.briar.android.contact.ConversationAdapter.ConversationListener;
|
import org.briarproject.briar.android.contact.ConversationAdapter.ConversationListener;
|
||||||
|
import org.briarproject.briar.android.contact.ConversationVisitor.BodyCache;
|
||||||
import org.briarproject.briar.android.forum.ForumActivity;
|
import org.briarproject.briar.android.forum.ForumActivity;
|
||||||
import org.briarproject.briar.android.introduction.IntroductionActivity;
|
import org.briarproject.briar.android.introduction.IntroductionActivity;
|
||||||
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
|
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
|
||||||
@@ -62,24 +66,15 @@ import org.briarproject.briar.api.client.ProtocolStateException;
|
|||||||
import org.briarproject.briar.api.client.SessionId;
|
import org.briarproject.briar.api.client.SessionId;
|
||||||
import org.briarproject.briar.api.forum.ForumSharingManager;
|
import org.briarproject.briar.api.forum.ForumSharingManager;
|
||||||
import org.briarproject.briar.api.introduction.IntroductionManager;
|
import org.briarproject.briar.api.introduction.IntroductionManager;
|
||||||
import org.briarproject.briar.api.introduction.IntroductionMessage;
|
import org.briarproject.briar.api.messaging.ConversationManager;
|
||||||
import org.briarproject.briar.api.introduction.IntroductionRequest;
|
|
||||||
import org.briarproject.briar.api.introduction.IntroductionResponse;
|
|
||||||
import org.briarproject.briar.api.introduction.event.IntroductionRequestReceivedEvent;
|
|
||||||
import org.briarproject.briar.api.introduction.event.IntroductionResponseReceivedEvent;
|
|
||||||
import org.briarproject.briar.api.messaging.MessagingManager;
|
import org.briarproject.briar.api.messaging.MessagingManager;
|
||||||
import org.briarproject.briar.api.messaging.PrivateMessage;
|
import org.briarproject.briar.api.messaging.PrivateMessage;
|
||||||
import org.briarproject.briar.api.messaging.PrivateMessageFactory;
|
import org.briarproject.briar.api.messaging.PrivateMessageFactory;
|
||||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
||||||
|
import org.briarproject.briar.api.messaging.PrivateRequest;
|
||||||
|
import org.briarproject.briar.api.messaging.PrivateResponse;
|
||||||
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
|
import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent;
|
||||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
|
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
|
||||||
import org.briarproject.briar.api.sharing.InvitationMessage;
|
|
||||||
import org.briarproject.briar.api.sharing.InvitationRequest;
|
|
||||||
import org.briarproject.briar.api.sharing.InvitationResponse;
|
|
||||||
import org.briarproject.briar.api.sharing.event.InvitationRequestReceivedEvent;
|
|
||||||
import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent;
|
|
||||||
import org.thoughtcrime.securesms.components.util.FutureTaskListener;
|
|
||||||
import org.thoughtcrime.securesms.components.util.ListenableFutureTask;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -87,13 +82,10 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import de.hdodenhof.circleimageview.CircleImageView;
|
import de.hdodenhof.circleimageview.CircleImageView;
|
||||||
@@ -120,7 +112,8 @@ import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.S
|
|||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
public class ConversationActivity extends BriarActivity
|
public class ConversationActivity extends BriarActivity
|
||||||
implements EventListener, ConversationListener, TextInputListener {
|
implements EventListener, ConversationListener, TextInputListener,
|
||||||
|
BodyCache {
|
||||||
|
|
||||||
public static final String CONTACT_ID = "briar.CONTACT_ID";
|
public static final String CONTACT_ID = "briar.CONTACT_ID";
|
||||||
|
|
||||||
@@ -138,7 +131,9 @@ public class ConversationActivity extends BriarActivity
|
|||||||
Executor cryptoExecutor;
|
Executor cryptoExecutor;
|
||||||
|
|
||||||
private final Map<MessageId, String> bodyCache = new ConcurrentHashMap<>();
|
private final Map<MessageId, String> bodyCache = new ConcurrentHashMap<>();
|
||||||
|
private final MutableLiveData<String> contactName = new MutableLiveData<>();
|
||||||
|
|
||||||
|
private ConversationVisitor visitor;
|
||||||
private ConversationAdapter adapter;
|
private ConversationAdapter adapter;
|
||||||
private Toolbar toolbar;
|
private Toolbar toolbar;
|
||||||
private CircleImageView toolbarAvatar;
|
private CircleImageView toolbarAvatar;
|
||||||
@@ -147,24 +142,14 @@ public class ConversationActivity extends BriarActivity
|
|||||||
private BriarRecyclerView list;
|
private BriarRecyclerView list;
|
||||||
private TextInputView textInputView;
|
private TextInputView textInputView;
|
||||||
|
|
||||||
private final ListenableFutureTask<String> contactNameTask =
|
|
||||||
new ListenableFutureTask<>(new Callable<String>() {
|
|
||||||
@Override
|
|
||||||
public String call() throws Exception {
|
|
||||||
Contact c = contactManager.getContact(contactId);
|
|
||||||
contactName = c.getAuthor().getName();
|
|
||||||
return c.getAuthor().getName();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
private final AtomicBoolean contactNameTaskStarted =
|
|
||||||
new AtomicBoolean(false);
|
|
||||||
|
|
||||||
// Fields that are accessed from background threads must be volatile
|
// Fields that are accessed from background threads must be volatile
|
||||||
@Inject
|
@Inject
|
||||||
volatile ContactManager contactManager;
|
volatile ContactManager contactManager;
|
||||||
@Inject
|
@Inject
|
||||||
volatile MessagingManager messagingManager;
|
volatile MessagingManager messagingManager;
|
||||||
@Inject
|
@Inject
|
||||||
|
volatile ConversationManager conversationManager;
|
||||||
|
@Inject
|
||||||
volatile EventBus eventBus;
|
volatile EventBus eventBus;
|
||||||
@Inject
|
@Inject
|
||||||
volatile SettingsManager settingsManager;
|
volatile SettingsManager settingsManager;
|
||||||
@@ -181,8 +166,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
|
|
||||||
private volatile ContactId contactId;
|
private volatile ContactId contactId;
|
||||||
@Nullable
|
@Nullable
|
||||||
private volatile String contactName;
|
|
||||||
@Nullable
|
|
||||||
private volatile AuthorId contactAuthorId;
|
private volatile AuthorId contactAuthorId;
|
||||||
@Nullable
|
@Nullable
|
||||||
private volatile GroupId messagingGroupId;
|
private volatile GroupId messagingGroupId;
|
||||||
@@ -211,6 +194,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
setTransitionName(toolbarAvatar, getAvatarTransitionName(contactId));
|
setTransitionName(toolbarAvatar, getAvatarTransitionName(contactId));
|
||||||
setTransitionName(toolbarStatus, getBulbTransitionName(contactId));
|
setTransitionName(toolbarStatus, getBulbTransitionName(contactId));
|
||||||
|
|
||||||
|
visitor = new ConversationVisitor(this, this, contactName);
|
||||||
adapter = new ConversationAdapter(this, this);
|
adapter = new ConversationAdapter(this, this);
|
||||||
list = findViewById(R.id.conversationView);
|
list = findViewById(R.id.conversationView);
|
||||||
list.setLayoutManager(new LinearLayoutManager(this));
|
list.setLayoutManager(new LinearLayoutManager(this));
|
||||||
@@ -294,9 +278,9 @@ public class ConversationActivity extends BriarActivity
|
|||||||
runOnDbThread(() -> {
|
runOnDbThread(() -> {
|
||||||
try {
|
try {
|
||||||
long start = now();
|
long start = now();
|
||||||
if (contactName == null || contactAuthorId == null) {
|
if (contactAuthorId == null) {
|
||||||
Contact contact = contactManager.getContact(contactId);
|
Contact contact = contactManager.getContact(contactId);
|
||||||
contactName = contact.getAuthor().getName();
|
contactName.postValue(contact.getAuthor().getName());
|
||||||
contactAuthorId = contact.getAuthor().getId();
|
contactAuthorId = contact.getAuthor().getId();
|
||||||
}
|
}
|
||||||
logDuration(LOG, "Loading contact", start);
|
logDuration(LOG, "Loading contact", start);
|
||||||
@@ -310,12 +294,13 @@ public class ConversationActivity extends BriarActivity
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// contactAuthorId and contactName are expected to be set
|
||||||
private void displayContactDetails() {
|
private void displayContactDetails() {
|
||||||
runOnUiThreadUnlessDestroyed(() -> {
|
runOnUiThreadUnlessDestroyed(() -> {
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
toolbarAvatar.setImageDrawable(
|
toolbarAvatar.setImageDrawable(
|
||||||
new IdenticonDrawable(contactAuthorId.getBytes()));
|
new IdenticonDrawable(contactAuthorId.getBytes()));
|
||||||
toolbarTitle.setText(contactName);
|
toolbarTitle.setText(contactName.getValue());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,23 +328,9 @@ public class ConversationActivity extends BriarActivity
|
|||||||
try {
|
try {
|
||||||
long start = now();
|
long start = now();
|
||||||
Collection<PrivateMessageHeader> headers =
|
Collection<PrivateMessageHeader> headers =
|
||||||
messagingManager.getMessageHeaders(contactId);
|
conversationManager.getMessageHeaders(contactId);
|
||||||
Collection<IntroductionMessage> introductions =
|
|
||||||
introductionManager.getIntroductionMessages(contactId);
|
|
||||||
Collection<InvitationMessage> forumInvitations =
|
|
||||||
forumSharingManager.getInvitationMessages(contactId);
|
|
||||||
Collection<InvitationMessage> blogInvitations =
|
|
||||||
blogSharingManager.getInvitationMessages(contactId);
|
|
||||||
Collection<InvitationMessage> groupInvitations =
|
|
||||||
groupInvitationManager.getInvitationMessages(contactId);
|
|
||||||
List<InvitationMessage> invitations = new ArrayList<>(
|
|
||||||
forumInvitations.size() + blogInvitations.size() +
|
|
||||||
groupInvitations.size());
|
|
||||||
invitations.addAll(forumInvitations);
|
|
||||||
invitations.addAll(blogInvitations);
|
|
||||||
invitations.addAll(groupInvitations);
|
|
||||||
logDuration(LOG, "Loading messages", start);
|
logDuration(LOG, "Loading messages", start);
|
||||||
displayMessages(revision, headers, introductions, invitations);
|
displayMessages(revision, headers);
|
||||||
} catch (NoSuchContactException e) {
|
} catch (NoSuchContactException e) {
|
||||||
finishOnUiThread();
|
finishOnUiThread();
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
@@ -369,15 +340,12 @@ public class ConversationActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void displayMessages(int revision,
|
private void displayMessages(int revision,
|
||||||
Collection<PrivateMessageHeader> headers,
|
Collection<PrivateMessageHeader> headers) {
|
||||||
Collection<IntroductionMessage> introductions,
|
|
||||||
Collection<InvitationMessage> invitations) {
|
|
||||||
runOnUiThreadUnlessDestroyed(() -> {
|
runOnUiThreadUnlessDestroyed(() -> {
|
||||||
if (revision == adapter.getRevision()) {
|
if (revision == adapter.getRevision()) {
|
||||||
adapter.incrementRevision();
|
adapter.incrementRevision();
|
||||||
textInputView.setSendButtonEnabled(true);
|
textInputView.setSendButtonEnabled(true);
|
||||||
List<ConversationItem> items = createItems(headers,
|
List<ConversationItem> items = createItems(headers);
|
||||||
introductions, invitations);
|
|
||||||
adapter.addAll(items);
|
adapter.addAll(items);
|
||||||
list.showData();
|
list.showData();
|
||||||
// Scroll to the bottom
|
// Scroll to the bottom
|
||||||
@@ -396,41 +364,9 @@ public class ConversationActivity extends BriarActivity
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
private List<ConversationItem> createItems(
|
private List<ConversationItem> createItems(
|
||||||
Collection<PrivateMessageHeader> headers,
|
Collection<PrivateMessageHeader> headers) {
|
||||||
Collection<IntroductionMessage> introductions,
|
List<ConversationItem> items = new ArrayList<>(headers.size());
|
||||||
Collection<InvitationMessage> invitations) {
|
for (PrivateMessageHeader h : headers) items.add(h.accept(visitor));
|
||||||
int size =
|
|
||||||
headers.size() + introductions.size() + invitations.size();
|
|
||||||
List<ConversationItem> items = new ArrayList<>(size);
|
|
||||||
for (PrivateMessageHeader h : headers) {
|
|
||||||
ConversationItem item = ConversationItem.from(h);
|
|
||||||
String body = bodyCache.get(h.getId());
|
|
||||||
if (body == null) loadMessageBody(h.getId());
|
|
||||||
else item.setBody(body);
|
|
||||||
items.add(item);
|
|
||||||
}
|
|
||||||
for (IntroductionMessage m : introductions) {
|
|
||||||
ConversationItem item;
|
|
||||||
if (m instanceof IntroductionRequest) {
|
|
||||||
IntroductionRequest i = (IntroductionRequest) m;
|
|
||||||
item = ConversationItem.from(this, contactName, i);
|
|
||||||
} else {
|
|
||||||
IntroductionResponse i = (IntroductionResponse) m;
|
|
||||||
item = ConversationItem.from(this, contactName, i);
|
|
||||||
}
|
|
||||||
items.add(item);
|
|
||||||
}
|
|
||||||
for (InvitationMessage i : invitations) {
|
|
||||||
ConversationItem item;
|
|
||||||
if (i instanceof InvitationRequest) {
|
|
||||||
InvitationRequest r = (InvitationRequest) i;
|
|
||||||
item = ConversationItem.from(this, contactName, r);
|
|
||||||
} else {
|
|
||||||
InvitationResponse r = (InvitationResponse) i;
|
|
||||||
item = ConversationItem.from(this, contactName, r);
|
|
||||||
}
|
|
||||||
items.add(item);
|
|
||||||
}
|
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -476,9 +412,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
|
PrivateMessageReceivedEvent p = (PrivateMessageReceivedEvent) e;
|
||||||
if (p.getContactId().equals(contactId)) {
|
if (p.getContactId().equals(contactId)) {
|
||||||
LOG.info("Message received, adding");
|
LOG.info("Message received, adding");
|
||||||
PrivateMessageHeader h = p.getMessageHeader();
|
onNewPrivateMessage(p.getMessageHeader());
|
||||||
addConversationItem(ConversationItem.from(h));
|
|
||||||
loadMessageBody(h.getId());
|
|
||||||
}
|
}
|
||||||
} else if (e instanceof MessagesSentEvent) {
|
} else if (e instanceof MessagesSentEvent) {
|
||||||
MessagesSentEvent m = (MessagesSentEvent) e;
|
MessagesSentEvent m = (MessagesSentEvent) e;
|
||||||
@@ -504,38 +438,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
LOG.info("Contact disconnected");
|
LOG.info("Contact disconnected");
|
||||||
displayContactOnlineStatus();
|
displayContactOnlineStatus();
|
||||||
}
|
}
|
||||||
} else if (e instanceof IntroductionRequestReceivedEvent) {
|
|
||||||
IntroductionRequestReceivedEvent event =
|
|
||||||
(IntroductionRequestReceivedEvent) e;
|
|
||||||
if (event.getContactId().equals(contactId)) {
|
|
||||||
LOG.info("Introduction request received, adding...");
|
|
||||||
IntroductionRequest ir = event.getIntroductionRequest();
|
|
||||||
handleIntroductionRequest(ir);
|
|
||||||
}
|
|
||||||
} else if (e instanceof IntroductionResponseReceivedEvent) {
|
|
||||||
IntroductionResponseReceivedEvent event =
|
|
||||||
(IntroductionResponseReceivedEvent) e;
|
|
||||||
if (event.getContactId().equals(contactId)) {
|
|
||||||
LOG.info("Introduction response received, adding...");
|
|
||||||
IntroductionResponse ir = event.getIntroductionResponse();
|
|
||||||
handleIntroductionResponse(ir);
|
|
||||||
}
|
|
||||||
} else if (e instanceof InvitationRequestReceivedEvent) {
|
|
||||||
InvitationRequestReceivedEvent event =
|
|
||||||
(InvitationRequestReceivedEvent) e;
|
|
||||||
if (event.getContactId().equals(contactId)) {
|
|
||||||
LOG.info("Invitation received, adding...");
|
|
||||||
InvitationRequest ir = event.getRequest();
|
|
||||||
handleInvitationRequest(ir);
|
|
||||||
}
|
|
||||||
} else if (e instanceof InvitationResponseReceivedEvent) {
|
|
||||||
InvitationResponseReceivedEvent event =
|
|
||||||
(InvitationResponseReceivedEvent) e;
|
|
||||||
if (event.getContactId().equals(contactId)) {
|
|
||||||
LOG.info("Invitation response received, adding...");
|
|
||||||
InvitationResponse ir = event.getResponse();
|
|
||||||
handleInvitationResponse(ir);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,84 +450,33 @@ public class ConversationActivity extends BriarActivity
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleIntroductionRequest(IntroductionRequest m) {
|
private void onNewPrivateMessage(PrivateMessageHeader h) {
|
||||||
getContactNameTask().addListener(new FutureTaskListener<String>() {
|
runOnUiThreadUnlessDestroyed(() -> {
|
||||||
@Override
|
if (h instanceof PrivateRequest || h instanceof PrivateResponse) {
|
||||||
public void onSuccess(String contactName) {
|
String cName = contactName.getValue();
|
||||||
runOnUiThreadUnlessDestroyed(() -> {
|
if (cName == null) {
|
||||||
ConversationItem item = ConversationItem
|
// Wait for the contact name to be loaded
|
||||||
.from(ConversationActivity.this, contactName, m);
|
contactName.observe(this, new Observer<String>() {
|
||||||
addConversationItem(item);
|
@Override
|
||||||
});
|
public void onChanged(@Nullable String cName) {
|
||||||
}
|
if (cName != null) {
|
||||||
|
addConversationItem(h.accept(visitor));
|
||||||
@Override
|
contactName.removeObserver(this);
|
||||||
public void onFailure(Throwable exception) {
|
}
|
||||||
runOnUiThreadUnlessDestroyed(
|
}
|
||||||
() -> handleDbException((DbException) exception));
|
});
|
||||||
|
} else {
|
||||||
|
addConversationItem(h.accept(visitor));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addConversationItem(h.accept(visitor));
|
||||||
|
loadMessageBody(h.getId());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleIntroductionResponse(IntroductionResponse m) {
|
private void markMessages(Collection<MessageId> messageIds, boolean sent,
|
||||||
getContactNameTask().addListener(new FutureTaskListener<String>() {
|
boolean seen) {
|
||||||
@Override
|
|
||||||
public void onSuccess(String contactName) {
|
|
||||||
runOnUiThreadUnlessDestroyed(() -> {
|
|
||||||
ConversationItem item = ConversationItem
|
|
||||||
.from(ConversationActivity.this, contactName, m);
|
|
||||||
addConversationItem(item);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Throwable exception) {
|
|
||||||
runOnUiThreadUnlessDestroyed(
|
|
||||||
() -> handleDbException((DbException) exception));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleInvitationRequest(InvitationRequest m) {
|
|
||||||
getContactNameTask().addListener(new FutureTaskListener<String>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(String contactName) {
|
|
||||||
runOnUiThreadUnlessDestroyed(() -> {
|
|
||||||
ConversationItem item = ConversationItem
|
|
||||||
.from(ConversationActivity.this, contactName, m);
|
|
||||||
addConversationItem(item);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Throwable exception) {
|
|
||||||
runOnUiThreadUnlessDestroyed(
|
|
||||||
() -> handleDbException((DbException) exception));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleInvitationResponse(InvitationResponse m) {
|
|
||||||
getContactNameTask().addListener(new FutureTaskListener<String>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(String contactName) {
|
|
||||||
runOnUiThreadUnlessDestroyed(() -> {
|
|
||||||
ConversationItem item = ConversationItem
|
|
||||||
.from(ConversationActivity.this, contactName, m);
|
|
||||||
addConversationItem(item);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Throwable exception) {
|
|
||||||
runOnUiThreadUnlessDestroyed(
|
|
||||||
() -> handleDbException((DbException) exception));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void markMessages(Collection<MessageId> messageIds,
|
|
||||||
boolean sent, boolean seen) {
|
|
||||||
runOnUiThreadUnlessDestroyed(() -> {
|
runOnUiThreadUnlessDestroyed(() -> {
|
||||||
adapter.incrementRevision();
|
adapter.incrementRevision();
|
||||||
Set<MessageId> messages = new HashSet<>(messageIds);
|
Set<MessageId> messages = new HashSet<>(messageIds);
|
||||||
@@ -678,7 +529,8 @@ public class ConversationActivity extends BriarActivity
|
|||||||
//noinspection ConstantConditions init in loadGroupId()
|
//noinspection ConstantConditions init in loadGroupId()
|
||||||
storeMessage(privateMessageFactory.createPrivateMessage(
|
storeMessage(privateMessageFactory.createPrivateMessage(
|
||||||
messagingGroupId, timestamp, body), body);
|
messagingGroupId, timestamp, body), body);
|
||||||
} catch (FormatException e) {throw new RuntimeException(e);
|
} catch (FormatException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -693,10 +545,8 @@ public class ConversationActivity extends BriarActivity
|
|||||||
PrivateMessageHeader h = new PrivateMessageHeader(
|
PrivateMessageHeader h = new PrivateMessageHeader(
|
||||||
message.getId(), message.getGroupId(),
|
message.getId(), message.getGroupId(),
|
||||||
message.getTimestamp(), true, false, false, false);
|
message.getTimestamp(), true, false, false, false);
|
||||||
ConversationItem item = ConversationItem.from(h);
|
|
||||||
item.setBody(body);
|
|
||||||
bodyCache.put(message.getId(), body);
|
bodyCache.put(message.getId(), body);
|
||||||
addConversationItem(item);
|
addConversationItem(h.accept(visitor));
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
@@ -823,7 +673,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
@UiThread
|
@UiThread
|
||||||
@Override
|
@Override
|
||||||
public void respondToRequest(ConversationRequestItem item, boolean accept) {
|
public void respondToRequest(ConversationRequestItem item, boolean accept) {
|
||||||
item.setAnswered(true);
|
item.setAnswered();
|
||||||
int position = adapter.findItemPosition(item);
|
int position = adapter.findItemPosition(item);
|
||||||
if (position != INVALID_POSITION) {
|
if (position != INVALID_POSITION) {
|
||||||
adapter.notifyItemChanged(position, item);
|
adapter.notifyItemChanged(position, item);
|
||||||
@@ -909,10 +759,11 @@ public class ConversationActivity extends BriarActivity
|
|||||||
groupInvitationManager.respondToInvitation(contactId, id, accept);
|
groupInvitationManager.respondToInvitation(contactId, id, accept);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ListenableFutureTask<String> getContactNameTask() {
|
@Nullable
|
||||||
if (!contactNameTaskStarted.getAndSet(true))
|
@Override
|
||||||
runOnDbThread(contactNameTask);
|
public String getBody(MessageId m) {
|
||||||
return contactNameTask;
|
String body = bodyCache.get(m);
|
||||||
|
if (body == null) loadMessageBody(m);
|
||||||
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +1,20 @@
|
|||||||
package org.briarproject.briar.android.contact;
|
package org.briarproject.briar.android.contact;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.support.annotation.LayoutRes;
|
import android.support.annotation.LayoutRes;
|
||||||
import android.support.annotation.StringRes;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.briar.R;
|
|
||||||
import org.briarproject.briar.android.contact.ConversationRequestItem.RequestType;
|
|
||||||
import org.briarproject.briar.api.blog.BlogInvitationRequest;
|
|
||||||
import org.briarproject.briar.api.blog.BlogInvitationResponse;
|
|
||||||
import org.briarproject.briar.api.client.BaseMessageHeader;
|
|
||||||
import org.briarproject.briar.api.forum.ForumInvitationRequest;
|
|
||||||
import org.briarproject.briar.api.forum.ForumInvitationResponse;
|
|
||||||
import org.briarproject.briar.api.introduction.IntroductionRequest;
|
|
||||||
import org.briarproject.briar.api.introduction.IntroductionResponse;
|
|
||||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
|
||||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
|
|
||||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
|
|
||||||
import org.briarproject.briar.api.sharing.InvitationRequest;
|
|
||||||
import org.briarproject.briar.api.sharing.InvitationResponse;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.BLOG;
|
|
||||||
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.FORUM;
|
|
||||||
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.GROUP;
|
|
||||||
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.INTRODUCTION;
|
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
abstract class ConversationItem {
|
abstract class ConversationItem {
|
||||||
|
|
||||||
protected @Nullable String body;
|
@Nullable
|
||||||
|
protected String body;
|
||||||
private final MessageId id;
|
private final MessageId id;
|
||||||
private final GroupId groupId;
|
private final GroupId groupId;
|
||||||
private final long time;
|
private final long time;
|
||||||
@@ -78,216 +58,4 @@ abstract class ConversationItem {
|
|||||||
|
|
||||||
@LayoutRes
|
@LayoutRes
|
||||||
abstract public int getLayout();
|
abstract public int getLayout();
|
||||||
|
|
||||||
static ConversationItem from(PrivateMessageHeader h) {
|
|
||||||
if (h.isLocal()) {
|
|
||||||
return new ConversationMessageOutItem(h);
|
|
||||||
} else {
|
|
||||||
return new ConversationMessageInItem(h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ConversationItem from(Context ctx, String contactName,
|
|
||||||
IntroductionRequest ir) {
|
|
||||||
if (ir.isLocal()) {
|
|
||||||
String text = ctx.getString(R.string.introduction_request_sent,
|
|
||||||
contactName, ir.getName());
|
|
||||||
return new ConversationNoticeOutItem(ir.getMessageId(),
|
|
||||||
ir.getGroupId(), text, ir.getMessage(), ir.getTimestamp(),
|
|
||||||
ir.isSent(), ir.isSeen());
|
|
||||||
} else {
|
|
||||||
String text;
|
|
||||||
if (ir.wasAnswered()) {
|
|
||||||
text = ctx.getString(
|
|
||||||
R.string.introduction_request_answered_received,
|
|
||||||
contactName, ir.getName());
|
|
||||||
} else if (ir.contactExists()){
|
|
||||||
text = ctx.getString(
|
|
||||||
R.string.introduction_request_exists_received,
|
|
||||||
contactName, ir.getName());
|
|
||||||
} else {
|
|
||||||
text = ctx.getString(R.string.introduction_request_received,
|
|
||||||
contactName, ir.getName());
|
|
||||||
}
|
|
||||||
return new ConversationRequestItem(ir.getMessageId(),
|
|
||||||
ir.getGroupId(), INTRODUCTION, ir.getSessionId(), text,
|
|
||||||
ir.getMessage(), ir.getTimestamp(), ir.isRead(), null,
|
|
||||||
ir.wasAnswered(), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ConversationItem from(Context ctx, String contactName,
|
|
||||||
IntroductionResponse ir) {
|
|
||||||
if (ir.isLocal()) {
|
|
||||||
String text;
|
|
||||||
if (ir.wasAccepted()) {
|
|
||||||
text = ctx.getString(
|
|
||||||
R.string.introduction_response_accepted_sent,
|
|
||||||
ir.getName());
|
|
||||||
text += "\n\n" + ctx.getString(
|
|
||||||
R.string.introduction_response_accepted_sent_info,
|
|
||||||
ir.getName());
|
|
||||||
} else {
|
|
||||||
text = ctx.getString(
|
|
||||||
R.string.introduction_response_declined_sent,
|
|
||||||
ir.getName());
|
|
||||||
}
|
|
||||||
return new ConversationNoticeOutItem(ir.getMessageId(),
|
|
||||||
ir.getGroupId(), text, null, ir.getTimestamp(), ir.isSent(),
|
|
||||||
ir.isSeen());
|
|
||||||
} else {
|
|
||||||
String text;
|
|
||||||
if (ir.wasAccepted()) {
|
|
||||||
text = ctx.getString(
|
|
||||||
R.string.introduction_response_accepted_received,
|
|
||||||
contactName, ir.getName());
|
|
||||||
} else {
|
|
||||||
if (ir.isIntroducer()) {
|
|
||||||
text = ctx.getString(
|
|
||||||
R.string.introduction_response_declined_received,
|
|
||||||
contactName, ir.getName());
|
|
||||||
} else {
|
|
||||||
text = ctx.getString(
|
|
||||||
R.string.introduction_response_declined_received_by_introducee,
|
|
||||||
contactName, ir.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new ConversationNoticeInItem(ir.getMessageId(),
|
|
||||||
ir.getGroupId(), text, null, ir.getTimestamp(),
|
|
||||||
ir.isRead());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ConversationItem from(Context ctx, String contactName,
|
|
||||||
InvitationRequest ir) {
|
|
||||||
if (ir.isLocal()) {
|
|
||||||
String text;
|
|
||||||
if (ir instanceof ForumInvitationRequest) {
|
|
||||||
text = ctx.getString(R.string.forum_invitation_sent,
|
|
||||||
((ForumInvitationRequest) ir).getForumName(),
|
|
||||||
contactName);
|
|
||||||
} else if (ir instanceof BlogInvitationRequest) {
|
|
||||||
text = ctx.getString(R.string.blogs_sharing_invitation_sent,
|
|
||||||
((BlogInvitationRequest) ir).getBlogAuthorName(),
|
|
||||||
contactName);
|
|
||||||
} else if (ir instanceof GroupInvitationRequest) {
|
|
||||||
text = ctx.getString(
|
|
||||||
R.string.groups_invitations_invitation_sent,
|
|
||||||
contactName, ir.getShareable().getName());
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("Unknown InvitationRequest");
|
|
||||||
}
|
|
||||||
return new ConversationNoticeOutItem(ir.getId(), ir.getGroupId(),
|
|
||||||
text, ir.getMessage(), ir.getTimestamp(), ir.isSent(),
|
|
||||||
ir.isSeen());
|
|
||||||
} else {
|
|
||||||
String text;
|
|
||||||
RequestType type;
|
|
||||||
if (ir instanceof ForumInvitationRequest) {
|
|
||||||
text = ctx.getString(R.string.forum_invitation_received,
|
|
||||||
contactName,
|
|
||||||
((ForumInvitationRequest) ir).getForumName());
|
|
||||||
type = FORUM;
|
|
||||||
} else if (ir instanceof BlogInvitationRequest) {
|
|
||||||
text = ctx.getString(R.string.blogs_sharing_invitation_received,
|
|
||||||
contactName,
|
|
||||||
((BlogInvitationRequest) ir).getBlogAuthorName());
|
|
||||||
type = BLOG;
|
|
||||||
} else if (ir instanceof GroupInvitationRequest) {
|
|
||||||
text = ctx.getString(
|
|
||||||
R.string.groups_invitations_invitation_received,
|
|
||||||
contactName, ir.getShareable().getName());
|
|
||||||
type = GROUP;
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("Unknown InvitationRequest");
|
|
||||||
}
|
|
||||||
return new ConversationRequestItem(ir.getId(),
|
|
||||||
ir.getGroupId(), type, ir.getSessionId(), text,
|
|
||||||
ir.getMessage(), ir.getTimestamp(), ir.isRead(),
|
|
||||||
ir.getShareable().getId(), !ir.isAvailable(),
|
|
||||||
ir.canBeOpened());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ConversationItem from(Context ctx, String contactName,
|
|
||||||
InvitationResponse ir) {
|
|
||||||
@StringRes int res;
|
|
||||||
if (ir.isLocal()) {
|
|
||||||
if (ir.wasAccepted()) {
|
|
||||||
if (ir instanceof ForumInvitationResponse) {
|
|
||||||
res = R.string.forum_invitation_response_accepted_sent;
|
|
||||||
} else if (ir instanceof BlogInvitationResponse) {
|
|
||||||
res = R.string.blogs_sharing_response_accepted_sent;
|
|
||||||
} else if (ir instanceof GroupInvitationResponse) {
|
|
||||||
res = R.string.groups_invitations_response_accepted_sent;
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Unknown InvitationResponse");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ir instanceof ForumInvitationResponse) {
|
|
||||||
res = R.string.forum_invitation_response_declined_sent;
|
|
||||||
} else if (ir instanceof BlogInvitationResponse) {
|
|
||||||
res = R.string.blogs_sharing_response_declined_sent;
|
|
||||||
} else if (ir instanceof GroupInvitationResponse) {
|
|
||||||
res = R.string.groups_invitations_response_declined_sent;
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Unknown InvitationResponse");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String text = ctx.getString(res, contactName);
|
|
||||||
return new ConversationNoticeOutItem(ir.getId(), ir.getGroupId(),
|
|
||||||
text, null, ir.getTimestamp(), ir.isSent(), ir.isSeen());
|
|
||||||
} else {
|
|
||||||
if (ir.wasAccepted()) {
|
|
||||||
if (ir instanceof ForumInvitationResponse) {
|
|
||||||
res = R.string.forum_invitation_response_accepted_received;
|
|
||||||
} else if (ir instanceof BlogInvitationResponse) {
|
|
||||||
res = R.string.blogs_sharing_response_accepted_received;
|
|
||||||
} else if (ir instanceof GroupInvitationResponse) {
|
|
||||||
res = R.string.groups_invitations_response_accepted_received;
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Unknown InvitationResponse");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ir instanceof ForumInvitationResponse) {
|
|
||||||
res = R.string.forum_invitation_response_declined_received;
|
|
||||||
} else if (ir instanceof BlogInvitationResponse) {
|
|
||||||
res = R.string.blogs_sharing_response_declined_received;
|
|
||||||
} else if (ir instanceof GroupInvitationResponse) {
|
|
||||||
res = R.string.groups_invitations_response_declined_received;
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Unknown InvitationResponse");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String text = ctx.getString(res, contactName);
|
|
||||||
return new ConversationNoticeInItem(ir.getId(), ir.getGroupId(),
|
|
||||||
text, null, ir.getTimestamp(), ir.isRead());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method should not be used to display the resulting ConversationItem
|
|
||||||
* in the UI, but only to update list information based on the
|
|
||||||
* BaseMessageHeader.
|
|
||||||
**/
|
|
||||||
static ConversationItem from(Context ctx, BaseMessageHeader h) {
|
|
||||||
if (h instanceof PrivateMessageHeader) {
|
|
||||||
return from((PrivateMessageHeader) h);
|
|
||||||
} else if(h instanceof IntroductionRequest) {
|
|
||||||
return from(ctx, "", (IntroductionRequest) h);
|
|
||||||
} else if(h instanceof IntroductionResponse) {
|
|
||||||
return from(ctx, "", (IntroductionResponse) h);
|
|
||||||
} else if(h instanceof InvitationRequest) {
|
|
||||||
return from(ctx, "", (InvitationRequest) h);
|
|
||||||
} else if(h instanceof InvitationResponse) {
|
|
||||||
return from(ctx, "", (InvitationResponse) h);
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("Unknown message header");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.api.messaging.PrivateResponse;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
@@ -17,13 +18,17 @@ class ConversationNoticeInItem extends ConversationItem {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private final String msgText;
|
private final String msgText;
|
||||||
|
|
||||||
ConversationNoticeInItem(MessageId id, GroupId groupId,
|
ConversationNoticeInItem(MessageId id, GroupId groupId, String text,
|
||||||
String text, @Nullable String msgText, long time,
|
@Nullable String msgText, long time, boolean read) {
|
||||||
boolean read) {
|
|
||||||
super(id, groupId, text, time, read);
|
super(id, groupId, text, time, read);
|
||||||
this.msgText = msgText;
|
this.msgText = msgText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConversationNoticeInItem(String text, PrivateResponse r) {
|
||||||
|
super(r.getId(), r.getGroupId(), text, r.getTimestamp(), r.isRead());
|
||||||
|
this.msgText = null;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
String getMsgText() {
|
String getMsgText() {
|
||||||
return msgText;
|
return msgText;
|
||||||
@@ -39,5 +44,4 @@ class ConversationNoticeInItem extends ConversationItem {
|
|||||||
public int getLayout() {
|
public int getLayout() {
|
||||||
return R.layout.list_item_conversation_notice_in;
|
return R.layout.list_item_conversation_notice_in;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package org.briarproject.briar.android.contact;
|
|||||||
import android.support.annotation.LayoutRes;
|
import android.support.annotation.LayoutRes;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.api.messaging.PrivateRequest;
|
||||||
|
import org.briarproject.briar.api.messaging.PrivateResponse;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
@@ -17,11 +17,16 @@ class ConversationNoticeOutItem extends ConversationOutItem {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private final String msgText;
|
private final String msgText;
|
||||||
|
|
||||||
ConversationNoticeOutItem(MessageId id, GroupId groupId,
|
ConversationNoticeOutItem(String text, PrivateRequest r) {
|
||||||
String text, @Nullable String msgText, long time,
|
super(r.getId(), r.getGroupId(), text, r.getTimestamp(), r.isSent(),
|
||||||
boolean sent, boolean seen) {
|
r.isSeen());
|
||||||
super(id, groupId, text, time, sent, seen);
|
this.msgText = r.getMessage();
|
||||||
this.msgText = msgText;
|
}
|
||||||
|
|
||||||
|
ConversationNoticeOutItem(String text, PrivateResponse r) {
|
||||||
|
super(r.getId(), r.getGroupId(), text, r.getTimestamp(), r.isSent(),
|
||||||
|
r.isSeen());
|
||||||
|
this.msgText = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -34,5 +39,4 @@ class ConversationNoticeOutItem extends ConversationOutItem {
|
|||||||
public int getLayout() {
|
public int getLayout() {
|
||||||
return R.layout.list_item_conversation_notice_out;
|
return R.layout.list_item_conversation_notice_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import android.support.annotation.LayoutRes;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.api.client.SessionId;
|
import org.briarproject.briar.api.client.SessionId;
|
||||||
|
import org.briarproject.briar.api.messaging.PrivateRequest;
|
||||||
|
import org.briarproject.briar.api.sharing.InvitationRequest;
|
||||||
|
import org.briarproject.briar.api.sharing.Shareable;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
@@ -15,7 +17,7 @@ import javax.annotation.concurrent.NotThreadSafe;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class ConversationRequestItem extends ConversationNoticeInItem {
|
class ConversationRequestItem extends ConversationNoticeInItem {
|
||||||
|
|
||||||
enum RequestType { INTRODUCTION, FORUM, BLOG, GROUP }
|
enum RequestType {INTRODUCTION, FORUM, BLOG, GROUP}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private final GroupId requestedGroupId;
|
private final GroupId requestedGroupId;
|
||||||
@@ -24,17 +26,19 @@ class ConversationRequestItem extends ConversationNoticeInItem {
|
|||||||
private final boolean canBeOpened;
|
private final boolean canBeOpened;
|
||||||
private boolean answered;
|
private boolean answered;
|
||||||
|
|
||||||
ConversationRequestItem(MessageId id, GroupId groupId,
|
ConversationRequestItem(String text, RequestType type, PrivateRequest r) {
|
||||||
RequestType requestType, SessionId sessionId, String text,
|
super(r.getId(), r.getGroupId(), text, r.getMessage(),
|
||||||
@Nullable String msgText, long time, boolean read,
|
r.getTimestamp(), r.isRead());
|
||||||
@Nullable GroupId requestedGroupId, boolean answered,
|
this.requestType = type;
|
||||||
boolean canBeOpened) {
|
this.sessionId = r.getSessionId();
|
||||||
super(id, groupId, text, msgText, time, read);
|
this.answered = r.wasAnswered();
|
||||||
this.requestType = requestType;
|
if (r instanceof InvitationRequest) {
|
||||||
this.sessionId = sessionId;
|
this.requestedGroupId = ((Shareable) r.getNameable()).getId();
|
||||||
this.requestedGroupId = requestedGroupId;
|
this.canBeOpened = ((InvitationRequest) r).canBeOpened();
|
||||||
this.answered = answered;
|
} else {
|
||||||
this.canBeOpened = canBeOpened;
|
this.requestedGroupId = null;
|
||||||
|
this.canBeOpened = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestType getRequestType() {
|
RequestType getRequestType() {
|
||||||
@@ -54,8 +58,8 @@ class ConversationRequestItem extends ConversationNoticeInItem {
|
|||||||
return answered;
|
return answered;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAnswered(boolean answered) {
|
void setAnswered() {
|
||||||
this.answered = answered;
|
this.answered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canBeOpened() {
|
public boolean canBeOpened() {
|
||||||
@@ -67,5 +71,4 @@ class ConversationRequestItem extends ConversationNoticeInItem {
|
|||||||
public int getLayout() {
|
public int getLayout() {
|
||||||
return R.layout.list_item_conversation_request;
|
return R.layout.list_item_conversation_request;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,246 @@
|
|||||||
|
package org.briarproject.briar.android.contact;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.annotation.UiThread;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
import org.briarproject.briar.api.blog.BlogInvitationRequest;
|
||||||
|
import org.briarproject.briar.api.blog.BlogInvitationResponse;
|
||||||
|
import org.briarproject.briar.api.forum.ForumInvitationRequest;
|
||||||
|
import org.briarproject.briar.api.forum.ForumInvitationResponse;
|
||||||
|
import org.briarproject.briar.api.introduction.IntroductionRequest;
|
||||||
|
import org.briarproject.briar.api.introduction.IntroductionResponse;
|
||||||
|
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
||||||
|
import org.briarproject.briar.api.messaging.PrivateMessageVisitor;
|
||||||
|
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
|
||||||
|
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.BLOG;
|
||||||
|
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.FORUM;
|
||||||
|
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.GROUP;
|
||||||
|
import static org.briarproject.briar.android.contact.ConversationRequestItem.RequestType.INTRODUCTION;
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
@NotNullByDefault
|
||||||
|
class ConversationVisitor implements PrivateMessageVisitor<ConversationItem> {
|
||||||
|
|
||||||
|
private final Context ctx;
|
||||||
|
private final BodyCache bodyCache;
|
||||||
|
private final LiveData<String> contactName;
|
||||||
|
|
||||||
|
ConversationVisitor(Context ctx, BodyCache bodyCache,
|
||||||
|
LiveData<String> contactName) {
|
||||||
|
this.ctx = ctx;
|
||||||
|
this.bodyCache = bodyCache;
|
||||||
|
this.contactName = contactName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConversationItem visitPrivateMessageHeader(PrivateMessageHeader h) {
|
||||||
|
ConversationItem item;
|
||||||
|
if (h.isLocal()) item = new ConversationMessageOutItem(h);
|
||||||
|
else item = new ConversationMessageInItem(h);
|
||||||
|
String body = bodyCache.getBody(h.getId());
|
||||||
|
if (body != null) item.setBody(body);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConversationItem visitBlogInvitationRequest(
|
||||||
|
BlogInvitationRequest r) {
|
||||||
|
if (r.isLocal()) {
|
||||||
|
String text = ctx.getString(R.string.blogs_sharing_invitation_sent,
|
||||||
|
r.getName(), contactName.getValue());
|
||||||
|
return new ConversationNoticeOutItem(text, r);
|
||||||
|
} else {
|
||||||
|
String text = ctx.getString(
|
||||||
|
R.string.blogs_sharing_invitation_received,
|
||||||
|
contactName.getValue(), r.getName());
|
||||||
|
return new ConversationRequestItem(text, BLOG, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConversationItem visitBlogInvitationResponse(
|
||||||
|
BlogInvitationResponse r) {
|
||||||
|
if (r.isLocal()) {
|
||||||
|
String text;
|
||||||
|
if (r.wasAccepted()) {
|
||||||
|
text = ctx.getString(
|
||||||
|
R.string.blogs_sharing_response_accepted_sent,
|
||||||
|
contactName.getValue());
|
||||||
|
} else {
|
||||||
|
text = ctx.getString(
|
||||||
|
R.string.blogs_sharing_response_declined_sent,
|
||||||
|
contactName.getValue());
|
||||||
|
}
|
||||||
|
return new ConversationNoticeOutItem(text, r);
|
||||||
|
} else {
|
||||||
|
String text;
|
||||||
|
if (r.wasAccepted()) {
|
||||||
|
text = ctx.getString(
|
||||||
|
R.string.blogs_sharing_response_accepted_received,
|
||||||
|
contactName.getValue());
|
||||||
|
} else {
|
||||||
|
text = ctx.getString(
|
||||||
|
R.string.blogs_sharing_response_declined_received,
|
||||||
|
contactName.getValue());
|
||||||
|
}
|
||||||
|
return new ConversationNoticeInItem(text, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConversationItem visitForumInvitationRequest(
|
||||||
|
ForumInvitationRequest r) {
|
||||||
|
if (r.isLocal()) {
|
||||||
|
String text = ctx.getString(R.string.forum_invitation_sent,
|
||||||
|
r.getName(), contactName.getValue());
|
||||||
|
return new ConversationNoticeOutItem(text, r);
|
||||||
|
} else {
|
||||||
|
String text = ctx.getString(
|
||||||
|
R.string.forum_invitation_received,
|
||||||
|
contactName.getValue(), r.getName());
|
||||||
|
return new ConversationRequestItem(text, FORUM, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConversationItem visitForumInvitationResponse(
|
||||||
|
ForumInvitationResponse r) {
|
||||||
|
if (r.isLocal()) {
|
||||||
|
String text;
|
||||||
|
if (r.wasAccepted()) {
|
||||||
|
text = ctx.getString(
|
||||||
|
R.string.forum_invitation_response_accepted_sent,
|
||||||
|
contactName.getValue());
|
||||||
|
} else {
|
||||||
|
text = ctx.getString(
|
||||||
|
R.string.forum_invitation_response_declined_sent,
|
||||||
|
contactName.getValue());
|
||||||
|
}
|
||||||
|
return new ConversationNoticeOutItem(text, r);
|
||||||
|
} else {
|
||||||
|
String text;
|
||||||
|
if (r.wasAccepted()) {
|
||||||
|
text = ctx.getString(
|
||||||
|
R.string.forum_invitation_response_accepted_received,
|
||||||
|
contactName.getValue());
|
||||||
|
} else {
|
||||||
|
text = ctx.getString(
|
||||||
|
R.string.forum_invitation_response_declined_received,
|
||||||
|
contactName.getValue());
|
||||||
|
}
|
||||||
|
return new ConversationNoticeInItem(text, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConversationItem visitGroupInvitationRequest(
|
||||||
|
GroupInvitationRequest r) {
|
||||||
|
if (r.isLocal()) {
|
||||||
|
String text = ctx.getString(
|
||||||
|
R.string.groups_invitations_invitation_sent,
|
||||||
|
contactName.getValue(), r.getName());
|
||||||
|
return new ConversationNoticeOutItem(text, r);
|
||||||
|
} else {
|
||||||
|
String text = ctx.getString(
|
||||||
|
R.string.groups_invitations_invitation_received,
|
||||||
|
contactName.getValue(), r.getName());
|
||||||
|
return new ConversationRequestItem(text, GROUP, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConversationItem visitGroupInvitationResponse(
|
||||||
|
GroupInvitationResponse r) {
|
||||||
|
if (r.isLocal()) {
|
||||||
|
String text;
|
||||||
|
if (r.wasAccepted()) {
|
||||||
|
text = ctx.getString(
|
||||||
|
R.string.groups_invitations_response_accepted_sent,
|
||||||
|
contactName.getValue());
|
||||||
|
} else {
|
||||||
|
text = ctx.getString(
|
||||||
|
R.string.groups_invitations_response_declined_sent,
|
||||||
|
contactName.getValue());
|
||||||
|
}
|
||||||
|
return new ConversationNoticeOutItem(text, r);
|
||||||
|
} else {
|
||||||
|
String text;
|
||||||
|
if (r.wasAccepted()) {
|
||||||
|
text = ctx.getString(
|
||||||
|
R.string.groups_invitations_response_accepted_received,
|
||||||
|
contactName.getValue());
|
||||||
|
} else {
|
||||||
|
text = ctx.getString(
|
||||||
|
R.string.groups_invitations_response_declined_received,
|
||||||
|
contactName.getValue());
|
||||||
|
}
|
||||||
|
return new ConversationNoticeInItem(text, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConversationItem visitIntroductionRequest(IntroductionRequest r) {
|
||||||
|
if (r.isLocal()) {
|
||||||
|
String text = ctx.getString(R.string.introduction_request_sent,
|
||||||
|
contactName.getValue(), r.getName());
|
||||||
|
return new ConversationNoticeOutItem(text, r);
|
||||||
|
} else {
|
||||||
|
String text = ctx.getString(R.string.introduction_request_received,
|
||||||
|
contactName.getValue(), r.getName());
|
||||||
|
return new ConversationRequestItem(text, INTRODUCTION, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConversationItem visitIntroductionResponse(IntroductionResponse r) {
|
||||||
|
if (r.isLocal()) {
|
||||||
|
String text;
|
||||||
|
if (r.wasAccepted()) {
|
||||||
|
String introducee = r.getIntroducedAuthor().getName();
|
||||||
|
text = ctx.getString(
|
||||||
|
R.string.introduction_response_accepted_sent,
|
||||||
|
introducee)
|
||||||
|
+ "\n\n" + ctx.getString(
|
||||||
|
R.string.introduction_response_accepted_sent_info,
|
||||||
|
introducee);
|
||||||
|
} else {
|
||||||
|
text = ctx.getString(
|
||||||
|
R.string.introduction_response_declined_sent,
|
||||||
|
r.getIntroducedAuthor().getName());
|
||||||
|
}
|
||||||
|
return new ConversationNoticeOutItem(text, r);
|
||||||
|
} else {
|
||||||
|
String text;
|
||||||
|
if (r.wasAccepted()) {
|
||||||
|
text = ctx.getString(
|
||||||
|
R.string.introduction_response_accepted_received,
|
||||||
|
contactName.getValue(),
|
||||||
|
r.getIntroducedAuthor().getName());
|
||||||
|
} else if (r.isIntroducer()) {
|
||||||
|
text = ctx.getString(
|
||||||
|
R.string.introduction_response_declined_received,
|
||||||
|
contactName.getValue(),
|
||||||
|
r.getIntroducedAuthor().getName());
|
||||||
|
} else {
|
||||||
|
text = ctx.getString(
|
||||||
|
R.string.introduction_response_declined_received_by_introducee,
|
||||||
|
contactName.getValue(),
|
||||||
|
r.getIntroducedAuthor().getName());
|
||||||
|
}
|
||||||
|
return new ConversationNoticeInItem(text, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BodyCache {
|
||||||
|
@Nullable
|
||||||
|
String getBody(MessageId m);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -84,11 +84,10 @@ class ForumControllerImpl extends
|
|||||||
} else if (e instanceof ForumInvitationResponseReceivedEvent) {
|
} else if (e instanceof ForumInvitationResponseReceivedEvent) {
|
||||||
ForumInvitationResponseReceivedEvent f =
|
ForumInvitationResponseReceivedEvent f =
|
||||||
(ForumInvitationResponseReceivedEvent) e;
|
(ForumInvitationResponseReceivedEvent) e;
|
||||||
ForumInvitationResponse r =
|
ForumInvitationResponse r = f.getMessageHeader();
|
||||||
(ForumInvitationResponse) f.getResponse();
|
|
||||||
if (r.getShareableId().equals(getGroupId()) && r.wasAccepted()) {
|
if (r.getShareableId().equals(getGroupId()) && r.wasAccepted()) {
|
||||||
LOG.info("Forum invitation was accepted");
|
LOG.info("Forum invitation was accepted");
|
||||||
onForumInvitationAccepted(r.getContactId());
|
onForumInvitationAccepted(f.getContactId());
|
||||||
}
|
}
|
||||||
} else if (e instanceof ContactLeftShareableEvent) {
|
} else if (e instanceof ContactLeftShareableEvent) {
|
||||||
ContactLeftShareableEvent c = (ContactLeftShareableEvent) e;
|
ContactLeftShareableEvent c = (ContactLeftShareableEvent) e;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.briar.android.introduction;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -82,8 +83,8 @@ public class IntroductionMessageFragment extends BaseFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||||
Bundle savedInstanceState) {
|
ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
|
||||||
// change toolbar text
|
// change toolbar text
|
||||||
ActionBar actionBar = introductionActivity.getSupportActionBar();
|
ActionBar actionBar = introductionActivity.getSupportActionBar();
|
||||||
@@ -182,7 +183,7 @@ public class IntroductionMessageFragment extends BaseFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSendClick(String text) {
|
public void onSendClick(@NonNull String text) {
|
||||||
// disable button to prevent accidental double invitations
|
// disable button to prevent accidental double invitations
|
||||||
ui.message.setSendButtonEnabled(false);
|
ui.message.setSendButtonEnabled(false);
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import com.google.zxing.Result;
|
import com.google.zxing.Result;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.UnsupportedVersionException;
|
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementResult;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementResult;
|
||||||
@@ -23,6 +22,7 @@ import org.briarproject.bramble.api.keyagreement.KeyAgreementTask;
|
|||||||
import org.briarproject.bramble.api.keyagreement.Payload;
|
import org.briarproject.bramble.api.keyagreement.Payload;
|
||||||
import org.briarproject.bramble.api.keyagreement.PayloadEncoder;
|
import org.briarproject.bramble.api.keyagreement.PayloadEncoder;
|
||||||
import org.briarproject.bramble.api.keyagreement.PayloadParser;
|
import org.briarproject.bramble.api.keyagreement.PayloadParser;
|
||||||
|
import org.briarproject.bramble.api.keyagreement.UnsupportedVersionException;
|
||||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementAbortedEvent;
|
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementAbortedEvent;
|
||||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementFailedEvent;
|
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementFailedEvent;
|
||||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementFinishedEvent;
|
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementFinishedEvent;
|
||||||
@@ -244,8 +244,14 @@ public class KeyAgreementFragment extends BaseEventFragment
|
|||||||
task.connectAndRunProtocol(remotePayload);
|
task.connectAndRunProtocol(remotePayload);
|
||||||
} catch (UnsupportedVersionException e) {
|
} catch (UnsupportedVersionException e) {
|
||||||
reset();
|
reset();
|
||||||
String msg = getString(R.string.qr_code_unsupported,
|
String msg;
|
||||||
getString(R.string.app_name));
|
if (e.isTooOld()) {
|
||||||
|
msg = getString(R.string.qr_code_too_old,
|
||||||
|
getString(R.string.app_name));
|
||||||
|
} else {
|
||||||
|
msg = getString(R.string.qr_code_too_new,
|
||||||
|
getString(R.string.app_name));
|
||||||
|
}
|
||||||
showNextFragment(ContactExchangeErrorFragment.newInstance(msg));
|
showNextFragment(ContactExchangeErrorFragment.newInstance(msg));
|
||||||
} catch (CameraException e) {
|
} catch (CameraException e) {
|
||||||
logCameraExceptionAndFinish(e);
|
logCameraExceptionAndFinish(e);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import android.graphics.drawable.ClipDrawable;
|
|||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.graphics.drawable.LayerDrawable;
|
import android.graphics.drawable.LayerDrawable;
|
||||||
import android.graphics.drawable.ShapeDrawable;
|
import android.graphics.drawable.ShapeDrawable;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@ import static android.graphics.Paint.Style.FILL;
|
|||||||
import static android.graphics.Paint.Style.STROKE;
|
import static android.graphics.Paint.Style.STROKE;
|
||||||
import static android.graphics.drawable.ClipDrawable.HORIZONTAL;
|
import static android.graphics.drawable.ClipDrawable.HORIZONTAL;
|
||||||
import static android.view.Gravity.LEFT;
|
import static android.view.Gravity.LEFT;
|
||||||
|
import static android.view.Gravity.START;
|
||||||
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_STRONG;
|
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_STRONG;
|
||||||
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK;
|
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK;
|
||||||
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.STRONG;
|
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.STRONG;
|
||||||
@@ -35,11 +37,11 @@ public class StrengthMeter extends ProgressBar {
|
|||||||
this(context, null);
|
this(context, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public StrengthMeter(Context context, AttributeSet attrs) {
|
public StrengthMeter(Context context, @Nullable AttributeSet attrs) {
|
||||||
super(context, attrs, android.R.attr.progressBarStyleHorizontal);
|
super(context, attrs, android.R.attr.progressBarStyleHorizontal);
|
||||||
bar = new ShapeDrawable();
|
bar = new ShapeDrawable();
|
||||||
bar.getPaint().setColor(RED);
|
bar.getPaint().setColor(RED);
|
||||||
ClipDrawable clip = new ClipDrawable(bar, LEFT, HORIZONTAL);
|
ClipDrawable clip = new ClipDrawable(bar, LEFT & START, HORIZONTAL);
|
||||||
ShapeDrawable background = new ShapeDrawable();
|
ShapeDrawable background = new ShapeDrawable();
|
||||||
Paint p = background.getPaint();
|
Paint p = background.getPaint();
|
||||||
p.setStyle(FILL);
|
p.setStyle(FILL);
|
||||||
@@ -50,6 +52,7 @@ public class StrengthMeter extends ProgressBar {
|
|||||||
Drawable[] layers = new Drawable[] { clip, background };
|
Drawable[] layers = new Drawable[] { clip, background };
|
||||||
setProgressDrawable(new LayerDrawable(layers));
|
setProgressDrawable(new LayerDrawable(layers));
|
||||||
setIndeterminate(false);
|
setIndeterminate(false);
|
||||||
|
if (isInEditMode()) setStrength(STRONG);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package org.briarproject.briar.android.panic;
|
||||||
|
|
||||||
|
import info.guardianproject.trustedintents.ApkSignaturePin;
|
||||||
|
|
||||||
|
// needs to be public, because TrustedIntents will instantiate
|
||||||
|
public final class FDroidSignaturePin extends ApkSignaturePin {
|
||||||
|
|
||||||
|
public FDroidSignaturePin() {
|
||||||
|
this.fingerprints = new String[] {
|
||||||
|
"927f7e38b6acbecd84e02dace33efa9a7a2f0979750f28f585688ee38b3a4e28"};
|
||||||
|
this.certificates = new byte[][] {
|
||||||
|
{48, -126, 3, 95, 48, -126, 2, 71, -96, 3, 2, 1, 2, 2, 4, 28,
|
||||||
|
-30, 107, -102, 48, 13, 6, 9, 42, -122, 72, -122, -9,
|
||||||
|
13, 1, 1, 11, 5, 0, 48, 96, 49, 11, 48, 9, 6, 3, 85, 4,
|
||||||
|
6, 19, 2, 85, 75, 49, 12, 48, 10, 6, 3, 85, 4, 8, 19, 3,
|
||||||
|
79, 82, 71, 49, 12, 48, 10, 6, 3, 85, 4, 7, 19, 3, 79,
|
||||||
|
82, 71, 49, 19, 48, 17, 6, 3, 85, 4, 10, 19, 10, 102,
|
||||||
|
100, 114, 111, 105, 100, 46, 111, 114, 103, 49, 15, 48,
|
||||||
|
13, 6, 3, 85, 4, 11, 19, 6, 70, 68, 114, 111, 105, 100,
|
||||||
|
49, 15, 48, 13, 6, 3, 85, 4, 3, 19, 6, 70, 68, 114, 111,
|
||||||
|
105, 100, 48, 30, 23, 13, 49, 55, 49, 50, 48, 55, 49,
|
||||||
|
55, 51, 48, 52, 50, 90, 23, 13, 52, 53, 48, 52, 50, 52,
|
||||||
|
49, 55, 51, 48, 52, 50, 90, 48, 96, 49, 11, 48, 9, 6, 3,
|
||||||
|
85, 4, 6, 19, 2, 85, 75, 49, 12, 48, 10, 6, 3, 85, 4, 8,
|
||||||
|
19, 3, 79, 82, 71, 49, 12, 48, 10, 6, 3, 85, 4, 7, 19,
|
||||||
|
3, 79, 82, 71, 49, 19, 48, 17, 6, 3, 85, 4, 10, 19, 10,
|
||||||
|
102, 100, 114, 111, 105, 100, 46, 111, 114, 103, 49, 15,
|
||||||
|
48, 13, 6, 3, 85, 4, 11, 19, 6, 70, 68, 114, 111, 105,
|
||||||
|
100, 49, 15, 48, 13, 6, 3, 85, 4, 3, 19, 6, 70, 68, 114,
|
||||||
|
111, 105, 100, 48, -126, 1, 34, 48, 13, 6, 9, 42, -122,
|
||||||
|
72, -122, -9, 13, 1, 1, 1, 5, 0, 3, -126, 1, 15, 0, 48,
|
||||||
|
-126, 1, 10, 2, -126, 1, 1, 0, -107, -115, -106, 1, -26,
|
||||||
|
72, -105, -99, 62, 3, -55, 34, 99, -112, -68, -20, -115,
|
||||||
|
31, 34, 118, -50, 12, -32, -59, 74, -58, -37, -87, 21,
|
||||||
|
105, 36, -82, 13, -51, 66, 4, 55, -111, 13, -46, -7,
|
||||||
|
-69, -15, 36, 118, -7, 101, -86, 123, -83, -103, 110,
|
||||||
|
116, -54, 112, 46, 12, 96, -76, -48, -70, -33, -81, 52,
|
||||||
|
59, 73, 107, -126, -72, -25, 32, 93, 29, -20, 5, -41,
|
||||||
|
-27, 123, -9, 104, -31, -59, -1, -83, -93, 99, 85, -116,
|
||||||
|
-62, -55, 18, -63, 6, -51, -110, 33, 9, 7, -49, 102,
|
||||||
|
-20, -122, -124, -68, 93, -102, 31, 48, 86, 96, -99,
|
||||||
|
105, -52, 95, 12, 57, 99, 12, -24, 70, 40, -99, -20,
|
||||||
|
-21, -85, -70, -105, 95, 117, -31, 126, -126, -39, 46,
|
||||||
|
-62, 59, -23, -74, 108, -12, -56, -40, -96, 79, -37,
|
||||||
|
-82, 1, 99, -104, 48, -60, 92, 14, 109, 127, -22, 31,
|
||||||
|
115, -27, 108, 9, 92, 118, -45, 103, 117, 57, -50, -82,
|
||||||
|
114, -113, 68, -82, 87, 96, 111, 72, 65, -63, 12, 31,
|
||||||
|
-34, -31, -55, -101, 101, 101, 59, 73, -119, -122, 82,
|
||||||
|
28, 47, -108, -85, 59, 46, 89, -93, -1, 9, -11, -51, 63,
|
||||||
|
-44, 109, -76, -103, -26, -49, -80, 6, 52, -27, 73,
|
||||||
|
-104, 40, 2, -101, -124, 60, -52, -105, -70, -24, -62,
|
||||||
|
88, 38, 53, -99, -92, 31, 119, 26, 79, 60, -124, 25,
|
||||||
|
-115, -89, -115, -109, 0, 6, 122, -78, 116, 82, 3, 39,
|
||||||
|
-67, 45, -43, 17, -39, 2, 3, 1, 0, 1, -93, 33, 48, 31,
|
||||||
|
48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, 63, 109, -42,
|
||||||
|
-109, 25, 22, 7, -37, -22, -41, -38, 58, -56, 2, -68,
|
||||||
|
-38, -22, 65, -28, -60, 48, 13, 6, 9, 42, -122, 72,
|
||||||
|
-122, -9, 13, 1, 1, 11, 5, 0, 3, -126, 1, 1, 0, 94, 17,
|
||||||
|
31, 36, 85, -11, 85, 44, 19, -80, -20, -92, -118, 93,
|
||||||
|
40, 45, 96, 31, -3, -37, -110, -96, 102, 81, 61, -74,
|
||||||
|
-125, -117, -112, 58, -47, 17, 78, -18, 111, -116, 26,
|
||||||
|
-91, 73, 100, 84, -99, 21, 87, 73, -106, 108, -51, -125,
|
||||||
|
-21, 119, -88, -78, 2, 82, -109, -64, -9, -86, -112,
|
||||||
|
-115, 66, -86, 46, 71, 107, -65, 96, -102, 47, 35, -45,
|
||||||
|
-126, 33, 34, 121, -25, -85, -121, -56, -42, 22, -1,
|
||||||
|
-95, -86, 81, 100, -70, 113, 104, -73, 22, -19, 79, -19,
|
||||||
|
52, 62, 42, 76, -112, 94, -34, 42, -57, -75, -90, -58,
|
||||||
|
118, 127, -106, -39, 108, -56, -79, 103, -33, 22, 3, 47,
|
||||||
|
103, -76, -81, 53, -22, -44, -26, -102, 63, -99, 39, 38,
|
||||||
|
-108, 75, 33, 10, 25, -110, -125, -115, 114, -69, 73,
|
||||||
|
-112, 36, 74, 77, -82, -44, 29, -123, -8, -117, 71,
|
||||||
|
-105, 15, -109, 51, 22, 4, 80, 1, 43, 118, 121, -113,
|
||||||
|
-70, 83, -56, 82, -110, 4, -63, 16, -57, 126, -70, 81,
|
||||||
|
73, 61, 2, -61, 24, -14, -10, 4, -21, 90, 24, 66, 41,
|
||||||
|
-57, -60, -113, -18, -54, -1, 103, -75, 32, -64, 67,
|
||||||
|
103, 109, -79, -12, -113, -27, 114, 89, 116, 115, -13,
|
||||||
|
-123, -70, 61, -41, -46, -118, 29, -105, -97, -75, 39,
|
||||||
|
-51, 60, 88, 125, 55, -46, -95, 52, 57, 52, -115, 80,
|
||||||
|
44, 109, 119, -116, -62, -77, -74, -88, 41, 57, -65,
|
||||||
|
-71, -115, -67, 23, 66, -21, 56, 51, -91, 109}};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -31,13 +31,12 @@ public class PanicPreferencesFragment extends PreferenceFragmentCompat
|
|||||||
public static final String KEY_LOCK = "pref_key_lock";
|
public static final String KEY_LOCK = "pref_key_lock";
|
||||||
public static final String KEY_PANIC_APP = "pref_key_panic_app";
|
public static final String KEY_PANIC_APP = "pref_key_panic_app";
|
||||||
public static final String KEY_PURGE = "pref_key_purge";
|
public static final String KEY_PURGE = "pref_key_purge";
|
||||||
public static final String KEY_UNINSTALL = "pref_key_uninstall";
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(PanicPreferencesFragment.class.getName());
|
Logger.getLogger(PanicPreferencesFragment.class.getName());
|
||||||
|
|
||||||
private PackageManager pm;
|
private PackageManager pm;
|
||||||
private SwitchPreference lockPref, purgePref, uninstallPref;
|
private SwitchPreference lockPref, purgePref;
|
||||||
private ListPreference panicAppPref;
|
private ListPreference panicAppPref;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -49,7 +48,6 @@ public class PanicPreferencesFragment extends PreferenceFragmentCompat
|
|||||||
lockPref = (SwitchPreference) findPreference(KEY_LOCK);
|
lockPref = (SwitchPreference) findPreference(KEY_LOCK);
|
||||||
panicAppPref = (ListPreference) findPreference(KEY_PANIC_APP);
|
panicAppPref = (ListPreference) findPreference(KEY_PANIC_APP);
|
||||||
purgePref = (SwitchPreference) findPreference(KEY_PURGE);
|
purgePref = (SwitchPreference) findPreference(KEY_PURGE);
|
||||||
uninstallPref = (SwitchPreference) findPreference(KEY_UNINSTALL);
|
|
||||||
|
|
||||||
// check for connect/disconnect intents from panic trigger apps
|
// check for connect/disconnect intents from panic trigger apps
|
||||||
if (PanicResponder.checkForDisconnectIntent(getActivity())) {
|
if (PanicResponder.checkForDisconnectIntent(getActivity())) {
|
||||||
@@ -97,16 +95,11 @@ public class PanicPreferencesFragment extends PreferenceFragmentCompat
|
|||||||
showPanicApp(packageName);
|
showPanicApp(packageName);
|
||||||
|
|
||||||
if (packageName.equals(Panic.PACKAGE_NAME_NONE)) {
|
if (packageName.equals(Panic.PACKAGE_NAME_NONE)) {
|
||||||
lockPref.setEnabled(false);
|
|
||||||
purgePref.setChecked(false);
|
purgePref.setChecked(false);
|
||||||
purgePref.setEnabled(false);
|
purgePref.setEnabled(false);
|
||||||
uninstallPref.setChecked(false);
|
|
||||||
uninstallPref.setEnabled(false);
|
|
||||||
getActivity().setResult(Activity.RESULT_CANCELED);
|
getActivity().setResult(Activity.RESULT_CANCELED);
|
||||||
} else {
|
} else {
|
||||||
lockPref.setEnabled(true);
|
|
||||||
purgePref.setEnabled(true);
|
purgePref.setEnabled(true);
|
||||||
uninstallPref.setEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -145,27 +138,15 @@ public class PanicPreferencesFragment extends PreferenceFragmentCompat
|
|||||||
@Override
|
@Override
|
||||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
|
||||||
String key) {
|
String key) {
|
||||||
if (key.equals(KEY_PURGE)) {
|
// enable locking if purging gets enabled
|
||||||
// enable locking if purging gets enabled
|
if (key.equals(KEY_PURGE) &&
|
||||||
if (sharedPreferences.getBoolean(KEY_PURGE, false)) {
|
sharedPreferences.getBoolean(KEY_PURGE, false)) {
|
||||||
lockPref.setChecked(true);
|
|
||||||
}
|
|
||||||
// disable uninstall if purging gets disabled
|
|
||||||
else {
|
|
||||||
uninstallPref.setChecked(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// enable purging and locking if uninstall gets enabled
|
|
||||||
if (key.equals(KEY_UNINSTALL) &&
|
|
||||||
sharedPreferences.getBoolean(KEY_UNINSTALL, false)) {
|
|
||||||
lockPref.setChecked(true);
|
lockPref.setChecked(true);
|
||||||
purgePref.setChecked(true);
|
|
||||||
}
|
}
|
||||||
// disable purging and uninstalling if locking gets disabled
|
// disable purging if locking gets disabled
|
||||||
if (key.equals(KEY_LOCK) &&
|
if (key.equals(KEY_LOCK) &&
|
||||||
!sharedPreferences.getBoolean(KEY_LOCK, true)) {
|
!sharedPreferences.getBoolean(KEY_LOCK, true)) {
|
||||||
purgePref.setChecked(false);
|
purgePref.setChecked(false);
|
||||||
uninstallPref.setChecked(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,10 +160,8 @@ public class PanicPreferencesFragment extends PreferenceFragmentCompat
|
|||||||
panicAppPref.setIcon(
|
panicAppPref.setIcon(
|
||||||
android.R.drawable.ic_menu_close_clear_cancel);
|
android.R.drawable.ic_menu_close_clear_cancel);
|
||||||
|
|
||||||
// disable panic actions
|
// disable destructive panic actions
|
||||||
lockPref.setEnabled(false);
|
|
||||||
purgePref.setEnabled(false);
|
purgePref.setEnabled(false);
|
||||||
uninstallPref.setEnabled(false);
|
|
||||||
} else {
|
} else {
|
||||||
// display connected panic app
|
// display connected panic app
|
||||||
try {
|
try {
|
||||||
@@ -192,10 +171,8 @@ public class PanicPreferencesFragment extends PreferenceFragmentCompat
|
|||||||
panicAppPref.setIcon(
|
panicAppPref.setIcon(
|
||||||
pm.getApplicationIcon(triggerPackageName));
|
pm.getApplicationIcon(triggerPackageName));
|
||||||
|
|
||||||
// enable panic actions
|
// enable destructive panic actions
|
||||||
lockPref.setEnabled(true);
|
|
||||||
purgePref.setEnabled(true);
|
purgePref.setEnabled(true);
|
||||||
uninstallPref.setEnabled(true);
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
// revert back to no app, just to be safe
|
// revert back to no app, just to be safe
|
||||||
PanicResponder.setTriggerPackageName(getActivity(),
|
PanicResponder.setTriggerPackageName(getActivity(),
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.briarproject.briar.android.panic;
|
|||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v7.preference.PreferenceManager;
|
import android.support.v7.preference.PreferenceManager;
|
||||||
@@ -11,7 +10,6 @@ import org.briarproject.bramble.api.account.AccountManager;
|
|||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
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;
|
||||||
import org.iilab.IilabEngineeringRSA2048Pin;
|
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -22,10 +20,8 @@ import info.guardianproject.panic.Panic;
|
|||||||
import info.guardianproject.panic.PanicResponder;
|
import info.guardianproject.panic.PanicResponder;
|
||||||
import info.guardianproject.trustedintents.TrustedIntents;
|
import info.guardianproject.trustedintents.TrustedIntents;
|
||||||
|
|
||||||
import static android.content.Intent.ACTION_DELETE;
|
|
||||||
import static org.briarproject.briar.android.panic.PanicPreferencesFragment.KEY_LOCK;
|
import static org.briarproject.briar.android.panic.PanicPreferencesFragment.KEY_LOCK;
|
||||||
import static org.briarproject.briar.android.panic.PanicPreferencesFragment.KEY_PURGE;
|
import static org.briarproject.briar.android.panic.PanicPreferencesFragment.KEY_PURGE;
|
||||||
import static org.briarproject.briar.android.panic.PanicPreferencesFragment.KEY_UNINSTALL;
|
|
||||||
|
|
||||||
public class PanicResponderActivity extends BriarActivity {
|
public class PanicResponderActivity extends BriarActivity {
|
||||||
|
|
||||||
@@ -44,8 +40,8 @@ public class PanicResponderActivity extends BriarActivity {
|
|||||||
TrustedIntents trustedIntents = TrustedIntents.get(this);
|
TrustedIntents trustedIntents = TrustedIntents.get(this);
|
||||||
// Guardian Project Ripple
|
// Guardian Project Ripple
|
||||||
trustedIntents.addTrustedSigner(GuardianProjectRSA4096.class);
|
trustedIntents.addTrustedSigner(GuardianProjectRSA4096.class);
|
||||||
// Amnesty International's Panic Button, made by iilab.org
|
// F-Droid
|
||||||
trustedIntents.addTrustedSigner(IilabEngineeringRSA2048Pin.class);
|
trustedIntents.addTrustedSigner(FDroidSignaturePin.class);
|
||||||
|
|
||||||
Intent intent = trustedIntents.getIntentFromTrustedSender(this);
|
Intent intent = trustedIntents.getIntentFromTrustedSender(this);
|
||||||
if (intent != null) {
|
if (intent != null) {
|
||||||
@@ -60,23 +56,16 @@ public class PanicResponderActivity extends BriarActivity {
|
|||||||
LOG.info("Panic Trigger came from connected app");
|
LOG.info("Panic Trigger came from connected app");
|
||||||
|
|
||||||
// Performing panic responses
|
// Performing panic responses
|
||||||
if (sharedPref.getBoolean(KEY_UNINSTALL, false)) {
|
if (sharedPref.getBoolean(KEY_PURGE, false)) {
|
||||||
LOG.info("Purging all data...");
|
LOG.info("Purging all data...");
|
||||||
deleteAllData();
|
deleteAllData();
|
||||||
|
|
||||||
LOG.info("Uninstalling...");
|
|
||||||
Intent uninstall = new Intent(ACTION_DELETE);
|
|
||||||
uninstall.setData(
|
|
||||||
Uri.parse("package:" + getPackageName()));
|
|
||||||
startActivity(uninstall);
|
|
||||||
} else if (sharedPref.getBoolean(KEY_PURGE, false)) {
|
|
||||||
LOG.info("Purging all data...");
|
|
||||||
deleteAllData();
|
|
||||||
} else if (sharedPref.getBoolean(KEY_LOCK, true)) {
|
|
||||||
LOG.info("Signing out...");
|
|
||||||
signOut(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// non-destructive actions are allowed by non-connected trusted apps
|
||||||
|
if (sharedPref.getBoolean(KEY_LOCK, true)) {
|
||||||
|
LOG.info("Signing out...");
|
||||||
|
signOut(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,11 +99,10 @@ class GroupControllerImpl extends
|
|||||||
} else if (e instanceof GroupInvitationResponseReceivedEvent) {
|
} else if (e instanceof GroupInvitationResponseReceivedEvent) {
|
||||||
GroupInvitationResponseReceivedEvent g =
|
GroupInvitationResponseReceivedEvent g =
|
||||||
(GroupInvitationResponseReceivedEvent) e;
|
(GroupInvitationResponseReceivedEvent) e;
|
||||||
GroupInvitationResponse r =
|
GroupInvitationResponse r = g.getMessageHeader();
|
||||||
(GroupInvitationResponse) g.getResponse();
|
|
||||||
if (getGroupId().equals(r.getShareableId()) && r.wasAccepted()) {
|
if (getGroupId().equals(r.getShareableId()) && r.wasAccepted()) {
|
||||||
listener.runOnUiThreadUnlessDestroyed(
|
listener.runOnUiThreadUnlessDestroyed(
|
||||||
() -> listener.onInvitationAccepted(r.getContactId()));
|
() -> listener.onInvitationAccepted(g.getContactId()));
|
||||||
}
|
}
|
||||||
} else if (e instanceof GroupDissolvedEvent) {
|
} else if (e instanceof GroupDissolvedEvent) {
|
||||||
GroupDissolvedEvent g = (GroupDissolvedEvent) e;
|
GroupDissolvedEvent g = (GroupDissolvedEvent) e;
|
||||||
|
|||||||
@@ -292,8 +292,7 @@ public class DevReportActivity extends BaseCrashReportDialog
|
|||||||
cb.setChecked(required || !excluded);
|
cb.setChecked(required || !excluded);
|
||||||
cb.setEnabled(!required);
|
cb.setEnabled(!required);
|
||||||
cb.setOnCheckedChangeListener(DevReportActivity.this);
|
cb.setOnCheckedChangeListener(DevReportActivity.this);
|
||||||
TextView title = v.findViewById(R.id.title);
|
cb.setText(field.toString());
|
||||||
title.setText(field.toString());
|
|
||||||
TextView content = v.findViewById(R.id.content);
|
TextView content = v.findViewById(R.id.content);
|
||||||
content.setText(value);
|
content.setText(value);
|
||||||
report.addView(v);
|
report.addView(v);
|
||||||
|
|||||||
@@ -89,7 +89,6 @@ import static org.briarproject.briar.api.android.AndroidNotificationManager.GROU
|
|||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_BLOG;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_BLOG;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_FORUM;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_FORUM;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_GROUP;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_GROUP;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_LOCK_SCREEN;
|
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_PRIVATE;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_PRIVATE;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_RINGTONE_NAME;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_RINGTONE_NAME;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_RINGTONE_URI;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_RINGTONE_URI;
|
||||||
@@ -127,7 +126,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
private SwitchPreference notifyForumPosts;
|
private SwitchPreference notifyForumPosts;
|
||||||
private SwitchPreference notifyBlogPosts;
|
private SwitchPreference notifyBlogPosts;
|
||||||
private SwitchPreference notifyVibration;
|
private SwitchPreference notifyVibration;
|
||||||
private SwitchPreference notifyLockscreen;
|
|
||||||
|
|
||||||
private Preference notifySound;
|
private Preference notifySound;
|
||||||
|
|
||||||
@@ -179,8 +177,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
"pref_key_notify_blog_posts");
|
"pref_key_notify_blog_posts");
|
||||||
notifyVibration = (SwitchPreference) findPreference(
|
notifyVibration = (SwitchPreference) findPreference(
|
||||||
"pref_key_notify_vibration");
|
"pref_key_notify_vibration");
|
||||||
notifyLockscreen = (SwitchPreference) findPreference(
|
|
||||||
"pref_key_notify_lock_screen");
|
|
||||||
notifySound = findPreference("pref_key_notify_sound");
|
notifySound = findPreference("pref_key_notify_sound");
|
||||||
|
|
||||||
language.setOnPreferenceChangeListener(this);
|
language.setOnPreferenceChangeListener(this);
|
||||||
@@ -207,10 +203,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
torMobile.setOnPreferenceChangeListener(this);
|
torMobile.setOnPreferenceChangeListener(this);
|
||||||
screenLock.setOnPreferenceChangeListener(this);
|
screenLock.setOnPreferenceChangeListener(this);
|
||||||
screenLockTimeout.setOnPreferenceChangeListener(this);
|
screenLockTimeout.setOnPreferenceChangeListener(this);
|
||||||
if (SDK_INT >= 21) {
|
|
||||||
notifyLockscreen.setVisible(true);
|
|
||||||
notifyLockscreen.setOnPreferenceChangeListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
findPreference("pref_key_send_feedback").setOnPreferenceClickListener(
|
findPreference("pref_key_send_feedback").setOnPreferenceClickListener(
|
||||||
preference -> {
|
preference -> {
|
||||||
@@ -380,8 +372,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
notifyForumPosts.setOnPreferenceChangeListener(this);
|
notifyForumPosts.setOnPreferenceChangeListener(this);
|
||||||
notifyBlogPosts.setOnPreferenceChangeListener(this);
|
notifyBlogPosts.setOnPreferenceChangeListener(this);
|
||||||
notifyVibration.setOnPreferenceChangeListener(this);
|
notifyVibration.setOnPreferenceChangeListener(this);
|
||||||
notifyLockscreen.setChecked(settings.getBoolean(
|
|
||||||
PREF_NOTIFY_LOCK_SCREEN, false));
|
|
||||||
notifySound.setOnPreferenceClickListener(
|
notifySound.setOnPreferenceClickListener(
|
||||||
pref -> onNotificationSoundClicked());
|
pref -> onNotificationSoundClicked());
|
||||||
String text;
|
String text;
|
||||||
@@ -409,7 +399,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
setupNotificationPreference(notifyBlogPosts, BLOG_CHANNEL_ID,
|
setupNotificationPreference(notifyBlogPosts, BLOG_CHANNEL_ID,
|
||||||
R.string.notify_blog_posts_setting_summary_26);
|
R.string.notify_blog_posts_setting_summary_26);
|
||||||
notifyVibration.setVisible(false);
|
notifyVibration.setVisible(false);
|
||||||
notifyLockscreen.setVisible(false);
|
|
||||||
notifySound.setVisible(false);
|
notifySound.setVisible(false);
|
||||||
}
|
}
|
||||||
setSettingsEnabled(true);
|
setSettingsEnabled(true);
|
||||||
@@ -432,7 +421,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
notifyForumPosts.setEnabled(enabled);
|
notifyForumPosts.setEnabled(enabled);
|
||||||
notifyBlogPosts.setEnabled(enabled);
|
notifyBlogPosts.setEnabled(enabled);
|
||||||
notifyVibration.setEnabled(enabled);
|
notifyVibration.setEnabled(enabled);
|
||||||
notifyLockscreen.setEnabled(enabled);
|
|
||||||
notifySound.setEnabled(enabled);
|
notifySound.setEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -553,10 +541,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
Settings s = new Settings();
|
Settings s = new Settings();
|
||||||
s.putBoolean(PREF_NOTIFY_VIBRATION, (Boolean) newValue);
|
s.putBoolean(PREF_NOTIFY_VIBRATION, (Boolean) newValue);
|
||||||
storeSettings(s);
|
storeSettings(s);
|
||||||
} else if (preference == notifyLockscreen) {
|
|
||||||
Settings s = new Settings();
|
|
||||||
s.putBoolean(PREF_NOTIFY_LOCK_SCREEN, (Boolean) newValue);
|
|
||||||
storeSettings(s);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.briar.android.sharing;
|
package org.briarproject.briar.android.sharing;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -26,7 +27,7 @@ public abstract class InvitationAdapter<I extends InvitationItem, VH extends Inv
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(VH ui, int position) {
|
public void onBindViewHolder(@NonNull VH ui, int position) {
|
||||||
I item = getItemAt(position);
|
I item = getItemAt(position);
|
||||||
if (item == null) return;
|
if (item == null) return;
|
||||||
ui.onBind(item, listener);
|
ui.onBind(item, listener);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.briar.android.threaded;
|
package org.briarproject.briar.android.threaded;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
@@ -36,8 +37,9 @@ public class ThreadItemAdapter<I extends ThreadItem>
|
|||||||
this.layoutManager = layoutManager;
|
this.layoutManager = layoutManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public BaseThreadItemViewHolder<I> onCreateViewHolder(
|
public BaseThreadItemViewHolder<I> onCreateViewHolder(@NonNull
|
||||||
ViewGroup parent, int viewType) {
|
ViewGroup parent, int viewType) {
|
||||||
View v = LayoutInflater.from(parent.getContext())
|
View v = LayoutInflater.from(parent.getContext())
|
||||||
.inflate(R.layout.list_item_thread, parent, false);
|
.inflate(R.layout.list_item_thread, parent, false);
|
||||||
@@ -45,7 +47,8 @@ public class ThreadItemAdapter<I extends ThreadItem>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(BaseThreadItemViewHolder<I> ui, int position) {
|
public void onBindViewHolder(@NonNull BaseThreadItemViewHolder<I> ui,
|
||||||
|
int position) {
|
||||||
I item = items.get(position);
|
I item = items.get(position);
|
||||||
ui.bind(item, listener);
|
ui.bind(item, listener);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
package org.briarproject.briar.android.util;
|
package org.briarproject.briar.android.util;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
|
||||||
import android.support.annotation.ColorRes;
|
import android.support.annotation.ColorRes;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
|
|
||||||
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static android.support.v4.app.NotificationCompat.VISIBILITY_PRIVATE;
|
import static android.support.v4.app.NotificationCompat.VISIBILITY_PRIVATE;
|
||||||
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
|
|
||||||
|
|
||||||
|
|
||||||
public class BriarNotificationBuilder extends NotificationCompat.Builder {
|
public class BriarNotificationBuilder extends NotificationCompat.Builder {
|
||||||
@@ -22,6 +21,7 @@ public class BriarNotificationBuilder extends NotificationCompat.Builder {
|
|||||||
|
|
||||||
setLights(ContextCompat.getColor(context, R.color.briar_green_light),
|
setLights(ContextCompat.getColor(context, R.color.briar_green_light),
|
||||||
750, 500);
|
750, 500);
|
||||||
|
if (SDK_INT >= 21) setVisibility(VISIBILITY_PRIVATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BriarNotificationBuilder setColorRes(@ColorRes int res) {
|
public BriarNotificationBuilder setColorRes(@ColorRes int res) {
|
||||||
@@ -29,13 +29,8 @@ public class BriarNotificationBuilder extends NotificationCompat.Builder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BriarNotificationBuilder setLockscreenVisibility(String category,
|
public BriarNotificationBuilder setNotificationCategory(String category) {
|
||||||
boolean show) {
|
if (SDK_INT >= 21) setCategory(category);
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
|
||||||
setCategory(category);
|
|
||||||
if (show) setVisibility(VISIBILITY_PRIVATE);
|
|
||||||
else setVisibility(VISIBILITY_SECRET);
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
|
|||||||
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
|
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
|
||||||
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
|
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
|
||||||
import static android.view.KeyEvent.ACTION_DOWN;
|
import static android.view.KeyEvent.ACTION_DOWN;
|
||||||
import static android.view.KeyEvent.ACTION_UP;
|
|
||||||
import static android.view.KeyEvent.KEYCODE_ENTER;
|
import static android.view.KeyEvent.KEYCODE_ENTER;
|
||||||
import static android.view.inputmethod.EditorInfo.IME_NULL;
|
import static android.view.inputmethod.EditorInfo.IME_NULL;
|
||||||
import static org.briarproject.briar.BuildConfig.APPLICATION_ID;
|
import static org.briarproject.briar.BuildConfig.APPLICATION_ID;
|
||||||
@@ -157,7 +156,7 @@ public class UiUtils {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the runnable when clicking the link in the textView's text.
|
* Executes the runnable when clicking the link in the textView's text.
|
||||||
*
|
* <p>
|
||||||
* Attention: This assumes that there's only <b>one</b> link in the text.
|
* Attention: This assumes that there's only <b>one</b> link in the text.
|
||||||
*/
|
*/
|
||||||
public static void onSingleLinkClick(TextView textView, Runnable runnable) {
|
public static void onSingleLinkClick(TextView textView, Runnable runnable) {
|
||||||
|
|||||||
@@ -5,11 +5,10 @@ import android.content.res.TypedArray;
|
|||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.support.annotation.DimenRes;
|
import android.support.annotation.DimenRes;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
|
import android.support.constraint.ConstraintLayout;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.RelativeLayout;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
@@ -30,7 +29,7 @@ import static org.briarproject.bramble.api.identity.Author.Status.OURSELVES;
|
|||||||
import static org.briarproject.briar.android.util.UiUtils.resolveAttribute;
|
import static org.briarproject.briar.android.util.UiUtils.resolveAttribute;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
public class AuthorView extends RelativeLayout {
|
public class AuthorView extends ConstraintLayout {
|
||||||
|
|
||||||
public static final int NORMAL = 0;
|
public static final int NORMAL = 0;
|
||||||
public static final int REBLOGGER = 1;
|
public static final int REBLOGGER = 1;
|
||||||
@@ -133,32 +132,24 @@ public class AuthorView extends RelativeLayout {
|
|||||||
date.setVisibility(VISIBLE);
|
date.setVisibility(VISIBLE);
|
||||||
setAvatarSize(R.dimen.blogs_avatar_normal_size);
|
setAvatarSize(R.dimen.blogs_avatar_normal_size);
|
||||||
setTextSize(authorName, R.dimen.text_size_small);
|
setTextSize(authorName, R.dimen.text_size_small);
|
||||||
setCenterVertical(authorName, false);
|
|
||||||
setCenterVertical(trustIndicator, false);
|
|
||||||
break;
|
break;
|
||||||
case REBLOGGER:
|
case REBLOGGER:
|
||||||
avatarIcon.setVisibility(VISIBLE);
|
avatarIcon.setVisibility(VISIBLE);
|
||||||
date.setVisibility(VISIBLE);
|
date.setVisibility(VISIBLE);
|
||||||
setAvatarSize(R.dimen.blogs_avatar_normal_size);
|
setAvatarSize(R.dimen.blogs_avatar_normal_size);
|
||||||
setTextSize(authorName, R.dimen.text_size_small);
|
setTextSize(authorName, R.dimen.text_size_small);
|
||||||
setCenterVertical(authorName, false);
|
|
||||||
setCenterVertical(trustIndicator, false);
|
|
||||||
break;
|
break;
|
||||||
case COMMENTER:
|
case COMMENTER:
|
||||||
avatarIcon.setVisibility(INVISIBLE);
|
avatarIcon.setVisibility(INVISIBLE);
|
||||||
date.setVisibility(VISIBLE);
|
date.setVisibility(VISIBLE);
|
||||||
setAvatarSize(R.dimen.blogs_avatar_comment_size);
|
setAvatarSize(R.dimen.blogs_avatar_comment_size);
|
||||||
setTextSize(authorName, R.dimen.text_size_tiny);
|
setTextSize(authorName, R.dimen.text_size_tiny);
|
||||||
setCenterVertical(authorName, false);
|
|
||||||
setCenterVertical(trustIndicator, false);
|
|
||||||
break;
|
break;
|
||||||
case LIST:
|
case LIST:
|
||||||
avatarIcon.setVisibility(INVISIBLE);
|
avatarIcon.setVisibility(INVISIBLE);
|
||||||
date.setVisibility(GONE);
|
date.setVisibility(GONE);
|
||||||
setAvatarSize(R.dimen.listitem_picture_size_small);
|
setAvatarSize(R.dimen.listitem_picture_size_small);
|
||||||
setTextSize(authorName, R.dimen.text_size_medium);
|
setTextSize(authorName, R.dimen.text_size_medium);
|
||||||
setCenterVertical(authorName, true);
|
|
||||||
setCenterVertical(trustIndicator, true);
|
|
||||||
break;
|
break;
|
||||||
case RSS_FEED:
|
case RSS_FEED:
|
||||||
avatarIcon.setVisibility(INVISIBLE);
|
avatarIcon.setVisibility(INVISIBLE);
|
||||||
@@ -166,8 +157,6 @@ public class AuthorView extends RelativeLayout {
|
|||||||
avatar.setImageResource(R.drawable.ic_rss_feed);
|
avatar.setImageResource(R.drawable.ic_rss_feed);
|
||||||
setAvatarSize(R.dimen.blogs_avatar_normal_size);
|
setAvatarSize(R.dimen.blogs_avatar_normal_size);
|
||||||
setTextSize(authorName, R.dimen.text_size_small);
|
setTextSize(authorName, R.dimen.text_size_small);
|
||||||
setCenterVertical(authorName, false);
|
|
||||||
setCenterVertical(trustIndicator, false);
|
|
||||||
break;
|
break;
|
||||||
case RSS_FEED_REBLOGGED:
|
case RSS_FEED_REBLOGGED:
|
||||||
avatarIcon.setVisibility(INVISIBLE);
|
avatarIcon.setVisibility(INVISIBLE);
|
||||||
@@ -175,8 +164,6 @@ public class AuthorView extends RelativeLayout {
|
|||||||
avatar.setImageResource(R.drawable.ic_rss_feed);
|
avatar.setImageResource(R.drawable.ic_rss_feed);
|
||||||
setAvatarSize(R.dimen.blogs_avatar_comment_size);
|
setAvatarSize(R.dimen.blogs_avatar_comment_size);
|
||||||
setTextSize(authorName, R.dimen.text_size_tiny);
|
setTextSize(authorName, R.dimen.text_size_tiny);
|
||||||
setCenterVertical(authorName, false);
|
|
||||||
setCenterVertical(trustIndicator, false);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,10 +181,4 @@ public class AuthorView extends RelativeLayout {
|
|||||||
v.setTextSize(COMPLEX_UNIT_PX, textSize);
|
v.setTextSize(COMPLEX_UNIT_PX, textSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCenterVertical(View v, boolean center) {
|
|
||||||
LayoutParams params = (LayoutParams) v.getLayoutParams();
|
|
||||||
params.addRule(CENTER_VERTICAL, center ? RelativeLayout.TRUE : 0);
|
|
||||||
v.setLayoutParams(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,7 @@ public class QrCodeView extends FrameLayout {
|
|||||||
private boolean fullscreen = false;
|
private boolean fullscreen = false;
|
||||||
private FullscreenListener listener;
|
private FullscreenListener listener;
|
||||||
|
|
||||||
public QrCodeView(@NonNull Context context,
|
public QrCodeView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||||
@Nullable AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
LayoutInflater inflater = (LayoutInflater) context
|
LayoutInflater inflater = (LayoutInflater) context
|
||||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.briarproject.briar.android.view;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.support.v7.widget.AppCompatTextView;
|
import android.support.v7.widget.AppCompatTextView;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
@@ -11,13 +10,11 @@ import android.view.LayoutInflater;
|
|||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import de.hdodenhof.circleimageview.CircleImageView;
|
import de.hdodenhof.circleimageview.CircleImageView;
|
||||||
import im.delight.android.identicons.IdenticonDrawable;
|
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
public class TextAvatarView extends FrameLayout {
|
public class TextAvatarView extends FrameLayout {
|
||||||
@@ -35,7 +32,6 @@ public class TextAvatarView extends FrameLayout {
|
|||||||
character = findViewById(R.id.textAvatarView);
|
character = findViewById(R.id.textAvatarView);
|
||||||
background = findViewById(R.id.avatarBackground);
|
background = findViewById(R.id.avatarBackground);
|
||||||
badge = findViewById(R.id.unreadCountView);
|
badge = findViewById(R.id.unreadCountView);
|
||||||
badge.setVisibility(INVISIBLE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextAvatarView(Context context) {
|
public TextAvatarView(Context context) {
|
||||||
@@ -72,10 +68,4 @@ public class TextAvatarView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAuthorAvatar(Author author) {
|
|
||||||
Drawable drawable = new IdenticonDrawable(author.getId().getBytes());
|
|
||||||
background.setImageDrawable(drawable);
|
|
||||||
character.setVisibility(GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,9 +61,11 @@ public class TextInputView extends KeyboardAwareLinearLayout {
|
|||||||
public TextInputView(Context context, @Nullable AttributeSet attrs,
|
public TextInputView(Context context, @Nullable AttributeSet attrs,
|
||||||
int defStyleAttr) {
|
int defStyleAttr) {
|
||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
BriarApplication app =
|
if (!isInEditMode()) {
|
||||||
(BriarApplication) context.getApplicationContext();
|
BriarApplication app =
|
||||||
app.getApplicationComponent().inject(this);
|
(BriarApplication) context.getApplicationContext();
|
||||||
|
app.getApplicationComponent().inject(this);
|
||||||
|
}
|
||||||
setOrientation(VERTICAL);
|
setOrientation(VERTICAL);
|
||||||
setLayoutTransition(new LayoutTransition());
|
setLayoutTransition(new LayoutTransition());
|
||||||
inflateLayout(context);
|
inflateLayout(context);
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public class UnreadMessageButton extends FrameLayout {
|
|||||||
setDirection(direction);
|
setDirection(direction);
|
||||||
attributes.recycle();
|
attributes.recycle();
|
||||||
|
|
||||||
setUnreadCount(0);
|
if (!isInEditMode()) setUnreadCount(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDirection(int direction) {
|
private void setDirection(int direction) {
|
||||||
@@ -64,11 +64,11 @@ public class UnreadMessageButton extends FrameLayout {
|
|||||||
|
|
||||||
public void setUnreadCount(int count) {
|
public void setUnreadCount(int count) {
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
setVisibility(INVISIBLE);
|
fab.hide();
|
||||||
|
unread.setVisibility(INVISIBLE);
|
||||||
} else {
|
} else {
|
||||||
// FIXME: Use animations when upgrading to support library 24.2.0
|
fab.show();
|
||||||
// https://code.google.com/p/android/issues/detail?id=216469
|
unread.setVisibility(VISIBLE);
|
||||||
setVisibility(VISIBLE);
|
|
||||||
unread.setText(String.valueOf(count));
|
unread.setText(String.valueOf(count));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.content.Intent;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -42,8 +43,8 @@ public class LinkDialogFragment extends DialogFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||||
Bundle savedInstanceState) {
|
ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
|
||||||
View v = inflater.inflate(R.layout.fragment_link_dialog, container,
|
View v = inflater.inflate(R.layout.fragment_link_dialog, container,
|
||||||
false);
|
false);
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ public interface AndroidNotificationManager {
|
|||||||
String PREF_NOTIFY_RINGTONE_NAME = "notifyRingtoneName";
|
String PREF_NOTIFY_RINGTONE_NAME = "notifyRingtoneName";
|
||||||
String PREF_NOTIFY_RINGTONE_URI = "notifyRingtoneUri";
|
String PREF_NOTIFY_RINGTONE_URI = "notifyRingtoneUri";
|
||||||
String PREF_NOTIFY_VIBRATION = "notifyVibration";
|
String PREF_NOTIFY_VIBRATION = "notifyVibration";
|
||||||
String PREF_NOTIFY_LOCK_SCREEN = "notifyLockScreen";
|
|
||||||
|
|
||||||
// Notification IDs
|
// Notification IDs
|
||||||
int ONGOING_NOTIFICATION_ID = 1;
|
int ONGOING_NOTIFICATION_ID = 1;
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2014 Open Whisper Systems
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.thoughtcrime.securesms.components.util;
|
|
||||||
|
|
||||||
public interface FutureTaskListener<V> {
|
|
||||||
void onSuccess(V result);
|
|
||||||
|
|
||||||
void onFailure(Throwable error);
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user