mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 02:39:05 +01:00
Compare commits
21 Commits
beta-0.16.
...
gradle-lib
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa79a31911 | ||
|
|
8171dd8bc9 | ||
|
|
4b88f0d9f1 | ||
|
|
116419f505 | ||
|
|
87b2624aa8 | ||
|
|
71fe6f3148 | ||
|
|
21df6cb809 | ||
|
|
1f0c385a5c | ||
|
|
986ea05fb2 | ||
|
|
030b52261d | ||
|
|
a50e13c2e3 | ||
|
|
c8326103b4 | ||
|
|
ddea031cbf | ||
|
|
f0d8532f71 | ||
|
|
4883d157dc | ||
|
|
a1bec1e927 | ||
|
|
37d4d79c64 | ||
|
|
05bc3f6a71 | ||
|
|
8b3960781a | ||
|
|
f3de4f53c5 | ||
|
|
166fc2948c |
@@ -12,8 +12,8 @@ android {
|
||||
defaultConfig {
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 26
|
||||
versionCode 1616
|
||||
versionName "0.16.16"
|
||||
versionCode 1700
|
||||
versionName "0.17.0"
|
||||
consumerProguardFiles 'proguard-rules.txt'
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ dependencies {
|
||||
implementation project(path: ':bramble-core', configuration: 'default')
|
||||
implementation fileTree(dir: 'libs', include: '*.jar')
|
||||
|
||||
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
|
||||
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||
|
||||
compileOnly 'javax.annotation:jsr250-api:1.0'
|
||||
}
|
||||
@@ -43,6 +43,7 @@ dependencyVerification {
|
||||
'com.madgag.spongycastle:core:1.58.0.0:core-1.58.0.0.jar:199617dd5698c5a9312b898c0a4cec7ce9dd8649d07f65d91629f58229d72728',
|
||||
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
|
||||
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
|
||||
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
|
||||
'org.jacoco:org.jacoco.agent:0.7.4.201502262128:org.jacoco.agent-0.7.4.201502262128-runtime.jar:e357a0f1d573c2f702a273992b1b6cb661734f66311854efb3778a888515c5b5',
|
||||
'org.jacoco:org.jacoco.agent:0.7.4.201502262128:org.jacoco.agent-0.7.4.201502262128.jar:47b4bec6df11a1118da3953da8b9fa1e7079d6fec857faa1a3cf912e53a6fd4e',
|
||||
@@ -54,16 +55,14 @@ dependencyVerification {
|
||||
}
|
||||
|
||||
ext.torBinaryDir = 'src/main/res/raw'
|
||||
ext.torVersion = '0.2.9.14'
|
||||
ext.geoipVersion = '2017-11-06'
|
||||
ext.torDownloadUrl = 'https://briarproject.org/build/'
|
||||
|
||||
def torBinaries = [
|
||||
"tor_arm" : '1710ea6c47b7f4c1a88bdf4858c7893837635db10e8866854eed8d61629f50e8',
|
||||
"tor_arm_pie": '974e6949507db8fa2ea45231817c2c3677ed4ccf5488a2252317d744b0be1917',
|
||||
"tor_x86" : '3a5e45b3f051fcda9353b098b7086e762ffe7ba9242f7d7c8bf6523faaa8b1e9',
|
||||
"tor_x86_pie": 'd1d96d8ce1a4b68accf04850185780d10cd5563d3552f7e1f040f8ca32cb4e51',
|
||||
"geoip" : '8239b98374493529a29096e45fc5877d4d6fdad0146ad8380b291f90d61484ea'
|
||||
"tor_arm" : '8ed0b347ffed1d6a4d2fd14495118eb92be83e9cc06e057e15220dc288b31688',
|
||||
"tor_arm_pie": '64403262511c29f462ca5e7c7621bfc3c944898364d1d5ad35a016bb8a034283',
|
||||
"tor_x86" : '61e014607a2079bcf1646289c67bff6372b1aded6e1d8d83d7791efda9a4d5ab',
|
||||
"tor_x86_pie": '18fbc98356697dd0895836ab46d5c9877d1c539193464f7db1e82a65adaaf288',
|
||||
"geoip" : 'fe49d3adb86d3c512373101422a017dbb86c85a570524663f09dd8ce143a24f3'
|
||||
]
|
||||
|
||||
def downloadBinary(name) {
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
-dontwarn dagger.**
|
||||
-dontnote dagger.**
|
||||
|
||||
-keep class net.i2p.crypto.eddsa.** { *; }
|
||||
|
||||
-dontwarn sun.misc.Unsafe
|
||||
-dontnote com.google.common.**
|
||||
|
||||
|
||||
@@ -5,15 +5,15 @@ targetCompatibility = 1.8
|
||||
apply plugin: 'witness'
|
||||
|
||||
dependencies {
|
||||
implementation "com.google.dagger:dagger:2.0.2"
|
||||
implementation "com.google.dagger:dagger:$daggerVersion"
|
||||
implementation 'com.google.code.findbugs:jsr305:3.0.2'
|
||||
|
||||
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"
|
||||
testImplementation "junit:junit:$junitVersion"
|
||||
testImplementation "org.jmock:jmock:$jmockVersion"
|
||||
testImplementation "org.jmock:jmock-junit4:$jmockVersion"
|
||||
testImplementation "org.jmock:jmock-legacy:$jmockVersion"
|
||||
testImplementation "org.hamcrest:hamcrest-library:$hamcrestVersion"
|
||||
testImplementation "org.hamcrest:hamcrest-core:$hamcrestVersion"
|
||||
}
|
||||
|
||||
dependencyVerification {
|
||||
|
||||
@@ -20,6 +20,10 @@ public interface CryptoComponent {
|
||||
|
||||
KeyParser getSignatureKeyParser();
|
||||
|
||||
KeyPair generateEdKeyPair();
|
||||
|
||||
KeyParser getEdKeyParser();
|
||||
|
||||
KeyParser getMessageKeyParser();
|
||||
|
||||
/**
|
||||
@@ -61,7 +65,6 @@ public interface CryptoComponent {
|
||||
* @param ourKeyPair our ephemeral keypair
|
||||
* @param alice true if ourKeyPair belongs to Alice
|
||||
* @return the shared secret
|
||||
* @throws GeneralSecurityException
|
||||
*/
|
||||
SecretKey deriveSharedSecret(byte[] theirPublicKey, KeyPair ourKeyPair,
|
||||
boolean alice) throws GeneralSecurityException;
|
||||
@@ -106,7 +109,6 @@ public interface CryptoComponent {
|
||||
* @param ourKeyPair our ephemeral keypair
|
||||
* @param alice true if ourKeyPair belongs to Alice
|
||||
* @return the shared secret
|
||||
* @throws GeneralSecurityException
|
||||
*/
|
||||
SecretKey deriveMasterSecret(byte[] theirPublicKey, KeyPair ourKeyPair,
|
||||
boolean alice) throws GeneralSecurityException;
|
||||
@@ -130,7 +132,7 @@ public interface CryptoComponent {
|
||||
long streamNumber);
|
||||
|
||||
/**
|
||||
* Signs the given byte[] with the given PrivateKey.
|
||||
* Signs the given byte[] with the given ECDSA private key.
|
||||
*
|
||||
* @param label A label specific to this signature
|
||||
* to ensure that the signature cannot be repurposed
|
||||
@@ -139,8 +141,17 @@ public interface CryptoComponent {
|
||||
throws GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Verifies that the given signature is valid for the signedData
|
||||
* and the given publicKey.
|
||||
* Signs the given byte[] with the given Ed25519 private key.
|
||||
*
|
||||
* @param label A label specific to this signature
|
||||
* to ensure that the signature cannot be repurposed
|
||||
*/
|
||||
byte[] signEd(String label, byte[] toSign, byte[] privateKey)
|
||||
throws GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Verifies that the given signature is valid for the signed data
|
||||
* and the given ECDSA public key.
|
||||
*
|
||||
* @param label A label that was specific to this signature
|
||||
* to ensure that the signature cannot be repurposed
|
||||
@@ -149,6 +160,17 @@ public interface CryptoComponent {
|
||||
boolean verify(String label, byte[] signedData, byte[] publicKey,
|
||||
byte[] signature) throws GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Verifies that the given signature is valid for the signed data
|
||||
* and the given Ed25519 public key.
|
||||
*
|
||||
* @param label A label that was specific to this signature
|
||||
* to ensure that the signature cannot be repurposed
|
||||
* @return true if the signature was valid, false otherwise.
|
||||
*/
|
||||
boolean verifyEd(String label, byte[] signedData, byte[] publicKey,
|
||||
byte[] signature) throws GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Returns the hash of the given inputs. The inputs are unambiguously
|
||||
* combined by prefixing each input with its length.
|
||||
|
||||
@@ -36,4 +36,8 @@ public class ClientId implements Comparable<ClientId> {
|
||||
return id.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,18 +11,19 @@ dependencies {
|
||||
implementation 'com.madgag.spongycastle:core:1.58.0.0'
|
||||
implementation 'com.h2database:h2:1.4.192' // This is the last version that supports Java 1.6
|
||||
implementation 'org.bitlet:weupnp:0.1.4'
|
||||
implementation 'net.i2p.crypto:eddsa:0.2.0'
|
||||
|
||||
apt 'com.google.dagger:dagger-compiler:2.0.2'
|
||||
apt "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||
|
||||
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
||||
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"
|
||||
testImplementation "junit:junit:$junitVersion"
|
||||
testImplementation "org.jmock:jmock:$jmockVersion"
|
||||
testImplementation "org.jmock:jmock-junit4:$jmockVersion"
|
||||
testImplementation "org.jmock:jmock-legacy:$jmockVersion"
|
||||
testImplementation "org.hamcrest:hamcrest-library:$hamcrestVersion"
|
||||
testImplementation "org.hamcrest:hamcrest-core:$hamcrestVersion"
|
||||
|
||||
testApt 'com.google.dagger:dagger-compiler:2.0.2'
|
||||
testApt "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||
}
|
||||
|
||||
dependencyVerification {
|
||||
@@ -37,6 +38,7 @@ dependencyVerification {
|
||||
'com.madgag.spongycastle:core:1.58.0.0:core-1.58.0.0.jar:199617dd5698c5a9312b898c0a4cec7ce9dd8649d07f65d91629f58229d72728',
|
||||
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
|
||||
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
|
||||
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
|
||||
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
|
||||
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package org.briarproject.bramble.crypto;
|
||||
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey;
|
||||
import net.i2p.crypto.eddsa.KeyPairGenerator;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||
import org.briarproject.bramble.api.crypto.KeyParser;
|
||||
@@ -56,6 +60,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
|
||||
private static final int AGREEMENT_KEY_PAIR_BITS = 256;
|
||||
private static final int SIGNATURE_KEY_PAIR_BITS = 256;
|
||||
private static final int ED_KEY_PAIR_BITS = 256;
|
||||
private static final int STORAGE_IV_BYTES = 24; // 196 bits
|
||||
private static final int PBKDF_SALT_BYTES = 32; // 256 bits
|
||||
private static final int PBKDF_TARGET_MILLIS = 500;
|
||||
@@ -99,6 +104,8 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
private final ECKeyPairGenerator signatureKeyPairGenerator;
|
||||
private final KeyParser agreementKeyParser, signatureKeyParser;
|
||||
private final MessageEncrypter messageEncrypter;
|
||||
private final KeyPairGenerator edKeyPairGenerator;
|
||||
private final KeyParser edKeyParser;
|
||||
|
||||
@Inject
|
||||
CryptoComponentImpl(SecureRandomProvider secureRandomProvider) {
|
||||
@@ -132,6 +139,9 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
signatureKeyParser = new Sec1KeyParser(PARAMETERS,
|
||||
SIGNATURE_KEY_PAIR_BITS);
|
||||
messageEncrypter = new MessageEncrypter(secureRandom);
|
||||
edKeyPairGenerator = new KeyPairGenerator();
|
||||
edKeyPairGenerator.initialize(ED_KEY_PAIR_BITS, secureRandom);
|
||||
edKeyParser = new EdKeyParser();
|
||||
}
|
||||
|
||||
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
|
||||
@@ -190,6 +200,21 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
return secret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyPair generateEdKeyPair() {
|
||||
java.security.KeyPair keyPair = edKeyPairGenerator.generateKeyPair();
|
||||
EdDSAPublicKey edPublicKey = (EdDSAPublicKey) keyPair.getPublic();
|
||||
PublicKey publicKey = new EdPublicKey(edPublicKey.getAbyte());
|
||||
EdDSAPrivateKey edPrivateKey = (EdDSAPrivateKey) keyPair.getPrivate();
|
||||
PrivateKey privateKey = new EdPrivateKey(edPrivateKey.getSeed());
|
||||
return new KeyPair(publicKey, privateKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyParser getEdKeyParser() {
|
||||
return edKeyParser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyPair generateAgreementKeyPair() {
|
||||
AsymmetricCipherKeyPair keyPair =
|
||||
@@ -416,19 +441,41 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
@Override
|
||||
public byte[] sign(String label, byte[] toSign, byte[] privateKey)
|
||||
throws GeneralSecurityException {
|
||||
Signature signature = new SignatureImpl(secureRandom);
|
||||
KeyParser keyParser = getSignatureKeyParser();
|
||||
return sign(new SignatureImpl(secureRandom), signatureKeyParser, label,
|
||||
toSign, privateKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] signEd(String label, byte[] toSign, byte[] privateKey)
|
||||
throws GeneralSecurityException {
|
||||
return sign(new EdSignature(), edKeyParser, label, toSign, privateKey);
|
||||
}
|
||||
|
||||
private byte[] sign(Signature sig, KeyParser keyParser, String label,
|
||||
byte[] toSign, byte[] privateKey) throws GeneralSecurityException {
|
||||
PrivateKey key = keyParser.parsePrivateKey(privateKey);
|
||||
signature.initSign(key);
|
||||
updateSignature(signature, label, toSign);
|
||||
return signature.sign();
|
||||
sig.initSign(key);
|
||||
updateSignature(sig, label, toSign);
|
||||
return sig.sign();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(String label, byte[] signedData, byte[] publicKey,
|
||||
byte[] signature) throws GeneralSecurityException {
|
||||
Signature sig = new SignatureImpl(secureRandom);
|
||||
KeyParser keyParser = getSignatureKeyParser();
|
||||
return verify(new SignatureImpl(secureRandom), signatureKeyParser,
|
||||
label, signedData, publicKey, signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verifyEd(String label, byte[] signedData, byte[] publicKey,
|
||||
byte[] signature) throws GeneralSecurityException {
|
||||
return verify(new EdSignature(), edKeyParser, label, signedData,
|
||||
publicKey, signature);
|
||||
}
|
||||
|
||||
private boolean verify(Signature sig, KeyParser keyParser, String label,
|
||||
byte[] signedData, byte[] publicKey, byte[] signature)
|
||||
throws GeneralSecurityException {
|
||||
PublicKey key = keyParser.parsePublicKey(publicKey);
|
||||
sig.initVerify(key);
|
||||
updateSignature(sig, label, signedData);
|
||||
@@ -436,7 +483,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
}
|
||||
|
||||
private void updateSignature(Signature signature, String label,
|
||||
byte[] toSign) {
|
||||
byte[] toSign) throws GeneralSecurityException {
|
||||
byte[] labelBytes = StringUtils.toUtf8(label);
|
||||
byte[] length = new byte[INT_32_BYTES];
|
||||
ByteUtils.writeUint32(labelBytes.length, length, 0);
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.briarproject.bramble.crypto;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.KeyParser;
|
||||
import org.briarproject.bramble.api.crypto.PrivateKey;
|
||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
@NotNullByDefault
|
||||
class EdKeyParser implements KeyParser {
|
||||
|
||||
@Override
|
||||
public PublicKey parsePublicKey(byte[] encodedKey)
|
||||
throws GeneralSecurityException {
|
||||
if (encodedKey.length != 32) throw new GeneralSecurityException();
|
||||
return new EdPublicKey(encodedKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrivateKey parsePrivateKey(byte[] encodedKey)
|
||||
throws GeneralSecurityException {
|
||||
if (encodedKey.length != 32) throw new GeneralSecurityException();
|
||||
return new EdPrivateKey(encodedKey);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.briarproject.bramble.crypto;
|
||||
|
||||
import org.briarproject.bramble.api.Bytes;
|
||||
import org.briarproject.bramble.api.crypto.PrivateKey;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
@NotNullByDefault
|
||||
class EdPrivateKey extends Bytes implements PrivateKey {
|
||||
|
||||
EdPrivateKey(byte[] bytes) {
|
||||
super(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
return getBytes();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.briarproject.bramble.crypto;
|
||||
|
||||
import org.briarproject.bramble.api.Bytes;
|
||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
@NotNullByDefault
|
||||
class EdPublicKey extends Bytes implements PublicKey {
|
||||
|
||||
EdPublicKey(byte[] bytes) {
|
||||
super(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getEncoded() {
|
||||
return getBytes();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.briarproject.bramble.crypto;
|
||||
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey;
|
||||
import net.i2p.crypto.eddsa.EdDSASecurityProvider;
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec;
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.PrivateKey;
|
||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.Provider;
|
||||
|
||||
import static net.i2p.crypto.eddsa.EdDSAEngine.SIGNATURE_ALGORITHM;
|
||||
|
||||
@NotNullByDefault
|
||||
class EdSignature implements Signature {
|
||||
|
||||
private static final Provider PROVIDER = new EdDSASecurityProvider();
|
||||
|
||||
private static final EdDSANamedCurveSpec CURVE_SPEC =
|
||||
EdDSANamedCurveTable.getByName("Ed25519");
|
||||
|
||||
private final java.security.Signature signature;
|
||||
|
||||
EdSignature() {
|
||||
try {
|
||||
signature = java.security.Signature
|
||||
.getInstance(SIGNATURE_ALGORITHM, PROVIDER);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initSign(PrivateKey k) throws GeneralSecurityException {
|
||||
if (!(k instanceof EdPrivateKey))
|
||||
throw new IllegalArgumentException();
|
||||
EdDSAPrivateKey privateKey = new EdDSAPrivateKey(
|
||||
new EdDSAPrivateKeySpec(k.getEncoded(), CURVE_SPEC));
|
||||
signature.initSign(privateKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initVerify(PublicKey k) throws GeneralSecurityException {
|
||||
if (!(k instanceof EdPublicKey))
|
||||
throw new IllegalArgumentException();
|
||||
EdDSAPublicKey publicKey = new EdDSAPublicKey(
|
||||
new EdDSAPublicKeySpec(k.getEncoded(), CURVE_SPEC));
|
||||
signature.initVerify(publicKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(byte b) throws GeneralSecurityException {
|
||||
signature.update(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(byte[] b) throws GeneralSecurityException {
|
||||
signature.update(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(byte[] b, int off, int len)
|
||||
throws GeneralSecurityException {
|
||||
signature.update(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] sign() throws GeneralSecurityException {
|
||||
return signature.sign();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(byte[] sig) throws GeneralSecurityException {
|
||||
return signature.verify(sig);
|
||||
}
|
||||
}
|
||||
@@ -22,25 +22,25 @@ interface Signature {
|
||||
/**
|
||||
* @see {@link java.security.Signature#update(byte)}
|
||||
*/
|
||||
void update(byte b);
|
||||
void update(byte b) throws GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* @see {@link java.security.Signature#update(byte[])}
|
||||
*/
|
||||
void update(byte[] b);
|
||||
void update(byte[] b) throws GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* @see {@link java.security.Signature#update(byte[], int, int)}
|
||||
*/
|
||||
void update(byte[] b, int off, int len);
|
||||
void update(byte[] b, int off, int len) throws GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* @see {@link java.security.Signature#sign()}
|
||||
*/
|
||||
byte[] sign();
|
||||
byte[] sign() throws GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* @see {@link java.security.Signature#verify(byte[])}
|
||||
*/
|
||||
boolean verify(byte[] signature);
|
||||
boolean verify(byte[] signature) throws GeneralSecurityException;
|
||||
}
|
||||
|
||||
@@ -90,6 +90,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
private final ReentrantReadWriteLock lock =
|
||||
new ReentrantReadWriteLock(true);
|
||||
|
||||
private volatile int shutdownHandle = -1;
|
||||
|
||||
@Inject
|
||||
DatabaseComponentImpl(Database<T> db, Class<T> txnClass, EventBus eventBus,
|
||||
ShutdownManager shutdown) {
|
||||
@@ -101,20 +103,22 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
|
||||
@Override
|
||||
public boolean open() throws DbException {
|
||||
boolean reopened = db.open();
|
||||
shutdown.addShutdownHook(() -> {
|
||||
Runnable shutdownHook = () -> {
|
||||
try {
|
||||
close();
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
});
|
||||
};
|
||||
boolean reopened = db.open();
|
||||
shutdownHandle = shutdown.addShutdownHook(shutdownHook);
|
||||
return reopened;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws DbException {
|
||||
if (closed.getAndSet(true)) return;
|
||||
shutdown.removeShutdownHook(shutdownHandle);
|
||||
db.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -129,8 +129,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
||||
public Map<TransportId, TransportProperties> getLocalProperties()
|
||||
throws DbException {
|
||||
Map<TransportId, TransportProperties> local;
|
||||
// TODO: Transaction can be read-only when code is simplified
|
||||
Transaction txn = db.startTransaction(false);
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
local = getLocalProperties(txn);
|
||||
db.commitTransaction(txn);
|
||||
@@ -165,8 +164,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
||||
throws DbException {
|
||||
try {
|
||||
TransportProperties p = null;
|
||||
// TODO: Transaction can be read-only when code is simplified
|
||||
Transaction txn = db.startTransaction(false);
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
// Find the latest local update
|
||||
LatestUpdate latest = findLatest(txn, localGroup.getId(), t,
|
||||
@@ -192,8 +190,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
||||
public Map<ContactId, TransportProperties> getRemoteProperties(
|
||||
TransportId t) throws DbException {
|
||||
Map<ContactId, TransportProperties> remote = new HashMap<>();
|
||||
// TODO: Transaction can be read-only when code is simplified
|
||||
Transaction txn = db.startTransaction(false);
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
for (Contact c : db.getContacts(txn))
|
||||
remote.put(c.getId(), getRemoteProperties(txn, c, t));
|
||||
@@ -227,8 +224,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
||||
public TransportProperties getRemoteProperties(ContactId c, TransportId t)
|
||||
throws DbException {
|
||||
TransportProperties p;
|
||||
// TODO: Transaction can be read-only when code is simplified
|
||||
Transaction txn = db.startTransaction(false);
|
||||
Transaction txn = db.startTransaction(true);
|
||||
try {
|
||||
p = getRemoteProperties(txn, db.getContact(txn, c), t);
|
||||
db.commitTransaction(txn);
|
||||
@@ -318,7 +314,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
||||
|
||||
private Map<TransportId, LatestUpdate> findLatestLocal(Transaction txn)
|
||||
throws DbException, FormatException {
|
||||
// TODO: This can be simplified before 1.0
|
||||
Map<TransportId, LatestUpdate> latestUpdates = new HashMap<>();
|
||||
Map<MessageId, BdfDictionary> metadata = clientHelper
|
||||
.getMessageMetadataAsDictionary(txn, localGroup.getId());
|
||||
@@ -326,17 +321,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
||||
BdfDictionary meta = e.getValue();
|
||||
TransportId t = new TransportId(meta.getString("transportId"));
|
||||
long version = meta.getLong("version");
|
||||
LatestUpdate latest = latestUpdates.get(t);
|
||||
if (latest == null) {
|
||||
latestUpdates.put(t, new LatestUpdate(e.getKey(), version));
|
||||
} else if (version > latest.version) {
|
||||
// This update is newer - delete the previous one
|
||||
db.removeMessage(txn, latest.messageId);
|
||||
latestUpdates.put(t, new LatestUpdate(e.getKey(), version));
|
||||
} else {
|
||||
// We've already found a newer update - delete this one
|
||||
db.removeMessage(txn, e.getKey());
|
||||
}
|
||||
latestUpdates.put(t, new LatestUpdate(e.getKey(), version));
|
||||
}
|
||||
return latestUpdates;
|
||||
}
|
||||
@@ -344,38 +329,16 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
|
||||
@Nullable
|
||||
private LatestUpdate findLatest(Transaction txn, GroupId g, TransportId t,
|
||||
boolean local) throws DbException, FormatException {
|
||||
// TODO: This can be simplified before 1.0
|
||||
LatestUpdate latest = null;
|
||||
Map<MessageId, BdfDictionary> metadata =
|
||||
clientHelper.getMessageMetadataAsDictionary(txn, g);
|
||||
for (Entry<MessageId, BdfDictionary> e : metadata.entrySet()) {
|
||||
BdfDictionary meta = e.getValue();
|
||||
if (meta.getString("transportId").equals(t.getString())
|
||||
&& meta.getBoolean("local") == local) {
|
||||
long version = meta.getLong("version");
|
||||
if (latest == null) {
|
||||
latest = new LatestUpdate(e.getKey(), version);
|
||||
} else if (version > latest.version) {
|
||||
// This update is newer - delete the previous one
|
||||
if (local) {
|
||||
db.removeMessage(txn, latest.messageId);
|
||||
} else {
|
||||
db.deleteMessage(txn, latest.messageId);
|
||||
db.deleteMessageMetadata(txn, latest.messageId);
|
||||
}
|
||||
latest = new LatestUpdate(e.getKey(), version);
|
||||
} else {
|
||||
// We've already found a newer update - delete this one
|
||||
if (local) {
|
||||
db.removeMessage(txn, e.getKey());
|
||||
} else {
|
||||
db.deleteMessage(txn, e.getKey());
|
||||
db.deleteMessageMetadata(txn, e.getKey());
|
||||
}
|
||||
}
|
||||
return new LatestUpdate(e.getKey(), meta.getLong("version"));
|
||||
}
|
||||
}
|
||||
return latest;
|
||||
return null;
|
||||
}
|
||||
|
||||
private TransportProperties parseProperties(BdfList message)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.briarproject.bramble.crypto;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
public class EcdsaSignatureTest extends SignatureTest {
|
||||
|
||||
@Override
|
||||
protected KeyPair generateKeyPair() {
|
||||
return crypto.generateSignatureKeyPair();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] sign(String label, byte[] toSign, byte[] privateKey)
|
||||
throws GeneralSecurityException {
|
||||
return crypto.sign(label, toSign, privateKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean verify(String label, byte[] signedData, byte[] publicKey,
|
||||
byte[] signature) throws GeneralSecurityException {
|
||||
return crypto.verify(label, signedData, publicKey, signature);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.briarproject.bramble.crypto;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
public class EdSignatureTest extends SignatureTest {
|
||||
|
||||
@Override
|
||||
protected KeyPair generateKeyPair() {
|
||||
return crypto.generateEdKeyPair();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] sign(String label, byte[] toSign, byte[] privateKey)
|
||||
throws GeneralSecurityException {
|
||||
return crypto.signEd(label, toSign, privateKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean verify(String label, byte[] signedData, byte[] publicKey,
|
||||
byte[] signature) throws GeneralSecurityException {
|
||||
return crypto.verifyEd(label, signedData, publicKey, signature);
|
||||
}
|
||||
}
|
||||
@@ -8,23 +8,32 @@ import org.briarproject.bramble.test.TestUtils;
|
||||
import org.briarproject.bramble.util.StringUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SignatureTest extends BrambleTestCase {
|
||||
public abstract class SignatureTest extends BrambleTestCase {
|
||||
|
||||
private final CryptoComponent crypto;
|
||||
protected final CryptoComponent crypto;
|
||||
|
||||
private final byte[] publicKey, privateKey;
|
||||
private final String label = StringUtils.getRandomString(42);
|
||||
private final byte[] inputBytes = TestUtils.getRandomBytes(123);
|
||||
|
||||
public SignatureTest() {
|
||||
protected abstract KeyPair generateKeyPair();
|
||||
|
||||
protected abstract byte[] sign(String label, byte[] toSign,
|
||||
byte[] privateKey) throws GeneralSecurityException;
|
||||
|
||||
protected abstract boolean verify(String label, byte[] signedData,
|
||||
byte[] publicKey, byte[] signature) throws GeneralSecurityException;
|
||||
|
||||
SignatureTest() {
|
||||
crypto = new CryptoComponentImpl(new TestSecureRandomProvider());
|
||||
KeyPair k = crypto.generateSignatureKeyPair();
|
||||
KeyPair k = generateKeyPair();
|
||||
publicKey = k.getPublic().getEncoded();
|
||||
privateKey = k.getPrivate().getEncoded();
|
||||
}
|
||||
@@ -33,19 +42,19 @@ public class SignatureTest extends BrambleTestCase {
|
||||
public void testIdenticalKeysAndInputsProduceIdenticalSignatures()
|
||||
throws Exception {
|
||||
// Calculate the Signature twice - the results should be identical
|
||||
byte[] sig1 = crypto.sign(label, inputBytes, privateKey);
|
||||
byte[] sig2 = crypto.sign(label, inputBytes, privateKey);
|
||||
byte[] sig1 = sign(label, inputBytes, privateKey);
|
||||
byte[] sig2 = sign(label, inputBytes, privateKey);
|
||||
assertArrayEquals(sig1, sig2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferentKeysProduceDifferentSignatures() throws Exception {
|
||||
// Generate second private key
|
||||
KeyPair k2 = crypto.generateSignatureKeyPair();
|
||||
KeyPair k2 = generateKeyPair();
|
||||
byte[] privateKey2 = k2.getPrivate().getEncoded();
|
||||
// Calculate the signature with each key
|
||||
byte[] sig1 = crypto.sign(label, inputBytes, privateKey);
|
||||
byte[] sig2 = crypto.sign(label, inputBytes, privateKey2);
|
||||
byte[] sig1 = sign(label, inputBytes, privateKey);
|
||||
byte[] sig2 = sign(label, inputBytes, privateKey2);
|
||||
assertFalse(Arrays.equals(sig1, sig2));
|
||||
}
|
||||
|
||||
@@ -56,8 +65,8 @@ public class SignatureTest extends BrambleTestCase {
|
||||
byte[] inputBytes2 = TestUtils.getRandomBytes(123);
|
||||
// Calculate the signature with different inputs
|
||||
// the results should be different
|
||||
byte[] sig1 = crypto.sign(label, inputBytes, privateKey);
|
||||
byte[] sig2 = crypto.sign(label, inputBytes2, privateKey);
|
||||
byte[] sig1 = sign(label, inputBytes, privateKey);
|
||||
byte[] sig2 = sign(label, inputBytes2, privateKey);
|
||||
assertFalse(Arrays.equals(sig1, sig2));
|
||||
}
|
||||
|
||||
@@ -68,25 +77,25 @@ public class SignatureTest extends BrambleTestCase {
|
||||
String label2 = StringUtils.getRandomString(42);
|
||||
// Calculate the signature with different inputs
|
||||
// the results should be different
|
||||
byte[] sig1 = crypto.sign(label, inputBytes, privateKey);
|
||||
byte[] sig2 = crypto.sign(label2, inputBytes, privateKey);
|
||||
byte[] sig1 = sign(label, inputBytes, privateKey);
|
||||
byte[] sig2 = sign(label2, inputBytes, privateKey);
|
||||
assertFalse(Arrays.equals(sig1, sig2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSignatureVerification() throws Exception {
|
||||
byte[] sig = crypto.sign(label, inputBytes, privateKey);
|
||||
assertTrue(crypto.verify(label, inputBytes, publicKey, sig));
|
||||
byte[] sig = sign(label, inputBytes, privateKey);
|
||||
assertTrue(verify(label, inputBytes, publicKey, sig));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferentKeyFailsVerification() throws Exception {
|
||||
// Generate second private key
|
||||
KeyPair k2 = crypto.generateSignatureKeyPair();
|
||||
KeyPair k2 = generateKeyPair();
|
||||
byte[] privateKey2 = k2.getPrivate().getEncoded();
|
||||
// calculate the signature with different key, should fail to verify
|
||||
byte[] sig = crypto.sign(label, inputBytes, privateKey2);
|
||||
assertFalse(crypto.verify(label, inputBytes, publicKey, sig));
|
||||
byte[] sig = sign(label, inputBytes, privateKey2);
|
||||
assertFalse(verify(label, inputBytes, publicKey, sig));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -94,8 +103,8 @@ public class SignatureTest extends BrambleTestCase {
|
||||
// Generate a second input
|
||||
byte[] inputBytes2 = TestUtils.getRandomBytes(123);
|
||||
// calculate the signature with different input, should fail to verify
|
||||
byte[] sig = crypto.sign(label, inputBytes, privateKey);
|
||||
assertFalse(crypto.verify(label, inputBytes2, publicKey, sig));
|
||||
byte[] sig = sign(label, inputBytes, privateKey);
|
||||
assertFalse(verify(label, inputBytes2, publicKey, sig));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -103,8 +112,8 @@ public class SignatureTest extends BrambleTestCase {
|
||||
// Generate a second label
|
||||
String label2 = StringUtils.getRandomString(42);
|
||||
// calculate the signature with different label, should fail to verify
|
||||
byte[] sig = crypto.sign(label, inputBytes, privateKey);
|
||||
assertFalse(crypto.verify(label2, inputBytes, publicKey, sig));
|
||||
byte[] sig = sign(label, inputBytes, privateKey);
|
||||
assertFalse(verify(label2, inputBytes, publicKey, sig));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -47,10 +47,11 @@ import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
|
||||
import org.briarproject.bramble.api.transport.IncomingKeys;
|
||||
import org.briarproject.bramble.api.transport.OutgoingKeys;
|
||||
import org.briarproject.bramble.api.transport.TransportKeys;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.BrambleTestCase;
|
||||
import org.briarproject.bramble.test.TestUtils;
|
||||
import org.briarproject.bramble.util.StringUtils;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.Mockery;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -73,13 +74,7 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private final Database<Object> database = context.mock(Database.class);
|
||||
private final ShutdownManager shutdown =
|
||||
context.mock(ShutdownManager.class);
|
||||
private final EventBus eventBus = context.mock(EventBus.class);
|
||||
public class DatabaseComponentImplTest extends BrambleTestCase {
|
||||
|
||||
private final Object txn = new Object();
|
||||
private final ClientId clientId;
|
||||
@@ -130,8 +125,13 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testSimpleCalls() throws Exception {
|
||||
int shutdownHandle = 12345;
|
||||
Mockery context = new Mockery();
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
// open()
|
||||
oneOf(database).open();
|
||||
@@ -194,6 +194,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
// endTransaction()
|
||||
oneOf(database).commitTransaction(txn);
|
||||
// close()
|
||||
oneOf(shutdown).removeShutdownHook(shutdownHandle);
|
||||
oneOf(database).close();
|
||||
}});
|
||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||
@@ -220,11 +221,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
db.close();
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalMessagesAreNotStoredUnlessGroupExists()
|
||||
throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -244,10 +252,17 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddLocalMessage() throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -279,11 +294,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVariousMethodsThrowExceptionIfContactIsMissing()
|
||||
throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
// Check whether the contact is in the DB (which it's not)
|
||||
exactly(18).of(database).startTransaction();
|
||||
@@ -478,11 +500,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVariousMethodsThrowExceptionIfLocalAuthorIsMissing()
|
||||
throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
// Check whether the pseudonym is in the DB (which it's not)
|
||||
exactly(3).of(database).startTransaction();
|
||||
@@ -523,11 +552,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVariousMethodsThrowExceptionIfGroupIsMissing()
|
||||
throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
// Check whether the group is in the DB (which it's not)
|
||||
exactly(8).of(database).startTransaction();
|
||||
@@ -621,11 +657,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVariousMethodsThrowExceptionIfMessageIsMissing()
|
||||
throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
// Check whether the message is in the DB (which it's not)
|
||||
exactly(11).of(database).startTransaction();
|
||||
@@ -749,11 +792,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVariousMethodsThrowExceptionIfTransportIsMissing()
|
||||
throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
// startTransaction()
|
||||
oneOf(database).startTransaction();
|
||||
@@ -840,12 +890,19 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateAck() throws Exception {
|
||||
Collection<MessageId> messagesToAck = Arrays.asList(messageId,
|
||||
messageId1);
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -868,6 +925,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -875,6 +934,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
byte[] raw1 = new byte[size];
|
||||
Collection<MessageId> ids = Arrays.asList(messageId, messageId1);
|
||||
Collection<byte[]> messages = Arrays.asList(raw, raw1);
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -905,12 +969,19 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateOffer() throws Exception {
|
||||
MessageId messageId1 = new MessageId(TestUtils.getRandomId());
|
||||
Collection<MessageId> ids = Arrays.asList(messageId, messageId1);
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -936,12 +1007,19 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateRequest() throws Exception {
|
||||
MessageId messageId1 = new MessageId(TestUtils.getRandomId());
|
||||
Collection<MessageId> ids = Arrays.asList(messageId, messageId1);
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -964,6 +1042,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -971,6 +1051,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
byte[] raw1 = new byte[size];
|
||||
Collection<MessageId> ids = Arrays.asList(messageId, messageId1);
|
||||
Collection<byte[]> messages = Arrays.asList(raw, raw1);
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -1002,10 +1087,17 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReceiveAck() throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -1028,10 +1120,17 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReceiveMessage() throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -1076,10 +1175,17 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReceiveDuplicateMessage() throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -1106,10 +1212,17 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReceiveMessageWithoutVisibleGroup() throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -1129,6 +1242,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1136,6 +1251,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
MessageId messageId1 = new MessageId(TestUtils.getRandomId());
|
||||
MessageId messageId2 = new MessageId(TestUtils.getRandomId());
|
||||
MessageId messageId3 = new MessageId(TestUtils.getRandomId());
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -1176,10 +1296,17 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReceiveRequest() throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -1203,10 +1330,17 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChangingVisibilityCallsListeners() throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -1236,11 +1370,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotChangingVisibilityDoesNotCallListeners()
|
||||
throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -1262,6 +1403,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1269,6 +1412,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
TransportKeys transportKeys = createTransportKeys();
|
||||
Map<ContactId, TransportKeys> keys = Collections.singletonMap(
|
||||
contactId, transportKeys);
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
// startTransaction()
|
||||
oneOf(database).startTransaction();
|
||||
@@ -1298,6 +1446,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
private TransportKeys createTransportKeys() {
|
||||
@@ -1330,6 +1480,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
Settings merged = new Settings();
|
||||
merged.put("foo", "bar");
|
||||
merged.put("baz", "qux");
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
context.checking(new Expectations() {{
|
||||
// startTransaction()
|
||||
oneOf(database).startTransaction();
|
||||
@@ -1359,6 +1514,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
@@ -1388,6 +1545,12 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
private void testCannotStartTransactionDuringTransaction(
|
||||
boolean firstTxnReadOnly, boolean secondTxnReadOnly)
|
||||
throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -1397,12 +1560,22 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
shutdown);
|
||||
|
||||
assertNotNull(db.startTransaction(firstTxnReadOnly));
|
||||
db.startTransaction(secondTxnReadOnly);
|
||||
fail();
|
||||
try {
|
||||
db.startTransaction(secondTxnReadOnly);
|
||||
fail();
|
||||
} finally {
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCannotAddLocalIdentityAsContact() throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -1426,10 +1599,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCannotAddDuplicateContact() throws Exception {
|
||||
Mockery context = new Mockery();
|
||||
@SuppressWarnings("unchecked")
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
@@ -1455,12 +1636,18 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
} finally {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testMessageDependencies() throws Exception {
|
||||
int shutdownHandle = 12345;
|
||||
Mockery context = new Mockery();
|
||||
Database<Object> database = context.mock(Database.class);
|
||||
ShutdownManager shutdown = context.mock(ShutdownManager.class);
|
||||
EventBus eventBus = context.mock(EventBus.class);
|
||||
MessageId messageId2 = new MessageId(TestUtils.getRandomId());
|
||||
context.checking(new Expectations() {{
|
||||
// open()
|
||||
@@ -1506,6 +1693,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
// endTransaction()
|
||||
oneOf(database).commitTransaction(txn);
|
||||
// close()
|
||||
oneOf(shutdown).removeShutdownHook(shutdownHandle);
|
||||
oneOf(database).close();
|
||||
}});
|
||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||
@@ -1526,5 +1714,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
db.endTransaction(transaction);
|
||||
}
|
||||
db.close();
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,17 +150,14 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
||||
int port = ss.getLocalPort();
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
AtomicBoolean error = new AtomicBoolean(false);
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
ss.accept();
|
||||
latch.countDown();
|
||||
} catch (IOException e) {
|
||||
error.set(true);
|
||||
}
|
||||
new Thread(() -> {
|
||||
try {
|
||||
ss.accept();
|
||||
latch.countDown();
|
||||
} catch (IOException e) {
|
||||
error.set(true);
|
||||
}
|
||||
}.start();
|
||||
}).start();
|
||||
// Tell the plugin about the port
|
||||
TransportProperties p = new TransportProperties();
|
||||
p.put("ipPorts", addrString + ":" + port);
|
||||
@@ -243,17 +240,14 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
||||
ss.bind(new InetSocketAddress(addrString, 0), 10);
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
AtomicBoolean error = new AtomicBoolean(false);
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
ss.accept();
|
||||
latch.countDown();
|
||||
} catch (IOException e) {
|
||||
error.set(true);
|
||||
}
|
||||
new Thread(() -> {
|
||||
try {
|
||||
ss.accept();
|
||||
latch.countDown();
|
||||
} catch (IOException e) {
|
||||
error.set(true);
|
||||
}
|
||||
}.start();
|
||||
}).start();
|
||||
// Tell the plugin about the port
|
||||
BdfList descriptor = new BdfList();
|
||||
descriptor.add(TRANSPORT_ID_LAN);
|
||||
|
||||
@@ -215,6 +215,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
||||
long timestamp = 123456789;
|
||||
Message message = getMessage(contactGroupId, timestamp);
|
||||
Metadata meta = new Metadata();
|
||||
// Version 4 is being delivered
|
||||
BdfDictionary metaDictionary = BdfDictionary.of(
|
||||
new BdfEntry("transportId", "foo"),
|
||||
new BdfEntry("version", 4),
|
||||
@@ -222,19 +223,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
||||
);
|
||||
Map<MessageId, BdfDictionary> messageMetadata =
|
||||
new LinkedHashMap<>();
|
||||
// Old remote updates for the same transport should be deleted
|
||||
MessageId fooVersion2 = new MessageId(getRandomId());
|
||||
messageMetadata.put(fooVersion2, BdfDictionary.of(
|
||||
new BdfEntry("transportId", "foo"),
|
||||
new BdfEntry("version", 2),
|
||||
new BdfEntry("local", false)
|
||||
));
|
||||
MessageId fooVersion1 = new MessageId(getRandomId());
|
||||
messageMetadata.put(fooVersion1, BdfDictionary.of(
|
||||
new BdfEntry("transportId", "foo"),
|
||||
new BdfEntry("version", 1),
|
||||
new BdfEntry("local", false)
|
||||
));
|
||||
// An older remote update for the same transport should be deleted
|
||||
MessageId fooVersion3 = new MessageId(getRandomId());
|
||||
messageMetadata.put(fooVersion3, BdfDictionary.of(
|
||||
new BdfEntry("transportId", "foo"),
|
||||
@@ -248,11 +237,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||
contactGroupId);
|
||||
will(returnValue(messageMetadata));
|
||||
// Versions 1-3 should be deleted
|
||||
oneOf(db).deleteMessage(txn, fooVersion1);
|
||||
oneOf(db).deleteMessageMetadata(txn, fooVersion1);
|
||||
oneOf(db).deleteMessage(txn, fooVersion2);
|
||||
oneOf(db).deleteMessageMetadata(txn, fooVersion2);
|
||||
// The previous update (version 3) should be deleted
|
||||
oneOf(db).deleteMessage(txn, fooVersion3);
|
||||
oneOf(db).deleteMessageMetadata(txn, fooVersion3);
|
||||
}});
|
||||
@@ -268,6 +253,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
||||
long timestamp = 123456789;
|
||||
Message message = getMessage(contactGroupId, timestamp);
|
||||
Metadata meta = new Metadata();
|
||||
// Version 3 is being delivered
|
||||
BdfDictionary metaDictionary = BdfDictionary.of(
|
||||
new BdfEntry("transportId", "foo"),
|
||||
new BdfEntry("version", 3),
|
||||
@@ -275,19 +261,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
||||
);
|
||||
Map<MessageId, BdfDictionary> messageMetadata =
|
||||
new LinkedHashMap<>();
|
||||
// Old remote updates for the same transport should be deleted
|
||||
MessageId fooVersion2 = new MessageId(getRandomId());
|
||||
messageMetadata.put(fooVersion2, BdfDictionary.of(
|
||||
new BdfEntry("transportId", "foo"),
|
||||
new BdfEntry("version", 2),
|
||||
new BdfEntry("local", false)
|
||||
));
|
||||
MessageId fooVersion1 = new MessageId(getRandomId());
|
||||
messageMetadata.put(fooVersion1, BdfDictionary.of(
|
||||
new BdfEntry("transportId", "foo"),
|
||||
new BdfEntry("version", 1),
|
||||
new BdfEntry("local", false)
|
||||
));
|
||||
// A newer remote update for the same transport should not be deleted
|
||||
MessageId fooVersion4 = new MessageId(getRandomId());
|
||||
messageMetadata.put(fooVersion4, BdfDictionary.of(
|
||||
@@ -302,11 +275,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||
contactGroupId);
|
||||
will(returnValue(messageMetadata));
|
||||
// Versions 1 and 2 should be deleted, version 4 should not
|
||||
oneOf(db).deleteMessage(txn, fooVersion1);
|
||||
oneOf(db).deleteMessageMetadata(txn, fooVersion1);
|
||||
oneOf(db).deleteMessage(txn, fooVersion2);
|
||||
oneOf(db).deleteMessageMetadata(txn, fooVersion2);
|
||||
// The update being delivered (version 3) should be deleted
|
||||
oneOf(db).deleteMessage(txn, message.getId());
|
||||
oneOf(db).deleteMessageMetadata(txn, message.getId());
|
||||
@@ -343,7 +311,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
||||
|
||||
@Test
|
||||
public void testReturnsLatestLocalProperties() throws Exception {
|
||||
Transaction txn = new Transaction(null, false);
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
expectGetLocalProperties(txn);
|
||||
|
||||
@@ -357,7 +325,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
||||
@Test
|
||||
public void testReturnsEmptyPropertiesIfNoLocalPropertiesAreFound()
|
||||
throws Exception {
|
||||
Transaction txn = new Transaction(null, false);
|
||||
Transaction txn = new Transaction(null, true);
|
||||
Map<MessageId, BdfDictionary> messageMetadata =
|
||||
new LinkedHashMap<>();
|
||||
// A local update for another transport should be ignored
|
||||
@@ -369,7 +337,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
||||
));
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(false);
|
||||
oneOf(db).startTransaction(true);
|
||||
will(returnValue(txn));
|
||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||
localGroup.getId());
|
||||
@@ -384,7 +352,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
||||
|
||||
@Test
|
||||
public void testReturnsLocalProperties() throws Exception {
|
||||
Transaction txn = new Transaction(null, false);
|
||||
Transaction txn = new Transaction(null, true);
|
||||
Map<MessageId, BdfDictionary> messageMetadata =
|
||||
new LinkedHashMap<>();
|
||||
// A local update for another transport should be ignored
|
||||
@@ -404,7 +372,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
||||
BdfList fooUpdate = BdfList.of("foo", 1, fooPropertiesDict);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(false);
|
||||
oneOf(db).startTransaction(true);
|
||||
will(returnValue(txn));
|
||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||
localGroup.getId());
|
||||
@@ -423,7 +391,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
||||
@Test
|
||||
public void testReturnsRemotePropertiesOrEmptyProperties()
|
||||
throws Exception {
|
||||
Transaction txn = new Transaction(null, false);
|
||||
Transaction txn = new Transaction(null, true);
|
||||
Contact contact1 = getContact(false);
|
||||
Contact contact2 = getContact(true);
|
||||
Contact contact3 = getContact(true);
|
||||
@@ -457,7 +425,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
||||
BdfList fooUpdate = BdfList.of("foo", 1, fooPropertiesDict);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(db).startTransaction(false);
|
||||
oneOf(db).startTransaction(true);
|
||||
will(returnValue(txn));
|
||||
oneOf(db).getContacts(txn);
|
||||
will(returnValue(contacts));
|
||||
@@ -638,28 +606,14 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
||||
return new Message(messageId, g, timestamp, raw);
|
||||
}
|
||||
|
||||
private void expectGetLocalProperties(Transaction txn)
|
||||
throws Exception {
|
||||
Map<MessageId, BdfDictionary> messageMetadata =
|
||||
new LinkedHashMap<>();
|
||||
// The only update for transport "foo" should be returned
|
||||
private void expectGetLocalProperties(Transaction txn) throws Exception {
|
||||
Map<MessageId, BdfDictionary> messageMetadata = new LinkedHashMap<>();
|
||||
// The latest update for transport "foo" should be returned
|
||||
MessageId fooVersion999 = new MessageId(getRandomId());
|
||||
messageMetadata.put(fooVersion999, BdfDictionary.of(
|
||||
new BdfEntry("transportId", "foo"),
|
||||
new BdfEntry("version", 999)
|
||||
));
|
||||
// An old update for transport "bar" should be deleted
|
||||
MessageId barVersion2 = new MessageId(getRandomId());
|
||||
messageMetadata.put(barVersion2, BdfDictionary.of(
|
||||
new BdfEntry("transportId", "bar"),
|
||||
new BdfEntry("version", 2)
|
||||
));
|
||||
// An even older update for transport "bar" should be deleted
|
||||
MessageId barVersion1 = new MessageId(getRandomId());
|
||||
messageMetadata.put(barVersion1, BdfDictionary.of(
|
||||
new BdfEntry("transportId", "bar"),
|
||||
new BdfEntry("version", 1)
|
||||
));
|
||||
// The latest update for transport "bar" should be returned
|
||||
MessageId barVersion3 = new MessageId(getRandomId());
|
||||
messageMetadata.put(barVersion3, BdfDictionary.of(
|
||||
@@ -674,8 +628,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
|
||||
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
|
||||
localGroup.getId());
|
||||
will(returnValue(messageMetadata));
|
||||
oneOf(db).removeMessage(txn, barVersion1);
|
||||
oneOf(db).removeMessage(txn, barVersion2);
|
||||
// Retrieve and parse the latest local properties
|
||||
oneOf(clientHelper).getMessageAsList(txn, fooVersion999);
|
||||
will(returnValue(fooUpdate));
|
||||
|
||||
@@ -12,16 +12,16 @@ dependencies {
|
||||
implementation 'net.java.dev.jna:jna:4.4.0'
|
||||
implementation 'net.java.dev.jna:jna-platform:4.4.0'
|
||||
|
||||
apt 'com.google.dagger:dagger-compiler:2.0.2'
|
||||
apt "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||
|
||||
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
||||
testImplementation project(path: ':bramble-core', configuration: 'testOutput')
|
||||
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"
|
||||
testImplementation "junit:junit:$junitVersion"
|
||||
testImplementation "org.jmock:jmock:$jmockVersion"
|
||||
testImplementation "org.jmock:jmock-junit4:$jmockVersion"
|
||||
testImplementation "org.jmock:jmock-legacy:$jmockVersion"
|
||||
testImplementation "org.hamcrest:hamcrest-library:$hamcrestVersion"
|
||||
testImplementation "org.hamcrest:hamcrest-core:$hamcrestVersion"
|
||||
}
|
||||
|
||||
dependencyVerification {
|
||||
@@ -36,6 +36,7 @@ dependencyVerification {
|
||||
'com.madgag.spongycastle:core:1.58.0.0:core-1.58.0.0.jar:199617dd5698c5a9312b898c0a4cec7ce9dd8649d07f65d91629f58229d72728',
|
||||
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
|
||||
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
|
||||
'net.java.dev.jna:jna-platform:4.4.0:jna-platform-4.4.0.jar:e9dda9e884fc107eb6367710540789a12dfa8ad28be9326b22ca6e352e325499',
|
||||
'net.java.dev.jna:jna:4.4.0:jna-4.4.0.jar:c4dadeeecaa90c8847902082aee5eb107fcf59c5d0e63a17fcaf273c0e2d2bd1',
|
||||
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
|
||||
|
||||
@@ -6,7 +6,6 @@ dependencies {
|
||||
implementation project(path: ':bramble-core', configuration: 'default')
|
||||
implementation project(path: ':bramble-android', configuration: 'default')
|
||||
|
||||
def supportVersion = '27.0.1'
|
||||
implementation "com.android.support:support-v4:$supportVersion"
|
||||
implementation("com.android.support:appcompat-v7:$supportVersion") {
|
||||
exclude module: 'support-v4'
|
||||
@@ -20,7 +19,7 @@ dependencies {
|
||||
}
|
||||
implementation "com.android.support:cardview-v7:$supportVersion"
|
||||
implementation "com.android.support:support-annotations:$supportVersion"
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.1.0-beta3'
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
|
||||
|
||||
implementation('ch.acra:acra:4.8.5') {
|
||||
exclude module: 'support-v4'
|
||||
@@ -34,7 +33,7 @@ dependencies {
|
||||
implementation 'com.github.bumptech.glide:glide:3.8.0'
|
||||
implementation 'uk.co.samuelwall:material-tap-target-prompt:2.1.0'
|
||||
|
||||
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
|
||||
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||
|
||||
compileOnly 'javax.annotation:jsr250-api:1.0'
|
||||
|
||||
@@ -43,12 +42,12 @@ dependencies {
|
||||
testImplementation 'org.robolectric:robolectric:3.5.1'
|
||||
testImplementation 'org.robolectric:shadows-support-v4:3.0'
|
||||
testImplementation 'org.mockito:mockito-core:2.8.9'
|
||||
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"
|
||||
testImplementation "junit:junit:$junitVersion"
|
||||
testImplementation "org.jmock:jmock:$jmockVersion"
|
||||
testImplementation "org.jmock:jmock-junit4:$jmockVersion"
|
||||
testImplementation "org.jmock:jmock-legacy:$jmockVersion"
|
||||
testImplementation "org.hamcrest:hamcrest-library:$hamcrestVersion"
|
||||
testImplementation "org.hamcrest:hamcrest-core:$hamcrestVersion"
|
||||
}
|
||||
|
||||
dependencyVerification {
|
||||
@@ -61,8 +60,8 @@ dependencyVerification {
|
||||
'ch.acra:acra:4.8.5:acra-4.8.5.aar:afd5b28934d5166b55f261c85685ad59e8a4ebe9ca1960906afaa8c76d8dc9eb',
|
||||
'classworlds:classworlds:1.1-alpha-2:classworlds-1.1-alpha-2.jar:2bf4e59f3acd106fea6145a9a88fe8956509f8b9c0fdd11eb96fee757269e3f3',
|
||||
'com.almworks.sqlite4java:sqlite4java:0.282:sqlite4java-0.282.jar:9e1d8dd83ca6003f841e3af878ce2dc7c22497493a7bb6d1b62ec1b0d0a83c05',
|
||||
'com.android.support.constraint:constraint-layout-solver:1.1.0-beta3:constraint-layout-solver-1.1.0-beta3.jar:c9084108415046c423983bdff8cf04c8e9a5bed41b8d5329f3764c08312ee3dd',
|
||||
'com.android.support.constraint:constraint-layout:1.1.0-beta3:constraint-layout-1.1.0-beta3.aar:1754a6bd135feae485aa2ebf9e170f0f3d3282b392f8aa3067d0ed668839db79',
|
||||
'com.android.support.constraint:constraint-layout-solver:1.0.2:constraint-layout-solver-1.0.2.jar:8c62525a9bc5cff5633a96cb9b32fffeccaf41b8841aa87fc22607070dea9b8d',
|
||||
'com.android.support.constraint:constraint-layout:1.0.2:constraint-layout-1.0.2.aar:b0c688cc2b7172608f8153a689d746da40f71e52d7e2fe2bfd9df2f92db77085',
|
||||
'com.android.support:animated-vector-drawable:27.0.1:animated-vector-drawable-27.0.1.aar:365050110411c86c7eec86101b49ab53557ffe6667f60b19055f1d35c38a577b',
|
||||
'com.android.support:appcompat-v7:27.0.1:appcompat-v7-27.0.1.aar:1402c29a49db30346c21a7d40634461765b3ab826f5dd95bc4dcc76787b21851',
|
||||
'com.android.support:cardview-v7:27.0.1:cardview-v7-27.0.1.aar:43fccd44086c51eaa9d78be2fcf0dfea1556c8876a6fd325ea8d24e860054202',
|
||||
@@ -108,6 +107,7 @@ dependencyVerification {
|
||||
'nekohtml:xercesMinimal:1.9.6.2:xercesMinimal-1.9.6.2.jar:95b8b357d19f63797dd7d67622fd3f18374d64acbc6584faba1c7759a31e8438',
|
||||
'net.bytebuddy:byte-buddy-agent:1.6.14:byte-buddy-agent-1.6.14.jar:c141a2d6809c3eeff4a43d25992826abccebdd4b793af3e7a5f346e88ae73a33',
|
||||
'net.bytebuddy:byte-buddy:1.6.14:byte-buddy-1.6.14.jar:917758b3c651e278a15a029ba1d42dbf802d8b0e1fe2aa4b81c5750c64f461c1',
|
||||
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
|
||||
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
|
||||
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
|
||||
'org.apache.maven.wagon:wagon-file:1.0-beta-6:wagon-file-1.0-beta-6.jar:7298feeb36ff14dd933c38e62585fb9973fea32fb3c4bc5379428cb1aac5dd3c',
|
||||
@@ -185,19 +185,19 @@ android {
|
||||
defaultConfig {
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 26
|
||||
versionCode 1616
|
||||
versionName "0.16.16"
|
||||
applicationId "org.briarproject.briar.beta"
|
||||
resValue "string", "app_package", "org.briarproject.briar.beta"
|
||||
resValue "string", "app_name", "Briar Beta"
|
||||
versionCode 1700
|
||||
versionName "0.17.0"
|
||||
applicationId "org.briarproject.briar.android"
|
||||
resValue "string", "app_package", "org.briarproject.briar.android"
|
||||
resValue "string", "app_name", "Briar"
|
||||
buildConfigField "String", "GitHash", "\"${getGitHash()}\""
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
applicationIdSuffix ".debug"
|
||||
resValue "string", "app_package", "org.briarproject.briar.beta.debug"
|
||||
resValue "string", "app_name", "Briar Beta Debug"
|
||||
resValue "string", "app_package", "org.briarproject.briar.android.debug"
|
||||
resValue "string", "app_name", "Briar Debug"
|
||||
shrinkResources false
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
package org.briarproject.briar.android;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Application;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.support.v4.app.TaskStackBuilder;
|
||||
|
||||
@@ -47,7 +44,6 @@ import org.briarproject.briar.api.sharing.event.InvitationResponseReceivedEvent;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
@@ -61,10 +57,8 @@ import javax.inject.Inject;
|
||||
import static android.app.Notification.DEFAULT_LIGHTS;
|
||||
import static android.app.Notification.DEFAULT_SOUND;
|
||||
import static android.app.Notification.DEFAULT_VIBRATE;
|
||||
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
||||
import static android.content.Context.NOTIFICATION_SERVICE;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static android.support.v4.app.NotificationCompat.CATEGORY_MESSAGE;
|
||||
import static android.support.v4.app.NotificationCompat.CATEGORY_SOCIAL;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
@@ -89,12 +83,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
private static final int BLOG_POST_NOTIFICATION_ID = 6;
|
||||
private static final int INTRODUCTION_SUCCESS_NOTIFICATION_ID = 7;
|
||||
|
||||
// Channel IDs
|
||||
private static final String CONTACT_CHANNEL_ID = "contacts";
|
||||
private static final String GROUP_CHANNEL_ID = "groups";
|
||||
private static final String FORUM_CHANNEL_ID = "forums";
|
||||
private static final String BLOG_CHANNEL_ID = "blogs";
|
||||
|
||||
private static final long SOUND_DELAY = TimeUnit.SECONDS.toMillis(2);
|
||||
|
||||
private static final Logger LOG =
|
||||
@@ -103,9 +91,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
private final Executor dbExecutor;
|
||||
private final SettingsManager settingsManager;
|
||||
private final AndroidExecutor androidExecutor;
|
||||
private final Clock clock;
|
||||
private final Context appContext;
|
||||
private final NotificationManager notificationManager;
|
||||
private final Clock clock;
|
||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||
|
||||
// The following must only be accessed on the main UI thread
|
||||
@@ -134,8 +121,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
this.androidExecutor = androidExecutor;
|
||||
this.clock = clock;
|
||||
appContext = app.getApplicationContext();
|
||||
notificationManager = (NotificationManager)
|
||||
appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -147,33 +132,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
} catch (DbException e) {
|
||||
throw new ServiceException(e);
|
||||
}
|
||||
if (SDK_INT >= 26) {
|
||||
// Create notification channels
|
||||
Callable<Void> task = () -> {
|
||||
createNotificationChannel(CONTACT_CHANNEL_ID,
|
||||
R.string.contact_list_button);
|
||||
createNotificationChannel(GROUP_CHANNEL_ID,
|
||||
R.string.groups_button);
|
||||
createNotificationChannel(FORUM_CHANNEL_ID,
|
||||
R.string.forums_button);
|
||||
createNotificationChannel(BLOG_CHANNEL_ID,
|
||||
R.string.blogs_button);
|
||||
return null;
|
||||
};
|
||||
try {
|
||||
androidExecutor.runOnUiThread(task).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
throw new ServiceException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(26)
|
||||
private void createNotificationChannel(String channelId,
|
||||
@StringRes int name) {
|
||||
notificationManager.createNotificationChannel(
|
||||
new NotificationChannel(channelId, appContext.getString(name),
|
||||
IMPORTANCE_DEFAULT));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -198,34 +156,44 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
private void clearContactNotification() {
|
||||
contactCounts.clear();
|
||||
contactTotal = 0;
|
||||
notificationManager.cancel(PRIVATE_MESSAGE_NOTIFICATION_ID);
|
||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||
NotificationManager nm = (NotificationManager) o;
|
||||
nm.cancel(PRIVATE_MESSAGE_NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void clearGroupMessageNotification() {
|
||||
groupCounts.clear();
|
||||
groupTotal = 0;
|
||||
notificationManager.cancel(GROUP_MESSAGE_NOTIFICATION_ID);
|
||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||
NotificationManager nm = (NotificationManager) o;
|
||||
nm.cancel(GROUP_MESSAGE_NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void clearForumPostNotification() {
|
||||
forumCounts.clear();
|
||||
forumTotal = 0;
|
||||
notificationManager.cancel(FORUM_POST_NOTIFICATION_ID);
|
||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||
NotificationManager nm = (NotificationManager) o;
|
||||
nm.cancel(FORUM_POST_NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void clearBlogPostNotification() {
|
||||
blogCounts.clear();
|
||||
blogTotal = 0;
|
||||
notificationManager.cancel(BLOG_POST_NOTIFICATION_ID);
|
||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||
NotificationManager nm = (NotificationManager) o;
|
||||
nm.cancel(BLOG_POST_NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void clearIntroductionSuccessNotification() {
|
||||
introductionTotal = 0;
|
||||
notificationManager.cancel(INTRODUCTION_SUCCESS_NOTIFICATION_ID);
|
||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||
NotificationManager nm = (NotificationManager) o;
|
||||
nm.cancel(INTRODUCTION_SUCCESS_NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -301,8 +269,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
if (contactTotal == 0) {
|
||||
clearContactNotification();
|
||||
} else if (settings.getBoolean(PREF_NOTIFY_PRIVATE, true)) {
|
||||
BriarNotificationBuilder b = new BriarNotificationBuilder(
|
||||
appContext, CONTACT_CHANNEL_ID);
|
||||
BriarNotificationBuilder b =
|
||||
new BriarNotificationBuilder(appContext);
|
||||
b.setSmallIcon(R.drawable.notification_private_message);
|
||||
b.setColorRes(R.color.briar_primary);
|
||||
b.setContentTitle(appContext.getText(R.string.app_name));
|
||||
@@ -337,8 +305,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
t.addNextIntent(i);
|
||||
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
||||
}
|
||||
notificationManager.notify(PRIVATE_MESSAGE_NOTIFICATION_ID,
|
||||
b.build());
|
||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||
NotificationManager nm = (NotificationManager) o;
|
||||
nm.notify(PRIVATE_MESSAGE_NOTIFICATION_ID, b.build());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,7 +378,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
clearGroupMessageNotification();
|
||||
} else if (settings.getBoolean(PREF_NOTIFY_GROUP, true)) {
|
||||
BriarNotificationBuilder b =
|
||||
new BriarNotificationBuilder(appContext, GROUP_CHANNEL_ID);
|
||||
new BriarNotificationBuilder(appContext);
|
||||
b.setSmallIcon(R.drawable.notification_private_group);
|
||||
b.setColorRes(R.color.briar_primary);
|
||||
b.setContentTitle(appContext.getText(R.string.app_name));
|
||||
@@ -445,8 +414,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
t.addNextIntent(i);
|
||||
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
||||
}
|
||||
notificationManager.notify(GROUP_MESSAGE_NOTIFICATION_ID,
|
||||
b.build());
|
||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||
NotificationManager nm = (NotificationManager) o;
|
||||
nm.notify(GROUP_MESSAGE_NOTIFICATION_ID, b.build());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,7 +455,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
clearForumPostNotification();
|
||||
} else if (settings.getBoolean(PREF_NOTIFY_FORUM, true)) {
|
||||
BriarNotificationBuilder b =
|
||||
new BriarNotificationBuilder(appContext, FORUM_CHANNEL_ID);
|
||||
new BriarNotificationBuilder(appContext);
|
||||
b.setSmallIcon(R.drawable.notification_forum);
|
||||
b.setColorRes(R.color.briar_primary);
|
||||
b.setContentTitle(appContext.getText(R.string.app_name));
|
||||
@@ -521,7 +491,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
t.addNextIntent(i);
|
||||
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
||||
}
|
||||
notificationManager.notify(FORUM_POST_NOTIFICATION_ID, b.build());
|
||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||
NotificationManager nm = (NotificationManager) o;
|
||||
nm.notify(FORUM_POST_NOTIFICATION_ID, b.build());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -560,7 +532,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
clearBlogPostNotification();
|
||||
} else if (settings.getBoolean(PREF_NOTIFY_BLOG, true)) {
|
||||
BriarNotificationBuilder b =
|
||||
new BriarNotificationBuilder(appContext, BLOG_CHANNEL_ID);
|
||||
new BriarNotificationBuilder(appContext);
|
||||
b.setSmallIcon(R.drawable.notification_blog);
|
||||
b.setColorRes(R.color.briar_primary);
|
||||
b.setContentTitle(appContext.getText(R.string.app_name));
|
||||
@@ -583,7 +555,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
t.addNextIntent(i);
|
||||
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
||||
|
||||
notificationManager.notify(BLOG_POST_NOTIFICATION_ID, b.build());
|
||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||
NotificationManager nm = (NotificationManager) o;
|
||||
nm.notify(BLOG_POST_NOTIFICATION_ID, b.build());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,8 +577,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
|
||||
@UiThread
|
||||
private void updateIntroductionNotification() {
|
||||
BriarNotificationBuilder b =
|
||||
new BriarNotificationBuilder(appContext, CONTACT_CHANNEL_ID);
|
||||
BriarNotificationBuilder b = new BriarNotificationBuilder(appContext);
|
||||
b.setSmallIcon(R.drawable.notification_introduction);
|
||||
b.setColorRes(R.color.briar_primary);
|
||||
b.setContentTitle(appContext.getText(R.string.app_name));
|
||||
@@ -626,8 +599,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
||||
t.addNextIntent(i);
|
||||
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
||||
|
||||
notificationManager.notify(INTRODUCTION_SUCCESS_NOTIFICATION_ID,
|
||||
b.build());
|
||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||
NotificationManager nm = (NotificationManager) o;
|
||||
nm.notify(INTRODUCTION_SUCCESS_NOTIFICATION_ID, b.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6,8 +6,8 @@ package org.briarproject.briar.android;
|
||||
*/
|
||||
public interface BriarApplication {
|
||||
|
||||
// This build expires on 30 April 2018
|
||||
long EXPIRY_DATE = 1525046400 * 1000L;
|
||||
// This build expires on 31 December 2018
|
||||
long EXPIRY_DATE = 1546214400 * 1000L;
|
||||
|
||||
AndroidComponent getApplicationComponent();
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
@@ -25,12 +26,9 @@ import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
|
||||
import static android.app.NotificationManager.IMPORTANCE_NONE;
|
||||
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static android.support.v4.app.NotificationCompat.CATEGORY_SERVICE;
|
||||
import static android.support.v4.app.NotificationCompat.PRIORITY_MIN;
|
||||
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
|
||||
@@ -40,21 +38,9 @@ import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResul
|
||||
|
||||
public class BriarService extends Service {
|
||||
|
||||
public static String EXTRA_START_RESULT =
|
||||
"org.briarproject.briar.START_RESULT";
|
||||
public static String EXTRA_NOTIFICATION_ID =
|
||||
"org.briarproject.briar.FAILURE_NOTIFICATION_ID";
|
||||
public static String EXTRA_STARTUP_FAILED =
|
||||
"org.briarproject.briar.STARTUP_FAILED";
|
||||
|
||||
private static final int ONGOING_NOTIFICATION_ID = 1;
|
||||
private static final int FAILURE_NOTIFICATION_ID = 2;
|
||||
|
||||
// Channels are sorted by channel ID in the Settings app, so use IDs
|
||||
// that will sort below the main channels such as contacts
|
||||
private static final String ONGOING_CHANNEL_ID = "zForegroundService";
|
||||
private static final String FAILURE_CHANNEL_ID = "zStartupFailure";
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(BriarService.class.getName());
|
||||
|
||||
@@ -88,26 +74,20 @@ public class BriarService extends Service {
|
||||
stopSelf();
|
||||
return;
|
||||
}
|
||||
// Create notification channels
|
||||
if (SDK_INT >= 26) {
|
||||
NotificationManager nm = (NotificationManager)
|
||||
getSystemService(NOTIFICATION_SERVICE);
|
||||
NotificationChannel ongoingChannel = new NotificationChannel(
|
||||
ONGOING_CHANNEL_ID,
|
||||
getString(R.string.ongoing_notification_title),
|
||||
IMPORTANCE_NONE);
|
||||
ongoingChannel.setLockscreenVisibility(VISIBILITY_SECRET);
|
||||
nm.createNotificationChannel(ongoingChannel);
|
||||
NotificationChannel failureChannel = new NotificationChannel(
|
||||
FAILURE_CHANNEL_ID,
|
||||
getString(R.string.startup_failed_notification_title),
|
||||
IMPORTANCE_DEFAULT);
|
||||
failureChannel.setLockscreenVisibility(VISIBILITY_SECRET);
|
||||
nm.createNotificationChannel(failureChannel);
|
||||
// Create mandatory notification channel
|
||||
String channelId = "foregroundService";
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
NotificationChannel channel = new NotificationChannel(channelId,
|
||||
getString(R.string.app_name),
|
||||
NotificationManager.IMPORTANCE_NONE);
|
||||
channel.setLockscreenVisibility(VISIBILITY_SECRET);
|
||||
NotificationManager nm =
|
||||
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
nm.createNotificationChannel(channel);
|
||||
}
|
||||
// Show an ongoing notification that the service is running
|
||||
NotificationCompat.Builder b =
|
||||
new NotificationCompat.Builder(this, ONGOING_CHANNEL_ID);
|
||||
new NotificationCompat.Builder(this, channelId);
|
||||
b.setSmallIcon(R.drawable.notification_ongoing);
|
||||
b.setColor(ContextCompat.getColor(this, R.color.briar_primary));
|
||||
b.setContentTitle(getText(R.string.ongoing_notification_title));
|
||||
@@ -117,37 +97,34 @@ public class BriarService extends Service {
|
||||
Intent i = new Intent(this, NavDrawerActivity.class);
|
||||
i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP);
|
||||
b.setContentIntent(PendingIntent.getActivity(this, 0, i, 0));
|
||||
if (SDK_INT >= 21) {
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
b.setCategory(CATEGORY_SERVICE);
|
||||
b.setVisibility(VISIBILITY_SECRET);
|
||||
}
|
||||
b.setPriority(PRIORITY_MIN);
|
||||
startForeground(ONGOING_NOTIFICATION_ID, b.build());
|
||||
// Start the services in a background thread
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
String nickname = databaseConfig.getLocalAuthorName();
|
||||
StartResult result = lifecycleManager.startServices(nickname);
|
||||
if (result == SUCCESS) {
|
||||
started = true;
|
||||
} else if (result == ALREADY_RUNNING) {
|
||||
LOG.info("Already running");
|
||||
stopSelf();
|
||||
} else {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.warning("Startup failed: " + result);
|
||||
showStartupFailureNotification(result);
|
||||
stopSelf();
|
||||
}
|
||||
new Thread(() -> {
|
||||
String nickname = databaseConfig.getLocalAuthorName();
|
||||
StartResult result = lifecycleManager.startServices(nickname);
|
||||
if (result == SUCCESS) {
|
||||
started = true;
|
||||
} else if (result == ALREADY_RUNNING) {
|
||||
LOG.info("Already running");
|
||||
stopSelf();
|
||||
} else {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.warning("Startup failed: " + result);
|
||||
showStartupFailureNotification(result);
|
||||
stopSelf();
|
||||
}
|
||||
}.start();
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void showStartupFailureNotification(StartResult result) {
|
||||
androidExecutor.runOnUiThread(() -> {
|
||||
NotificationCompat.Builder b = new NotificationCompat.Builder(
|
||||
BriarService.this, FAILURE_CHANNEL_ID);
|
||||
NotificationCompat.Builder b =
|
||||
new NotificationCompat.Builder(BriarService.this);
|
||||
b.setSmallIcon(android.R.drawable.stat_notify_error);
|
||||
b.setContentTitle(getText(
|
||||
R.string.startup_failed_notification_title));
|
||||
@@ -156,8 +133,9 @@ public class BriarService extends Service {
|
||||
Intent i = new Intent(BriarService.this,
|
||||
StartupFailureActivity.class);
|
||||
i.setFlags(FLAG_ACTIVITY_NEW_TASK);
|
||||
i.putExtra(EXTRA_START_RESULT, result);
|
||||
i.putExtra(EXTRA_NOTIFICATION_ID, FAILURE_NOTIFICATION_ID);
|
||||
i.putExtra("briar.START_RESULT", result);
|
||||
i.putExtra("briar.FAILURE_NOTIFICATION_ID",
|
||||
FAILURE_NOTIFICATION_ID);
|
||||
b.setContentIntent(PendingIntent.getActivity(BriarService.this,
|
||||
0, i, FLAG_UPDATE_CURRENT));
|
||||
Object o = getSystemService(NOTIFICATION_SERVICE);
|
||||
@@ -166,7 +144,7 @@ public class BriarService extends Service {
|
||||
// Bring the dashboard to the front to clear the back stack
|
||||
i = new Intent(BriarService.this, NavDrawerActivity.class);
|
||||
i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP);
|
||||
i.putExtra(EXTRA_STARTUP_FAILED, true);
|
||||
i.putExtra("briar.STARTUP_FAILED", true);
|
||||
startActivity(i);
|
||||
});
|
||||
}
|
||||
@@ -187,12 +165,9 @@ public class BriarService extends Service {
|
||||
LOG.info("Destroyed");
|
||||
stopForeground(true);
|
||||
// Stop the services in a background thread
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (started) lifecycleManager.stopServices();
|
||||
}
|
||||
}.start();
|
||||
new Thread(() -> {
|
||||
if (started) lifecycleManager.stopServices();
|
||||
}).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -10,8 +10,6 @@ import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
import org.briarproject.briar.android.activity.BaseActivity;
|
||||
|
||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult;
|
||||
import static org.briarproject.briar.android.BriarService.EXTRA_NOTIFICATION_ID;
|
||||
import static org.briarproject.briar.android.BriarService.EXTRA_START_RESULT;
|
||||
|
||||
public class StartupFailureActivity extends BaseActivity {
|
||||
|
||||
@@ -29,9 +27,8 @@ public class StartupFailureActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
private void handleIntent(Intent i) {
|
||||
StartResult result =
|
||||
(StartResult) i.getSerializableExtra(EXTRA_START_RESULT);
|
||||
int notificationId = i.getIntExtra(EXTRA_NOTIFICATION_ID, -1);
|
||||
StartResult result = (StartResult) i.getSerializableExtra("briar.START_RESULT");
|
||||
int notificationId = i.getIntExtra("briar.FAILURE_NOTIFICATION_ID", -1);
|
||||
|
||||
// cancel notification
|
||||
if (notificationId > -1) {
|
||||
|
||||
@@ -18,7 +18,7 @@ public interface TestingConstants {
|
||||
* Whether this is a beta build. This should be set to false for final
|
||||
* release builds.
|
||||
*/
|
||||
boolean IS_BETA_BUILD = true;
|
||||
boolean IS_BETA_BUILD = false;
|
||||
|
||||
/**
|
||||
* Default log level. Disable logging for final release builds.
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.LayoutRes;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.View;
|
||||
@@ -139,9 +138,7 @@ public abstract class BaseActivity extends AppCompatActivity
|
||||
dialogFrag =
|
||||
ScreenFilterDialogFragment.newInstance(new ArrayList<>(apps));
|
||||
dialogFrag.setCancelable(false);
|
||||
// Show dialog unless onSaveInstanceState() has been called, see #1112
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
if (!fm.isStateSaved()) dialogFrag.show(fm, dialogFrag.getTag());
|
||||
dialogFrag.show(getSupportFragmentManager(), dialogFrag.getTag());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,7 +27,6 @@ import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
|
||||
import static android.os.Build.MANUFACTURER;
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING;
|
||||
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PASSWORD;
|
||||
@@ -36,6 +35,7 @@ import static org.briarproject.briar.android.util.UiUtils.getDozeWhitelistingInt
|
||||
@SuppressLint("Registered")
|
||||
public abstract class BriarActivity extends BaseActivity {
|
||||
|
||||
public static final String KEY_STARTUP_FAILED = "briar.STARTUP_FAILED";
|
||||
public static final String GROUP_ID = "briar.GROUP_ID";
|
||||
public static final String GROUP_NAME = "briar.GROUP_NAME";
|
||||
|
||||
@@ -79,10 +79,6 @@ public abstract class BriarActivity extends BaseActivity {
|
||||
|
||||
public void setSceneTransitionAnimation() {
|
||||
if (SDK_INT < 21) return;
|
||||
// workaround for #1007
|
||||
if (SDK_INT == 24 && MANUFACTURER.equalsIgnoreCase("Samsung")) {
|
||||
return;
|
||||
}
|
||||
Transition slide = new Slide(Gravity.RIGHT);
|
||||
slide.excludeTarget(android.R.id.statusBarBackground, true);
|
||||
slide.excludeTarget(android.R.id.navigationBarBackground, true);
|
||||
@@ -130,8 +126,8 @@ public abstract class BriarActivity extends BaseActivity {
|
||||
b.setNegativeButton(R.string.cancel,
|
||||
(dialog, which) -> dialog.dismiss());
|
||||
b.setOnDismissListener(dialog -> {
|
||||
CheckBox checkBox =
|
||||
((AlertDialog) dialog).findViewById(R.id.checkbox);
|
||||
CheckBox checkBox = (CheckBox) ((AlertDialog) dialog)
|
||||
.findViewById(R.id.checkbox);
|
||||
if (checkBox.isChecked())
|
||||
briarController.doNotAskAgainForDozeWhiteListing();
|
||||
});
|
||||
|
||||
@@ -123,25 +123,22 @@ public class BriarControllerImpl implements BriarController {
|
||||
|
||||
@Override
|
||||
public void signOut(ResultHandler<Void> eventHandler) {
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// Wait for the service to finish starting up
|
||||
IBinder binder = serviceConnection.waitForBinder();
|
||||
BriarService service =
|
||||
((BriarService.BriarBinder) binder).getService();
|
||||
service.waitForStartup();
|
||||
// Shut down the service and wait for it to shut down
|
||||
LOG.info("Shutting down service");
|
||||
service.shutdown();
|
||||
service.waitForShutdown();
|
||||
} catch (InterruptedException e) {
|
||||
LOG.warning("Interrupted while waiting for service");
|
||||
}
|
||||
eventHandler.onResult(null);
|
||||
new Thread(() -> {
|
||||
try {
|
||||
// Wait for the service to finish starting up
|
||||
IBinder binder = serviceConnection.waitForBinder();
|
||||
BriarService service =
|
||||
((BriarService.BriarBinder) binder).getService();
|
||||
service.waitForStartup();
|
||||
// Shut down the service and wait for it to shut down
|
||||
LOG.info("Shutting down service");
|
||||
service.shutdown();
|
||||
service.waitForShutdown();
|
||||
} catch (InterruptedException e) {
|
||||
LOG.warning("Interrupted while waiting for service");
|
||||
}
|
||||
}.start();
|
||||
eventHandler.onResult(null);
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void unbindService() {
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
package org.briarproject.briar.android.login;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
import org.briarproject.briar.android.login.PowerView.OnCheckedChangedListener;
|
||||
import org.briarproject.briar.android.util.UiUtils;
|
||||
|
||||
import static android.view.View.INVISIBLE;
|
||||
@@ -21,15 +19,12 @@ import static android.view.View.VISIBLE;
|
||||
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING;
|
||||
import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog;
|
||||
|
||||
@NotNullByDefault
|
||||
public class DozeFragment extends SetupFragment
|
||||
implements OnCheckedChangedListener {
|
||||
@TargetApi(23)
|
||||
public class DozeFragment extends SetupFragment {
|
||||
|
||||
private final static String TAG = DozeFragment.class.getName();
|
||||
|
||||
private DozeView dozeView;
|
||||
private HuaweiView huaweiView;
|
||||
private Button next;
|
||||
private Button dozeButton;
|
||||
private ProgressBar progressBar;
|
||||
private boolean secondAttempt = false;
|
||||
|
||||
@@ -38,22 +33,15 @@ public class DozeFragment extends SetupFragment
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
getActivity().setTitle(getString(R.string.setup_doze_title));
|
||||
setHasOptionsMenu(false);
|
||||
View v = inflater.inflate(R.layout.fragment_setup_doze, container,
|
||||
false);
|
||||
dozeView = v.findViewById(R.id.dozeView);
|
||||
dozeView.setOnCheckedChangedListener(this);
|
||||
huaweiView = v.findViewById(R.id.huaweiView);
|
||||
huaweiView.setOnCheckedChangedListener(this);
|
||||
next = v.findViewById(R.id.next);
|
||||
dozeButton = v.findViewById(R.id.dozeButton);
|
||||
progressBar = v.findViewById(R.id.progress);
|
||||
|
||||
dozeView.setOnButtonClickListener(this::askForDozeWhitelisting);
|
||||
next.setOnClickListener(this);
|
||||
dozeButton.setOnClickListener(view -> askForDozeWhitelisting());
|
||||
|
||||
return v;
|
||||
}
|
||||
@@ -77,34 +65,25 @@ public class DozeFragment extends SetupFragment
|
||||
public void onActivityResult(int request, int result, Intent data) {
|
||||
super.onActivityResult(request, result, data);
|
||||
if (request == REQUEST_DOZE_WHITELISTING) {
|
||||
if (!dozeView.needsToBeShown() || secondAttempt) {
|
||||
dozeView.setChecked(true);
|
||||
} else if (getContext() != null) {
|
||||
if (!setupController.needsDozeWhitelisting() || secondAttempt) {
|
||||
dozeButton.setEnabled(false);
|
||||
onClick(dozeButton);
|
||||
} else {
|
||||
secondAttempt = true;
|
||||
showOnboardingDialog(getContext(), getHelpText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCheckedChanged() {
|
||||
if (dozeView.isChecked() && huaweiView.isChecked()) {
|
||||
next.setEnabled(true);
|
||||
} else {
|
||||
next.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("BatteryLife")
|
||||
private void askForDozeWhitelisting() {
|
||||
if (getContext() == null) return;
|
||||
Intent i = UiUtils.getDozeWhitelistingIntent(getContext());
|
||||
startActivityForResult(i, REQUEST_DOZE_WHITELISTING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
next.setVisibility(INVISIBLE);
|
||||
dozeButton.setVisibility(INVISIBLE);
|
||||
progressBar.setVisibility(VISIBLE);
|
||||
setupController.createAccount();
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
package org.briarproject.briar.android.login;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
|
||||
import static org.briarproject.briar.android.util.UiUtils.needsDozeWhitelisting;
|
||||
|
||||
@UiThread
|
||||
@NotNullByDefault
|
||||
class DozeView extends PowerView {
|
||||
|
||||
@Nullable
|
||||
private Runnable onButtonClickListener;
|
||||
|
||||
public DozeView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public DozeView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public DozeView(Context context, @Nullable AttributeSet attrs,
|
||||
int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setText(R.string.setup_doze_intro);
|
||||
setButtonText(R.string.setup_doze_button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsToBeShown() {
|
||||
return needsToBeShown(getContext());
|
||||
}
|
||||
|
||||
public static boolean needsToBeShown(Context context) {
|
||||
return needsDozeWhitelisting(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getHelpText() {
|
||||
return R.string.setup_doze_explanation;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onButtonClick() {
|
||||
if (onButtonClickListener == null) throw new IllegalStateException();
|
||||
onButtonClickListener.run();
|
||||
}
|
||||
|
||||
public void setOnButtonClickListener(Runnable runnable) {
|
||||
onButtonClickListener = runnable;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package org.briarproject.briar.android.login;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@UiThread
|
||||
@NotNullByDefault
|
||||
class HuaweiView extends PowerView {
|
||||
|
||||
private final static String PACKAGE_NAME = "com.huawei.systemmanager";
|
||||
private final static String CLASS_NAME =
|
||||
PACKAGE_NAME + ".optimize.process.ProtectActivity";
|
||||
|
||||
public HuaweiView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public HuaweiView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public HuaweiView(Context context, @Nullable AttributeSet attrs,
|
||||
int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setText(R.string.setup_huawei_text);
|
||||
setButtonText(R.string.setup_huawei_button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsToBeShown() {
|
||||
return needsToBeShown(getContext());
|
||||
}
|
||||
|
||||
public static boolean needsToBeShown(Context context) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
List<ResolveInfo> resolveInfos = pm.queryIntentActivities(getIntent(),
|
||||
PackageManager.MATCH_DEFAULT_ONLY);
|
||||
return !resolveInfos.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
@StringRes
|
||||
protected int getHelpText() {
|
||||
return R.string.setup_huawei_help;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onButtonClick() {
|
||||
getContext().startActivity(getIntent());
|
||||
setChecked(true);
|
||||
}
|
||||
|
||||
private static Intent getIntent() {
|
||||
Intent intent = new Intent();
|
||||
intent.setClassName(PACKAGE_NAME, CLASS_NAME);
|
||||
return intent;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -66,7 +66,7 @@ public class PasswordFragment extends SetupFragment {
|
||||
component.inject(this);
|
||||
|
||||
// the controller is not yet available in onCreateView()
|
||||
if (!setupController.needToShowDozeFragment()) {
|
||||
if (!setupController.needsDozeWhitelisting()) {
|
||||
nextButton.setText(R.string.create_account_button);
|
||||
}
|
||||
}
|
||||
@@ -102,7 +102,7 @@ public class PasswordFragment extends SetupFragment {
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (!setupController.needToShowDozeFragment()) {
|
||||
if (!setupController.needsDozeWhitelisting()) {
|
||||
nextButton.setVisibility(INVISIBLE);
|
||||
progressBar.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
@@ -1,162 +0,0 @@
|
||||
package org.briarproject.briar.android.login;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.annotation.UiThread;
|
||||
import android.support.constraint.ConstraintLayout;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
|
||||
import static android.content.Context.LAYOUT_INFLATER_SERVICE;
|
||||
import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog;
|
||||
|
||||
@UiThread
|
||||
@NotNullByDefault
|
||||
abstract class PowerView extends ConstraintLayout {
|
||||
|
||||
private final TextView textView;
|
||||
private final ImageView checkImage;
|
||||
private final Button button;
|
||||
|
||||
private boolean checked = false;
|
||||
|
||||
@Nullable
|
||||
private OnCheckedChangedListener onCheckedChangedListener;
|
||||
|
||||
public PowerView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public PowerView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public PowerView(Context context, @Nullable AttributeSet attrs,
|
||||
int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater) context
|
||||
.getSystemService(LAYOUT_INFLATER_SERVICE);
|
||||
View v = inflater.inflate(R.layout.power_view, this, true);
|
||||
|
||||
textView = v.findViewById(R.id.textView);
|
||||
checkImage = v.findViewById(R.id.checkImage);
|
||||
button = v.findViewById(R.id.button);
|
||||
button.setOnClickListener(view -> onButtonClick());
|
||||
ImageButton helpButton = v.findViewById(R.id.helpButton);
|
||||
helpButton.setOnClickListener(view -> onHelpButtonClick());
|
||||
|
||||
// we need to manage the checkImage state ourselves, because automatic
|
||||
// state saving is done based on the view's ID and there can be
|
||||
// multiple ImageViews with the same ID in the view hierarchy
|
||||
setSaveFromParentEnabled(true);
|
||||
|
||||
if (!isInEditMode() && !needsToBeShown()) {
|
||||
setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
Parcelable superState = super.onSaveInstanceState();
|
||||
SavedState ss = new SavedState(superState);
|
||||
ss.value = new boolean[] {checked};
|
||||
return ss;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Parcelable state) {
|
||||
SavedState ss = (SavedState) state;
|
||||
super.onRestoreInstanceState(ss.getSuperState());
|
||||
setChecked(ss.value[0]); // also calls listener
|
||||
}
|
||||
|
||||
public abstract boolean needsToBeShown();
|
||||
|
||||
public void setChecked(boolean checked) {
|
||||
this.checked = checked;
|
||||
if (checked) {
|
||||
checkImage.setImageResource(R.drawable.ic_check_white);
|
||||
} else {
|
||||
checkImage.setImageResource(R.drawable.contact_disconnected);
|
||||
}
|
||||
if (onCheckedChangedListener != null) {
|
||||
onCheckedChangedListener.onCheckedChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isChecked() {
|
||||
return getVisibility() == GONE || checked;
|
||||
}
|
||||
|
||||
public void setOnCheckedChangedListener(
|
||||
OnCheckedChangedListener onCheckedChangedListener) {
|
||||
this.onCheckedChangedListener = onCheckedChangedListener;
|
||||
}
|
||||
|
||||
@StringRes
|
||||
protected abstract int getHelpText();
|
||||
|
||||
protected void setText(@StringRes int res) {
|
||||
textView.setText(res);
|
||||
}
|
||||
|
||||
protected void setButtonText(@StringRes int res) {
|
||||
button.setText(res);
|
||||
}
|
||||
|
||||
protected abstract void onButtonClick();
|
||||
|
||||
private void onHelpButtonClick() {
|
||||
showOnboardingDialog(getContext(),
|
||||
getContext().getString(getHelpText()));
|
||||
}
|
||||
|
||||
private static class SavedState extends BaseSavedState {
|
||||
private boolean[] value = {false};
|
||||
|
||||
private SavedState(@Nullable Parcelable superState) {
|
||||
super(superState);
|
||||
}
|
||||
|
||||
private SavedState(Parcel in) {
|
||||
super(in);
|
||||
in.readBooleanArray(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
super.writeToParcel(out, flags);
|
||||
out.writeBooleanArray(value);
|
||||
}
|
||||
|
||||
static final Parcelable.Creator<SavedState> CREATOR
|
||||
= new Parcelable.Creator<SavedState>() {
|
||||
public SavedState createFromParcel(Parcel in) {
|
||||
return new SavedState(in);
|
||||
}
|
||||
|
||||
public SavedState[] newArray(int size) {
|
||||
return new SavedState[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
interface OnCheckedChangedListener {
|
||||
void onCheckedChanged();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,7 +8,7 @@ public interface SetupController {
|
||||
|
||||
void setSetupActivity(SetupActivity setupActivity);
|
||||
|
||||
boolean needToShowDozeFragment();
|
||||
boolean needsDozeWhitelisting();
|
||||
|
||||
void setAuthorName(String authorName);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.android.controller.handler.ResultHandler;
|
||||
import org.briarproject.briar.android.controller.handler.UiResultHandler;
|
||||
import org.briarproject.briar.android.util.UiUtils;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@@ -40,10 +41,9 @@ public class SetupControllerImpl extends PasswordControllerImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needToShowDozeFragment() {
|
||||
public boolean needsDozeWhitelisting() {
|
||||
if (setupActivity == null) throw new IllegalStateException();
|
||||
return DozeView.needsToBeShown(setupActivity) ||
|
||||
HuaweiView.needsToBeShown(setupActivity);
|
||||
return UiUtils.needsDozeWhitelisting(setupActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,7 +61,7 @@ public class SetupControllerImpl extends PasswordControllerImpl
|
||||
@Override
|
||||
public void showDozeOrCreateAccount() {
|
||||
if (setupActivity == null) throw new IllegalStateException();
|
||||
if (needToShowDozeFragment()) {
|
||||
if (needsDozeWhitelisting()) {
|
||||
setupActivity.showDozeFragment();
|
||||
} else {
|
||||
createAccount();
|
||||
|
||||
@@ -51,7 +51,6 @@ import static android.support.v4.view.GravityCompat.START;
|
||||
import static android.support.v4.widget.DrawerLayout.LOCK_MODE_LOCKED_CLOSED;
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static org.briarproject.briar.android.BriarService.EXTRA_STARTUP_FAILED;
|
||||
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PASSWORD;
|
||||
import static org.briarproject.briar.android.navdrawer.NavDrawerController.ExpiryWarning.NO;
|
||||
import static org.briarproject.briar.android.navdrawer.NavDrawerController.ExpiryWarning.UPDATE;
|
||||
@@ -168,7 +167,7 @@ public class NavDrawerActivity extends BriarActivity implements
|
||||
}
|
||||
|
||||
private void exitIfStartupFailed(Intent intent) {
|
||||
if (intent.getBooleanExtra(EXTRA_STARTUP_FAILED, false)) {
|
||||
if (intent.getBooleanExtra(KEY_STARTUP_FAILED, false)) {
|
||||
finish();
|
||||
LOG.info("Exiting");
|
||||
System.exit(0);
|
||||
|
||||
@@ -29,6 +29,8 @@ import javax.inject.Inject;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.briar.android.BriarApplication.EXPIRY_DATE;
|
||||
import static org.briarproject.briar.android.TestingConstants.IS_BETA_BUILD;
|
||||
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
|
||||
import static org.briarproject.briar.android.controller.BriarControllerImpl.DOZE_ASK_AGAIN;
|
||||
import static org.briarproject.briar.android.navdrawer.NavDrawerController.ExpiryWarning.NO;
|
||||
import static org.briarproject.briar.android.navdrawer.NavDrawerController.ExpiryWarning.SHOW;
|
||||
@@ -44,7 +46,7 @@ public class NavDrawerControllerImpl extends DbControllerImpl
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(NavDrawerControllerImpl.class.getName());
|
||||
private static final String EXPIRY_DATE_WARNING = "expiryDateWarning";
|
||||
private static final String EXPIRY_SHOW_UPDATE = "expiryShowUpdateAgain";
|
||||
private static final String EXPIRY_SHOW_UPDATE = "expiryShowUpdate";
|
||||
|
||||
private final PluginManager pluginManager;
|
||||
private final SettingsManager settingsManager;
|
||||
@@ -106,6 +108,10 @@ public class NavDrawerControllerImpl extends DbControllerImpl
|
||||
|
||||
@Override
|
||||
public void showExpiryWarning(ResultHandler<ExpiryWarning> handler) {
|
||||
if (!IS_DEBUG_BUILD && !IS_BETA_BUILD) {
|
||||
handler.onResult(NO);
|
||||
return;
|
||||
}
|
||||
runOnDbThread(() -> {
|
||||
try {
|
||||
Settings settings =
|
||||
|
||||
@@ -12,8 +12,8 @@ import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
|
||||
|
||||
public class BriarNotificationBuilder extends NotificationCompat.Builder {
|
||||
|
||||
public BriarNotificationBuilder(Context context, String channelId) {
|
||||
super(context, channelId);
|
||||
public BriarNotificationBuilder(Context context) {
|
||||
super(context);
|
||||
// Auto-cancel does not fire the delete intent, see
|
||||
// https://issuetracker.google.com/issues/36961721
|
||||
setAutoCancel(true);
|
||||
|
||||
@@ -28,7 +28,6 @@ import javax.annotation.Nullable;
|
||||
import static android.content.Context.INPUT_METHOD_SERVICE;
|
||||
import static android.content.Context.LAYOUT_INFLATER_SERVICE;
|
||||
import static android.view.KeyEvent.KEYCODE_BACK;
|
||||
import static android.view.KeyEvent.KEYCODE_ENTER;
|
||||
import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
|
||||
|
||||
@UiThread
|
||||
@@ -83,22 +82,16 @@ public class TextInputView extends KeyboardAwareLinearLayout
|
||||
hideEmojiDrawer();
|
||||
return true;
|
||||
}
|
||||
if (keyCode == KEYCODE_ENTER && event.isCtrlPressed()) {
|
||||
trySendMessage();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
ui.sendButton.setOnClickListener(v -> trySendMessage());
|
||||
ui.sendButton.setOnClickListener(v -> {
|
||||
if (listener != null) {
|
||||
listener.onSendClick(ui.editText.getText().toString());
|
||||
}
|
||||
});
|
||||
ui.emojiDrawer.setEmojiEventListener(this);
|
||||
}
|
||||
|
||||
private void trySendMessage() {
|
||||
if (listener != null) {
|
||||
listener.onSendClick(ui.editText.getText().toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisibility(int visibility) {
|
||||
if (visibility == GONE && isKeyboardOpen()) {
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M11,18h2v-2h-2v2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM12,6c-2.21,0 -4,1.79 -4,4h2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2c0,2 -3,1.75 -3,5h2c0,-2.25 3,-2.5 3,-5 0,-2.21 -1.79,-4 -4,-4z"/>
|
||||
</vector>
|
||||
10
briar-android/src/main/res/drawable/navigation_accept.xml
Normal file
10
briar-android/src/main/res/drawable/navigation_accept.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:alpha="0.54"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
|
||||
</vector>
|
||||
@@ -26,7 +26,7 @@
|
||||
app:hintEnabled="false"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
app:layout_constraintTop_toBottomOf="parent">
|
||||
|
||||
<android.support.design.widget.TextInputEditText
|
||||
android:id="@+id/nickname_entry"
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true">
|
||||
@@ -17,47 +16,38 @@
|
||||
android:paddingStart="@dimen/margin_activity_horizontal"
|
||||
android:paddingTop="@dimen/margin_activity_vertical">
|
||||
|
||||
<org.briarproject.briar.android.login.DozeView
|
||||
android:id="@+id/dozeView"
|
||||
<TextView
|
||||
android:id="@+id/setup_explanation"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:text="@string/setup_doze_intro"
|
||||
android:textSize="@dimen/text_size_medium"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<org.briarproject.briar.android.login.HuaweiView
|
||||
android:id="@+id/huaweiView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/dozeView"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/next"
|
||||
android:id="@+id/dozeButton"
|
||||
style="@style/BriarButton.Default"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:enabled="false"
|
||||
android:text="@string/create_account_button"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/huaweiView"
|
||||
app:layout_constraintVertical_bias="1.0"
|
||||
tools:enabled="true"/>
|
||||
android:layout_marginTop="@dimen/margin_activity_horizontal"
|
||||
android:text="@string/setup_doze_button"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/setup_explanation"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress"
|
||||
style="?android:attr/progressBarStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/next"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/dozeButton"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/next"/>
|
||||
app:layout_constraintTop_toTopOf="@+id/dozeButton"/>
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:parentTag="android.support.constraint.ConstraintLayout">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textSize="@dimen/text_size_medium"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@string/setup_huawei_text"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/checkImage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/contact_disconnected"
|
||||
android:tint="?colorControlNormal"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/button"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/button"
|
||||
tools:ignore="ContentDescription"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/button"
|
||||
style="@style/BriarButton.Default"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/helpButton"
|
||||
app:layout_constraintStart_toEndOf="@+id/checkImage"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textView"
|
||||
tools:text="@string/setup_huawei_button"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/helpButton"
|
||||
style="@style/BriarButton.Default"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/help"
|
||||
android:src="@drawable/ic_help_outline_white"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/button"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/button"/>
|
||||
|
||||
</merge>
|
||||
@@ -16,7 +16,6 @@
|
||||
<color name="briar_primary_dark">@color/briar_blue_dark</color>
|
||||
|
||||
<color name="briar_accent">@color/briar_blue</color>
|
||||
<color name="control_normal_light">#757575</color>
|
||||
|
||||
<!-- text colors -->
|
||||
<color name="briar_text_link">#06b9ff</color>
|
||||
|
||||
@@ -21,11 +21,6 @@
|
||||
<string name="more_info">More Information</string>
|
||||
<string name="don_t_ask_again">Don\'t ask again</string>
|
||||
|
||||
<string name="setup_huawei_text">Please tap the button below and make sure Briar is protected in the \"Protected Apps\" screen.</string>
|
||||
<string name="setup_huawei_button">Protect Briar</string>
|
||||
<string name="setup_huawei_help">If Briar is not added to the protected apps list, it will be unable to run in the background.</string>
|
||||
<string name="warning_dozed">%s was unable to run in the background</string>
|
||||
|
||||
<!-- Login -->
|
||||
<string name="enter_password">Enter your password:</string>
|
||||
<string name="try_again">Wrong password, try again</string>
|
||||
@@ -39,10 +34,10 @@
|
||||
<string name="startup_failed_db_error">For some reason, your Briar database is corrupted beyond repair. Your account, your data and all your contacts are lost. Unfortunately, you need to reinstall Briar and set up a new account.</string>
|
||||
<string name="startup_failed_service_error">Briar was unable to start a required plugin. Reinstalling Briar usually solves this problem. However, please note that you will then lose your account and all data associated with it since Briar is not using central servers to store your data on.</string>
|
||||
<plurals name="expiry_warning">
|
||||
<item quantity="one">This is a beta version of Briar. Your account will expire in %d day and cannot be renewed.</item>
|
||||
<item quantity="other">This is a beta version of Briar. Your account will expire in %d days and cannot be renewed.</item>
|
||||
<item quantity="one">This is a test version of Briar. Your account will expire in %d day and cannot be renewed.</item>
|
||||
<item quantity="other">This is a test version of Briar. Your account will expire in %d days and cannot be renewed.</item>
|
||||
</plurals>
|
||||
<string name="expiry_update">The beta expiry date has been extended. Your account will now expire in %d days.</string>
|
||||
<string name="expiry_update">The testing expiry date has been extended. Your account will now expire in %d days.</string>
|
||||
<string name="expiry_date_reached">This software has expired.\nThank you for testing!</string>
|
||||
|
||||
<!-- Navigation Drawer -->
|
||||
@@ -100,8 +95,8 @@
|
||||
<string name="ellipsis">…</string>
|
||||
<string name="text_too_long">The entered text is too long</string>
|
||||
<string name="show_onboarding">Show Help Dialog</string>
|
||||
<string name="warning_dozed">%s was unable to run in the background</string>
|
||||
<string name="fix">Fix</string>
|
||||
<string name="help">Help</string>
|
||||
|
||||
<!-- Contacts and Private Conversations-->
|
||||
<string name="no_contacts">It seems that you are new here and have no contacts yet.\n\nTap the + icon at the top and follow the instructions to add some friends to your list.\n\nPlease remember: You can only add new contacts face-to-face to prevent anyone from impersonating you or reading your messages in the future.</string>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<item name="colorPrimary">@color/briar_primary</item>
|
||||
<item name="colorPrimaryDark">@color/briar_primary_dark</item>
|
||||
<item name="colorAccent">@color/briar_accent</item>
|
||||
<item name="colorControlNormal">@color/control_normal_light</item>
|
||||
<item name="android:textColorLink">@color/briar_text_link</item>
|
||||
<item name="android:windowBackground">@color/window_background</item>
|
||||
<item name="android:windowAnimationStyle">@style/ActivityAnimation</item>
|
||||
|
||||
@@ -61,7 +61,7 @@ public class PasswordFragmentTest {
|
||||
String safePass = "really.safe.password";
|
||||
|
||||
passwordFragment.setupController = setupController;
|
||||
when(setupController.needToShowDozeFragment()).thenReturn(false);
|
||||
when(setupController.needsDozeWhitelisting()).thenReturn(false);
|
||||
when(setupController.estimatePasswordStrength(safePass))
|
||||
.thenReturn(STRONG);
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ import static org.briarproject.briar.api.blog.BlogManager.CLIENT_ID;
|
||||
@NotNullByDefault
|
||||
public interface BlogPostFactory {
|
||||
|
||||
String SIGNING_LABEL_POST = CLIENT_ID + "/POST";
|
||||
String SIGNING_LABEL_COMMENT = CLIENT_ID + "/COMMENT";
|
||||
String SIGNING_LABEL_POST = CLIENT_ID.getString() + "/POST";
|
||||
String SIGNING_LABEL_COMMENT = CLIENT_ID.getString() + "/COMMENT";
|
||||
|
||||
BlogPost createBlogPost(GroupId groupId, long timestamp,
|
||||
@Nullable MessageId parent, LocalAuthor author, String body)
|
||||
|
||||
@@ -16,7 +16,7 @@ import static org.briarproject.briar.api.forum.ForumManager.CLIENT_ID;
|
||||
@NotNullByDefault
|
||||
public interface ForumPostFactory {
|
||||
|
||||
String SIGNING_LABEL_POST = CLIENT_ID + "/POST";
|
||||
String SIGNING_LABEL_POST = CLIENT_ID.getString() + "/POST";
|
||||
|
||||
@CryptoExecutor
|
||||
ForumPost createPost(GroupId groupId, long timestamp,
|
||||
|
||||
@@ -13,8 +13,8 @@ import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT
|
||||
@NotNullByDefault
|
||||
public interface GroupMessageFactory {
|
||||
|
||||
String SIGNING_LABEL_JOIN = CLIENT_ID + "/JOIN";
|
||||
String SIGNING_LABEL_POST = CLIENT_ID + "/POST";
|
||||
String SIGNING_LABEL_JOIN = CLIENT_ID.getString() + "/JOIN";
|
||||
String SIGNING_LABEL_POST = CLIENT_ID.getString() + "/POST";
|
||||
|
||||
/**
|
||||
* Creates a join announcement message for the creator of a group.
|
||||
|
||||
@@ -12,7 +12,7 @@ import static org.briarproject.briar.api.privategroup.invitation.GroupInvitation
|
||||
@NotNullByDefault
|
||||
public interface GroupInvitationFactory {
|
||||
|
||||
String SIGNING_LABEL_INVITE = CLIENT_ID + "/INVITE";
|
||||
String SIGNING_LABEL_INVITE = CLIENT_ID.getString() + "/INVITE";
|
||||
|
||||
/**
|
||||
* Returns a signature to include when inviting a member to join a private
|
||||
|
||||
@@ -13,20 +13,20 @@ dependencies {
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.8.0'
|
||||
implementation 'org.jsoup:jsoup:1.10.3'
|
||||
|
||||
apt 'com.google.dagger:dagger-compiler:2.0.2'
|
||||
apt "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||
|
||||
testImplementation project(path: ':bramble-core', configuration: 'default')
|
||||
testImplementation project(path: ':bramble-core', configuration: 'testOutput')
|
||||
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
||||
testImplementation 'net.jodah:concurrentunit:0.4.2'
|
||||
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"
|
||||
testImplementation "junit:junit:$junitVersion"
|
||||
testImplementation "org.jmock:jmock:$jmockVersion"
|
||||
testImplementation "org.jmock:jmock-junit4:$jmockVersion"
|
||||
testImplementation "org.jmock:jmock-legacy:$jmockVersion"
|
||||
testImplementation "org.hamcrest:hamcrest-library:$hamcrestVersion"
|
||||
testImplementation "org.hamcrest:hamcrest-core:$hamcrestVersion"
|
||||
|
||||
testApt 'com.google.dagger:dagger-compiler:2.0.2'
|
||||
testApt "com.google.dagger:dagger-compiler:$daggerVersion"
|
||||
}
|
||||
|
||||
dependencyVerification {
|
||||
@@ -45,6 +45,7 @@ dependencyVerification {
|
||||
'com.squareup.okio:okio:1.13.0:okio-1.13.0.jar:734269c3ebc5090e3b23566db558f421f0b4027277c79ad5d176b8ec168bb850',
|
||||
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
|
||||
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
|
||||
'net.jodah:concurrentunit:0.4.2:concurrentunit-0.4.2.jar:5583078e1acf91734939e985bc9e7ee947b0e93a8eef679da6bb07bbeb47ced3',
|
||||
'org.apache.ant:ant-launcher:1.9.4:ant-launcher-1.9.4.jar:7bccea20b41801ca17bcbc909a78c835d0f443f12d639c77bd6ae3d05861608d',
|
||||
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
|
||||
|
||||
@@ -98,7 +98,8 @@ class IntroduceeManager {
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(IntroduceeManager.class.getName());
|
||||
|
||||
static final String SIGNING_LABEL_RESPONSE = CLIENT_ID + "/RESPONSE";
|
||||
static final String SIGNING_LABEL_RESPONSE =
|
||||
CLIENT_ID.getString() + "/RESPONSE";
|
||||
|
||||
private final MessageSender messageSender;
|
||||
private final DatabaseComponent db;
|
||||
|
||||
36
build.gradle
36
build.gradle
@@ -21,22 +21,34 @@ buildscript {
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.0.1'
|
||||
classpath 'net.ltgt.gradle:gradle-apt-plugin:0.9'
|
||||
classpath 'de.undercouch:gradle-download-task:3.2.0'
|
||||
classpath 'de.undercouch:gradle-download-task:3.3.0'
|
||||
classpath files('libs/gradle-witness.jar')
|
||||
}
|
||||
}
|
||||
|
||||
// If a Java 6 JRE is available, check we're not using any Java 7 or 8 APIs
|
||||
ext.useJava6StandardLibrary = { task ->
|
||||
def home = System.env.JAVA_6_HOME;
|
||||
if (home != null && !home.isEmpty()) {
|
||||
println "Setting Java 6 bootstrap classpath for ${task.name}"
|
||||
task.dependsOn createJavaLangInvokeJar
|
||||
task.options.bootstrapClasspath = files(
|
||||
"${project.rootDir}/build/invoke.jar",
|
||||
"${home}/jre/lib/rt.jar",
|
||||
"${home}/jre/lib/jsse.jar"
|
||||
)
|
||||
|
||||
ext {
|
||||
// Define common library version centrally
|
||||
daggerVersion = '2.0.2'
|
||||
supportVersion = '27.0.1'
|
||||
junitVersion = '4.12'
|
||||
jmockVersion = '2.8.2'
|
||||
hamcrestVersion = '1.3'
|
||||
torVersion = '0.2.9.12'
|
||||
geoipVersion = '2017-09-06'
|
||||
|
||||
// If a Java 6 JRE is available, check we're not using any Java 7 or 8 APIs
|
||||
useJava6StandardLibrary = { task ->
|
||||
def home = System.env.JAVA_6_HOME;
|
||||
if (home != null && !home.isEmpty()) {
|
||||
println "Setting Java 6 bootstrap classpath for ${task.name}"
|
||||
task.dependsOn createJavaLangInvokeJar
|
||||
task.options.bootstrapClasspath = files(
|
||||
"${project.rootDir}/build/invoke.jar",
|
||||
"${home}/jre/lib/rt.jar",
|
||||
"${home}/jre/lib/jsse.jar"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user