mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Compare commits
130 Commits
831_refact
...
beta-0.16.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1748c9a86 | ||
|
|
9df624c62a | ||
|
|
b03a7dce3e | ||
|
|
6c59d7dd5f | ||
|
|
050191f0ef | ||
|
|
4b5a19ce5d | ||
|
|
7c4dd991b9 | ||
|
|
8455569e88 | ||
|
|
d25676559c | ||
|
|
a9437f7985 | ||
|
|
8141a97fc9 | ||
|
|
db842bd7e4 | ||
|
|
6dbec3a864 | ||
|
|
29f658cf4d | ||
|
|
ca83744a84 | ||
|
|
d91a9e2be4 | ||
|
|
8408c3f467 | ||
|
|
544c83a64c | ||
|
|
3800cd5e4f | ||
|
|
259f2cd419 | ||
|
|
20eb022c36 | ||
|
|
531e555b52 | ||
|
|
a9024aa34b | ||
|
|
d4e3b7842c | ||
|
|
167fddfbcc | ||
|
|
a48d642648 | ||
|
|
9a70f054c7 | ||
|
|
ca43d13bd6 | ||
|
|
5b71004179 | ||
|
|
63befccdbf | ||
|
|
4ecf7c02d0 | ||
|
|
f25badc18c | ||
|
|
6e931e9ba5 | ||
|
|
7e749124bf | ||
|
|
5822eb7808 | ||
|
|
7a7e086541 | ||
|
|
abab3167c2 | ||
|
|
8d08570568 | ||
|
|
2007078f13 | ||
|
|
dfb71a7978 | ||
|
|
480b0e3a03 | ||
|
|
8f8751f4ac | ||
|
|
de2ea112ee | ||
|
|
6f99a53fd9 | ||
|
|
a8a9b9032d | ||
|
|
6b15fb89de | ||
|
|
a711d6b8a1 | ||
|
|
5678f8aaa4 | ||
|
|
2fe37f6c26 | ||
|
|
a879747968 | ||
|
|
95e8fd7ee0 | ||
|
|
4416aaaa4c | ||
|
|
500d5f0efe | ||
|
|
fc8978fd90 | ||
|
|
73df126bd4 | ||
|
|
9146488c7d | ||
|
|
613a7fe376 | ||
|
|
ecb62f00d4 | ||
|
|
c4540a03cd | ||
|
|
3e31da99b5 | ||
|
|
098c1d0b1e | ||
|
|
178e908c86 | ||
|
|
ecf7cf14ae | ||
|
|
09e2a15a73 | ||
|
|
ab387860a6 | ||
|
|
f63fc94f2b | ||
|
|
41e5928cca | ||
|
|
8303175494 | ||
|
|
151eb6935b | ||
|
|
6a419c0c7b | ||
|
|
1795b32121 | ||
|
|
01971768ce | ||
|
|
ef7483ab01 | ||
|
|
527d11473d | ||
|
|
775dadc9a0 | ||
|
|
800b10a988 | ||
|
|
c977bf047d | ||
|
|
660a25f21d | ||
|
|
e7fd6d23af | ||
|
|
46982897f0 | ||
|
|
d24de68d64 | ||
|
|
7514c46a3f | ||
|
|
6632c0f8e3 | ||
|
|
79aafcda69 | ||
|
|
05af21e8dc | ||
|
|
0dc62cbbdc | ||
|
|
f3a084cfd2 | ||
|
|
8b32f82566 | ||
|
|
d598b6ed44 | ||
|
|
f5dc6f24b9 | ||
|
|
37454392da | ||
|
|
de7f9111d3 | ||
|
|
96d2889a6c | ||
|
|
f6412d1e9a | ||
|
|
b377cd6b1c | ||
|
|
f6cdbda5bb | ||
|
|
855c600a3e | ||
|
|
ea6e8303b0 | ||
|
|
d4934040d9 | ||
|
|
3449677b24 | ||
|
|
1ad3a6646e | ||
|
|
2d10f6b2bd | ||
|
|
5b05424d83 | ||
|
|
0826022d82 | ||
|
|
a901bfb9cb | ||
|
|
03cdce122a | ||
|
|
f2e0e16969 | ||
|
|
0c441e2ff3 | ||
|
|
21302304a5 | ||
|
|
6839d8b844 | ||
|
|
aee65a716c | ||
|
|
6a07d8f2c9 | ||
|
|
3c1ea81cd0 | ||
|
|
025f417bc7 | ||
|
|
c9dcd906c9 | ||
|
|
7024e04d15 | ||
|
|
0b8ac947db | ||
|
|
948410a064 | ||
|
|
2841339cac | ||
|
|
e8e82bd805 | ||
|
|
6876f40a0e | ||
|
|
5f4e1ecdfd | ||
|
|
044719432a | ||
|
|
d1a929da85 | ||
|
|
2a8978a60d | ||
|
|
c0afad7a26 | ||
|
|
37281c6c23 | ||
|
|
76a5e25656 | ||
|
|
3575b74837 | ||
|
|
f1c7996960 |
20
.gitlab-ci.yml
Normal file
20
.gitlab-ci.yml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
image: registry.gitlab.com/fdroid/ci-images-base:latest
|
||||||
|
|
||||||
|
cache:
|
||||||
|
paths:
|
||||||
|
- .gradle/wrapper
|
||||||
|
- .gradle/caches
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- export GRADLE_USER_HOME=$PWD/.gradle
|
||||||
|
# - export ANDROID_COMPILE_SDK=`sed -n 's,.*compileSdkVersion\s*\([0-9][0-9]*\).*,\1,p' app/build.gradle`
|
||||||
|
# - echo y | android --silent update sdk --no-ui --filter android-${ANDROID_COMPILE_SDK}
|
||||||
|
|
||||||
|
test:
|
||||||
|
script:
|
||||||
|
- ./gradlew test
|
||||||
|
|
||||||
|
after_script:
|
||||||
|
# this file changes every time but should not be cached
|
||||||
|
- rm -f $GRADLE_USER_HOME/caches/modules-2/modules-2.lock
|
||||||
|
- rm -fr $GRADLE_USER_HOME/caches/*/plugin-resolution/
|
||||||
@@ -12,8 +12,8 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 22
|
targetSdkVersion 22
|
||||||
versionCode 1
|
versionCode 14
|
||||||
versionName "1.0"
|
versionName "0.14"
|
||||||
consumerProguardFiles 'proguard-rules.txt'
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,38 +25,38 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':bramble-core')
|
compile project(':bramble-core')
|
||||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
compile fileTree(dir: 'libs', include: '*.jar')
|
||||||
provided 'javax.annotation:jsr250-api:1.0'
|
provided 'javax.annotation:jsr250-api:1.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
def torBinaryDir = 'src/main/res/raw'
|
def torBinaryDir = 'src/main/res/raw'
|
||||||
|
|
||||||
task downloadTorGeoIp(type: Download) {
|
task downloadTorGeoIp(type: Download) {
|
||||||
src 'https://briarproject.org/build/geoip-2015-12-01.zip'
|
src 'https://briarproject.org/build/geoip-2017-05-02.zip'
|
||||||
dest "$torBinaryDir/geoip.zip"
|
dest "$torBinaryDir/geoip.zip"
|
||||||
onlyIfNewer true
|
onlyIfNewer true
|
||||||
}
|
}
|
||||||
|
|
||||||
task downloadTorBinaryArm(type: Download) {
|
task downloadTorBinaryArm(type: Download) {
|
||||||
src 'https://briarproject.org/build/tor-0.2.7.6-arm.zip'
|
src 'https://briarproject.org/build/tor-0.2.9.11-arm.zip'
|
||||||
dest "$torBinaryDir/tor_arm.zip"
|
dest "$torBinaryDir/tor_arm.zip"
|
||||||
onlyIfNewer true
|
onlyIfNewer true
|
||||||
}
|
}
|
||||||
|
|
||||||
task downloadTorBinaryArmPie(type: Download) {
|
task downloadTorBinaryArmPie(type: Download) {
|
||||||
src 'https://briarproject.org/build/tor-0.2.7.6-arm-pie.zip'
|
src 'https://briarproject.org/build/tor-0.2.9.11-arm-pie.zip'
|
||||||
dest "$torBinaryDir/tor_arm_pie.zip"
|
dest "$torBinaryDir/tor_arm_pie.zip"
|
||||||
onlyIfNewer true
|
onlyIfNewer true
|
||||||
}
|
}
|
||||||
|
|
||||||
task downloadTorBinaryX86(type: Download) {
|
task downloadTorBinaryX86(type: Download) {
|
||||||
src 'https://briarproject.org/build/tor-0.2.7.6-x86.zip'
|
src 'https://briarproject.org/build/tor-0.2.9.11-x86.zip'
|
||||||
dest "$torBinaryDir/tor_x86.zip"
|
dest "$torBinaryDir/tor_x86.zip"
|
||||||
onlyIfNewer true
|
onlyIfNewer true
|
||||||
}
|
}
|
||||||
|
|
||||||
task downloadTorBinaryX86Pie(type: Download) {
|
task downloadTorBinaryX86Pie(type: Download) {
|
||||||
src 'https://briarproject.org/build/tor-0.2.7.6-x86-pie.zip'
|
src 'https://briarproject.org/build/tor-0.2.9.11-x86-pie.zip'
|
||||||
dest "$torBinaryDir/tor_x86_pie.zip"
|
dest "$torBinaryDir/tor_x86_pie.zip"
|
||||||
onlyIfNewer true
|
onlyIfNewer true
|
||||||
}
|
}
|
||||||
@@ -64,31 +64,31 @@ task downloadTorBinaryX86Pie(type: Download) {
|
|||||||
task verifyTorGeoIp(type: Verify, dependsOn: 'downloadTorGeoIp') {
|
task verifyTorGeoIp(type: Verify, dependsOn: 'downloadTorGeoIp') {
|
||||||
src "$torBinaryDir/geoip.zip"
|
src "$torBinaryDir/geoip.zip"
|
||||||
algorithm 'SHA-256'
|
algorithm 'SHA-256'
|
||||||
checksum '9bcdaf0a7ba0933735328d8ec466c25c25dbb459efc2bce9e55c774eabea5162'
|
checksum '51f4d1272fb867e1f3b36b67a584e2a33c40b40f62305457d799fd399cd77c9b'
|
||||||
}
|
}
|
||||||
|
|
||||||
task verifyTorBinaryArm(type: Verify, dependsOn: 'downloadTorBinaryArm') {
|
task verifyTorBinaryArm(type: Verify, dependsOn: 'downloadTorBinaryArm') {
|
||||||
src "$torBinaryDir/tor_arm.zip"
|
src "$torBinaryDir/tor_arm.zip"
|
||||||
algorithm 'SHA-256'
|
algorithm 'SHA-256'
|
||||||
checksum '83272962eda701cd5d74d2418651c4ff0f0b1dff51f558a292d1a1c42bf12146'
|
checksum '1da6008663a8ad98b349e62acbbf42c379f65ec504fa467cb119c187cd5a4c6b'
|
||||||
}
|
}
|
||||||
|
|
||||||
task verifyTorBinaryArmPie(type: Verify, dependsOn: 'downloadTorBinaryArmPie') {
|
task verifyTorBinaryArmPie(type: Verify, dependsOn: 'downloadTorBinaryArmPie') {
|
||||||
src "$torBinaryDir/tor_arm_pie.zip"
|
src "$torBinaryDir/tor_arm_pie.zip"
|
||||||
algorithm 'SHA-256'
|
algorithm 'SHA-256'
|
||||||
checksum 'd0300d1e45de11ebb24ed62b9c492be9c2e88590b7822195ab38c7a76ffcf646'
|
checksum 'eb061f880829e05f104690ac744848133f2dacef04759d425a2cff0df32c271e'
|
||||||
}
|
}
|
||||||
|
|
||||||
task verifyTorBinaryX86(type: Verify, dependsOn: 'downloadTorBinaryX86') {
|
task verifyTorBinaryX86(type: Verify, dependsOn: 'downloadTorBinaryX86') {
|
||||||
src "$torBinaryDir/tor_x86.zip"
|
src "$torBinaryDir/tor_x86.zip"
|
||||||
algorithm 'SHA-256'
|
algorithm 'SHA-256'
|
||||||
checksum 'b8813d97b01ee1b9c9a4233c1b9bbe9f9f6b494ae6f9cbd84de8a3911911615e'
|
checksum 'f5308aff8303daca082f82227d02b51ddedba4ab1d1420739ada0427ae5dbb41'
|
||||||
}
|
}
|
||||||
|
|
||||||
task verifyTorBinaryX86Pie(type: Verify, dependsOn: 'downloadTorBinaryX86Pie') {
|
task verifyTorBinaryX86Pie(type: Verify, dependsOn: 'downloadTorBinaryX86Pie') {
|
||||||
src "$torBinaryDir/tor_x86_pie.zip"
|
src "$torBinaryDir/tor_x86_pie.zip"
|
||||||
algorithm 'SHA-256'
|
algorithm 'SHA-256'
|
||||||
checksum '9c66e765aa196dc089951a1b2140cc8290305c2fcbf365121f99e01a233baf4e'
|
checksum '889a6c81ac73d05d35ed610ca5a913cee44d333e4ae1749c2a107f2f7dd8197b'
|
||||||
}
|
}
|
||||||
|
|
||||||
project.afterEvaluate {
|
project.afterEvaluate {
|
||||||
|
|||||||
Binary file not shown.
@@ -7,12 +7,12 @@ apply plugin: 'witness'
|
|||||||
dependencies {
|
dependencies {
|
||||||
compile "com.google.dagger:dagger:2.0.2"
|
compile "com.google.dagger:dagger:2.0.2"
|
||||||
compile 'com.google.dagger:dagger-compiler:2.0.2'
|
compile 'com.google.dagger:dagger-compiler:2.0.2'
|
||||||
compile 'com.google.code.findbugs:jsr305:3.0.1'
|
compile 'com.google.code.findbugs:jsr305:3.0.2'
|
||||||
|
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
testCompile "org.jmock:jmock:2.8.1"
|
testCompile "org.jmock:jmock:2.8.2"
|
||||||
testCompile "org.jmock:jmock-junit4:2.8.1"
|
testCompile "org.jmock:jmock-junit4:2.8.2"
|
||||||
testCompile "org.jmock:jmock-legacy:2.8.1"
|
testCompile "org.jmock:jmock-legacy:2.8.2"
|
||||||
testCompile "org.hamcrest:hamcrest-library:1.3"
|
testCompile "org.hamcrest:hamcrest-library:1.3"
|
||||||
testCompile "org.hamcrest:hamcrest-core:1.3"
|
testCompile "org.hamcrest:hamcrest-core:1.3"
|
||||||
}
|
}
|
||||||
@@ -21,7 +21,7 @@ dependencyVerification {
|
|||||||
verify = [
|
verify = [
|
||||||
'com.google.dagger:dagger:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
|
'com.google.dagger:dagger:84c0282ed8be73a29e0475d639da030b55dee72369e58dd35ae7d4fe6243dcf9',
|
||||||
'com.google.dagger:dagger-compiler:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
|
'com.google.dagger:dagger-compiler:b74bc9de063dd4c6400b232231f2ef5056145b8fbecbf5382012007dd1c071b3',
|
||||||
'com.google.code.findbugs:jsr305:c885ce34249682bc0236b4a7d56efcc12048e6135a5baf7a9cde8ad8cda13fcd',
|
'com.google.code.findbugs:jsr305:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
|
||||||
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||||
'com.google.dagger:dagger-producers:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
|
'com.google.dagger:dagger-producers:99ec15e8a0507ba569e7655bc1165ee5e5ca5aa914b3c8f7e2c2458f724edd6b',
|
||||||
'com.google.guava:guava:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
|
'com.google.guava:guava:d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99',
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.api;
|
package org.briarproject.bramble.api;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@@ -53,6 +54,12 @@ public class Bytes implements Comparable<Bytes> {
|
|||||||
return aBytes.length - bBytes.length;
|
return aBytes.length - bBytes.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getClass().getSimpleName() +
|
||||||
|
"(" + StringUtils.toHexString(getBytes()) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
public static class BytesComparator implements Comparator<Bytes> {
|
public static class BytesComparator implements Comparator<Bytes> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -137,7 +137,8 @@ public interface CryptoComponent {
|
|||||||
TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod);
|
TransportKeys rotateTransportKeys(TransportKeys k, long rotationPeriod);
|
||||||
|
|
||||||
/** Encodes the pseudo-random tag that is used to recognise a stream. */
|
/** Encodes the pseudo-random tag that is used to recognise a stream. */
|
||||||
void encodeTag(byte[] tag, SecretKey tagKey, long streamNumber);
|
void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion,
|
||||||
|
long streamNumber);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signs the given byte[] with the given PrivateKey.
|
* Signs the given byte[] with the given PrivateKey.
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ import org.briarproject.bramble.api.crypto.SecretKey;
|
|||||||
|
|
||||||
public interface TransportConstants {
|
public interface TransportConstants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current version of the transport protocol.
|
||||||
|
*/
|
||||||
|
int PROTOCOL_VERSION = 3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The length of the pseudo-random tag in bytes.
|
* The length of the pseudo-random tag in bytes.
|
||||||
*/
|
*/
|
||||||
@@ -14,21 +19,22 @@ public interface TransportConstants {
|
|||||||
*/
|
*/
|
||||||
int STREAM_HEADER_NONCE_LENGTH = 24;
|
int STREAM_HEADER_NONCE_LENGTH = 24;
|
||||||
|
|
||||||
/**
|
|
||||||
* The length of the stream header initialisation vector (IV) in bytes.
|
|
||||||
*/
|
|
||||||
int STREAM_HEADER_IV_LENGTH = STREAM_HEADER_NONCE_LENGTH - 8;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The length of the message authentication code (MAC) in bytes.
|
* The length of the message authentication code (MAC) in bytes.
|
||||||
*/
|
*/
|
||||||
int MAC_LENGTH = 16;
|
int MAC_LENGTH = 16;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length of the stream header plaintext in bytes. The stream header
|
||||||
|
* contains the protocol version, stream number and frame key.
|
||||||
|
*/
|
||||||
|
int STREAM_HEADER_PLAINTEXT_LENGTH = 2 + 8 + SecretKey.LENGTH;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The length of the stream header in bytes.
|
* The length of the stream header in bytes.
|
||||||
*/
|
*/
|
||||||
int STREAM_HEADER_LENGTH = STREAM_HEADER_IV_LENGTH + SecretKey.LENGTH
|
int STREAM_HEADER_LENGTH = STREAM_HEADER_NONCE_LENGTH
|
||||||
+ MAC_LENGTH;
|
+ STREAM_HEADER_PLAINTEXT_LENGTH + MAC_LENGTH;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The length of the frame nonce in bytes.
|
* The length of the frame nonce in bytes.
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public class PrivacyUtils {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static String scrubMacAddress(@Nullable String address) {
|
public static String scrubMacAddress(@Nullable String address) {
|
||||||
if (address == null) return null;
|
if (address == null || address.length() == 0) return null;
|
||||||
// this is a fake address we need to know about
|
// this is a fake address we need to know about
|
||||||
if (address.equals("02:00:00:00:00:00")) return address;
|
if (address.equals("02:00:00:00:00:00")) return address;
|
||||||
// keep first and last octet of MAC address
|
// keep first and last octet of MAC address
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "java"
|
id 'java'
|
||||||
id "net.ltgt.apt" version "0.9"
|
id 'net.ltgt.apt' version '0.9'
|
||||||
id "idea"
|
id 'idea'
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceCompatibility = 1.6
|
sourceCompatibility = 1.6
|
||||||
targetCompatibility = 1.6
|
targetCompatibility = 1.6
|
||||||
|
|
||||||
@@ -10,17 +11,18 @@ apply plugin: 'witness'
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':bramble-api')
|
compile project(':bramble-api')
|
||||||
compile fileTree(dir: 'libs', include: '*.jar')
|
compile 'com.madgag.spongycastle:core:1.56.0.0'
|
||||||
compile 'com.madgag.spongycastle:core:1.54.0.0'
|
compile 'com.h2database:h2:1.4.192' // This is the last version that supports Java 1.6
|
||||||
compile 'com.h2database:h2:1.4.190'
|
compile 'org.bitlet:weupnp:0.1.4'
|
||||||
|
|
||||||
testCompile project(path: ':bramble-api', configuration: 'testOutput')
|
testCompile project(path: ':bramble-api', configuration: 'testOutput')
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencyVerification {
|
dependencyVerification {
|
||||||
verify = [
|
verify = [
|
||||||
'com.madgag.spongycastle:core:1e7fa4b19ccccd1011364ab838d0b4702470c178bbbdd94c5c90b2d4d749ea1e',
|
'com.madgag.spongycastle:core:5e791b0eaa9e0c4594231b44f616a52adddb7dccedeb0ad9ad74887e19499a23',
|
||||||
'com.h2database:h2:23ba495a07bbbb3bd6c3084d10a96dad7a23741b8b6d64b213459a784195a98c'
|
'com.h2database:h2:225b22e9857235c46c93861410b60b8c81c10dc8985f4faf188985ba5445126c',
|
||||||
|
'org.bitlet:weupnp:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -54,6 +54,7 @@ public class BrambleCoreModule {
|
|||||||
c.inject(new IdentityModule.EagerSingletons());
|
c.inject(new IdentityModule.EagerSingletons());
|
||||||
c.inject(new LifecycleModule.EagerSingletons());
|
c.inject(new LifecycleModule.EagerSingletons());
|
||||||
c.inject(new PluginModule.EagerSingletons());
|
c.inject(new PluginModule.EagerSingletons());
|
||||||
|
c.inject(new PropertiesModule.EagerSingletons());
|
||||||
c.inject(new SyncModule.EagerSingletons());
|
c.inject(new SyncModule.EagerSingletons());
|
||||||
c.inject(new SystemModule.EagerSingletons());
|
c.inject(new SystemModule.EagerSingletons());
|
||||||
c.inject(new TransportModule.EagerSingletons());
|
c.inject(new TransportModule.EagerSingletons());
|
||||||
|
|||||||
@@ -45,8 +45,10 @@ import static org.briarproject.bramble.api.invitation.InvitationConstants.CODE_B
|
|||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.briarproject.bramble.crypto.EllipticCurveConstants.PARAMETERS;
|
import static org.briarproject.bramble.crypto.EllipticCurveConstants.PARAMETERS;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_32_BYTES;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
|
|
||||||
class CryptoComponentImpl implements CryptoComponent {
|
class CryptoComponentImpl implements CryptoComponent {
|
||||||
@@ -412,8 +414,11 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void encodeTag(byte[] tag, SecretKey tagKey, long streamNumber) {
|
public void encodeTag(byte[] tag, SecretKey tagKey, int protocolVersion,
|
||||||
|
long streamNumber) {
|
||||||
if (tag.length < TAG_LENGTH) throw new IllegalArgumentException();
|
if (tag.length < TAG_LENGTH) throw new IllegalArgumentException();
|
||||||
|
if (protocolVersion < 0 || protocolVersion > MAX_16_BIT_UNSIGNED)
|
||||||
|
throw new IllegalArgumentException();
|
||||||
if (streamNumber < 0 || streamNumber > MAX_32_BIT_UNSIGNED)
|
if (streamNumber < 0 || streamNumber > MAX_32_BIT_UNSIGNED)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
// Initialise the PRF
|
// Initialise the PRF
|
||||||
@@ -421,10 +426,14 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
// The output of the PRF must be long enough to use as a tag
|
// The output of the PRF must be long enough to use as a tag
|
||||||
int macLength = prf.getDigestSize();
|
int macLength = prf.getDigestSize();
|
||||||
if (macLength < TAG_LENGTH) throw new IllegalStateException();
|
if (macLength < TAG_LENGTH) throw new IllegalStateException();
|
||||||
// The input is the stream number as a 64-bit integer
|
// The input is the protocol version as a 16-bit integer, followed by
|
||||||
byte[] input = new byte[INT_64_BYTES];
|
// the stream number as a 64-bit integer
|
||||||
ByteUtils.writeUint64(streamNumber, input, 0);
|
byte[] protocolVersionBytes = new byte[INT_16_BYTES];
|
||||||
prf.update(input, 0, input.length);
|
ByteUtils.writeUint16(protocolVersion, protocolVersionBytes, 0);
|
||||||
|
prf.update(protocolVersionBytes, 0, protocolVersionBytes.length);
|
||||||
|
byte[] streamNumberBytes = new byte[INT_64_BYTES];
|
||||||
|
ByteUtils.writeUint64(streamNumber, streamNumberBytes, 0);
|
||||||
|
prf.update(streamNumberBytes, 0, streamNumberBytes.length);
|
||||||
byte[] mac = new byte[macLength];
|
byte[] mac = new byte[macLength];
|
||||||
prf.doFinal(mac, 0);
|
prf.doFinal(mac, 0);
|
||||||
// The output is the first TAG_LENGTH bytes of the MAC
|
// The output is the first TAG_LENGTH bytes of the MAC
|
||||||
|
|||||||
@@ -20,9 +20,11 @@ import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NO
|
|||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_PLAINTEXT_LENGTH;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@@ -117,7 +119,7 @@ class StreamDecrypterImpl implements StreamDecrypter {
|
|||||||
|
|
||||||
private void readStreamHeader() throws IOException {
|
private void readStreamHeader() throws IOException {
|
||||||
byte[] streamHeaderCiphertext = new byte[STREAM_HEADER_LENGTH];
|
byte[] streamHeaderCiphertext = new byte[STREAM_HEADER_LENGTH];
|
||||||
byte[] streamHeaderPlaintext = new byte[SecretKey.LENGTH];
|
byte[] streamHeaderPlaintext = new byte[STREAM_HEADER_PLAINTEXT_LENGTH];
|
||||||
// Read the stream header
|
// Read the stream header
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
while (offset < STREAM_HEADER_LENGTH) {
|
while (offset < STREAM_HEADER_LENGTH) {
|
||||||
@@ -126,21 +128,35 @@ class StreamDecrypterImpl implements StreamDecrypter {
|
|||||||
if (read == -1) throw new EOFException();
|
if (read == -1) throw new EOFException();
|
||||||
offset += read;
|
offset += read;
|
||||||
}
|
}
|
||||||
// The nonce consists of the stream number followed by the IV
|
// Extract the nonce
|
||||||
byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH];
|
byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH];
|
||||||
ByteUtils.writeUint64(streamNumber, streamHeaderNonce, 0);
|
System.arraycopy(streamHeaderCiphertext, 0, streamHeaderNonce, 0,
|
||||||
System.arraycopy(streamHeaderCiphertext, 0, streamHeaderNonce,
|
STREAM_HEADER_NONCE_LENGTH);
|
||||||
INT_64_BYTES, STREAM_HEADER_IV_LENGTH);
|
|
||||||
// Decrypt and authenticate the stream header
|
// Decrypt and authenticate the stream header
|
||||||
try {
|
try {
|
||||||
cipher.init(false, streamHeaderKey, streamHeaderNonce);
|
cipher.init(false, streamHeaderKey, streamHeaderNonce);
|
||||||
int decrypted = cipher.process(streamHeaderCiphertext,
|
int decrypted = cipher.process(streamHeaderCiphertext,
|
||||||
STREAM_HEADER_IV_LENGTH, SecretKey.LENGTH + MAC_LENGTH,
|
STREAM_HEADER_NONCE_LENGTH,
|
||||||
|
STREAM_HEADER_PLAINTEXT_LENGTH + MAC_LENGTH,
|
||||||
streamHeaderPlaintext, 0);
|
streamHeaderPlaintext, 0);
|
||||||
if (decrypted != SecretKey.LENGTH) throw new RuntimeException();
|
if (decrypted != STREAM_HEADER_PLAINTEXT_LENGTH)
|
||||||
|
throw new RuntimeException();
|
||||||
} catch (GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
frameKey = new SecretKey(streamHeaderPlaintext);
|
// Check the protocol version
|
||||||
|
int receivedProtocolVersion =
|
||||||
|
ByteUtils.readUint16(streamHeaderPlaintext, 0);
|
||||||
|
if (receivedProtocolVersion != PROTOCOL_VERSION)
|
||||||
|
throw new FormatException();
|
||||||
|
// Check the stream number
|
||||||
|
long receivedStreamNumber = ByteUtils.readUint64(streamHeaderPlaintext,
|
||||||
|
INT_16_BYTES);
|
||||||
|
if (receivedStreamNumber != streamNumber) throw new FormatException();
|
||||||
|
// Extract the frame key
|
||||||
|
byte[] frameKeyBytes = new byte[SecretKey.LENGTH];
|
||||||
|
System.arraycopy(streamHeaderPlaintext, INT_16_BYTES + INT_64_BYTES,
|
||||||
|
frameKeyBytes, 0, SecretKey.LENGTH);
|
||||||
|
frameKey = new SecretKey(frameKeyBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,8 @@ import javax.annotation.concurrent.Immutable;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Provider;
|
import javax.inject.Provider;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -36,22 +37,22 @@ class StreamEncrypterFactoryImpl implements StreamEncrypterFactory {
|
|||||||
AuthenticatedCipher cipher = cipherProvider.get();
|
AuthenticatedCipher cipher = cipherProvider.get();
|
||||||
long streamNumber = ctx.getStreamNumber();
|
long streamNumber = ctx.getStreamNumber();
|
||||||
byte[] tag = new byte[TAG_LENGTH];
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
crypto.encodeTag(tag, ctx.getTagKey(), streamNumber);
|
crypto.encodeTag(tag, ctx.getTagKey(), PROTOCOL_VERSION, streamNumber);
|
||||||
byte[] streamHeaderIv = new byte[STREAM_HEADER_IV_LENGTH];
|
byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH];
|
||||||
crypto.getSecureRandom().nextBytes(streamHeaderIv);
|
crypto.getSecureRandom().nextBytes(streamHeaderNonce);
|
||||||
SecretKey frameKey = crypto.generateSecretKey();
|
SecretKey frameKey = crypto.generateSecretKey();
|
||||||
return new StreamEncrypterImpl(out, cipher, streamNumber, tag,
|
return new StreamEncrypterImpl(out, cipher, streamNumber, tag,
|
||||||
streamHeaderIv, ctx.getHeaderKey(), frameKey);
|
streamHeaderNonce, ctx.getHeaderKey(), frameKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StreamEncrypter createInvitationStreamEncrypter(OutputStream out,
|
public StreamEncrypter createInvitationStreamEncrypter(OutputStream out,
|
||||||
SecretKey headerKey) {
|
SecretKey headerKey) {
|
||||||
AuthenticatedCipher cipher = cipherProvider.get();
|
AuthenticatedCipher cipher = cipherProvider.get();
|
||||||
byte[] streamHeaderIv = new byte[STREAM_HEADER_IV_LENGTH];
|
byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH];
|
||||||
crypto.getSecureRandom().nextBytes(streamHeaderIv);
|
crypto.getSecureRandom().nextBytes(streamHeaderNonce);
|
||||||
SecretKey frameKey = crypto.generateSecretKey();
|
SecretKey frameKey = crypto.generateSecretKey();
|
||||||
return new StreamEncrypterImpl(out, cipher, 0, null, streamHeaderIv,
|
return new StreamEncrypterImpl(out, cipher, 0, null, streamHeaderNonce,
|
||||||
headerKey, frameKey);
|
headerKey, frameKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_NO
|
|||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_PLAINTEXT_LENGTH;
|
||||||
|
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@@ -33,7 +35,7 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
|||||||
private final long streamNumber;
|
private final long streamNumber;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final byte[] tag;
|
private final byte[] tag;
|
||||||
private final byte[] streamHeaderIv;
|
private final byte[] streamHeaderNonce;
|
||||||
private final byte[] frameNonce, frameHeader;
|
private final byte[] frameNonce, frameHeader;
|
||||||
private final byte[] framePlaintext, frameCiphertext;
|
private final byte[] framePlaintext, frameCiphertext;
|
||||||
|
|
||||||
@@ -41,13 +43,13 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
|||||||
private boolean writeTag, writeStreamHeader;
|
private boolean writeTag, writeStreamHeader;
|
||||||
|
|
||||||
StreamEncrypterImpl(OutputStream out, AuthenticatedCipher cipher,
|
StreamEncrypterImpl(OutputStream out, AuthenticatedCipher cipher,
|
||||||
long streamNumber, @Nullable byte[] tag, byte[] streamHeaderIv,
|
long streamNumber, @Nullable byte[] tag, byte[] streamHeaderNonce,
|
||||||
SecretKey streamHeaderKey, SecretKey frameKey) {
|
SecretKey streamHeaderKey, SecretKey frameKey) {
|
||||||
this.out = out;
|
this.out = out;
|
||||||
this.cipher = cipher;
|
this.cipher = cipher;
|
||||||
this.streamNumber = streamNumber;
|
this.streamNumber = streamNumber;
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
this.streamHeaderIv = streamHeaderIv;
|
this.streamHeaderNonce = streamHeaderNonce;
|
||||||
this.streamHeaderKey = streamHeaderKey;
|
this.streamHeaderKey = streamHeaderKey;
|
||||||
this.frameKey = frameKey;
|
this.frameKey = frameKey;
|
||||||
frameNonce = new byte[FRAME_NONCE_LENGTH];
|
frameNonce = new byte[FRAME_NONCE_LENGTH];
|
||||||
@@ -114,22 +116,23 @@ class StreamEncrypterImpl implements StreamEncrypter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void writeStreamHeader() throws IOException {
|
private void writeStreamHeader() throws IOException {
|
||||||
// The nonce consists of the stream number followed by the IV
|
// The header contains the protocol version, stream number and frame key
|
||||||
byte[] streamHeaderNonce = new byte[STREAM_HEADER_NONCE_LENGTH];
|
byte[] streamHeaderPlaintext = new byte[STREAM_HEADER_PLAINTEXT_LENGTH];
|
||||||
ByteUtils.writeUint64(streamNumber, streamHeaderNonce, 0);
|
ByteUtils.writeUint16(PROTOCOL_VERSION, streamHeaderPlaintext, 0);
|
||||||
System.arraycopy(streamHeaderIv, 0, streamHeaderNonce, INT_64_BYTES,
|
ByteUtils.writeUint64(streamNumber, streamHeaderPlaintext,
|
||||||
STREAM_HEADER_IV_LENGTH);
|
INT_16_BYTES);
|
||||||
byte[] streamHeaderPlaintext = frameKey.getBytes();
|
System.arraycopy(frameKey.getBytes(), 0, streamHeaderPlaintext,
|
||||||
|
INT_16_BYTES + INT_64_BYTES, SecretKey.LENGTH);
|
||||||
byte[] streamHeaderCiphertext = new byte[STREAM_HEADER_LENGTH];
|
byte[] streamHeaderCiphertext = new byte[STREAM_HEADER_LENGTH];
|
||||||
System.arraycopy(streamHeaderIv, 0, streamHeaderCiphertext, 0,
|
System.arraycopy(streamHeaderNonce, 0, streamHeaderCiphertext, 0,
|
||||||
STREAM_HEADER_IV_LENGTH);
|
STREAM_HEADER_NONCE_LENGTH);
|
||||||
// Encrypt and authenticate the frame key
|
// Encrypt and authenticate the stream header key
|
||||||
try {
|
try {
|
||||||
cipher.init(true, streamHeaderKey, streamHeaderNonce);
|
cipher.init(true, streamHeaderKey, streamHeaderNonce);
|
||||||
int encrypted = cipher.process(streamHeaderPlaintext, 0,
|
int encrypted = cipher.process(streamHeaderPlaintext, 0,
|
||||||
SecretKey.LENGTH, streamHeaderCiphertext,
|
STREAM_HEADER_PLAINTEXT_LENGTH, streamHeaderCiphertext,
|
||||||
STREAM_HEADER_IV_LENGTH);
|
STREAM_HEADER_NONCE_LENGTH);
|
||||||
if (encrypted != SecretKey.LENGTH + MAC_LENGTH)
|
if (encrypted != STREAM_HEADER_PLAINTEXT_LENGTH + MAC_LENGTH)
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
} catch (GeneralSecurityException badCipher) {
|
} catch (GeneralSecurityException badCipher) {
|
||||||
throw new RuntimeException(badCipher);
|
throw new RuntimeException(badCipher);
|
||||||
|
|||||||
@@ -70,25 +70,7 @@ class XSalsa20Poly1305AuthenticatedCipher implements AuthenticatedCipher {
|
|||||||
byte[] subKey = new byte[SUBKEY_LENGTH];
|
byte[] subKey = new byte[SUBKEY_LENGTH];
|
||||||
xSalsa20Engine.processBytes(zero, 0, SUBKEY_LENGTH, subKey, 0);
|
xSalsa20Engine.processBytes(zero, 0, SUBKEY_LENGTH, subKey, 0);
|
||||||
|
|
||||||
// Reverse the order of the Poly130 subkey
|
// Clamp the subkey
|
||||||
//
|
|
||||||
// NaCl and libsodium use the first 32 bytes of XSalsa20 as the
|
|
||||||
// subkey for crypto_onetimeauth_poly1305, which interprets it
|
|
||||||
// as r[0] ... r[15], k[0] ... k[15]. See section 9 of the NaCl
|
|
||||||
// paper (http://cr.yp.to/highspeed/naclcrypto-20090310.pdf),
|
|
||||||
// where the XSalsa20 output is defined as (r, s, t, ...).
|
|
||||||
//
|
|
||||||
// BC's Poly1305 implementation interprets the subkey as
|
|
||||||
// k[0] ... k[15], r[0] ... r[15] (per poly1305_aes_clamp in
|
|
||||||
// the reference implementation).
|
|
||||||
//
|
|
||||||
// To be NaCl-compatible, we reverse the subkey.
|
|
||||||
System.arraycopy(subKey, 0, zero, 0, SUBKEY_LENGTH / 2);
|
|
||||||
System.arraycopy(subKey, SUBKEY_LENGTH / 2, subKey, 0,
|
|
||||||
SUBKEY_LENGTH / 2);
|
|
||||||
System.arraycopy(zero, 0, subKey, SUBKEY_LENGTH / 2,
|
|
||||||
SUBKEY_LENGTH / 2);
|
|
||||||
// Now we can clamp the correct part of the subkey
|
|
||||||
Poly1305KeyGenerator.clamp(subKey);
|
Poly1305KeyGenerator.clamp(subKey);
|
||||||
|
|
||||||
// Initialize Poly1305 with the subkey
|
// Initialize Poly1305 with the subkey
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import javax.annotation.concurrent.ThreadSafe;
|
|||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
|
|
||||||
@@ -126,7 +127,8 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
for (long streamNumber : inKeys.getWindow().getUnseen()) {
|
for (long streamNumber : inKeys.getWindow().getUnseen()) {
|
||||||
TagContext tagCtx = new TagContext(c, inKeys, streamNumber);
|
TagContext tagCtx = new TagContext(c, inKeys, streamNumber);
|
||||||
byte[] tag = new byte[TAG_LENGTH];
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
crypto.encodeTag(tag, inKeys.getTagKey(), streamNumber);
|
crypto.encodeTag(tag, inKeys.getTagKey(), PROTOCOL_VERSION,
|
||||||
|
streamNumber);
|
||||||
inContexts.put(new Bytes(tag), tagCtx);
|
inContexts.put(new Bytes(tag), tagCtx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,7 +244,8 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
// Add tags for any stream numbers added to the window
|
// Add tags for any stream numbers added to the window
|
||||||
for (long streamNumber : change.getAdded()) {
|
for (long streamNumber : change.getAdded()) {
|
||||||
byte[] addTag = new byte[TAG_LENGTH];
|
byte[] addTag = new byte[TAG_LENGTH];
|
||||||
crypto.encodeTag(addTag, inKeys.getTagKey(), streamNumber);
|
crypto.encodeTag(addTag, inKeys.getTagKey(), PROTOCOL_VERSION,
|
||||||
|
streamNumber);
|
||||||
inContexts.put(new Bytes(addTag), new TagContext(
|
inContexts.put(new Bytes(addTag), new TagContext(
|
||||||
tagCtx.contactId, inKeys, streamNumber));
|
tagCtx.contactId, inKeys, streamNumber));
|
||||||
}
|
}
|
||||||
@@ -250,7 +253,8 @@ class TransportKeyManagerImpl implements TransportKeyManager {
|
|||||||
for (long streamNumber : change.getRemoved()) {
|
for (long streamNumber : change.getRemoved()) {
|
||||||
if (streamNumber == tagCtx.streamNumber) continue;
|
if (streamNumber == tagCtx.streamNumber) continue;
|
||||||
byte[] removeTag = new byte[TAG_LENGTH];
|
byte[] removeTag = new byte[TAG_LENGTH];
|
||||||
crypto.encodeTag(removeTag, inKeys.getTagKey(), streamNumber);
|
crypto.encodeTag(removeTag, inKeys.getTagKey(),
|
||||||
|
PROTOCOL_VERSION, streamNumber);
|
||||||
inContexts.remove(new Bytes(removeTag));
|
inContexts.remove(new Bytes(removeTag));
|
||||||
}
|
}
|
||||||
// Write the window back to the DB
|
// Write the window back to the DB
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ import static junit.framework.Assert.assertEquals;
|
|||||||
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
import static org.briarproject.bramble.util.ByteUtils.INT_16_BYTES;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
@@ -22,7 +23,8 @@ public class StreamDecrypterImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
private final AuthenticatedCipher cipher;
|
private final AuthenticatedCipher cipher;
|
||||||
private final SecretKey streamHeaderKey, frameKey;
|
private final SecretKey streamHeaderKey, frameKey;
|
||||||
private final byte[] streamHeaderIv, payload;
|
private final byte[] streamHeaderNonce, protocolVersionBytes;
|
||||||
|
private final byte[] streamNumberBytes, payload;
|
||||||
private final int payloadLength = 123, paddingLength = 234;
|
private final int payloadLength = 123, paddingLength = 234;
|
||||||
private final long streamNumber = 1234;
|
private final long streamNumber = 1234;
|
||||||
|
|
||||||
@@ -30,7 +32,12 @@ public class StreamDecrypterImplTest extends BrambleTestCase {
|
|||||||
cipher = new TestAuthenticatedCipher(); // Null cipher
|
cipher = new TestAuthenticatedCipher(); // Null cipher
|
||||||
streamHeaderKey = TestUtils.getSecretKey();
|
streamHeaderKey = TestUtils.getSecretKey();
|
||||||
frameKey = TestUtils.getSecretKey();
|
frameKey = TestUtils.getSecretKey();
|
||||||
streamHeaderIv = TestUtils.getRandomBytes(STREAM_HEADER_IV_LENGTH);
|
streamHeaderNonce =
|
||||||
|
TestUtils.getRandomBytes(STREAM_HEADER_NONCE_LENGTH);
|
||||||
|
protocolVersionBytes = new byte[2];
|
||||||
|
ByteUtils.writeUint16(PROTOCOL_VERSION, protocolVersionBytes, 0);
|
||||||
|
streamNumberBytes = new byte[8];
|
||||||
|
ByteUtils.writeUint64(streamNumber, streamNumberBytes, 0);
|
||||||
payload = TestUtils.getRandomBytes(payloadLength);
|
payload = TestUtils.getRandomBytes(payloadLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +54,9 @@ public class StreamDecrypterImplTest extends BrambleTestCase {
|
|||||||
byte[] payload1 = TestUtils.getRandomBytes(payloadLength1);
|
byte[] payload1 = TestUtils.getRandomBytes(payloadLength1);
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
out.write(streamHeaderIv);
|
out.write(streamHeaderNonce);
|
||||||
|
out.write(protocolVersionBytes);
|
||||||
|
out.write(streamNumberBytes);
|
||||||
out.write(frameKey.getBytes());
|
out.write(frameKey.getBytes());
|
||||||
out.write(new byte[MAC_LENGTH]);
|
out.write(new byte[MAC_LENGTH]);
|
||||||
out.write(frameHeader);
|
out.write(frameHeader);
|
||||||
@@ -76,6 +85,85 @@ public class StreamDecrypterImplTest extends BrambleTestCase {
|
|||||||
assertEquals(-1, s.readFrame(buffer));
|
assertEquals(-1, s.readFrame(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = IOException.class)
|
||||||
|
public void testWrongProtocolVersionThrowsException() throws Exception {
|
||||||
|
byte[] wrongProtocolVersionBytes = new byte[2];
|
||||||
|
ByteUtils.writeUint16(PROTOCOL_VERSION + 1, wrongProtocolVersionBytes,
|
||||||
|
0);
|
||||||
|
|
||||||
|
byte[] frameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
|
FrameEncoder.encodeHeader(frameHeader, false, payloadLength,
|
||||||
|
paddingLength);
|
||||||
|
|
||||||
|
byte[] frameHeader1 = new byte[FRAME_HEADER_LENGTH];
|
||||||
|
int payloadLength1 = 345, paddingLength1 = 456;
|
||||||
|
FrameEncoder.encodeHeader(frameHeader1, true, payloadLength1,
|
||||||
|
paddingLength1);
|
||||||
|
byte[] payload1 = TestUtils.getRandomBytes(payloadLength1);
|
||||||
|
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
out.write(streamHeaderNonce);
|
||||||
|
out.write(wrongProtocolVersionBytes);
|
||||||
|
out.write(streamNumberBytes);
|
||||||
|
out.write(frameKey.getBytes());
|
||||||
|
out.write(new byte[MAC_LENGTH]);
|
||||||
|
out.write(frameHeader);
|
||||||
|
out.write(payload);
|
||||||
|
out.write(new byte[paddingLength]);
|
||||||
|
out.write(new byte[MAC_LENGTH]);
|
||||||
|
out.write(frameHeader1);
|
||||||
|
out.write(payload1);
|
||||||
|
out.write(new byte[paddingLength1]);
|
||||||
|
out.write(new byte[MAC_LENGTH]);
|
||||||
|
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||||
|
StreamDecrypterImpl s = new StreamDecrypterImpl(in, cipher,
|
||||||
|
streamNumber, streamHeaderKey);
|
||||||
|
|
||||||
|
// Try to read the first frame
|
||||||
|
byte[] buffer = new byte[MAX_PAYLOAD_LENGTH];
|
||||||
|
s.readFrame(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IOException.class)
|
||||||
|
public void testWrongStreamNumberThrowsException() throws Exception {
|
||||||
|
byte[] wrongStreamNumberBytes = new byte[8];
|
||||||
|
ByteUtils.writeUint64(streamNumber + 1, wrongStreamNumberBytes, 0);
|
||||||
|
|
||||||
|
byte[] frameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
|
FrameEncoder.encodeHeader(frameHeader, false, payloadLength,
|
||||||
|
paddingLength);
|
||||||
|
|
||||||
|
byte[] frameHeader1 = new byte[FRAME_HEADER_LENGTH];
|
||||||
|
int payloadLength1 = 345, paddingLength1 = 456;
|
||||||
|
FrameEncoder.encodeHeader(frameHeader1, true, payloadLength1,
|
||||||
|
paddingLength1);
|
||||||
|
byte[] payload1 = TestUtils.getRandomBytes(payloadLength1);
|
||||||
|
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
out.write(streamHeaderNonce);
|
||||||
|
out.write(protocolVersionBytes);
|
||||||
|
out.write(wrongStreamNumberBytes);
|
||||||
|
out.write(frameKey.getBytes());
|
||||||
|
out.write(new byte[MAC_LENGTH]);
|
||||||
|
out.write(frameHeader);
|
||||||
|
out.write(payload);
|
||||||
|
out.write(new byte[paddingLength]);
|
||||||
|
out.write(new byte[MAC_LENGTH]);
|
||||||
|
out.write(frameHeader1);
|
||||||
|
out.write(payload1);
|
||||||
|
out.write(new byte[paddingLength1]);
|
||||||
|
out.write(new byte[MAC_LENGTH]);
|
||||||
|
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||||
|
StreamDecrypterImpl s = new StreamDecrypterImpl(in, cipher,
|
||||||
|
streamNumber, streamHeaderKey);
|
||||||
|
|
||||||
|
// Try to read the first frame
|
||||||
|
byte[] buffer = new byte[MAX_PAYLOAD_LENGTH];
|
||||||
|
s.readFrame(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = IOException.class)
|
@Test(expected = IOException.class)
|
||||||
public void testTruncatedFrameThrowsException() throws Exception {
|
public void testTruncatedFrameThrowsException() throws Exception {
|
||||||
byte[] frameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] frameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -83,7 +171,9 @@ public class StreamDecrypterImplTest extends BrambleTestCase {
|
|||||||
paddingLength);
|
paddingLength);
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
out.write(streamHeaderIv);
|
out.write(streamHeaderNonce);
|
||||||
|
out.write(protocolVersionBytes);
|
||||||
|
out.write(streamNumberBytes);
|
||||||
out.write(frameKey.getBytes());
|
out.write(frameKey.getBytes());
|
||||||
out.write(new byte[MAC_LENGTH]);
|
out.write(new byte[MAC_LENGTH]);
|
||||||
out.write(frameHeader);
|
out.write(frameHeader);
|
||||||
@@ -111,7 +201,9 @@ public class StreamDecrypterImplTest extends BrambleTestCase {
|
|||||||
byte[] payload = TestUtils.getRandomBytes(payloadLength);
|
byte[] payload = TestUtils.getRandomBytes(payloadLength);
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
out.write(streamHeaderIv);
|
out.write(streamHeaderNonce);
|
||||||
|
out.write(protocolVersionBytes);
|
||||||
|
out.write(streamNumberBytes);
|
||||||
out.write(frameKey.getBytes());
|
out.write(frameKey.getBytes());
|
||||||
out.write(new byte[MAC_LENGTH]);
|
out.write(new byte[MAC_LENGTH]);
|
||||||
out.write(frameHeader);
|
out.write(frameHeader);
|
||||||
@@ -138,7 +230,9 @@ public class StreamDecrypterImplTest extends BrambleTestCase {
|
|||||||
padding[paddingLength - 1] = 1;
|
padding[paddingLength - 1] = 1;
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
out.write(streamHeaderIv);
|
out.write(streamHeaderNonce);
|
||||||
|
out.write(protocolVersionBytes);
|
||||||
|
out.write(streamNumberBytes);
|
||||||
out.write(frameKey.getBytes());
|
out.write(frameKey.getBytes());
|
||||||
out.write(new byte[MAC_LENGTH]);
|
out.write(new byte[MAC_LENGTH]);
|
||||||
out.write(frameHeader);
|
out.write(frameHeader);
|
||||||
@@ -162,7 +256,9 @@ public class StreamDecrypterImplTest extends BrambleTestCase {
|
|||||||
paddingLength);
|
paddingLength);
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
out.write(streamHeaderIv);
|
out.write(streamHeaderNonce);
|
||||||
|
out.write(protocolVersionBytes);
|
||||||
|
out.write(streamNumberBytes);
|
||||||
out.write(frameKey.getBytes());
|
out.write(frameKey.getBytes());
|
||||||
out.write(new byte[MAC_LENGTH]);
|
out.write(new byte[MAC_LENGTH]);
|
||||||
out.write(frameHeader);
|
out.write(frameHeader);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.bramble.crypto;
|
|||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
|
import org.briarproject.bramble.util.ByteUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@@ -11,8 +12,9 @@ import static org.briarproject.bramble.api.transport.TransportConstants.FRAME_HE
|
|||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAC_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_IV_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_NONCE_LENGTH;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@@ -21,7 +23,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
|
|
||||||
private final AuthenticatedCipher cipher;
|
private final AuthenticatedCipher cipher;
|
||||||
private final SecretKey streamHeaderKey, frameKey;
|
private final SecretKey streamHeaderKey, frameKey;
|
||||||
private final byte[] tag, streamHeaderIv, payload;
|
private final byte[] tag, streamHeaderNonce, protocolVersionBytes;
|
||||||
|
private final byte[] streamNumberBytes, payload;
|
||||||
private final long streamNumber = 1234;
|
private final long streamNumber = 1234;
|
||||||
private final int payloadLength = 123, paddingLength = 234;
|
private final int payloadLength = 123, paddingLength = 234;
|
||||||
|
|
||||||
@@ -30,7 +33,12 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
streamHeaderKey = TestUtils.getSecretKey();
|
streamHeaderKey = TestUtils.getSecretKey();
|
||||||
frameKey = TestUtils.getSecretKey();
|
frameKey = TestUtils.getSecretKey();
|
||||||
tag = TestUtils.getRandomBytes(TAG_LENGTH);
|
tag = TestUtils.getRandomBytes(TAG_LENGTH);
|
||||||
streamHeaderIv = TestUtils.getRandomBytes(STREAM_HEADER_IV_LENGTH);
|
streamHeaderNonce =
|
||||||
|
TestUtils.getRandomBytes(STREAM_HEADER_NONCE_LENGTH);
|
||||||
|
protocolVersionBytes = new byte[2];
|
||||||
|
ByteUtils.writeUint16(PROTOCOL_VERSION, protocolVersionBytes, 0);
|
||||||
|
streamNumberBytes = new byte[8];
|
||||||
|
ByteUtils.writeUint64(streamNumber, streamNumberBytes, 0);
|
||||||
payload = TestUtils.getRandomBytes(payloadLength);
|
payload = TestUtils.getRandomBytes(payloadLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +46,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testRejectsNegativePayloadLength() throws Exception {
|
public void testRejectsNegativePayloadLength() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, -1, 0, false);
|
s.writeFrame(payload, -1, 0, false);
|
||||||
}
|
}
|
||||||
@@ -47,7 +56,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testRejectsNegativePaddingLength() throws Exception {
|
public void testRejectsNegativePaddingLength() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, 0, -1, false);
|
s.writeFrame(payload, 0, -1, false);
|
||||||
}
|
}
|
||||||
@@ -56,7 +66,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testRejectsMaxPayloadPlusPadding() throws Exception {
|
public void testRejectsMaxPayloadPlusPadding() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
byte[] bigPayload = new byte[MAX_PAYLOAD_LENGTH + 1];
|
byte[] bigPayload = new byte[MAX_PAYLOAD_LENGTH + 1];
|
||||||
s.writeFrame(bigPayload, MAX_PAYLOAD_LENGTH, 1, false);
|
s.writeFrame(bigPayload, MAX_PAYLOAD_LENGTH, 1, false);
|
||||||
@@ -66,7 +77,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testAcceptsMaxPayloadIncludingPadding() throws Exception {
|
public void testAcceptsMaxPayloadIncludingPadding() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
byte[] bigPayload = new byte[MAX_PAYLOAD_LENGTH];
|
byte[] bigPayload = new byte[MAX_PAYLOAD_LENGTH];
|
||||||
s.writeFrame(bigPayload, MAX_PAYLOAD_LENGTH - 1, 1, false);
|
s.writeFrame(bigPayload, MAX_PAYLOAD_LENGTH - 1, 1, false);
|
||||||
@@ -78,7 +90,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testAcceptsMaxPayloadWithoutPadding() throws Exception {
|
public void testAcceptsMaxPayloadWithoutPadding() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
byte[] bigPayload = new byte[MAX_PAYLOAD_LENGTH];
|
byte[] bigPayload = new byte[MAX_PAYLOAD_LENGTH];
|
||||||
s.writeFrame(bigPayload, MAX_PAYLOAD_LENGTH, 0, false);
|
s.writeFrame(bigPayload, MAX_PAYLOAD_LENGTH, 0, false);
|
||||||
@@ -90,14 +103,17 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWriteUnpaddedNonFinalFrameWithTag() throws Exception {
|
public void testWriteUnpaddedNonFinalFrameWithTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, payloadLength, 0, false);
|
s.writeFrame(payload, payloadLength, 0, false);
|
||||||
|
|
||||||
// Expect the tag, stream header, frame header, payload and MAC
|
// Expect the tag, stream header, frame header, payload and MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(tag);
|
expected.write(tag);
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -113,14 +129,17 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWriteUnpaddedFinalFrameWithTag() throws Exception {
|
public void testWriteUnpaddedFinalFrameWithTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, payloadLength, 0, true);
|
s.writeFrame(payload, payloadLength, 0, true);
|
||||||
|
|
||||||
// Expect the tag, stream header, frame header, payload and MAC
|
// Expect the tag, stream header, frame header, payload and MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(tag);
|
expected.write(tag);
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -136,13 +155,16 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWriteUnpaddedNonFinalFrameWithoutTag() throws Exception {
|
public void testWriteUnpaddedNonFinalFrameWithoutTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, null, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, null, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, payloadLength, 0, false);
|
s.writeFrame(payload, payloadLength, 0, false);
|
||||||
|
|
||||||
// Expect the stream header, frame header, payload and MAC
|
// Expect the stream header, frame header, payload and MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -158,13 +180,16 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWriteUnpaddedFinalFrameWithoutTag() throws Exception {
|
public void testWriteUnpaddedFinalFrameWithoutTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, null, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, null, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, payloadLength, 0, true);
|
s.writeFrame(payload, payloadLength, 0, true);
|
||||||
|
|
||||||
// Expect the stream header, frame header, payload and MAC
|
// Expect the stream header, frame header, payload and MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -180,14 +205,17 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWritePaddedNonFinalFrameWithTag() throws Exception {
|
public void testWritePaddedNonFinalFrameWithTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, payloadLength, paddingLength, false);
|
s.writeFrame(payload, payloadLength, paddingLength, false);
|
||||||
|
|
||||||
// Expect the tag, stream header, frame header, payload, padding and MAC
|
// Expect the tag, stream header, frame header, payload, padding and MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(tag);
|
expected.write(tag);
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -205,14 +233,17 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWritePaddedFinalFrameWithTag() throws Exception {
|
public void testWritePaddedFinalFrameWithTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, payloadLength, paddingLength, true);
|
s.writeFrame(payload, payloadLength, paddingLength, true);
|
||||||
|
|
||||||
// Expect the tag, stream header, frame header, payload, padding and MAC
|
// Expect the tag, stream header, frame header, payload, padding and MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(tag);
|
expected.write(tag);
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -230,13 +261,16 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWritePaddedNonFinalFrameWithoutTag() throws Exception {
|
public void testWritePaddedNonFinalFrameWithoutTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, null, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, null, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, payloadLength, paddingLength, false);
|
s.writeFrame(payload, payloadLength, paddingLength, false);
|
||||||
|
|
||||||
// Expect the stream header, frame header, payload, padding and MAC
|
// Expect the stream header, frame header, payload, padding and MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -254,13 +288,16 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWritePaddedFinalFrameWithoutTag() throws Exception {
|
public void testWritePaddedFinalFrameWithoutTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, null, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, null, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
s.writeFrame(payload, payloadLength, paddingLength, true);
|
s.writeFrame(payload, payloadLength, paddingLength, true);
|
||||||
|
|
||||||
// Expect the stream header, frame header, payload, padding and MAC
|
// Expect the stream header, frame header, payload, padding and MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -278,7 +315,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testWriteTwoFramesWithTag() throws Exception {
|
public void testWriteTwoFramesWithTag() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
int payloadLength1 = 345, paddingLength1 = 456;
|
int payloadLength1 = 345, paddingLength1 = 456;
|
||||||
byte[] payload1 = TestUtils.getRandomBytes(payloadLength1);
|
byte[] payload1 = TestUtils.getRandomBytes(payloadLength1);
|
||||||
|
|
||||||
@@ -289,7 +327,9 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
// MAC, second frame header, payload, padding, MAC
|
// MAC, second frame header, payload, padding, MAC
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(tag);
|
expected.write(tag);
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH];
|
||||||
@@ -315,7 +355,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
// Flush the stream once
|
// Flush the stream once
|
||||||
s.flush();
|
s.flush();
|
||||||
@@ -323,7 +364,9 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
// Expect the tag and stream header
|
// Expect the tag and stream header
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(tag);
|
expected.write(tag);
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
|
|
||||||
@@ -335,7 +378,8 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, tag, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, tag, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
// Flush the stream twice
|
// Flush the stream twice
|
||||||
s.flush();
|
s.flush();
|
||||||
@@ -344,7 +388,9 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
// Expect the tag and stream header
|
// Expect the tag and stream header
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(tag);
|
expected.write(tag);
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
|
|
||||||
@@ -355,14 +401,17 @@ public class StreamEncrypterImplTest extends BrambleTestCase {
|
|||||||
public void testFlushDoesNotWriteTagIfNull() throws Exception {
|
public void testFlushDoesNotWriteTagIfNull() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher,
|
||||||
streamNumber, null, streamHeaderIv, streamHeaderKey, frameKey);
|
streamNumber, null, streamHeaderNonce, streamHeaderKey,
|
||||||
|
frameKey);
|
||||||
|
|
||||||
// Flush the stream once
|
// Flush the stream once
|
||||||
s.flush();
|
s.flush();
|
||||||
|
|
||||||
// Expect the stream header
|
// Expect the stream header
|
||||||
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
ByteArrayOutputStream expected = new ByteArrayOutputStream();
|
||||||
expected.write(streamHeaderIv);
|
expected.write(streamHeaderNonce);
|
||||||
|
expected.write(protocolVersionBytes);
|
||||||
|
expected.write(streamNumberBytes);
|
||||||
expected.write(frameKey.getBytes());
|
expected.write(frameKey.getBytes());
|
||||||
expected.write(new byte[MAC_LENGTH]);
|
expected.write(new byte[MAC_LENGTH]);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package org.briarproject.bramble.crypto;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Bytes;
|
||||||
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
|
import org.briarproject.bramble.test.TestSecureRandomProvider;
|
||||||
|
import org.briarproject.bramble.test.TestUtils;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.assertTrue;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
|
|
||||||
|
public class TagEncodingTest extends BrambleTestCase {
|
||||||
|
|
||||||
|
private final CryptoComponent crypto;
|
||||||
|
private final SecretKey tagKey;
|
||||||
|
private final long streamNumber = 1234567890;
|
||||||
|
|
||||||
|
public TagEncodingTest() {
|
||||||
|
crypto = new CryptoComponentImpl(new TestSecureRandomProvider());
|
||||||
|
tagKey = TestUtils.getSecretKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKeyAffectsTag() throws Exception {
|
||||||
|
Set<Bytes> set = new HashSet<Bytes>();
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
|
SecretKey tagKey = TestUtils.getSecretKey();
|
||||||
|
crypto.encodeTag(tag, tagKey, PROTOCOL_VERSION, streamNumber);
|
||||||
|
assertTrue(set.add(new Bytes(tag)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProtocolVersionAffectsTag() throws Exception {
|
||||||
|
Set<Bytes> set = new HashSet<Bytes>();
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
|
crypto.encodeTag(tag, tagKey, PROTOCOL_VERSION + i, streamNumber);
|
||||||
|
assertTrue(set.add(new Bytes(tag)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStreamNumberAffectsTag() throws Exception {
|
||||||
|
Set<Bytes> set = new HashSet<Bytes>();
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
|
crypto.encodeTag(tag, tagKey, PROTOCOL_VERSION, streamNumber + i);
|
||||||
|
assertTrue(set.add(new Bytes(tag)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ import java.util.Collection;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@@ -115,7 +116,7 @@ public class SyncIntegrationTest extends BrambleTestCase {
|
|||||||
private void read(byte[] connectionData) throws Exception {
|
private void read(byte[] connectionData) throws Exception {
|
||||||
// Calculate the expected tag
|
// Calculate the expected tag
|
||||||
byte[] expectedTag = new byte[TAG_LENGTH];
|
byte[] expectedTag = new byte[TAG_LENGTH];
|
||||||
crypto.encodeTag(expectedTag, tagKey, streamNumber);
|
crypto.encodeTag(expectedTag, tagKey, PROTOCOL_VERSION, streamNumber);
|
||||||
|
|
||||||
// Read the tag
|
// Read the tag
|
||||||
InputStream in = new ByteArrayInputStream(connectionData);
|
InputStream in = new ByteArrayInputStream(connectionData);
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import java.util.concurrent.ScheduledExecutorService;
|
|||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
||||||
|
import static org.briarproject.bramble.api.transport.TransportConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
|
import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
|
||||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
@@ -86,7 +87,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
// Encode the tags (3 sets per contact)
|
// Encode the tags (3 sets per contact)
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
exactly(6).of(crypto).encodeTag(with(any(byte[].class)),
|
exactly(6).of(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(i));
|
with(tagKey), with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Save the keys that were rotated
|
// Save the keys that were rotated
|
||||||
@@ -133,7 +134,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
// Encode the tags (3 sets)
|
// Encode the tags (3 sets)
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(i));
|
with(tagKey), with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Save the keys
|
// Save the keys
|
||||||
@@ -199,7 +200,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
// Encode the tags (3 sets)
|
// Encode the tags (3 sets)
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(i));
|
with(tagKey), with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Rotate the transport keys (the keys are unaffected)
|
// Rotate the transport keys (the keys are unaffected)
|
||||||
@@ -247,7 +248,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
// Encode the tags (3 sets)
|
// Encode the tags (3 sets)
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(i));
|
with(tagKey), with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Rotate the transport keys (the keys are unaffected)
|
// Rotate the transport keys (the keys are unaffected)
|
||||||
@@ -306,7 +307,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
// Encode the tags (3 sets)
|
// Encode the tags (3 sets)
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(i));
|
with(tagKey), with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Rotate the transport keys (the keys are unaffected)
|
// Rotate the transport keys (the keys are unaffected)
|
||||||
@@ -355,7 +356,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
// Encode the tags (3 sets)
|
// Encode the tags (3 sets)
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(i));
|
with(tagKey), with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction(tags));
|
will(new EncodeTagAction(tags));
|
||||||
}
|
}
|
||||||
// Rotate the transport keys (the keys are unaffected)
|
// Rotate the transport keys (the keys are unaffected)
|
||||||
@@ -365,7 +366,8 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
oneOf(db).addTransportKeys(txn, contactId, transportKeys);
|
oneOf(db).addTransportKeys(txn, contactId, transportKeys);
|
||||||
// Encode a new tag after sliding the window
|
// Encode a new tag after sliding the window
|
||||||
oneOf(crypto).encodeTag(with(any(byte[].class)),
|
oneOf(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with((long) REORDERING_WINDOW_SIZE));
|
with(tagKey), with(PROTOCOL_VERSION),
|
||||||
|
with((long) REORDERING_WINDOW_SIZE));
|
||||||
will(new EncodeTagAction(tags));
|
will(new EncodeTagAction(tags));
|
||||||
// Save the reordering window (previous rotation period, base 1)
|
// Save the reordering window (previous rotation period, base 1)
|
||||||
oneOf(db).setReorderingWindow(txn, contactId, transportId, 999,
|
oneOf(db).setReorderingWindow(txn, contactId, transportId, 999,
|
||||||
@@ -428,7 +430,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
// Encode the tags (3 sets)
|
// Encode the tags (3 sets)
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(i));
|
with(tagKey), with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Schedule key rotation at the start of the next rotation period
|
// Schedule key rotation at the start of the next rotation period
|
||||||
@@ -450,7 +452,7 @@ public class TransportKeyManagerImplTest extends BrambleTestCase {
|
|||||||
// Encode the tags (3 sets)
|
// Encode the tags (3 sets)
|
||||||
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
for (long i = 0; i < REORDERING_WINDOW_SIZE; i++) {
|
||||||
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
exactly(3).of(crypto).encodeTag(with(any(byte[].class)),
|
||||||
with(tagKey), with(i));
|
with(tagKey), with(PROTOCOL_VERSION), with(i));
|
||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// Save the keys that were rotated
|
// Save the keys that were rotated
|
||||||
|
|||||||
@@ -7,10 +7,19 @@ apply plugin: 'witness'
|
|||||||
dependencies {
|
dependencies {
|
||||||
compile project(':bramble-core')
|
compile project(':bramble-core')
|
||||||
compile fileTree(dir: 'libs', include: '*.jar')
|
compile fileTree(dir: 'libs', include: '*.jar')
|
||||||
|
compile 'net.java.dev.jna:jna:4.4.0'
|
||||||
|
compile 'net.java.dev.jna:jna-platform:4.4.0'
|
||||||
|
|
||||||
testCompile project(path: ':bramble-core', configuration: 'testOutput')
|
testCompile project(path: ':bramble-core', configuration: 'testOutput')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencyVerification {
|
||||||
|
verify = [
|
||||||
|
'net.java.dev.jna:jna:c4dadeeecaa90c8847902082aee5eb107fcf59c5d0e63a17fcaf273c0e2d2bd1',
|
||||||
|
'net.java.dev.jna:jna-platform:e9dda9e884fc107eb6367710540789a12dfa8ad28be9326b22ca6e352e325499',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
tasks.withType(Test) {
|
tasks.withType(Test) {
|
||||||
systemProperty 'java.library.path', 'libs'
|
systemProperty 'java.library.path', 'libs'
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -5,13 +5,10 @@ dependencies {
|
|||||||
def supportVersion = '23.2.1'
|
def supportVersion = '23.2.1'
|
||||||
compile project(':briar-core')
|
compile project(':briar-core')
|
||||||
compile project(':bramble-android')
|
compile project(':bramble-android')
|
||||||
compile fileTree(dir: 'libs', include: '*.jar')
|
|
||||||
|
|
||||||
compile "com.android.support:support-v4:$supportVersion"
|
compile "com.android.support:support-v4:$supportVersion"
|
||||||
compile("com.android.support:appcompat-v7:$supportVersion") {
|
compile("com.android.support:appcompat-v7:$supportVersion") {
|
||||||
exclude module: 'support-v4'
|
exclude module: 'support-v4'
|
||||||
}
|
}
|
||||||
|
|
||||||
compile("com.android.support:preference-v14:$supportVersion") {
|
compile("com.android.support:preference-v14:$supportVersion") {
|
||||||
exclude module: 'support-v4'
|
exclude module: 'support-v4'
|
||||||
}
|
}
|
||||||
@@ -20,7 +17,7 @@ dependencies {
|
|||||||
exclude module: 'recyclerview-v7'
|
exclude module: 'recyclerview-v7'
|
||||||
}
|
}
|
||||||
compile "com.android.support:cardview-v7:$supportVersion"
|
compile "com.android.support:cardview-v7:$supportVersion"
|
||||||
compile 'com.android.support:support-annotations:23.4.0'
|
compile "com.android.support:support-annotations:$supportVersion"
|
||||||
compile('ch.acra:acra:4.8.5') {
|
compile('ch.acra:acra:4.8.5') {
|
||||||
exclude module: 'support-v4'
|
exclude module: 'support-v4'
|
||||||
exclude module: 'support-annotations'
|
exclude module: 'support-annotations'
|
||||||
@@ -28,15 +25,16 @@ dependencies {
|
|||||||
compile 'info.guardianproject.panic:panic:0.5'
|
compile 'info.guardianproject.panic:panic:0.5'
|
||||||
compile 'info.guardianproject.trustedintents:trustedintents:0.2'
|
compile 'info.guardianproject.trustedintents:trustedintents:0.2'
|
||||||
compile 'de.hdodenhof:circleimageview:2.1.0'
|
compile 'de.hdodenhof:circleimageview:2.1.0'
|
||||||
compile 'com.google.zxing:core:3.2.1'
|
compile 'com.google.zxing:core:3.3.0'
|
||||||
provided 'javax.annotation:jsr250-api:1.0'
|
|
||||||
compile 'com.jpardogo.materialtabstrip:library:1.1.0'
|
compile 'com.jpardogo.materialtabstrip:library:1.1.0'
|
||||||
compile 'com.github.bumptech.glide:glide:3.7.0'
|
compile 'com.github.bumptech.glide:glide:3.8.0'
|
||||||
compile 'uk.co.samuelwall:material-tap-target-prompt:1.3.0'
|
compile 'uk.co.samuelwall:material-tap-target-prompt:1.9.2'
|
||||||
|
|
||||||
|
provided 'javax.annotation:jsr250-api:1.0'
|
||||||
|
|
||||||
testCompile project(path: ':bramble-core', configuration: 'testOutput')
|
testCompile project(path: ':bramble-core', configuration: 'testOutput')
|
||||||
testCompile 'org.robolectric:robolectric:3.0'
|
testCompile 'org.robolectric:robolectric:3.0'
|
||||||
testCompile 'org.mockito:mockito-core:1.10.19'
|
testCompile 'org.mockito:mockito-core:2.8.9'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencyVerification {
|
dependencyVerification {
|
||||||
@@ -45,20 +43,18 @@ dependencyVerification {
|
|||||||
'info.guardianproject.panic:panic:a7ed9439826db2e9901649892cf9afbe76f00991b768d8f4c26332d7c9406cb2',
|
'info.guardianproject.panic:panic:a7ed9439826db2e9901649892cf9afbe76f00991b768d8f4c26332d7c9406cb2',
|
||||||
'info.guardianproject.trustedintents:trustedintents:6221456d8821a8d974c2acf86306900237cf6afaaa94a4c9c44e161350f80f3e',
|
'info.guardianproject.trustedintents:trustedintents:6221456d8821a8d974c2acf86306900237cf6afaaa94a4c9c44e161350f80f3e',
|
||||||
'de.hdodenhof:circleimageview:bcbc588e19e6dcf8c120b1957776bfe229efba5d2fbe5da7156372eeacf65503',
|
'de.hdodenhof:circleimageview:bcbc588e19e6dcf8c120b1957776bfe229efba5d2fbe5da7156372eeacf65503',
|
||||||
'com.google.zxing:core:b4d82452e7a6bf6ec2698904b332431717ed8f9a850224f295aec89de80f2259',
|
'com.google.zxing:core:bba7724e02a997cec38213af77133ee8e24b0d5cf5fa7ecbc16a4fa93f11ee0d',
|
||||||
'com.android.support:support-v4:81ce890f26d35c75ad17d0f998a7e3230330c3b41e0b629566bc744bee89e448',
|
'com.jpardogo.materialtabstrip:library:24d19232b319f8c73e25793432357919a7ed972186f57a3b2c9093ea74ad8311',
|
||||||
|
'com.github.bumptech.glide:glide:750d9e7b940dc0ee48f8680623b55d46e14e8727acc922d7b156e57e7c549655',
|
||||||
|
'uk.co.samuelwall:material-tap-target-prompt:5d4951124366bc5c52e57beaa294db7611f0aa2a8d80e0163e1383e1966ba5b2',
|
||||||
'com.android.support:appcompat-v7:00f9d93acacd6731f309724054bf51492814b4b2869f16d7d5c0038dcb8c9a0d',
|
'com.android.support:appcompat-v7:00f9d93acacd6731f309724054bf51492814b4b2869f16d7d5c0038dcb8c9a0d',
|
||||||
'com.android.support:preference-v14:44881bb46094e86d0bc2426f205419674a5b4eb514b44b5a4659b5de29f71eb7',
|
'com.android.support:preference-v14:44881bb46094e86d0bc2426f205419674a5b4eb514b44b5a4659b5de29f71eb7',
|
||||||
'com.android.support:design:003e0c0bea0a6891f8b2bc43f20ae7af2a49a17363e5bb10df5ee0bae12fa686',
|
'com.android.support:design:003e0c0bea0a6891f8b2bc43f20ae7af2a49a17363e5bb10df5ee0bae12fa686',
|
||||||
'com.android.support:support-annotations:e91a88dd0c5e99069b7f09d4a46b5e06f1e9c4c72fc0a8e987e25d86af480f01',
|
'com.android.support:cardview-v7:4595f1c4a28cfa083b6c0920ad4d49e1c2ca4b8302a955e548f68eb63b74931b',
|
||||||
'com.android.support:animated-vector-drawable:06d1963b85aa917099d7757e6a7b3e4dc06889413dc747f625ae8683606db3a1',
|
'com.android.support:animated-vector-drawable:06d1963b85aa917099d7757e6a7b3e4dc06889413dc747f625ae8683606db3a1',
|
||||||
'com.android.support:support-vector-drawable:799bafe4c3de812386f0b291f744d5d6876452722dd40189b9ab87dbbf594ea1',
|
'com.android.support:support-vector-drawable:799bafe4c3de812386f0b291f744d5d6876452722dd40189b9ab87dbbf594ea1',
|
||||||
'com.android.support:recyclerview-v7:44040a888e23e0c93162a3377cfe06751080e3c22d369ab0d4301ef60d63b0fe',
|
'com.android.support:recyclerview-v7:44040a888e23e0c93162a3377cfe06751080e3c22d369ab0d4301ef60d63b0fe',
|
||||||
'com.android.support:preference-v7:775101bd07bd052e455761c5c5d9523d7ad59f2f320e3e8cbde241fd6b1d6025',
|
'com.android.support:preference-v7:775101bd07bd052e455761c5c5d9523d7ad59f2f320e3e8cbde241fd6b1d6025',
|
||||||
'com.android.support:cardview-v7:4595f1c4a28cfa083b6c0920ad4d49e1c2ca4b8302a955e548f68eb63b74931b',
|
|
||||||
'com.jpardogo.materialtabstrip:library:24d19232b319f8c73e25793432357919a7ed972186f57a3b2c9093ea74ad8311',
|
|
||||||
'com.github.bumptech.glide:glide:76ef123957b5fbaebb05fcbe6606dd58c3bc3fcdadb257f99811d0ac9ea9b88b',
|
|
||||||
'uk.co.samuelwall:material-tap-target-prompt:f67e1caead12a914525b32cbf6da52a96b93ff89573f93cb41102ef3130fb64a',
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +78,10 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 22
|
targetSdkVersion 22
|
||||||
resValue "string", "app_package", "org.briarproject.briar"
|
versionCode 1607
|
||||||
|
versionName "0.16.7"
|
||||||
|
applicationId "org.briarproject.briar.beta"
|
||||||
|
resValue "string", "app_package", "org.briarproject.briar.beta"
|
||||||
buildConfigField "String", "GitHash", "\"${getGitHash()}\""
|
buildConfigField "String", "GitHash", "\"${getGitHash()}\""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,5 +106,6 @@ android {
|
|||||||
lintOptions {
|
lintOptions {
|
||||||
warning 'MissingTranslation'
|
warning 'MissingTranslation'
|
||||||
warning 'ImpliedQuantity'
|
warning 'ImpliedQuantity'
|
||||||
|
warning 'ExtraTranslation'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest
|
<manifest
|
||||||
package="org.briarproject.briar"
|
package="org.briarproject.briar"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
android:versionCode="13"
|
|
||||||
android:versionName="0.13">
|
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.bluetooth"/>
|
<uses-feature android:name="android.hardware.bluetooth"/>
|
||||||
<uses-feature android:name="android.hardware.camera" />
|
<uses-feature android:name="android.hardware.camera" />
|
||||||
@@ -21,7 +19,7 @@
|
|||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".android.BriarApplicationImpl"
|
android:name="org.briarproject.briar.android.BriarApplicationImpl"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
android:icon="@mipmap/ic_launcher_round"
|
android:icon="@mipmap/ic_launcher_round"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
@@ -29,7 +27,7 @@
|
|||||||
android:theme="@style/BriarTheme">
|
android:theme="@style/BriarTheme">
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".android.BriarService"
|
android:name="org.briarproject.briar.android.BriarService"
|
||||||
android:exported="false">
|
android:exported="false">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="org.briarproject.briar.android.BriarService"/>
|
<action android:name="org.briarproject.briar.android.BriarService"/>
|
||||||
@@ -37,7 +35,7 @@
|
|||||||
</service>
|
</service>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.reporting.DevReportActivity"
|
android:name="org.briarproject.briar.android.reporting.DevReportActivity"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:finishOnTaskLaunch="true"
|
android:finishOnTaskLaunch="true"
|
||||||
@@ -49,24 +47,24 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.splash.ExpiredActivity"
|
android:name="org.briarproject.briar.android.splash.ExpiredActivity"
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.login.PasswordActivity"
|
android:name="org.briarproject.briar.android.login.PasswordActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:windowSoftInputMode="stateVisible">
|
android:windowSoftInputMode="stateVisible">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.login.SetupActivity"
|
android:name="org.briarproject.briar.android.login.SetupActivity"
|
||||||
android:label="@string/setup_title"
|
android:label="@string/setup_title"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.splash.SplashScreenActivity"
|
android:name="org.briarproject.briar.android.splash.SplashScreenActivity"
|
||||||
android:theme="@style/BriarTheme.NoActionBar"
|
android:theme="@style/BriarTheme.NoActionBar"
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
@@ -76,268 +74,268 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.navdrawer.NavDrawerActivity"
|
android:name="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:theme="@style/BriarTheme.NoActionBar"
|
android:theme="@style/BriarTheme.NoActionBar"
|
||||||
android:launchMode="singleTop">
|
android:launchMode="singleTop">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.contact.ConversationActivity"
|
android:name="org.briarproject.briar.android.contact.ConversationActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/BriarTheme.NoActionBar"
|
android:theme="@style/BriarTheme.NoActionBar"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity"
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:windowSoftInputMode="stateHidden|adjustResize">
|
android:windowSoftInputMode="stateHidden|adjustResize">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.privategroup.creation.CreateGroupActivity"
|
android:name="org.briarproject.briar.android.privategroup.creation.CreateGroupActivity"
|
||||||
android:label="@string/groups_create_group_title"
|
android:label="@string/groups_create_group_title"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity"
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.privategroup.conversation.GroupActivity"
|
android:name="org.briarproject.briar.android.privategroup.conversation.GroupActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity"
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:theme="@style/BriarTheme.NoActionBar"
|
android:theme="@style/BriarTheme.NoActionBar"
|
||||||
android:windowSoftInputMode="adjustResize|stateHidden">
|
android:windowSoftInputMode="adjustResize|stateHidden">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.privategroup.invitation.GroupInvitationActivity"
|
android:name="org.briarproject.briar.android.privategroup.invitation.GroupInvitationActivity"
|
||||||
android:label="@string/groups_invitations_title"
|
android:label="@string/groups_invitations_title"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity">
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"/>
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.privategroup.memberlist.GroupMemberListActivity"
|
android:name="org.briarproject.briar.android.privategroup.memberlist.GroupMemberListActivity"
|
||||||
android:label="@string/groups_member_list"
|
android:label="@string/groups_member_list"
|
||||||
android:parentActivityName=".android.privategroup.conversation.GroupActivity"
|
android:parentActivityName="org.briarproject.briar.android.privategroup.conversation.GroupActivity"
|
||||||
android:windowSoftInputMode="adjustResize|stateHidden">
|
android:windowSoftInputMode="adjustResize|stateHidden">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.privategroup.conversation.GroupActivity"
|
android:value="org.briarproject.briar.android.privategroup.conversation.GroupActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.privategroup.reveal.RevealContactsActivity"
|
android:name="org.briarproject.briar.android.privategroup.reveal.RevealContactsActivity"
|
||||||
android:label="@string/groups_reveal_contacts"
|
android:label="@string/groups_reveal_contacts"
|
||||||
android:parentActivityName=".android.privategroup.conversation.GroupActivity"
|
android:parentActivityName="org.briarproject.briar.android.privategroup.conversation.GroupActivity"
|
||||||
android:windowSoftInputMode="adjustResize|stateAlwaysHidden">
|
android:windowSoftInputMode="adjustResize|stateAlwaysHidden">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.privategroup.conversation.GroupActivity"
|
android:value="org.briarproject.briar.android.privategroup.conversation.GroupActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.privategroup.creation.GroupInviteActivity"
|
android:name="org.briarproject.briar.android.privategroup.creation.GroupInviteActivity"
|
||||||
android:label="@string/groups_invite_members"
|
android:label="@string/groups_invite_members"
|
||||||
android:parentActivityName=".android.privategroup.conversation.GroupActivity"
|
android:parentActivityName="org.briarproject.briar.android.privategroup.conversation.GroupActivity"
|
||||||
android:windowSoftInputMode="adjustResize|stateHidden">
|
android:windowSoftInputMode="adjustResize|stateHidden">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.privategroup.conversation.GroupActivity"/>
|
android:value="org.briarproject.briar.android.privategroup.conversation.GroupActivity"/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.sharing.ForumInvitationActivity"
|
android:name="org.briarproject.briar.android.sharing.ForumInvitationActivity"
|
||||||
android:label="@string/forum_invitations_title"
|
android:label="@string/forum_invitations_title"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity">
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.sharing.BlogInvitationActivity"
|
android:name="org.briarproject.briar.android.sharing.BlogInvitationActivity"
|
||||||
android:label="@string/blogs_sharing_invitations_title"
|
android:label="@string/blogs_sharing_invitations_title"
|
||||||
android:parentActivityName=".android.contact.ConversationActivity">
|
android:parentActivityName="org.briarproject.briar.android.contact.ConversationActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.contact.ConversationActivity"
|
android:value="org.briarproject.briar.android.contact.ConversationActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.forum.CreateForumActivity"
|
android:name="org.briarproject.briar.android.forum.CreateForumActivity"
|
||||||
android:label="@string/create_forum_title"
|
android:label="@string/create_forum_title"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity"
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:windowSoftInputMode="stateVisible">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.forum.ForumActivity"
|
android:name="org.briarproject.briar.android.forum.ForumActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity"
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:theme="@style/BriarTheme.NoActionBar"
|
android:theme="@style/BriarTheme.NoActionBar"
|
||||||
android:windowSoftInputMode="adjustResize|stateHidden">
|
android:windowSoftInputMode="adjustResize|stateHidden">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.sharing.ShareForumActivity"
|
android:name="org.briarproject.briar.android.sharing.ShareForumActivity"
|
||||||
android:label="@string/activity_share_toolbar_header"
|
android:label="@string/activity_share_toolbar_header"
|
||||||
android:parentActivityName=".android.forum.ForumActivity"
|
android:parentActivityName="org.briarproject.briar.android.forum.ForumActivity"
|
||||||
android:windowSoftInputMode="adjustResize|stateHidden">
|
android:windowSoftInputMode="adjustResize|stateHidden">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.forum.ForumActivity"
|
android:value="org.briarproject.briar.android.forum.ForumActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.sharing.ShareBlogActivity"
|
android:name="org.briarproject.briar.android.sharing.ShareBlogActivity"
|
||||||
android:label="@string/activity_share_toolbar_header"
|
android:label="@string/activity_share_toolbar_header"
|
||||||
android:parentActivityName=".android.blog.BlogActivity"
|
android:parentActivityName="org.briarproject.briar.android.blog.BlogActivity"
|
||||||
android:windowSoftInputMode="adjustResize|stateHidden">
|
android:windowSoftInputMode="adjustResize|stateHidden">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.blog.BlogActivity"
|
android:value="org.briarproject.briar.android.blog.BlogActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.sharing.ForumSharingStatusActivity"
|
android:name="org.briarproject.briar.android.sharing.ForumSharingStatusActivity"
|
||||||
android:label="@string/sharing_status"
|
android:label="@string/sharing_status"
|
||||||
android:parentActivityName=".android.forum.ForumActivity">
|
android:parentActivityName="org.briarproject.briar.android.forum.ForumActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.forum.ForumActivity"
|
android:value="org.briarproject.briar.android.forum.ForumActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.sharing.BlogSharingStatusActivity"
|
android:name="org.briarproject.briar.android.sharing.BlogSharingStatusActivity"
|
||||||
android:label="@string/sharing_status"
|
android:label="@string/sharing_status"
|
||||||
android:parentActivityName=".android.blog.BlogActivity">
|
android:parentActivityName="org.briarproject.briar.android.blog.BlogActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.blog.BlogActivity"
|
android:value="org.briarproject.briar.android.blog.BlogActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.blog.BlogActivity"
|
android:name="org.briarproject.briar.android.blog.BlogActivity"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity"
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:theme="@style/BriarTheme.NoActionBar">
|
android:theme="@style/BriarTheme.NoActionBar">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"/>
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.blog.WriteBlogPostActivity"
|
android:name="org.briarproject.briar.android.blog.WriteBlogPostActivity"
|
||||||
android:label="@string/blogs_write_blog_post"
|
android:label="@string/blogs_write_blog_post"
|
||||||
android:parentActivityName=".android.blog.BlogActivity"
|
android:parentActivityName="org.briarproject.briar.android.blog.BlogActivity"
|
||||||
android:windowSoftInputMode="stateVisible|adjustResize">
|
android:windowSoftInputMode="stateVisible|adjustResize">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.blog.BlogActivity"
|
android:value="org.briarproject.briar.android.blog.BlogActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.blog.ReblogActivity"
|
android:name="org.briarproject.briar.android.blog.ReblogActivity"
|
||||||
android:label="@string/blogs_reblog_button"
|
android:label="@string/blogs_reblog_button"
|
||||||
android:parentActivityName=".android.blog.BlogActivity"
|
android:parentActivityName="org.briarproject.briar.android.blog.BlogActivity"
|
||||||
android:windowSoftInputMode="stateHidden">
|
android:windowSoftInputMode="stateHidden">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.blog.BlogActivity"
|
android:value="org.briarproject.briar.android.blog.BlogActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.blog.RssFeedImportActivity"
|
android:name="org.briarproject.briar.android.blog.RssFeedImportActivity"
|
||||||
android:label="@string/blogs_rss_feeds_import"
|
android:label="@string/blogs_rss_feeds_import"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity"
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:windowSoftInputMode="stateVisible|adjustResize">
|
android:windowSoftInputMode="stateVisible|adjustResize">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.blog.RssFeedManageActivity"
|
android:name="org.briarproject.briar.android.blog.RssFeedManageActivity"
|
||||||
android:label="@string/blogs_rss_feeds_manage"
|
android:label="@string/blogs_rss_feeds_manage"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity">
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.invitation.AddContactActivity"
|
android:name="org.briarproject.briar.android.invitation.AddContactActivity"
|
||||||
android:label="@string/add_contact_title"
|
android:label="@string/add_contact_title"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity">
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.keyagreement.KeyAgreementActivity"
|
android:name="org.briarproject.briar.android.keyagreement.KeyAgreementActivity"
|
||||||
android:label="@string/add_contact_title"
|
android:label="@string/add_contact_title"
|
||||||
android:theme="@style/BriarTheme.NoActionBar"
|
android:theme="@style/BriarTheme.NoActionBar"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity">
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"/>
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.introduction.IntroductionActivity"
|
android:name="org.briarproject.briar.android.introduction.IntroductionActivity"
|
||||||
android:label="@string/introduction_activity_title"
|
android:label="@string/introduction_activity_title"
|
||||||
android:parentActivityName=".android.contact.ConversationActivity"
|
android:parentActivityName="org.briarproject.briar.android.contact.ConversationActivity"
|
||||||
android:windowSoftInputMode="stateHidden|adjustResize">
|
android:windowSoftInputMode="stateHidden|adjustResize">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.contact.ConversationActivity"
|
android:value="org.briarproject.briar.android.contact.ConversationActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.StartupFailureActivity"
|
android:name="org.briarproject.briar.android.StartupFailureActivity"
|
||||||
android:label="@string/startup_failed_activity_title">
|
android:label="@string/startup_failed_activity_title">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.settings.SettingsActivity"
|
android:name="org.briarproject.briar.android.settings.SettingsActivity"
|
||||||
android:label="@string/settings_button"
|
android:label="@string/settings_button"
|
||||||
android:parentActivityName=".android.navdrawer.NavDrawerActivity"
|
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:permission="android.permission.READ_NETWORK_USAGE_HISTORY">
|
android:permission="android.permission.READ_NETWORK_USAGE_HISTORY">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.navdrawer.NavDrawerActivity"
|
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
/>
|
/>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MANAGE_NETWORK_USAGE"/>
|
<action android:name="android.intent.action.MANAGE_NETWORK_USAGE"/>
|
||||||
@@ -346,27 +344,27 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.login.ChangePasswordActivity"
|
android:name="org.briarproject.briar.android.login.ChangePasswordActivity"
|
||||||
android:label="@string/change_password"
|
android:label="@string/change_password"
|
||||||
android:parentActivityName=".android.settings.SettingsActivity">
|
android:parentActivityName="org.briarproject.briar.android.settings.SettingsActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.settings.SettingsActivity"
|
android:value="org.briarproject.briar.android.settings.SettingsActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.panic.PanicPreferencesActivity"
|
android:name="org.briarproject.briar.android.panic.PanicPreferencesActivity"
|
||||||
android:label="@string/panic_setting"
|
android:label="@string/panic_setting"
|
||||||
android:parentActivityName=".android.settings.SettingsActivity">
|
android:parentActivityName="org.briarproject.briar.android.settings.SettingsActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".android.settings.SettingsActivity"
|
android:value="org.briarproject.briar.android.settings.SettingsActivity"
|
||||||
/>
|
/>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.panic.PanicResponderActivity"
|
android:name="org.briarproject.briar.android.panic.PanicResponderActivity"
|
||||||
android:noHistory="true"
|
android:noHistory="true"
|
||||||
android:theme="@android:style/Theme.NoDisplay">
|
android:theme="@android:style/Theme.NoDisplay">
|
||||||
<!-- this can never have launchMode singleTask or singleInstance! -->
|
<!-- this can never have launchMode singleTask or singleInstance! -->
|
||||||
@@ -377,7 +375,7 @@
|
|||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".android.panic.ExitActivity"
|
android:name="org.briarproject.briar.android.panic.ExitActivity"
|
||||||
android:theme="@android:style/Theme.NoDisplay">
|
android:theme="@android:style/Theme.NoDisplay">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
|||||||
import org.briarproject.briar.api.blog.BlogManager;
|
import org.briarproject.briar.api.blog.BlogManager;
|
||||||
import org.briarproject.briar.api.blog.BlogPostFactory;
|
import org.briarproject.briar.api.blog.BlogPostFactory;
|
||||||
import org.briarproject.briar.api.blog.BlogSharingManager;
|
import org.briarproject.briar.api.blog.BlogSharingManager;
|
||||||
|
import org.briarproject.briar.api.client.MessageTracker;
|
||||||
import org.briarproject.briar.api.feed.FeedManager;
|
import org.briarproject.briar.api.feed.FeedManager;
|
||||||
import org.briarproject.briar.api.forum.ForumManager;
|
import org.briarproject.briar.api.forum.ForumManager;
|
||||||
import org.briarproject.briar.api.forum.ForumSharingManager;
|
import org.briarproject.briar.api.forum.ForumSharingManager;
|
||||||
@@ -78,6 +79,8 @@ public interface AndroidComponent
|
|||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
Executor databaseExecutor();
|
Executor databaseExecutor();
|
||||||
|
|
||||||
|
MessageTracker messageTracker();
|
||||||
|
|
||||||
LifecycleManager lifecycleManager();
|
LifecycleManager lifecycleManager();
|
||||||
|
|
||||||
IdentityManager identityManager();
|
IdentityManager identityManager();
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ import static android.content.Context.NOTIFICATION_SERVICE;
|
|||||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||||
import static android.support.v4.app.NotificationCompat.CATEGORY_MESSAGE;
|
import static android.support.v4.app.NotificationCompat.CATEGORY_MESSAGE;
|
||||||
import static android.support.v4.app.NotificationCompat.CATEGORY_SOCIAL;
|
import static android.support.v4.app.NotificationCompat.CATEGORY_SOCIAL;
|
||||||
|
import static android.support.v4.app.NotificationCompat.VISIBILITY_PRIVATE;
|
||||||
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
|
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
||||||
@@ -327,6 +328,11 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
b.setCategory(CATEGORY_MESSAGE);
|
b.setCategory(CATEGORY_MESSAGE);
|
||||||
|
boolean showOnLockScreen =
|
||||||
|
settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
|
||||||
|
if (showOnLockScreen)
|
||||||
|
b.setVisibility(VISIBILITY_PRIVATE);
|
||||||
|
else
|
||||||
b.setVisibility(VISIBILITY_SECRET);
|
b.setVisibility(VISIBILITY_SECRET);
|
||||||
}
|
}
|
||||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||||
@@ -347,17 +353,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
return defaults;
|
return defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearAllContactNotifications() {
|
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
clearContactNotification();
|
|
||||||
clearIntroductionSuccessNotification();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void showGroupMessageNotification(final GroupId g) {
|
private void showGroupMessageNotification(final GroupId g) {
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
androidExecutor.runOnUiThread(new Runnable() {
|
||||||
@@ -432,6 +427,11 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
b.setCategory(CATEGORY_SOCIAL);
|
b.setCategory(CATEGORY_SOCIAL);
|
||||||
|
boolean showOnLockScreen =
|
||||||
|
settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
|
||||||
|
if (showOnLockScreen)
|
||||||
|
b.setVisibility(VISIBILITY_PRIVATE);
|
||||||
|
else
|
||||||
b.setVisibility(VISIBILITY_SECRET);
|
b.setVisibility(VISIBILITY_SECRET);
|
||||||
}
|
}
|
||||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||||
@@ -440,16 +440,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearAllGroupMessageNotifications() {
|
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
clearGroupMessageNotification();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void showForumPostNotification(final GroupId g) {
|
private void showForumPostNotification(final GroupId g) {
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
androidExecutor.runOnUiThread(new Runnable() {
|
||||||
@@ -524,6 +514,11 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
b.setCategory(CATEGORY_SOCIAL);
|
b.setCategory(CATEGORY_SOCIAL);
|
||||||
|
boolean showOnLockScreen =
|
||||||
|
settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
|
||||||
|
if (showOnLockScreen)
|
||||||
|
b.setVisibility(VISIBILITY_PRIVATE);
|
||||||
|
else
|
||||||
b.setVisibility(VISIBILITY_SECRET);
|
b.setVisibility(VISIBILITY_SECRET);
|
||||||
}
|
}
|
||||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||||
@@ -532,16 +527,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearAllForumPostNotifications() {
|
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
clearForumPostNotification();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void showBlogPostNotification(final GroupId g) {
|
private void showBlogPostNotification(final GroupId g) {
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
androidExecutor.runOnUiThread(new Runnable() {
|
||||||
@@ -602,6 +587,11 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
b.setCategory(CATEGORY_SOCIAL);
|
b.setCategory(CATEGORY_SOCIAL);
|
||||||
|
boolean showOnLockScreen =
|
||||||
|
settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
|
||||||
|
if (showOnLockScreen)
|
||||||
|
b.setVisibility(VISIBILITY_PRIVATE);
|
||||||
|
else
|
||||||
b.setVisibility(VISIBILITY_SECRET);
|
b.setVisibility(VISIBILITY_SECRET);
|
||||||
}
|
}
|
||||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||||
@@ -658,6 +648,11 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
b.setCategory(CATEGORY_MESSAGE);
|
b.setCategory(CATEGORY_MESSAGE);
|
||||||
|
boolean showOnLockScreen =
|
||||||
|
settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
|
||||||
|
if (showOnLockScreen)
|
||||||
|
b.setVisibility(VISIBILITY_PRIVATE);
|
||||||
|
else
|
||||||
b.setVisibility(VISIBILITY_SECRET);
|
b.setVisibility(VISIBILITY_SECRET);
|
||||||
}
|
}
|
||||||
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
Object o = appContext.getSystemService(NOTIFICATION_SERVICE);
|
||||||
@@ -705,68 +700,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void blockAllContactNotifications() {
|
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
blockContacts = true;
|
|
||||||
blockIntroductions = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unblockAllContactNotifications() {
|
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
blockContacts = false;
|
|
||||||
blockIntroductions = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void blockAllGroupMessageNotifications() {
|
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
blockGroups = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unblockAllGroupMessageNotifications() {
|
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
blockGroups = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void blockAllForumPostNotifications() {
|
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
blockForums = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unblockAllForumPostNotifications() {
|
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
blockForums = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void blockAllBlogPostNotifications() {
|
public void blockAllBlogPostNotifications() {
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
androidExecutor.runOnUiThread(new Runnable() {
|
||||||
@@ -786,5 +719,4 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,8 +38,6 @@ public class AppModule {
|
|||||||
static class EagerSingletons {
|
static class EagerSingletons {
|
||||||
@Inject
|
@Inject
|
||||||
AndroidNotificationManager androidNotificationManager;
|
AndroidNotificationManager androidNotificationManager;
|
||||||
@Inject
|
|
||||||
ScreenFilterMonitor screenFilterMonitor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Application application;
|
private final Application application;
|
||||||
@@ -171,10 +169,8 @@ public class AppModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
|
||||||
ScreenFilterMonitor provideScreenFilterMonitor(
|
ScreenFilterMonitor provideScreenFilterMonitor(
|
||||||
LifecycleManager lifecycleManager, ScreenFilterMonitorImpl sfm) {
|
ScreenFilterMonitorImpl screenFilterMonitor) {
|
||||||
lifecycleManager.registerService(sfm);
|
return screenFilterMonitor;
|
||||||
return sfm;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,5 +6,9 @@ package org.briarproject.briar.android;
|
|||||||
*/
|
*/
|
||||||
public interface BriarApplication {
|
public interface BriarApplication {
|
||||||
|
|
||||||
|
// This build expires on 21 October 2017
|
||||||
|
long EXPIRY_DATE = 1508544000 * 1000L;
|
||||||
|
|
||||||
AndroidComponent getApplicationComponent();
|
AndroidComponent getApplicationComponent();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package org.briarproject.briar.android;
|
|||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.StrictMode;
|
||||||
|
import android.os.StrictMode.ThreadPolicy;
|
||||||
|
import android.os.StrictMode.VmPolicy;
|
||||||
|
|
||||||
import org.acra.ACRA;
|
import org.acra.ACRA;
|
||||||
import org.acra.ReportingInteractionMode;
|
import org.acra.ReportingInteractionMode;
|
||||||
@@ -33,6 +36,8 @@ import static org.acra.ReportField.REPORT_ID;
|
|||||||
import static org.acra.ReportField.STACK_TRACE;
|
import static org.acra.ReportField.STACK_TRACE;
|
||||||
import static org.acra.ReportField.USER_APP_START_DATE;
|
import static org.acra.ReportField.USER_APP_START_DATE;
|
||||||
import static org.acra.ReportField.USER_CRASH_DATE;
|
import static org.acra.ReportField.USER_CRASH_DATE;
|
||||||
|
import static org.briarproject.briar.android.TestingConstants.DEFAULT_LOG_LEVEL;
|
||||||
|
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
|
||||||
|
|
||||||
@ReportsCrashes(
|
@ReportsCrashes(
|
||||||
reportPrimerClass = BriarReportPrimer.class,
|
reportPrimerClass = BriarReportPrimer.class,
|
||||||
@@ -72,6 +77,9 @@ public class BriarApplicationImpl extends Application
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
|
||||||
|
if (IS_DEBUG_BUILD) enableStrictMode();
|
||||||
|
Logger.getLogger("").setLevel(DEFAULT_LOG_LEVEL);
|
||||||
LOG.info("Created");
|
LOG.info("Created");
|
||||||
|
|
||||||
applicationComponent = DaggerAndroidComponent.builder()
|
applicationComponent = DaggerAndroidComponent.builder()
|
||||||
@@ -85,6 +93,17 @@ public class BriarApplicationImpl extends Application
|
|||||||
AndroidEagerSingletons.initEagerSingletons(applicationComponent);
|
AndroidEagerSingletons.initEagerSingletons(applicationComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void enableStrictMode() {
|
||||||
|
ThreadPolicy.Builder threadPolicy = new ThreadPolicy.Builder();
|
||||||
|
threadPolicy.detectAll();
|
||||||
|
threadPolicy.penaltyLog();
|
||||||
|
StrictMode.setThreadPolicy(threadPolicy.build());
|
||||||
|
VmPolicy.Builder vmPolicy = new VmPolicy.Builder();
|
||||||
|
vmPolicy.detectAll();
|
||||||
|
vmPolicy.penaltyLog();
|
||||||
|
StrictMode.setVmPolicy(vmPolicy.build());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AndroidComponent getApplicationComponent() {
|
public AndroidComponent getApplicationComponent() {
|
||||||
return applicationComponent;
|
return applicationComponent;
|
||||||
|
|||||||
@@ -1,24 +1,13 @@
|
|||||||
package org.briarproject.briar.android;
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
import android.content.pm.Signature;
|
import android.content.pm.Signature;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.support.v7.preference.PreferenceManager;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.lifecycle.Service;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.lifecycle.ServiceException;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
||||||
|
|
||||||
@@ -27,37 +16,26 @@ import java.io.InputStream;
|
|||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
|
import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
|
||||||
import static android.content.Intent.ACTION_PACKAGE_ADDED;
|
|
||||||
import static android.content.Intent.EXTRA_REPLACING;
|
|
||||||
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
|
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
|
||||||
import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
|
import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
|
||||||
import static android.content.pm.PackageManager.GET_PERMISSIONS;
|
import static android.content.pm.PackageManager.GET_PERMISSIONS;
|
||||||
import static android.content.pm.PackageManager.GET_SIGNATURES;
|
import static android.content.pm.PackageManager.GET_SIGNATURES;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@NotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
class ScreenFilterMonitorImpl implements ScreenFilterMonitor {
|
||||||
public class ScreenFilterMonitorImpl extends BroadcastReceiver
|
|
||||||
implements Service, ScreenFilterMonitor {
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(ScreenFilterMonitorImpl.class.getName());
|
Logger.getLogger(ScreenFilterMonitorImpl.class.getName());
|
||||||
private static final String PREF_SCREEN_FILTER_APPS =
|
|
||||||
"shownScreenFilterApps";
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ignore Play Services if it uses this package name and public key - it's
|
* Ignore Play Services if it uses this package name and public key - it's
|
||||||
@@ -78,124 +56,17 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver
|
|||||||
"82BA35E003C1B4B10DD244A8EE24FFFD333872AB5221985EDAB0FC0D" +
|
"82BA35E003C1B4B10DD244A8EE24FFFD333872AB5221985EDAB0FC0D" +
|
||||||
"0B145B6AA192858E79020103";
|
"0B145B6AA192858E79020103";
|
||||||
|
|
||||||
private final Context appContext;
|
|
||||||
private final AndroidExecutor androidExecutor;
|
|
||||||
private final PackageManager pm;
|
private final PackageManager pm;
|
||||||
private final SharedPreferences prefs;
|
|
||||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
|
||||||
|
|
||||||
// The following must only be accessed on the UI thread
|
|
||||||
private final Set<String> apps = new HashSet<>();
|
|
||||||
private final Set<String> shownApps;
|
|
||||||
private boolean serviceStarted = false;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ScreenFilterMonitorImpl(AndroidExecutor executor, Application app) {
|
ScreenFilterMonitorImpl(Application app) {
|
||||||
this.androidExecutor = executor;
|
pm = app.getPackageManager();
|
||||||
this.appContext = app;
|
|
||||||
pm = appContext.getPackageManager();
|
|
||||||
prefs = PreferenceManager.getDefaultSharedPreferences(appContext);
|
|
||||||
shownApps = getShownScreenFilterApps();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startService() throws ServiceException {
|
|
||||||
if (used.getAndSet(true)) throw new IllegalStateException();
|
|
||||||
Future<Void> f = androidExecutor.runOnUiThread(new Callable<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void call() {
|
|
||||||
IntentFilter intentFilter = new IntentFilter();
|
|
||||||
intentFilter.addAction(ACTION_PACKAGE_ADDED);
|
|
||||||
intentFilter.addDataScheme("package");
|
|
||||||
appContext.registerReceiver(ScreenFilterMonitorImpl.this,
|
|
||||||
intentFilter);
|
|
||||||
apps.addAll(getInstalledScreenFilterApps());
|
|
||||||
serviceStarted = true;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
f.get();
|
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
|
||||||
throw new ServiceException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stopService() throws ServiceException {
|
|
||||||
Future<Void> f = androidExecutor.runOnUiThread(new Callable<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void call() {
|
|
||||||
serviceStarted = false;
|
|
||||||
appContext.unregisterReceiver(ScreenFilterMonitorImpl.this);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
f.get();
|
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
|
||||||
throw new ServiceException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<String> getShownScreenFilterApps() {
|
|
||||||
// Result must not be modified
|
|
||||||
Set<String> s = prefs.getStringSet(PREF_SCREEN_FILTER_APPS, null);
|
|
||||||
HashSet<String> result = new HashSet<>();
|
|
||||||
if (s != null) {
|
|
||||||
result.addAll(s);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
if (!intent.getBooleanExtra(EXTRA_REPLACING, false)) {
|
|
||||||
final String packageName =
|
|
||||||
intent.getData().getEncodedSchemeSpecificPart();
|
|
||||||
androidExecutor.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
String pkg = isOverlayApp(packageName);
|
|
||||||
if (pkg == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
apps.add(pkg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@UiThread
|
@UiThread
|
||||||
public Set<String> getApps() {
|
public Set<String> getApps() {
|
||||||
if (!serviceStarted) {
|
Set<String> screenFilterApps = new TreeSet<>();
|
||||||
apps.addAll(getInstalledScreenFilterApps());
|
|
||||||
}
|
|
||||||
TreeSet<String> buf = new TreeSet<>();
|
|
||||||
if (apps.isEmpty()) {
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
buf.addAll(apps);
|
|
||||||
buf.removeAll(shownApps);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@UiThread
|
|
||||||
public void storeAppsAsShown(Collection<String> s, boolean persistent) {
|
|
||||||
HashSet<String> buf = new HashSet<>(s);
|
|
||||||
shownApps.addAll(buf);
|
|
||||||
if (persistent && !s.isEmpty()) {
|
|
||||||
buf.addAll(getShownScreenFilterApps());
|
|
||||||
prefs.edit()
|
|
||||||
.putStringSet(PREF_SCREEN_FILTER_APPS, buf)
|
|
||||||
.apply();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<String> getInstalledScreenFilterApps() {
|
|
||||||
HashSet<String> screenFilterApps = new HashSet<>();
|
|
||||||
List<PackageInfo> packageInfos =
|
List<PackageInfo> packageInfos =
|
||||||
pm.getInstalledPackages(GET_PERMISSIONS);
|
pm.getInstalledPackages(GET_PERMISSIONS);
|
||||||
for (PackageInfo packageInfo : packageInfos) {
|
for (PackageInfo packageInfo : packageInfos) {
|
||||||
@@ -209,21 +80,6 @@ public class ScreenFilterMonitorImpl extends BroadcastReceiver
|
|||||||
return screenFilterApps;
|
return screenFilterApps;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if a package uses the SYSTEM_ALERT_WINDOW permission and if so
|
|
||||||
// returns the app name.
|
|
||||||
@Nullable
|
|
||||||
private String isOverlayApp(String pkg) {
|
|
||||||
try {
|
|
||||||
PackageInfo pkgInfo = pm.getPackageInfo(pkg, GET_PERMISSIONS);
|
|
||||||
if (isOverlayApp(pkgInfo)) {
|
|
||||||
return pkgToString(pkgInfo);
|
|
||||||
}
|
|
||||||
} catch (NameNotFoundException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetches the application name for a given package.
|
// Fetches the application name for a given package.
|
||||||
@Nullable
|
@Nullable
|
||||||
private String pkgToString(PackageInfo pkgInfo) {
|
private String pkgToString(PackageInfo pkgInfo) {
|
||||||
|
|||||||
@@ -10,13 +10,21 @@ import static java.util.logging.Level.OFF;
|
|||||||
public interface TestingConstants {
|
public interface TestingConstants {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this is an alpha or beta build. This should be set to false for
|
* Whether this is a debug build.
|
||||||
|
*/
|
||||||
|
boolean IS_DEBUG_BUILD = BuildConfig.DEBUG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this is a beta build. This should be set to false for final
|
||||||
* release builds.
|
* release builds.
|
||||||
*/
|
*/
|
||||||
boolean TESTING = BuildConfig.DEBUG;
|
boolean IS_BETA_BUILD = true;
|
||||||
|
|
||||||
/** Default log level. */
|
/**
|
||||||
Level DEFAULT_LOG_LEVEL = TESTING ? INFO : OFF;
|
* Default log level. Disable logging for final release builds.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
Level DEFAULT_LOG_LEVEL = IS_DEBUG_BUILD || IS_BETA_BUILD ? INFO : OFF;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to prevent screenshots from being taken. Setting this to true
|
* Whether to prevent screenshots from being taken. Setting this to true
|
||||||
@@ -24,5 +32,5 @@ public interface TestingConstants {
|
|||||||
* Unfortunately this also prevents the user from taking screenshots
|
* Unfortunately this also prevents the user from taking screenshots
|
||||||
* intentionally.
|
* intentionally.
|
||||||
*/
|
*/
|
||||||
boolean PREVENT_SCREENSHOTS = !TESTING;
|
boolean PREVENT_SCREENSHOTS = !IS_DEBUG_BUILD;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import org.briarproject.briar.android.privategroup.conversation.GroupConversatio
|
|||||||
import org.briarproject.briar.android.privategroup.creation.CreateGroupActivity;
|
import org.briarproject.briar.android.privategroup.creation.CreateGroupActivity;
|
||||||
import org.briarproject.briar.android.privategroup.creation.CreateGroupFragment;
|
import org.briarproject.briar.android.privategroup.creation.CreateGroupFragment;
|
||||||
import org.briarproject.briar.android.privategroup.creation.CreateGroupMessageFragment;
|
import org.briarproject.briar.android.privategroup.creation.CreateGroupMessageFragment;
|
||||||
import org.briarproject.briar.android.privategroup.creation.GroupCreateModule;
|
import org.briarproject.briar.android.privategroup.creation.CreateGroupModule;
|
||||||
import org.briarproject.briar.android.privategroup.creation.GroupInviteActivity;
|
import org.briarproject.briar.android.privategroup.creation.GroupInviteActivity;
|
||||||
import org.briarproject.briar.android.privategroup.creation.GroupInviteFragment;
|
import org.briarproject.briar.android.privategroup.creation.GroupInviteFragment;
|
||||||
import org.briarproject.briar.android.privategroup.invitation.GroupInvitationActivity;
|
import org.briarproject.briar.android.privategroup.invitation.GroupInvitationActivity;
|
||||||
@@ -71,7 +71,7 @@ import dagger.Component;
|
|||||||
@Component(
|
@Component(
|
||||||
modules = {ActivityModule.class, ForumModule.class, SharingModule.class,
|
modules = {ActivityModule.class, ForumModule.class, SharingModule.class,
|
||||||
BlogModule.class, ContactModule.class, GroupListModule.class,
|
BlogModule.class, ContactModule.class, GroupListModule.class,
|
||||||
GroupCreateModule.class, GroupInvitationModule.class,
|
CreateGroupModule.class, GroupInvitationModule.class,
|
||||||
GroupConversationModule.class, GroupMemberModule.class,
|
GroupConversationModule.class, GroupMemberModule.class,
|
||||||
GroupRevealModule.class},
|
GroupRevealModule.class},
|
||||||
dependencies = AndroidComponent.class)
|
dependencies = AndroidComponent.class)
|
||||||
|
|||||||
@@ -2,9 +2,13 @@ package org.briarproject.briar.android.activity;
|
|||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.support.annotation.LayoutRes;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewGroup.LayoutParams;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
@@ -13,7 +17,9 @@ import org.briarproject.briar.android.BriarApplication;
|
|||||||
import org.briarproject.briar.android.DestroyableContext;
|
import org.briarproject.briar.android.DestroyableContext;
|
||||||
import org.briarproject.briar.android.controller.ActivityLifecycleController;
|
import org.briarproject.briar.android.controller.ActivityLifecycleController;
|
||||||
import org.briarproject.briar.android.forum.ForumModule;
|
import org.briarproject.briar.android.forum.ForumModule;
|
||||||
import org.briarproject.briar.android.fragment.SFDialogFragment;
|
import org.briarproject.briar.android.fragment.ScreenFilterDialogFragment;
|
||||||
|
import org.briarproject.briar.android.widget.TapSafeFrameLayout;
|
||||||
|
import org.briarproject.briar.android.widget.TapSafeFrameLayout.OnTapFilteredListener;
|
||||||
import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -23,21 +29,23 @@ import java.util.Set;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
|
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
|
||||||
import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
|
import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
|
||||||
import static org.briarproject.briar.android.TestingConstants.PREVENT_SCREENSHOTS;
|
import static org.briarproject.briar.android.TestingConstants.PREVENT_SCREENSHOTS;
|
||||||
|
|
||||||
public abstract class BaseActivity extends AppCompatActivity
|
public abstract class BaseActivity extends AppCompatActivity
|
||||||
implements DestroyableContext {
|
implements DestroyableContext, OnTapFilteredListener {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected ScreenFilterMonitor screenFilterMonitor;
|
||||||
|
|
||||||
protected ActivityComponent activityComponent;
|
protected ActivityComponent activityComponent;
|
||||||
|
|
||||||
private final List<ActivityLifecycleController> lifecycleControllers =
|
private final List<ActivityLifecycleController> lifecycleControllers =
|
||||||
new ArrayList<>();
|
new ArrayList<>();
|
||||||
private boolean destroyed = false;
|
private boolean destroyed = false;
|
||||||
|
private ScreenFilterDialogFragment dialogFrag;
|
||||||
@Inject
|
|
||||||
protected ScreenFilterMonitor screenFilterMonitor;
|
|
||||||
private SFDialogFragment dialogFrag;
|
|
||||||
|
|
||||||
public abstract void injectActivity(ActivityComponent component);
|
public abstract void injectActivity(ActivityComponent component);
|
||||||
|
|
||||||
@@ -65,7 +73,6 @@ public abstract class BaseActivity extends AppCompatActivity
|
|||||||
for (ActivityLifecycleController alc : lifecycleControllers) {
|
for (ActivityLifecycleController alc : lifecycleControllers) {
|
||||||
alc.onActivityCreate(this);
|
alc.onActivityCreate(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActivityComponent getActivityComponent() {
|
public ActivityComponent getActivityComponent() {
|
||||||
@@ -97,12 +104,6 @@ public abstract class BaseActivity extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostResume() {
|
|
||||||
super.onPostResume();
|
|
||||||
showNewScreenFilterWarning();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
@@ -112,18 +113,14 @@ public abstract class BaseActivity extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void showNewScreenFilterWarning() {
|
private void showScreenFilterWarning() {
|
||||||
final Set<String> apps = screenFilterMonitor.getApps();
|
if (dialogFrag != null && dialogFrag.isVisible()) return;
|
||||||
if (apps.isEmpty()) {
|
Set<String> apps = screenFilterMonitor.getApps();
|
||||||
return;
|
if (apps.isEmpty()) return;
|
||||||
}
|
dialogFrag =
|
||||||
dialogFrag = SFDialogFragment.newInstance(new ArrayList<>(apps));
|
ScreenFilterDialogFragment.newInstance(new ArrayList<>(apps));
|
||||||
dialogFrag.setCancelable(false);
|
dialogFrag.setCancelable(false);
|
||||||
dialogFrag.show(getSupportFragmentManager(), "SFDialog");
|
dialogFrag.show(getSupportFragmentManager(), dialogFrag.getTag());
|
||||||
}
|
|
||||||
|
|
||||||
public void rememberShownApps(ArrayList<String> s, boolean permanent) {
|
|
||||||
screenFilterMonitor.storeAppsAsShown(s, permanent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -161,4 +158,70 @@ public abstract class BaseActivity extends AppCompatActivity
|
|||||||
supportFinishAfterTransition();
|
supportFinishAfterTransition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wraps the given view in a wrapper that notifies this activity when an
|
||||||
|
* obscured touch has been filtered, and returns the wrapper.
|
||||||
|
*/
|
||||||
|
private View makeTapSafeWrapper(View v) {
|
||||||
|
TapSafeFrameLayout wrapper = new TapSafeFrameLayout(this);
|
||||||
|
wrapper.setLayoutParams(new LayoutParams(MATCH_PARENT, MATCH_PARENT));
|
||||||
|
wrapper.setOnTapFilteredListener(this);
|
||||||
|
wrapper.addView(v);
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finds the AppCompat toolbar, if any, and configures it to filter
|
||||||
|
* obscured touches. If a custom toolbar is used, it will be part of the
|
||||||
|
* content view and thus protected by the wrapper. But the default toolbar
|
||||||
|
* is outside the wrapper.
|
||||||
|
*/
|
||||||
|
private void protectToolbar() {
|
||||||
|
View decorView = getWindow().getDecorView();
|
||||||
|
if (decorView instanceof ViewGroup) {
|
||||||
|
Toolbar toolbar = findToolbar((ViewGroup) decorView);
|
||||||
|
if (toolbar != null) toolbar.setFilterTouchesWhenObscured(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Toolbar findToolbar(ViewGroup vg) {
|
||||||
|
for (int i = 0, len = vg.getChildCount(); i < len; i++) {
|
||||||
|
View child = vg.getChildAt(i);
|
||||||
|
if (child instanceof Toolbar) return (Toolbar) child;
|
||||||
|
if (child instanceof ViewGroup) {
|
||||||
|
Toolbar toolbar = findToolbar((ViewGroup) child);
|
||||||
|
if (toolbar != null) return toolbar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContentView(@LayoutRes int layoutRes) {
|
||||||
|
setContentView(getLayoutInflater().inflate(layoutRes, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContentView(View v) {
|
||||||
|
super.setContentView(makeTapSafeWrapper(v));
|
||||||
|
protectToolbar();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContentView(View v, LayoutParams layoutParams) {
|
||||||
|
super.setContentView(makeTapSafeWrapper(v), layoutParams);
|
||||||
|
protectToolbar();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addContentView(View v, LayoutParams layoutParams) {
|
||||||
|
super.addContentView(makeTapSafeWrapper(v), layoutParams);
|
||||||
|
protectToolbar();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTapFiltered() {
|
||||||
|
showScreenFilterWarning();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.briarproject.briar.android.activity;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.transition.Slide;
|
import android.transition.Slide;
|
||||||
@@ -21,6 +20,7 @@ import org.briarproject.briar.android.panic.ExitActivity;
|
|||||||
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
|
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.briar.android.blog;
|
package org.briarproject.briar.android.blog;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
@@ -20,8 +21,10 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||||
import static android.view.View.INVISIBLE;
|
import static android.view.View.INVISIBLE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
|
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.MIN_DATE_RESOLUTION;
|
import static org.briarproject.briar.android.util.UiUtils.MIN_DATE_RESOLUTION;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@@ -57,7 +60,20 @@ abstract class BasePostFragment extends BaseFragment {
|
|||||||
false);
|
false);
|
||||||
progressBar = (ProgressBar) view.findViewById(R.id.progressBar);
|
progressBar = (ProgressBar) view.findViewById(R.id.progressBar);
|
||||||
progressBar.setVisibility(VISIBLE);
|
progressBar.setVisibility(VISIBLE);
|
||||||
ui = new BlogPostViewHolder(view);
|
ui = new BlogPostViewHolder(view, true, new OnBlogPostClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onBlogPostClick(BlogPostItem post) {
|
||||||
|
// We're already there
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAuthorClick(BlogPostItem post) {
|
||||||
|
Intent i = new Intent(getContext(), BlogActivity.class);
|
||||||
|
i.putExtra(GROUP_ID, post.getGroupId().getBytes());
|
||||||
|
i.setFlags(FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
getContext().startActivity(i);
|
||||||
|
}
|
||||||
|
});
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.briarproject.briar.android.blog;
|
|||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
@@ -15,6 +14,7 @@ import org.briarproject.briar.android.activity.BriarActivity;
|
|||||||
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
||||||
import org.briarproject.briar.android.sharing.BlogSharingStatusActivity;
|
import org.briarproject.briar.android.sharing.BlogSharingStatusActivity;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ class BlogControllerImpl extends BaseControllerImpl
|
|||||||
BlogInvitationResponseReceivedEvent b =
|
BlogInvitationResponseReceivedEvent b =
|
||||||
(BlogInvitationResponseReceivedEvent) e;
|
(BlogInvitationResponseReceivedEvent) e;
|
||||||
InvitationResponse r = b.getResponse();
|
InvitationResponse r = b.getResponse();
|
||||||
if (r.getGroupId().equals(groupId) && r.wasAccepted()) {
|
if (r.getShareableId().equals(groupId) && r.wasAccepted()) {
|
||||||
LOG.info("Blog invitation accepted");
|
LOG.info("Blog invitation accepted");
|
||||||
onBlogInvitationAccepted(b.getContactId());
|
onBlogInvitationAccepted(b.getContactId());
|
||||||
}
|
}
|
||||||
@@ -169,7 +169,7 @@ class BlogControllerImpl extends BaseControllerImpl
|
|||||||
LocalAuthor a = identityManager.getLocalAuthor();
|
LocalAuthor a = identityManager.getLocalAuthor();
|
||||||
Blog b = blogManager.getBlog(groupId);
|
Blog b = blogManager.getBlog(groupId);
|
||||||
boolean ours = a.getId().equals(b.getAuthor().getId());
|
boolean ours = a.getId().equals(b.getAuthor().getId());
|
||||||
boolean removable = blogManager.canBeRemoved(groupId);
|
boolean removable = blogManager.canBeRemoved(b);
|
||||||
BlogItem blog = new BlogItem(b, ours, removable);
|
BlogItem blog = new BlogItem(b, ours, removable);
|
||||||
long duration = System.currentTimeMillis() - now;
|
long duration = System.currentTimeMillis() - now;
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import org.briarproject.briar.R;
|
|||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.activity.BriarActivity;
|
import org.briarproject.briar.android.activity.BriarActivity;
|
||||||
import org.briarproject.briar.android.blog.BlogController.BlogSharingListener;
|
import org.briarproject.briar.android.blog.BlogController.BlogSharingListener;
|
||||||
import org.briarproject.briar.android.blog.BlogPostAdapter.OnBlogPostClickListener;
|
|
||||||
import org.briarproject.briar.android.controller.SharingController;
|
import org.briarproject.briar.android.controller.SharingController;
|
||||||
import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler;
|
import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler;
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||||
@@ -216,10 +215,19 @@ public class BlogFragment extends BaseFragment
|
|||||||
showNextFragment(f);
|
showNextFragment(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAuthorClick(BlogPostItem post) {
|
||||||
|
if (post.getGroupId().equals(groupId)) return; // We're already there
|
||||||
|
Intent i = new Intent(getContext(), BlogActivity.class);
|
||||||
|
i.putExtra(GROUP_ID, post.getGroupId().getBytes());
|
||||||
|
i.setFlags(FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
getContext().startActivity(i);
|
||||||
|
}
|
||||||
|
|
||||||
private void loadBlogPosts(final boolean reload) {
|
private void loadBlogPosts(final boolean reload) {
|
||||||
blogController.loadBlogPosts(
|
blogController.loadBlogPosts(
|
||||||
new UiResultExceptionHandler<Collection<BlogPostItem>, DbException>(
|
new UiResultExceptionHandler<Collection<BlogPostItem>,
|
||||||
this) {
|
DbException>(this) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(Collection<BlogPostItem> posts) {
|
public void onResultUi(Collection<BlogPostItem> posts) {
|
||||||
if (posts.isEmpty()) {
|
if (posts.isEmpty()) {
|
||||||
@@ -257,13 +265,13 @@ public class BlogFragment extends BaseFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setToolbarTitle(Author a) {
|
private void setToolbarTitle(Author a) {
|
||||||
String title = getString(R.string.blogs_personal_blog, a.getName());
|
getActivity().setTitle(a.getName());
|
||||||
getActivity().setTitle(title);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadSharedContacts() {
|
private void loadSharedContacts() {
|
||||||
blogController.loadSharingContacts(
|
blogController.loadSharingContacts(
|
||||||
new UiResultExceptionHandler<Collection<ContactId>, DbException>(this) {
|
new UiResultExceptionHandler<Collection<ContactId>,
|
||||||
|
DbException>(this) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(Collection<ContactId> contacts) {
|
public void onResultUi(Collection<ContactId> contacts) {
|
||||||
sharingController.addAll(contacts);
|
sharingController.addAll(contacts);
|
||||||
|
|||||||
@@ -23,8 +23,7 @@ class BlogPostAdapter
|
|||||||
int viewType) {
|
int viewType) {
|
||||||
View v = LayoutInflater.from(ctx).inflate(
|
View v = LayoutInflater.from(ctx).inflate(
|
||||||
R.layout.list_item_blog_post, parent, false);
|
R.layout.list_item_blog_post, parent, false);
|
||||||
BlogPostViewHolder ui = new BlogPostViewHolder(v);
|
BlogPostViewHolder ui = new BlogPostViewHolder(v, false, listener);
|
||||||
ui.setOnBlogPostClickListener(listener);
|
|
||||||
return ui;
|
return ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,8 +47,4 @@ class BlogPostAdapter
|
|||||||
return a.getId().equals(b.getId());
|
return a.getId().equals(b.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OnBlogPostClickListener {
|
|
||||||
void onBlogPostClick(BlogPostItem post);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,16 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
|||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
|
import org.briarproject.briar.android.blog.BaseController.BlogListener;
|
||||||
import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler;
|
import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler;
|
||||||
|
import org.briarproject.briar.api.blog.BlogPostHeader;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
public class BlogPostFragment extends BasePostFragment {
|
public class BlogPostFragment extends BasePostFragment implements BlogListener {
|
||||||
|
|
||||||
private static final String TAG = BlogPostFragment.class.getName();
|
private static final String TAG = BlogPostFragment.class.getName();
|
||||||
|
|
||||||
@@ -40,6 +42,7 @@ public class BlogPostFragment extends BasePostFragment {
|
|||||||
@Override
|
@Override
|
||||||
public void injectFragment(ActivityComponent component) {
|
public void injectFragment(ActivityComponent component) {
|
||||||
component.inject(this);
|
component.inject(this);
|
||||||
|
blogController.setBlogListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -59,4 +62,15 @@ public class BlogPostFragment extends BasePostFragment {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBlogPostAdded(BlogPostHeader header, boolean local) {
|
||||||
|
// doesn't matter here
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBlogRemoved() {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.app.Activity;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v4.app.ActivityOptionsCompat;
|
import android.support.v4.app.ActivityOptionsCompat;
|
||||||
@@ -20,7 +21,6 @@ import android.widget.TextView;
|
|||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.blog.BlogPostAdapter.OnBlogPostClickListener;
|
|
||||||
import org.briarproject.briar.android.view.AuthorView;
|
import org.briarproject.briar.android.view.AuthorView;
|
||||||
import org.briarproject.briar.api.blog.BlogCommentHeader;
|
import org.briarproject.briar.api.blog.BlogCommentHeader;
|
||||||
import org.briarproject.briar.api.blog.BlogPostHeader;
|
import org.briarproject.briar.api.blog.BlogPostHeader;
|
||||||
@@ -48,11 +48,16 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
|
|||||||
private final ImageView reblogButton;
|
private final ImageView reblogButton;
|
||||||
private final TextView body;
|
private final TextView body;
|
||||||
private final ViewGroup commentContainer;
|
private final ViewGroup commentContainer;
|
||||||
|
private final boolean fullText;
|
||||||
|
|
||||||
private OnBlogPostClickListener listener;
|
@NonNull
|
||||||
|
private final OnBlogPostClickListener listener;
|
||||||
|
|
||||||
BlogPostViewHolder(View v) {
|
BlogPostViewHolder(View v, boolean fullText,
|
||||||
|
@NonNull OnBlogPostClickListener listener) {
|
||||||
super(v);
|
super(v);
|
||||||
|
this.fullText = fullText;
|
||||||
|
this.listener = listener;
|
||||||
|
|
||||||
ctx = v.getContext();
|
ctx = v.getContext();
|
||||||
layout = (ViewGroup) v.findViewById(R.id.postLayout);
|
layout = (ViewGroup) v.findViewById(R.id.postLayout);
|
||||||
@@ -64,10 +69,6 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
|
|||||||
(ViewGroup) v.findViewById(R.id.commentContainer);
|
(ViewGroup) v.findViewById(R.id.commentContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setOnBlogPostClickListener(OnBlogPostClickListener listener) {
|
|
||||||
this.listener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setVisibility(int visibility) {
|
void setVisibility(int visibility) {
|
||||||
layout.setVisibility(visibility);
|
layout.setVisibility(visibility);
|
||||||
}
|
}
|
||||||
@@ -92,7 +93,7 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
|
|||||||
if (item == null) return;
|
if (item == null) return;
|
||||||
|
|
||||||
setTransitionName(item.getId());
|
setTransitionName(item.getId());
|
||||||
if (listener != null) {
|
if (!fullText) {
|
||||||
layout.setClickable(true);
|
layout.setClickable(true);
|
||||||
layout.setOnClickListener(new OnClickListener() {
|
layout.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -111,15 +112,20 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
|
|||||||
author.setPersona(
|
author.setPersona(
|
||||||
item.isRssFeed() ? AuthorView.RSS_FEED : AuthorView.NORMAL);
|
item.isRssFeed() ? AuthorView.RSS_FEED : AuthorView.NORMAL);
|
||||||
// TODO make author clickable more often #624
|
// TODO make author clickable more often #624
|
||||||
if (item.getHeader().getType() == POST) {
|
if (!fullText && item.getHeader().getType() == POST) {
|
||||||
author.setBlogLink(post.getGroupId());
|
author.setAuthorClickable(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
listener.onAuthorClick(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
author.unsetBlogLink();
|
author.setAuthorNotClickable();
|
||||||
}
|
}
|
||||||
|
|
||||||
// post body
|
// post body
|
||||||
Spanned bodyText = getSpanned(item.getBody());
|
Spanned bodyText = getSpanned(item.getBody());
|
||||||
if (listener == null) {
|
if (fullText) {
|
||||||
body.setText(bodyText);
|
body.setText(bodyText);
|
||||||
body.setTextIsSelectable(true);
|
body.setTextIsSelectable(true);
|
||||||
makeLinksClickable(body);
|
makeLinksClickable(body);
|
||||||
@@ -165,7 +171,14 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
|
|||||||
reblogger.setAuthor(item.getAuthor());
|
reblogger.setAuthor(item.getAuthor());
|
||||||
reblogger.setAuthorStatus(item.getAuthorStatus());
|
reblogger.setAuthorStatus(item.getAuthorStatus());
|
||||||
reblogger.setDate(item.getTimestamp());
|
reblogger.setDate(item.getTimestamp());
|
||||||
reblogger.setBlogLink(item.getGroupId());
|
if (!fullText) {
|
||||||
|
reblogger.setAuthorClickable(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
listener.onAuthorClick(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
reblogger.setVisibility(VISIBLE);
|
reblogger.setVisibility(VISIBLE);
|
||||||
reblogger.setPersona(AuthorView.REBLOGGER);
|
reblogger.setPersona(AuthorView.REBLOGGER);
|
||||||
|
|
||||||
@@ -188,7 +201,7 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
|
|||||||
// TODO make author clickable #624
|
// TODO make author clickable #624
|
||||||
|
|
||||||
body.setText(c.getComment());
|
body.setText(c.getComment());
|
||||||
if (listener == null) body.setTextIsSelectable(true);
|
if (fullText) body.setTextIsSelectable(true);
|
||||||
|
|
||||||
commentContainer.addView(v);
|
commentContainer.addView(v);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
|||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.blog.BlogPostAdapter.OnBlogPostClickListener;
|
|
||||||
import org.briarproject.briar.android.blog.FeedController.FeedListener;
|
import org.briarproject.briar.android.blog.FeedController.FeedListener;
|
||||||
import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler;
|
import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler;
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||||
@@ -34,6 +33,7 @@ import javax.annotation.Nullable;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static android.app.Activity.RESULT_OK;
|
import static android.app.Activity.RESULT_OK;
|
||||||
|
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||||
import static android.support.design.widget.Snackbar.LENGTH_LONG;
|
import static android.support.design.widget.Snackbar.LENGTH_LONG;
|
||||||
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
||||||
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_WRITE_BLOG_POST;
|
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_WRITE_BLOG_POST;
|
||||||
@@ -223,6 +223,14 @@ public class FeedFragment extends BaseFragment implements
|
|||||||
showNextFragment(f);
|
showNextFragment(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAuthorClick(BlogPostItem post) {
|
||||||
|
Intent i = new Intent(getContext(), BlogActivity.class);
|
||||||
|
i.putExtra(GROUP_ID, post.getGroupId().getBytes());
|
||||||
|
i.setFlags(FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
getContext().startActivity(i);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUniqueTag() {
|
public String getUniqueTag() {
|
||||||
return TAG;
|
return TAG;
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package org.briarproject.briar.android.blog;
|
||||||
|
|
||||||
|
interface OnBlogPostClickListener {
|
||||||
|
|
||||||
|
void onBlogPostClick(BlogPostItem post);
|
||||||
|
|
||||||
|
void onAuthorClick(BlogPostItem post);
|
||||||
|
}
|
||||||
@@ -18,8 +18,8 @@ public class ReblogActivity extends BriarActivity implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setSceneTransitionAnimation();
|
setSceneTransitionAnimation();
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
byte[] groupId = intent.getByteArrayExtra(GROUP_ID);
|
byte[] groupId = intent.getByteArrayExtra(GROUP_ID);
|
||||||
|
|||||||
@@ -161,7 +161,18 @@ public class ReblogFragment extends BaseFragment implements TextInputListener {
|
|||||||
private ViewHolder(View v) {
|
private ViewHolder(View v) {
|
||||||
scrollView = (ScrollView) v.findViewById(R.id.scrollView);
|
scrollView = (ScrollView) v.findViewById(R.id.scrollView);
|
||||||
progressBar = (ProgressBar) v.findViewById(R.id.progressBar);
|
progressBar = (ProgressBar) v.findViewById(R.id.progressBar);
|
||||||
post = new BlogPostViewHolder(v.findViewById(R.id.postLayout));
|
post = new BlogPostViewHolder(v.findViewById(R.id.postLayout),
|
||||||
|
true, new OnBlogPostClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onBlogPostClick(BlogPostItem post) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAuthorClick(BlogPostItem post) {
|
||||||
|
// probably don't want to allow author clicks here
|
||||||
|
}
|
||||||
|
});
|
||||||
input = (TextInputView) v.findViewById(R.id.inputText);
|
input = (TextInputView) v.findViewById(R.id.inputText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.os.Bundle;
|
|||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
import android.util.Patterns;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -20,9 +21,12 @@ import org.briarproject.briar.android.activity.BriarActivity;
|
|||||||
import org.briarproject.briar.api.feed.FeedManager;
|
import org.briarproject.briar.api.feed.FeedManager;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
@@ -98,10 +102,17 @@ public class RssFeedImportActivity extends BriarActivity {
|
|||||||
|
|
||||||
private void enableOrDisableImportButton() {
|
private void enableOrDisableImportButton() {
|
||||||
String url = urlInput.getText().toString();
|
String url = urlInput.getText().toString();
|
||||||
if (url.startsWith("http://") || url.startsWith("https://"))
|
importButton.setEnabled(validateAndNormaliseUrl(url) != null);
|
||||||
importButton.setEnabled(true);
|
}
|
||||||
else
|
|
||||||
importButton.setEnabled(false);
|
@Nullable
|
||||||
|
private String validateAndNormaliseUrl(String url) {
|
||||||
|
if (!Patterns.WEB_URL.matcher(url).matches()) return null;
|
||||||
|
try {
|
||||||
|
return new URL(url).toString();
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void publish() {
|
private void publish() {
|
||||||
@@ -109,7 +120,9 @@ public class RssFeedImportActivity extends BriarActivity {
|
|||||||
importButton.setVisibility(GONE);
|
importButton.setVisibility(GONE);
|
||||||
progressBar.setVisibility(VISIBLE);
|
progressBar.setVisibility(VISIBLE);
|
||||||
|
|
||||||
importFeed(urlInput.getText().toString());
|
String url = validateAndNormaliseUrl(urlInput.getText().toString());
|
||||||
|
if (url == null) throw new AssertionError();
|
||||||
|
importFeed(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void importFeed(final String url) {
|
private void importFeed(final String url) {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.briarproject.briar.android.contact;
|
package org.briarproject.briar.android.contact;
|
||||||
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -13,6 +12,8 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.contact.BaseContactListAdapter.OnContactClickListener;
|
import org.briarproject.briar.android.contact.BaseContactListAdapter.OnContactClickListener;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import im.delight.android.identicons.IdenticonDrawable;
|
import im.delight.android.identicons.IdenticonDrawable;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
|
|||||||
@@ -178,8 +178,6 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
notificationManager.blockAllContactNotifications();
|
|
||||||
notificationManager.clearAllContactNotifications();
|
|
||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
loadContacts();
|
loadContacts();
|
||||||
list.startPeriodicUpdate();
|
list.startPeriodicUpdate();
|
||||||
@@ -189,7 +187,6 @@ public class ContactListFragment extends BaseFragment implements EventListener {
|
|||||||
public void onStop() {
|
public void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
eventBus.removeListener(this);
|
eventBus.removeListener(this);
|
||||||
notificationManager.unblockAllContactNotifications();
|
|
||||||
adapter.clear();
|
adapter.clear();
|
||||||
list.showProgressBar();
|
list.showProgressBar();
|
||||||
list.stopPeriodicUpdate();
|
list.stopPeriodicUpdate();
|
||||||
|
|||||||
@@ -186,8 +186,8 @@ public class ConversationActivity extends BriarActivity
|
|||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle state) {
|
public void onCreate(@Nullable Bundle state) {
|
||||||
super.onCreate(state);
|
|
||||||
setSceneTransitionAnimation();
|
setSceneTransitionAnimation();
|
||||||
|
super.onCreate(state);
|
||||||
|
|
||||||
Intent i = getIntent();
|
Intent i = getIntent();
|
||||||
int id = i.getIntExtra(CONTACT_ID, -1);
|
int id = i.getIntExtra(CONTACT_ID, -1);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class DbControllerImpl implements DbController {
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(DbControllerImpl.class.getName());
|
Logger.getLogger(DbControllerImpl.class.getName());
|
||||||
|
|
||||||
private final Executor dbExecutor;
|
protected final Executor dbExecutor;
|
||||||
private final LifecycleManager lifecycleManager;
|
private final LifecycleManager lifecycleManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package org.briarproject.briar.android.controller;
|
package org.briarproject.briar.android.controller;
|
||||||
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
@@ -15,6 +13,7 @@ import java.util.Collection;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.briar.android.forum;
|
|||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.design.widget.TextInputLayout;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
@@ -38,16 +39,15 @@ import static org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_NAME_LEN
|
|||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
public class CreateForumActivity extends BriarActivity
|
public class CreateForumActivity extends BriarActivity {
|
||||||
implements OnEditorActionListener, OnClickListener {
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(CreateForumActivity.class.getName());
|
Logger.getLogger(CreateForumActivity.class.getName());
|
||||||
|
|
||||||
|
private TextInputLayout nameEntryLayout;
|
||||||
private EditText nameEntry;
|
private EditText nameEntry;
|
||||||
private Button createForumButton;
|
private Button createForumButton;
|
||||||
private ProgressBar progress;
|
private ProgressBar progress;
|
||||||
private TextView feedback;
|
|
||||||
|
|
||||||
// Fields that are accessed from background threads must be volatile
|
// Fields that are accessed from background threads must be volatile
|
||||||
@Inject
|
@Inject
|
||||||
@@ -59,12 +59,10 @@ public class CreateForumActivity extends BriarActivity
|
|||||||
|
|
||||||
setContentView(R.layout.activity_create_forum);
|
setContentView(R.layout.activity_create_forum);
|
||||||
|
|
||||||
|
nameEntryLayout =
|
||||||
|
(TextInputLayout) findViewById(R.id.createForumNameLayout);
|
||||||
nameEntry = (EditText) findViewById(R.id.createForumNameEntry);
|
nameEntry = (EditText) findViewById(R.id.createForumNameEntry);
|
||||||
TextWatcher nameEntryWatcher = new TextWatcher() {
|
nameEntry.addTextChangedListener(new TextWatcher() {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterTextChanged(Editable s) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count,
|
public void beforeTextChanged(CharSequence s, int start, int count,
|
||||||
@@ -72,21 +70,39 @@ public class CreateForumActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTextChanged(CharSequence text, int start,
|
public void onTextChanged(CharSequence s, int start,
|
||||||
int lengthBefore, int lengthAfter) {
|
int lengthBefore, int lengthAfter) {
|
||||||
enableOrDisableCreateButton();
|
enableOrDisableCreateButton();
|
||||||
}
|
}
|
||||||
};
|
|
||||||
nameEntry.setOnEditorActionListener(this);
|
|
||||||
nameEntry.addTextChangedListener(nameEntryWatcher);
|
|
||||||
|
|
||||||
feedback = (TextView) findViewById(R.id.createForumFeedback);
|
@Override
|
||||||
|
public void afterTextChanged(Editable s) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nameEntry.setOnEditorActionListener(new OnEditorActionListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onEditorAction(TextView v, int actionId,
|
||||||
|
KeyEvent e) {
|
||||||
|
createForum();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
createForumButton = (Button) findViewById(R.id.createForumButton);
|
createForumButton = (Button) findViewById(R.id.createForumButton);
|
||||||
createForumButton.setOnClickListener(this);
|
createForumButton.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
createForum();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
progress = (ProgressBar) findViewById(R.id.createForumProgressBar);
|
progress = (ProgressBar) findViewById(R.id.createForumProgressBar);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
showSoftKeyboard(nameEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -95,37 +111,28 @@ public class CreateForumActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void enableOrDisableCreateButton() {
|
private void enableOrDisableCreateButton() {
|
||||||
if (progress == null) return; // Not created yet
|
if (createForumButton == null) return; // Not created yet
|
||||||
createForumButton.setEnabled(validateName());
|
createForumButton.setEnabled(validateName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onEditorAction(TextView textView, int actionId, KeyEvent e) {
|
|
||||||
hideSoftKeyboard(textView);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean validateName() {
|
private boolean validateName() {
|
||||||
String name = nameEntry.getText().toString();
|
String name = nameEntry.getText().toString();
|
||||||
int length = StringUtils.toUtf8(name).length;
|
int length = StringUtils.toUtf8(name).length;
|
||||||
if (length > MAX_FORUM_NAME_LENGTH) {
|
if (length > MAX_FORUM_NAME_LENGTH) {
|
||||||
feedback.setText(R.string.name_too_long);
|
nameEntryLayout.setError(getString(R.string.name_too_long));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
feedback.setText("");
|
nameEntryLayout.setError(null);
|
||||||
return length > 0;
|
return length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void createForum() {
|
||||||
public void onClick(View view) {
|
|
||||||
if (view == createForumButton) {
|
|
||||||
hideSoftKeyboard(view);
|
|
||||||
if (!validateName()) return;
|
if (!validateName()) return;
|
||||||
|
hideSoftKeyboard(nameEntry);
|
||||||
createForumButton.setVisibility(GONE);
|
createForumButton.setVisibility(GONE);
|
||||||
progress.setVisibility(VISIBLE);
|
progress.setVisibility(VISIBLE);
|
||||||
storeForum(nameEntry.getText().toString());
|
storeForum(nameEntry.getText().toString());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void storeForum(final String name) {
|
private void storeForum(final String name) {
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
|
|||||||
import org.briarproject.briar.android.forum.ForumController.ForumListener;
|
import org.briarproject.briar.android.forum.ForumController.ForumListener;
|
||||||
import org.briarproject.briar.android.threaded.ThreadListControllerImpl;
|
import org.briarproject.briar.android.threaded.ThreadListControllerImpl;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
|
import org.briarproject.briar.api.client.MessageTracker;
|
||||||
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
|
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
|
||||||
import org.briarproject.briar.api.forum.Forum;
|
import org.briarproject.briar.api.forum.Forum;
|
||||||
import org.briarproject.briar.api.forum.ForumInvitationResponse;
|
import org.briarproject.briar.api.forum.ForumInvitationResponse;
|
||||||
@@ -55,10 +56,10 @@ class ForumControllerImpl extends
|
|||||||
LifecycleManager lifecycleManager, IdentityManager identityManager,
|
LifecycleManager lifecycleManager, IdentityManager identityManager,
|
||||||
@CryptoExecutor Executor cryptoExecutor,
|
@CryptoExecutor Executor cryptoExecutor,
|
||||||
ForumManager forumManager, ForumSharingManager forumSharingManager,
|
ForumManager forumManager, ForumSharingManager forumSharingManager,
|
||||||
EventBus eventBus, Clock clock,
|
EventBus eventBus, Clock clock, MessageTracker messageTracker,
|
||||||
AndroidNotificationManager notificationManager) {
|
AndroidNotificationManager notificationManager) {
|
||||||
super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor,
|
super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor,
|
||||||
eventBus, clock, notificationManager);
|
eventBus, clock, notificationManager, messageTracker);
|
||||||
this.forumManager = forumManager;
|
this.forumManager = forumManager;
|
||||||
this.forumSharingManager = forumSharingManager;
|
this.forumSharingManager = forumSharingManager;
|
||||||
}
|
}
|
||||||
@@ -84,7 +85,7 @@ class ForumControllerImpl extends
|
|||||||
(ForumInvitationResponseReceivedEvent) e;
|
(ForumInvitationResponseReceivedEvent) e;
|
||||||
ForumInvitationResponse r =
|
ForumInvitationResponse r =
|
||||||
(ForumInvitationResponse) f.getResponse();
|
(ForumInvitationResponse) f.getResponse();
|
||||||
if (r.getGroupId().equals(getGroupId()) && r.wasAccepted()) {
|
if (r.getShareableId().equals(getGroupId()) && r.wasAccepted()) {
|
||||||
LOG.info("Forum invitation was accepted");
|
LOG.info("Forum invitation was accepted");
|
||||||
onForumInvitationAccepted(r.getContactId());
|
onForumInvitationAccepted(r.getContactId());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,8 +119,6 @@ public class ForumListFragment extends BaseEventFragment implements
|
|||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
notificationManager.blockAllForumPostNotifications();
|
|
||||||
notificationManager.clearAllForumPostNotifications();
|
|
||||||
loadForums();
|
loadForums();
|
||||||
loadAvailableForums();
|
loadAvailableForums();
|
||||||
list.startPeriodicUpdate();
|
list.startPeriodicUpdate();
|
||||||
@@ -129,7 +127,6 @@ public class ForumListFragment extends BaseEventFragment implements
|
|||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
notificationManager.unblockAllForumPostNotifications();
|
|
||||||
adapter.clear();
|
adapter.clear();
|
||||||
list.showProgressBar();
|
list.showProgressBar();
|
||||||
list.stopPeriodicUpdate();
|
list.stopPeriodicUpdate();
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
package org.briarproject.briar.android.fragment;
|
|
||||||
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.v4.app.DialogFragment;
|
|
||||||
import android.support.v7.app.AlertDialog;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.CheckBox;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|
||||||
import org.briarproject.briar.R;
|
|
||||||
import org.briarproject.briar.android.activity.BaseActivity;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
|
||||||
@ParametersNotNullByDefault
|
|
||||||
public class SFDialogFragment extends DialogFragment {
|
|
||||||
|
|
||||||
public static SFDialogFragment newInstance(ArrayList<String> apps) {
|
|
||||||
SFDialogFragment frag = new SFDialogFragment();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putStringArrayList("apps", apps);
|
|
||||||
frag.setArguments(args);
|
|
||||||
return frag;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
|
||||||
AlertDialog.Builder builder =
|
|
||||||
new AlertDialog.Builder(
|
|
||||||
getActivity(),
|
|
||||||
R.style.BriarDialogThemeNoFilter);
|
|
||||||
builder.setTitle(R.string.screen_filter_title);
|
|
||||||
LayoutInflater li = getActivity().getLayoutInflater();
|
|
||||||
//Pass null here because it's an AlertDialog
|
|
||||||
View v =
|
|
||||||
li.inflate(R.layout.alert_dialog_checkbox, null,
|
|
||||||
false);
|
|
||||||
TextView t = (TextView) v.findViewById(R.id.alert_dialog_text);
|
|
||||||
final ArrayList<String> apps =
|
|
||||||
getArguments().getStringArrayList("apps");
|
|
||||||
t.setText(getString(R.string.screen_filter_body, TextUtils
|
|
||||||
.join("\n", apps)));
|
|
||||||
final CheckBox cb =
|
|
||||||
(CheckBox) v.findViewById(
|
|
||||||
R.id.checkBox_screen_filter_reminder);
|
|
||||||
builder.setNeutralButton(R.string.continue_button,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog,
|
|
||||||
int which) {
|
|
||||||
((BaseActivity) getActivity())
|
|
||||||
.rememberShownApps(apps, cb.isChecked());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.setView(v);
|
|
||||||
return builder.create();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package org.briarproject.briar.android.fragment;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.DialogFragment;
|
||||||
|
import android.support.v7.app.AlertDialog;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.briar.R;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public class ScreenFilterDialogFragment extends DialogFragment {
|
||||||
|
|
||||||
|
public static ScreenFilterDialogFragment newInstance(
|
||||||
|
ArrayList<String> apps) {
|
||||||
|
ScreenFilterDialogFragment frag = new ScreenFilterDialogFragment();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putStringArrayList("apps", apps);
|
||||||
|
frag.setArguments(args);
|
||||||
|
return frag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(),
|
||||||
|
R.style.BriarDialogThemeNoFilter);
|
||||||
|
builder.setTitle(R.string.screen_filter_title);
|
||||||
|
ArrayList<String> apps = getArguments().getStringArrayList("apps");
|
||||||
|
builder.setMessage(getString(R.string.screen_filter_body,
|
||||||
|
TextUtils.join("\n", apps)));
|
||||||
|
builder.setNeutralButton(R.string.continue_button,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return builder.create();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.briar.android.fragment;
|
package org.briarproject.briar.android.fragment;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -9,6 +8,8 @@ import android.view.ViewGroup;
|
|||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class SignOutFragment extends BaseFragment {
|
public class SignOutFragment extends BaseFragment {
|
||||||
|
|
||||||
private static final String TAG = SignOutFragment.class.getName();
|
private static final String TAG = SignOutFragment.class.getName();
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import im.delight.android.identicons.IdenticonDrawable;
|
|||||||
|
|
||||||
import static android.app.Activity.RESULT_OK;
|
import static android.app.Activity.RESULT_OK;
|
||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
import static android.view.View.VISIBLE;
|
|
||||||
import static android.widget.Toast.LENGTH_SHORT;
|
import static android.widget.Toast.LENGTH_SHORT;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_MESSAGE_LENGTH;
|
import static org.briarproject.briar.api.introduction.IntroductionConstants.MAX_INTRODUCTION_MESSAGE_LENGTH;
|
||||||
@@ -94,7 +93,6 @@ public class IntroductionMessageFragment extends BaseFragment
|
|||||||
View v = inflater.inflate(R.layout.introduction_message, container,
|
View v = inflater.inflate(R.layout.introduction_message, container,
|
||||||
false);
|
false);
|
||||||
ui = new ViewHolder(v);
|
ui = new ViewHolder(v);
|
||||||
ui.text.setVisibility(GONE);
|
|
||||||
ui.message.setSendButtonEnabled(false);
|
ui.message.setSendButtonEnabled(false);
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
@@ -156,17 +154,11 @@ public class IntroductionMessageFragment extends BaseFragment
|
|||||||
ui.contactName1.setText(c1.getAuthor().getName());
|
ui.contactName1.setText(c1.getAuthor().getName());
|
||||||
ui.contactName2.setText(c2.getAuthor().getName());
|
ui.contactName2.setText(c2.getAuthor().getName());
|
||||||
|
|
||||||
// set introduction text
|
|
||||||
ui.text.setText(String.format(
|
|
||||||
getString(R.string.introduction_message_text),
|
|
||||||
c1.getAuthor().getName(), c2.getAuthor().getName()));
|
|
||||||
|
|
||||||
// set button action
|
// set button action
|
||||||
ui.message.setListener(IntroductionMessageFragment.this);
|
ui.message.setListener(IntroductionMessageFragment.this);
|
||||||
|
|
||||||
// hide progress bar and show views
|
// hide progress bar and show views
|
||||||
ui.progressBar.setVisibility(GONE);
|
ui.progressBar.setVisibility(GONE);
|
||||||
ui.text.setVisibility(VISIBLE);
|
|
||||||
ui.message.setSendButtonEnabled(true);
|
ui.message.setSendButtonEnabled(true);
|
||||||
ui.message.showSoftKeyboard();
|
ui.message.showSoftKeyboard();
|
||||||
}
|
}
|
||||||
@@ -234,7 +226,6 @@ public class IntroductionMessageFragment extends BaseFragment
|
|||||||
private final ProgressBar progressBar;
|
private final ProgressBar progressBar;
|
||||||
private final CircleImageView avatar1, avatar2;
|
private final CircleImageView avatar1, avatar2;
|
||||||
private final TextView contactName1, contactName2;
|
private final TextView contactName1, contactName2;
|
||||||
private final TextView text;
|
|
||||||
private final TextInputView message;
|
private final TextInputView message;
|
||||||
|
|
||||||
private ViewHolder(View v) {
|
private ViewHolder(View v) {
|
||||||
@@ -243,7 +234,6 @@ public class IntroductionMessageFragment extends BaseFragment
|
|||||||
avatar2 = (CircleImageView) v.findViewById(R.id.avatarContact2);
|
avatar2 = (CircleImageView) v.findViewById(R.id.avatarContact2);
|
||||||
contactName1 = (TextView) v.findViewById(R.id.nameContact1);
|
contactName1 = (TextView) v.findViewById(R.id.nameContact1);
|
||||||
contactName2 = (TextView) v.findViewById(R.id.nameContact2);
|
contactName2 = (TextView) v.findViewById(R.id.nameContact2);
|
||||||
text = (TextView) v.findViewById(R.id.introductionText);
|
|
||||||
message = (TextInputView) v
|
message = (TextInputView) v
|
||||||
.findViewById(R.id.introductionMessageView);
|
.findViewById(R.id.introductionMessageView);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import android.hardware.Camera.CameraInfo;
|
|||||||
import android.hardware.Camera.Parameters;
|
import android.hardware.Camera.Parameters;
|
||||||
import android.hardware.Camera.Size;
|
import android.hardware.Camera.Size;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
@@ -43,6 +44,7 @@ public class CameraView extends SurfaceView implements SurfaceHolder.Callback,
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(CameraView.class.getName());
|
Logger.getLogger(CameraView.class.getName());
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private Camera camera = null;
|
private Camera camera = null;
|
||||||
private PreviewConsumer previewConsumer = null;
|
private PreviewConsumer previewConsumer = null;
|
||||||
private Surface surface = null;
|
private Surface surface = null;
|
||||||
@@ -86,6 +88,8 @@ public class CameraView extends SurfaceView implements SurfaceHolder.Callback,
|
|||||||
try {
|
try {
|
||||||
LOG.info("Opening camera");
|
LOG.info("Opening camera");
|
||||||
camera = Camera.open();
|
camera = Camera.open();
|
||||||
|
if (camera == null)
|
||||||
|
throw new RuntimeException("No back-facing camera.");
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
LOG.log(WARNING, "Error opening camera", e);
|
LOG.log(WARNING, "Error opening camera", e);
|
||||||
return;
|
return;
|
||||||
@@ -129,6 +133,7 @@ public class CameraView extends SurfaceView implements SurfaceHolder.Callback,
|
|||||||
private void startPreview(SurfaceHolder holder) {
|
private void startPreview(SurfaceHolder holder) {
|
||||||
LOG.info("Starting preview");
|
LOG.info("Starting preview");
|
||||||
try {
|
try {
|
||||||
|
if (camera == null) throw new IOException("Camera is null.");
|
||||||
camera.setPreviewDisplay(holder);
|
camera.setPreviewDisplay(holder);
|
||||||
camera.startPreview();
|
camera.startPreview();
|
||||||
previewStarted = true;
|
previewStarted = true;
|
||||||
@@ -142,6 +147,7 @@ public class CameraView extends SurfaceView implements SurfaceHolder.Callback,
|
|||||||
private void stopPreview() {
|
private void stopPreview() {
|
||||||
LOG.info("Stopping preview");
|
LOG.info("Stopping preview");
|
||||||
try {
|
try {
|
||||||
|
if (camera == null) throw new RuntimeException("Camera is null.");
|
||||||
stopConsumer();
|
stopConsumer();
|
||||||
camera.stopPreview();
|
camera.stopPreview();
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
@@ -152,12 +158,14 @@ public class CameraView extends SurfaceView implements SurfaceHolder.Callback,
|
|||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void startConsumer() {
|
private void startConsumer() {
|
||||||
|
if (camera == null) throw new RuntimeException("Camera is null");
|
||||||
if (autoFocus) camera.autoFocus(this);
|
if (autoFocus) camera.autoFocus(this);
|
||||||
previewConsumer.start(camera);
|
previewConsumer.start(camera);
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void stopConsumer() {
|
private void stopConsumer() {
|
||||||
|
if (camera == null) throw new RuntimeException("Camera is null");
|
||||||
if (autoFocus) camera.cancelAutoFocus();
|
if (autoFocus) camera.cancelAutoFocus();
|
||||||
previewConsumer.stop();
|
previewConsumer.stop();
|
||||||
}
|
}
|
||||||
@@ -176,6 +184,7 @@ public class CameraView extends SurfaceView implements SurfaceHolder.Callback,
|
|||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Display orientation " + orientation + " degrees");
|
LOG.info("Display orientation " + orientation + " degrees");
|
||||||
try {
|
try {
|
||||||
|
if (camera == null) throw new RuntimeException("Camera is null");
|
||||||
camera.setDisplayOrientation(orientation);
|
camera.setDisplayOrientation(orientation);
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
LOG.log(WARNING, "Error setting display orientation", e);
|
LOG.log(WARNING, "Error setting display orientation", e);
|
||||||
@@ -216,7 +225,11 @@ public class CameraView extends SurfaceView implements SurfaceHolder.Callback,
|
|||||||
setFocusMode(params);
|
setFocusMode(params);
|
||||||
params.setFlashMode(FLASH_MODE_OFF);
|
params.setFlashMode(FLASH_MODE_OFF);
|
||||||
setPreviewSize(params);
|
setPreviewSize(params);
|
||||||
|
try {
|
||||||
camera.setParameters(params);
|
camera.setParameters(params);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
LOG.log(WARNING, "Error setting best camera parameters", e);
|
||||||
|
}
|
||||||
return camera.getParameters();
|
return camera.getParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,7 +300,7 @@ public class CameraView extends SurfaceView implements SurfaceHolder.Callback,
|
|||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void logCameraParameters() {
|
private void logCameraParameters() {
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (camera != null && LOG.isLoggable(INFO)) {
|
||||||
Parameters params = camera.getParameters();
|
Parameters params = camera.getParameters();
|
||||||
if (Build.VERSION.SDK_INT >= 15) {
|
if (Build.VERSION.SDK_INT >= 15) {
|
||||||
LOG.info("Video stabilisation enabled: "
|
LOG.info("Video stabilisation enabled: "
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import org.briarproject.briar.android.activity.ActivityComponent;
|
|||||||
import org.briarproject.briar.android.activity.BriarActivity;
|
import org.briarproject.briar.android.activity.BriarActivity;
|
||||||
import org.briarproject.briar.android.blog.FeedFragment;
|
import org.briarproject.briar.android.blog.FeedFragment;
|
||||||
import org.briarproject.briar.android.contact.ContactListFragment;
|
import org.briarproject.briar.android.contact.ContactListFragment;
|
||||||
|
import org.briarproject.briar.android.controller.handler.UiResultHandler;
|
||||||
import org.briarproject.briar.android.forum.ForumListFragment;
|
import org.briarproject.briar.android.forum.ForumListFragment;
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
||||||
@@ -45,6 +46,9 @@ import javax.inject.Inject;
|
|||||||
import static android.support.v4.app.FragmentManager.POP_BACK_STACK_INCLUSIVE;
|
import static android.support.v4.app.FragmentManager.POP_BACK_STACK_INCLUSIVE;
|
||||||
import static android.support.v4.view.GravityCompat.START;
|
import static android.support.v4.view.GravityCompat.START;
|
||||||
import static android.support.v4.widget.DrawerLayout.LOCK_MODE_LOCKED_CLOSED;
|
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.util.UiUtils.getDaysUntilExpiry;
|
||||||
|
|
||||||
public class NavDrawerActivity extends BriarActivity implements
|
public class NavDrawerActivity extends BriarActivity implements
|
||||||
BaseFragmentListener, TransportStateListener,
|
BaseFragmentListener, TransportStateListener,
|
||||||
@@ -128,6 +132,12 @@ public class NavDrawerActivity extends BriarActivity implements
|
|||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
updateTransports();
|
updateTransports();
|
||||||
|
controller.showExpiryWarning(new UiResultHandler<Boolean>(this) {
|
||||||
|
@Override
|
||||||
|
public void onResultUi(Boolean showWarning) {
|
||||||
|
if (showWarning) showExpiryWarning();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void exitIfStartupFailed(Intent intent) {
|
private void exitIfStartupFailed(Intent intent) {
|
||||||
@@ -254,6 +264,34 @@ public class NavDrawerActivity extends BriarActivity implements
|
|||||||
// Do nothing for now
|
// Do nothing for now
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
private void showExpiryWarning() {
|
||||||
|
int daysUntilExpiry = getDaysUntilExpiry();
|
||||||
|
if (daysUntilExpiry < 0) signOut();
|
||||||
|
|
||||||
|
// show expiry warning text
|
||||||
|
final ViewGroup
|
||||||
|
expiryWarning = (ViewGroup) findViewById(R.id.expiryWarning);
|
||||||
|
TextView expiryWarningText =
|
||||||
|
(TextView) expiryWarning.findViewById(R.id.expiryWarningText);
|
||||||
|
expiryWarningText.setText(getResources()
|
||||||
|
.getQuantityString(R.plurals.expiry_warning, daysUntilExpiry,
|
||||||
|
daysUntilExpiry));
|
||||||
|
|
||||||
|
// make close button functional
|
||||||
|
ImageView expiryWarningClose =
|
||||||
|
(ImageView) expiryWarning.findViewById(R.id.expiryWarningClose);
|
||||||
|
expiryWarningClose.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
controller.expiryWarningDismissed();
|
||||||
|
expiryWarning.setVisibility(GONE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expiryWarning.setVisibility(VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
private void initializeTransports(final LayoutInflater inflater) {
|
private void initializeTransports(final LayoutInflater inflater) {
|
||||||
transports = new ArrayList<>(3);
|
transports = new ArrayList<>(3);
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,15 @@ package org.briarproject.briar.android.navdrawer;
|
|||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
import org.briarproject.briar.android.controller.ActivityLifecycleController;
|
import org.briarproject.briar.android.controller.ActivityLifecycleController;
|
||||||
|
import org.briarproject.briar.android.controller.handler.ResultHandler;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface NavDrawerController extends ActivityLifecycleController {
|
public interface NavDrawerController extends ActivityLifecycleController {
|
||||||
|
|
||||||
boolean isTransportRunning(TransportId transportId);
|
boolean isTransportRunning(TransportId transportId);
|
||||||
|
|
||||||
|
void showExpiryWarning(final ResultHandler<Boolean> handler);
|
||||||
|
|
||||||
|
void expiryWarningDismissed();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.briar.android.navdrawer;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
@@ -14,7 +15,10 @@ import org.briarproject.bramble.api.plugin.PluginManager;
|
|||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent;
|
import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent;
|
||||||
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
|
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
|
||||||
|
import org.briarproject.bramble.api.settings.Settings;
|
||||||
|
import org.briarproject.bramble.api.settings.SettingsManager;
|
||||||
import org.briarproject.briar.android.controller.DbControllerImpl;
|
import org.briarproject.briar.android.controller.DbControllerImpl;
|
||||||
|
import org.briarproject.briar.android.controller.handler.ResultHandler;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@@ -22,6 +26,9 @@ import java.util.logging.Logger;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
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.settings.SettingsFragment.SETTINGS_NAMESPACE;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -30,18 +37,21 @@ public class NavDrawerControllerImpl extends DbControllerImpl
|
|||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(NavDrawerControllerImpl.class.getName());
|
Logger.getLogger(NavDrawerControllerImpl.class.getName());
|
||||||
|
private static final String EXPIRY_DATE_WARNING = "expiryDateWarning";
|
||||||
|
|
||||||
private final PluginManager pluginManager;
|
private final PluginManager pluginManager;
|
||||||
|
private final SettingsManager settingsManager;
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
|
|
||||||
private volatile TransportStateListener listener;
|
private volatile TransportStateListener listener;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
NavDrawerControllerImpl(@DatabaseExecutor Executor dbExecutor,
|
NavDrawerControllerImpl(@DatabaseExecutor Executor dbExecutor,
|
||||||
LifecycleManager lifecycleManager,
|
LifecycleManager lifecycleManager, PluginManager pluginManager,
|
||||||
PluginManager pluginManager, EventBus eventBus) {
|
SettingsManager settingsManager, EventBus eventBus) {
|
||||||
super(dbExecutor, lifecycleManager);
|
super(dbExecutor, lifecycleManager);
|
||||||
this.pluginManager = pluginManager;
|
this.pluginManager = pluginManager;
|
||||||
|
this.settingsManager = settingsManager;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,6 +102,63 @@ public class NavDrawerControllerImpl extends DbControllerImpl
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showExpiryWarning(final ResultHandler<Boolean> handler) {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Settings settings =
|
||||||
|
settingsManager.getSettings(SETTINGS_NAMESPACE);
|
||||||
|
int warningInt = settings.getInt(EXPIRY_DATE_WARNING, 0);
|
||||||
|
|
||||||
|
if (warningInt == 0) {
|
||||||
|
// we have not warned before
|
||||||
|
handler.onResult(true);
|
||||||
|
} else {
|
||||||
|
long warningLong = warningInt * 1000L;
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
long daysSinceLastWarning =
|
||||||
|
(now - warningLong) / 1000 / 60 / 60 / 24;
|
||||||
|
long daysBeforeExpiry =
|
||||||
|
(EXPIRY_DATE - now) / 1000 / 60 / 60 / 24;
|
||||||
|
|
||||||
|
if (daysSinceLastWarning >= 30) {
|
||||||
|
handler.onResult(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (daysBeforeExpiry <= 3 && daysSinceLastWarning > 0) {
|
||||||
|
handler.onResult(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handler.onResult(false);
|
||||||
|
}
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void expiryWarningDismissed() {
|
||||||
|
runOnDbThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Settings settings = new Settings();
|
||||||
|
int date = (int) (System.currentTimeMillis() / 1000L);
|
||||||
|
settings.putInt(EXPIRY_DATE_WARNING, date);
|
||||||
|
settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTransportRunning(TransportId transportId) {
|
public boolean isTransportRunning(TransportId transportId) {
|
||||||
Plugin plugin = pluginManager.getPlugin(transportId);
|
Plugin plugin = pluginManager.getPlugin(transportId);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
|
|||||||
import org.briarproject.briar.android.privategroup.conversation.GroupController.GroupListener;
|
import org.briarproject.briar.android.privategroup.conversation.GroupController.GroupListener;
|
||||||
import org.briarproject.briar.android.threaded.ThreadListControllerImpl;
|
import org.briarproject.briar.android.threaded.ThreadListControllerImpl;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
|
import org.briarproject.briar.api.client.MessageTracker;
|
||||||
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
|
import org.briarproject.briar.api.client.MessageTracker.GroupCount;
|
||||||
import org.briarproject.briar.api.privategroup.GroupMember;
|
import org.briarproject.briar.api.privategroup.GroupMember;
|
||||||
import org.briarproject.briar.api.privategroup.GroupMessage;
|
import org.briarproject.briar.api.privategroup.GroupMessage;
|
||||||
@@ -60,9 +61,10 @@ class GroupControllerImpl extends
|
|||||||
@CryptoExecutor Executor cryptoExecutor,
|
@CryptoExecutor Executor cryptoExecutor,
|
||||||
PrivateGroupManager privateGroupManager,
|
PrivateGroupManager privateGroupManager,
|
||||||
GroupMessageFactory groupMessageFactory, EventBus eventBus,
|
GroupMessageFactory groupMessageFactory, EventBus eventBus,
|
||||||
Clock clock, AndroidNotificationManager notificationManager) {
|
MessageTracker messageTracker, Clock clock,
|
||||||
|
AndroidNotificationManager notificationManager) {
|
||||||
super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor,
|
super(dbExecutor, lifecycleManager, identityManager, cryptoExecutor,
|
||||||
eventBus, clock, notificationManager);
|
eventBus, clock, notificationManager, messageTracker);
|
||||||
this.privateGroupManager = privateGroupManager;
|
this.privateGroupManager = privateGroupManager;
|
||||||
this.groupMessageFactory = groupMessageFactory;
|
this.groupMessageFactory = groupMessageFactory;
|
||||||
}
|
}
|
||||||
@@ -106,7 +108,7 @@ class GroupControllerImpl extends
|
|||||||
(GroupInvitationResponseReceivedEvent) e;
|
(GroupInvitationResponseReceivedEvent) e;
|
||||||
final GroupInvitationResponse r =
|
final GroupInvitationResponse r =
|
||||||
(GroupInvitationResponse) g.getResponse();
|
(GroupInvitationResponse) g.getResponse();
|
||||||
if (getGroupId().equals(r.getGroupId()) && r.wasAccepted()) {
|
if (getGroupId().equals(r.getShareableId()) && r.wasAccepted()) {
|
||||||
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
listener.runOnUiThreadUnlessDestroyed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.briar.android.privategroup.conversation;
|
package org.briarproject.briar.android.privategroup.conversation;
|
||||||
|
|
||||||
import android.support.annotation.LayoutRes;
|
import android.support.annotation.LayoutRes;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
@@ -12,6 +11,7 @@ import org.briarproject.briar.R;
|
|||||||
import org.briarproject.briar.android.threaded.ThreadItem;
|
import org.briarproject.briar.android.threaded.ThreadItem;
|
||||||
import org.briarproject.briar.api.privategroup.GroupMessageHeader;
|
import org.briarproject.briar.api.privategroup.GroupMessageHeader;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
|
|||||||
@@ -1,25 +1,15 @@
|
|||||||
package org.briarproject.briar.android.privategroup.conversation;
|
package org.briarproject.briar.android.privategroup.conversation;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.privategroup.reveal.RevealContactsActivity;
|
|
||||||
import org.briarproject.briar.android.threaded.BaseThreadItemViewHolder;
|
import org.briarproject.briar.android.threaded.BaseThreadItemViewHolder;
|
||||||
import org.briarproject.briar.android.threaded.ThreadItemAdapter.ThreadItemListener;
|
import org.briarproject.briar.android.threaded.ThreadItemAdapter.ThreadItemListener;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.identity.Author.Status.OURSELVES;
|
import static org.briarproject.bramble.api.identity.Author.Status.OURSELVES;
|
||||||
import static org.briarproject.bramble.api.identity.Author.Status.UNKNOWN;
|
|
||||||
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
|
||||||
import static org.briarproject.briar.android.privategroup.VisibilityHelper.getVisibilityIcon;
|
|
||||||
import static org.briarproject.briar.android.privategroup.VisibilityHelper.getVisibilityString;
|
|
||||||
import static org.briarproject.briar.api.privategroup.Visibility.INVISIBLE;
|
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -27,16 +17,10 @@ class JoinMessageItemViewHolder
|
|||||||
extends BaseThreadItemViewHolder<GroupMessageItem> {
|
extends BaseThreadItemViewHolder<GroupMessageItem> {
|
||||||
|
|
||||||
private final boolean isCreator;
|
private final boolean isCreator;
|
||||||
private final ImageView icon;
|
|
||||||
private final TextView info;
|
|
||||||
private final Button options;
|
|
||||||
|
|
||||||
JoinMessageItemViewHolder(View v, boolean isCreator) {
|
JoinMessageItemViewHolder(View v, boolean isCreator) {
|
||||||
super(v);
|
super(v);
|
||||||
this.isCreator = isCreator;
|
this.isCreator = isCreator;
|
||||||
icon = (ImageView) v.findViewById(R.id.icon);
|
|
||||||
info = (TextView) v.findViewById(R.id.info);
|
|
||||||
options = (Button) v.findViewById(R.id.optionsButton);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -56,9 +40,6 @@ class JoinMessageItemViewHolder
|
|||||||
getContext().getString(R.string.groups_member_joined,
|
getContext().getString(R.string.groups_member_joined,
|
||||||
item.getAuthor().getName()));
|
item.getAuthor().getName()));
|
||||||
}
|
}
|
||||||
icon.setVisibility(View.GONE);
|
|
||||||
info.setVisibility(View.GONE);
|
|
||||||
options.setVisibility(View.GONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bind(final JoinMessageItem item) {
|
private void bind(final JoinMessageItem item) {
|
||||||
@@ -75,32 +56,6 @@ class JoinMessageItemViewHolder
|
|||||||
item.getAuthor().getName()));
|
item.getAuthor().getName()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.getStatus() == OURSELVES || item.getStatus() == UNKNOWN) {
|
|
||||||
icon.setVisibility(View.GONE);
|
|
||||||
info.setVisibility(View.GONE);
|
|
||||||
options.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
icon.setVisibility(View.VISIBLE);
|
|
||||||
icon.setImageResource(getVisibilityIcon(item.getVisibility()));
|
|
||||||
info.setVisibility(View.VISIBLE);
|
|
||||||
info.setText(getVisibilityString(getContext(), item.getVisibility(),
|
|
||||||
item.getAuthor().getName()));
|
|
||||||
if (item.getVisibility() == INVISIBLE) {
|
|
||||||
options.setVisibility(View.VISIBLE);
|
|
||||||
options.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
Intent i =
|
|
||||||
new Intent(ctx, RevealContactsActivity.class);
|
|
||||||
i.putExtra(GROUP_ID, item.getGroupId().getBytes());
|
|
||||||
ctx.startActivity(i);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
options.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
package org.briarproject.briar.android.privategroup.creation;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|
||||||
import org.briarproject.briar.android.contactselection.ContactSelectorActivity;
|
|
||||||
import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler;
|
|
||||||
import org.briarproject.briar.android.sharing.BaseMessageFragment.MessageFragmentListener;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_MSG_LENGTH;
|
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
|
||||||
@ParametersNotNullByDefault
|
|
||||||
public abstract class BaseGroupInviteActivity
|
|
||||||
extends ContactSelectorActivity implements MessageFragmentListener {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
CreateGroupController controller;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void contactsSelected(Collection<ContactId> contacts) {
|
|
||||||
super.contactsSelected(contacts);
|
|
||||||
|
|
||||||
showNextFragment(new CreateGroupMessageFragment());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onButtonClick(String message) {
|
|
||||||
if (groupId == null)
|
|
||||||
throw new IllegalStateException("GroupId was not initialized");
|
|
||||||
controller.sendInvitation(groupId, contacts, message,
|
|
||||||
new UiResultExceptionHandler<Void, DbException>(this) {
|
|
||||||
@Override
|
|
||||||
public void onResultUi(Void result) {
|
|
||||||
setResult(RESULT_OK);
|
|
||||||
supportFinishAfterTransition();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onExceptionUi(DbException exception) {
|
|
||||||
setResult(RESULT_CANCELED);
|
|
||||||
handleDbException(exception);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMaximumMessageLength() {
|
|
||||||
return MAX_GROUP_INVITATION_MSG_LENGTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,6 @@ package org.briarproject.briar.android.privategroup.creation;
|
|||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
@@ -10,14 +9,20 @@ import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
|
import org.briarproject.briar.android.activity.BriarActivity;
|
||||||
import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler;
|
import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler;
|
||||||
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
|
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
|
||||||
import org.briarproject.briar.android.sharing.BaseMessageFragment.MessageFragmentListener;
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
public class CreateGroupActivity extends BaseGroupInviteActivity implements
|
public class CreateGroupActivity extends BriarActivity
|
||||||
CreateGroupListener, MessageFragmentListener {
|
implements CreateGroupListener {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
CreateGroupController controller;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectActivity(ActivityComponent component) {
|
public void injectActivity(ActivityComponent component) {
|
||||||
@@ -28,32 +33,20 @@ public class CreateGroupActivity extends BaseGroupInviteActivity implements
|
|||||||
public void onCreate(@Nullable Bundle bundle) {
|
public void onCreate(@Nullable Bundle bundle) {
|
||||||
super.onCreate(bundle);
|
super.onCreate(bundle);
|
||||||
|
|
||||||
|
setContentView(R.layout.activity_fragment_container);
|
||||||
|
|
||||||
if (bundle == null) {
|
if (bundle == null) {
|
||||||
showInitialFragment(new CreateGroupFragment());
|
showInitialFragment(new CreateGroupFragment());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBackPressed() {
|
|
||||||
if (getSupportFragmentManager().getBackStackEntryCount() == 1) {
|
|
||||||
// At this point, the group had been created already,
|
|
||||||
// so don't allow to create it again.
|
|
||||||
openNewGroup();
|
|
||||||
overridePendingTransition(R.anim.screen_old_in,
|
|
||||||
R.anim.screen_new_out);
|
|
||||||
} else {
|
|
||||||
super.onBackPressed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGroupNameChosen(String name) {
|
public void onGroupNameChosen(String name) {
|
||||||
controller.createGroup(name,
|
controller.createGroup(name,
|
||||||
new UiResultExceptionHandler<GroupId, DbException>(this) {
|
new UiResultExceptionHandler<GroupId, DbException>(this) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(GroupId g) {
|
public void onResultUi(GroupId g) {
|
||||||
groupId = g;
|
openNewGroup(g);
|
||||||
switchToContactSelectorFragment(g);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -63,16 +56,10 @@ public class CreateGroupActivity extends BaseGroupInviteActivity implements
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void switchToContactSelectorFragment(GroupId g) {
|
private void openNewGroup(GroupId g) {
|
||||||
showNextFragment(GroupInviteFragment.newInstance(g));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void openNewGroup() {
|
|
||||||
Intent i = new Intent(this, GroupActivity.class);
|
Intent i = new Intent(this, GroupActivity.class);
|
||||||
i.putExtra(GROUP_ID, groupId.getBytes());
|
i.putExtra(GROUP_ID, g.getBytes());
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
// finish this activity, so we can't come back to it
|
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,18 +2,27 @@ package org.briarproject.briar.android.privategroup.creation;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.design.widget.TextInputLayout;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
import android.view.KeyEvent;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.TextView.OnEditorActionListener;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||||
|
|
||||||
|
import static android.view.View.GONE;
|
||||||
|
import static android.view.View.VISIBLE;
|
||||||
import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH;
|
import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH;
|
||||||
|
|
||||||
public class CreateGroupFragment extends BaseFragment {
|
public class CreateGroupFragment extends BaseFragment {
|
||||||
@@ -21,8 +30,10 @@ public class CreateGroupFragment extends BaseFragment {
|
|||||||
public final static String TAG = CreateGroupFragment.class.getName();
|
public final static String TAG = CreateGroupFragment.class.getName();
|
||||||
|
|
||||||
private CreateGroupListener listener;
|
private CreateGroupListener listener;
|
||||||
private EditText name;
|
private EditText nameEntry;
|
||||||
private Button button;
|
private Button createGroupButton;
|
||||||
|
private TextInputLayout nameLayout;
|
||||||
|
private ProgressBar progress;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Context context) {
|
public void onAttach(Context context) {
|
||||||
@@ -34,42 +45,54 @@ public class CreateGroupFragment extends BaseFragment {
|
|||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
|
|
||||||
// inflate view
|
|
||||||
View v = inflater.inflate(R.layout.fragment_create_group, container,
|
View v = inflater.inflate(R.layout.fragment_create_group, container,
|
||||||
false);
|
false);
|
||||||
name = (EditText) v.findViewById(R.id.name);
|
nameEntry = (EditText) v.findViewById(R.id.name);
|
||||||
name.addTextChangedListener(new TextWatcher() {
|
nameEntry.addTextChangedListener(new TextWatcher() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count,
|
public void beforeTextChanged(CharSequence s, int start, int count,
|
||||||
int after) {
|
int after) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTextChanged(CharSequence s, int start, int before,
|
public void onTextChanged(CharSequence s, int start,
|
||||||
int count) {
|
int lengthBefore, int lengthAfter) {
|
||||||
validateName();
|
enableOrDisableCreateButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterTextChanged(Editable s) {
|
public void afterTextChanged(Editable s) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
button = (Button) v.findViewById(R.id.button);
|
nameEntry.setOnEditorActionListener(new OnEditorActionListener() {
|
||||||
button.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public boolean onEditorAction(TextView v, int actionId,
|
||||||
listener.hideSoftKeyboard(name);
|
KeyEvent e) {
|
||||||
listener.onGroupNameChosen(name.getText().toString());
|
createGroup();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
nameLayout = (TextInputLayout) v.findViewById(R.id.nameLayout);
|
||||||
|
|
||||||
|
createGroupButton = (Button) v.findViewById(R.id.button);
|
||||||
|
createGroupButton.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
createGroup();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
progress = (ProgressBar) v.findViewById(R.id.progressBar);
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
listener.showSoftKeyboard(name);
|
listener.showSoftKeyboard(nameEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -82,12 +105,27 @@ public class CreateGroupFragment extends BaseFragment {
|
|||||||
return TAG;
|
return TAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateName() {
|
private void enableOrDisableCreateButton() {
|
||||||
String name = this.name.getText().toString();
|
if (createGroupButton == null) return; // Not created yet
|
||||||
if (name.length() < 1 || name.length() > MAX_GROUP_NAME_LENGTH)
|
createGroupButton.setEnabled(validateName());
|
||||||
button.setEnabled(false);
|
|
||||||
else if(!button.isEnabled())
|
|
||||||
button.setEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean validateName() {
|
||||||
|
String name = nameEntry.getText().toString();
|
||||||
|
int length = StringUtils.toUtf8(name).length;
|
||||||
|
if (length > MAX_GROUP_NAME_LENGTH) {
|
||||||
|
nameLayout.setError(getString(R.string.name_too_long));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
nameLayout.setError(null);
|
||||||
|
return length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createGroup() {
|
||||||
|
if (!validateName()) return;
|
||||||
|
listener.hideSoftKeyboard(nameEntry);
|
||||||
|
createGroupButton.setVisibility(GONE);
|
||||||
|
progress.setVisibility(VISIBLE);
|
||||||
|
listener.onGroupNameChosen(nameEntry.getText().toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import dagger.Module;
|
|||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
public class GroupCreateModule {
|
public class CreateGroupModule {
|
||||||
|
|
||||||
@ActivityScope
|
@ActivityScope
|
||||||
@Provides
|
@Provides
|
||||||
@@ -3,25 +3,43 @@ package org.briarproject.briar.android.privategroup.creation;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
|
import org.briarproject.briar.android.contactselection.ContactSelectorActivity;
|
||||||
|
import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler;
|
||||||
import org.briarproject.briar.android.sharing.BaseMessageFragment.MessageFragmentListener;
|
import org.briarproject.briar.android.sharing.BaseMessageFragment.MessageFragmentListener;
|
||||||
|
|
||||||
public class GroupInviteActivity extends BaseGroupInviteActivity
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_MSG_LENGTH;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
|
public class GroupInviteActivity extends ContactSelectorActivity
|
||||||
implements MessageFragmentListener {
|
implements MessageFragmentListener {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
CreateGroupController controller;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectActivity(ActivityComponent component) {
|
public void injectActivity(ActivityComponent component) {
|
||||||
component.inject(this);
|
component.inject(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle bundle) {
|
public void onCreate(@Nullable Bundle bundle) {
|
||||||
super.onCreate(bundle);
|
super.onCreate(bundle);
|
||||||
|
|
||||||
Intent i = getIntent();
|
Intent i = getIntent();
|
||||||
byte[] g = i.getByteArrayExtra(GROUP_ID);
|
byte[] g = i.getByteArrayExtra(GROUP_ID);
|
||||||
if (g == null) throw new IllegalStateException("No GroupId in intent.");
|
if (g == null) throw new IllegalStateException("No GroupId in intent");
|
||||||
groupId = new GroupId(g);
|
groupId = new GroupId(g);
|
||||||
|
|
||||||
if (bundle == null) {
|
if (bundle == null) {
|
||||||
@@ -29,4 +47,36 @@ public class GroupInviteActivity extends BaseGroupInviteActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void contactsSelected(Collection<ContactId> contacts) {
|
||||||
|
super.contactsSelected(contacts);
|
||||||
|
|
||||||
|
showNextFragment(new CreateGroupMessageFragment());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onButtonClick(String message) {
|
||||||
|
if (groupId == null)
|
||||||
|
throw new IllegalStateException("GroupId was not initialized");
|
||||||
|
controller.sendInvitation(groupId, contacts, message,
|
||||||
|
new UiResultExceptionHandler<Void, DbException>(this) {
|
||||||
|
@Override
|
||||||
|
public void onResultUi(Void result) {
|
||||||
|
setResult(RESULT_OK);
|
||||||
|
supportFinishAfterTransition();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExceptionUi(DbException exception) {
|
||||||
|
setResult(RESULT_CANCELED);
|
||||||
|
handleDbException(exception);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaximumMessageLength() {
|
||||||
|
return MAX_GROUP_INVITATION_MSG_LENGTH;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,15 +79,12 @@ class GroupListControllerImpl extends DbControllerImpl
|
|||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"GroupListListener needs to be attached");
|
"GroupListListener needs to be attached");
|
||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
notificationManager.blockAllGroupMessageNotifications();
|
|
||||||
notificationManager.clearAllGroupMessageNotifications();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@CallSuper
|
@CallSuper
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
eventBus.removeListener(this);
|
eventBus.removeListener(this);
|
||||||
notificationManager.unblockAllGroupMessageNotifications();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ class MemberListAdapter extends
|
|||||||
@Override
|
@Override
|
||||||
public boolean areContentsTheSame(MemberListItem m1, MemberListItem m2) {
|
public boolean areContentsTheSame(MemberListItem m1, MemberListItem m2) {
|
||||||
if (m1.isOnline() != m2.isOnline()) return false;
|
if (m1.isOnline() != m2.isOnline()) return false;
|
||||||
if (m1.getVisibility() != m2.getVisibility()) return false;
|
|
||||||
if (m1.getContactId() != m2.getContactId()) return false;
|
if (m1.getContactId() != m2.getContactId()) return false;
|
||||||
if (m1.getStatus() != m2.getStatus()) return false;
|
if (m1.getStatus() != m2.getStatus()) return false;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
package org.briarproject.briar.android.privategroup.memberlist;
|
package org.briarproject.briar.android.privategroup.memberlist;
|
||||||
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.identity.Author.Status;
|
import org.briarproject.bramble.api.identity.Author.Status;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.briar.api.privategroup.GroupMember;
|
import org.briarproject.briar.api.privategroup.GroupMember;
|
||||||
import org.briarproject.briar.api.privategroup.Visibility;
|
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@@ -40,10 +38,6 @@ class MemberListItem {
|
|||||||
return groupMember.getContactId();
|
return groupMember.getContactId();
|
||||||
}
|
}
|
||||||
|
|
||||||
Visibility getVisibility() {
|
|
||||||
return groupMember.getVisibility();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isOnline() {
|
boolean isOnline() {
|
||||||
return online;
|
return online;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,6 @@ import org.briarproject.briar.R;
|
|||||||
import org.briarproject.briar.android.view.AuthorView;
|
import org.briarproject.briar.android.view.AuthorView;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.identity.Author.Status.OURSELVES;
|
import static org.briarproject.bramble.api.identity.Author.Status.OURSELVES;
|
||||||
import static org.briarproject.bramble.api.identity.Author.Status.UNKNOWN;
|
|
||||||
import static org.briarproject.briar.android.privategroup.VisibilityHelper.getVisibilityIcon;
|
|
||||||
import static org.briarproject.briar.android.privategroup.VisibilityHelper.getVisibilityString;
|
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -22,16 +19,12 @@ class MemberListItemHolder extends RecyclerView.ViewHolder {
|
|||||||
private final AuthorView author;
|
private final AuthorView author;
|
||||||
private final ImageView bulb;
|
private final ImageView bulb;
|
||||||
private final TextView creator;
|
private final TextView creator;
|
||||||
private final ImageView icon;
|
|
||||||
private final TextView info;
|
|
||||||
|
|
||||||
MemberListItemHolder(View v) {
|
MemberListItemHolder(View v) {
|
||||||
super(v);
|
super(v);
|
||||||
author = (AuthorView) v.findViewById(R.id.authorView);
|
author = (AuthorView) v.findViewById(R.id.authorView);
|
||||||
bulb = (ImageView) v.findViewById(R.id.bulbView);
|
bulb = (ImageView) v.findViewById(R.id.bulbView);
|
||||||
creator = (TextView) v.findViewById(R.id.creatorView);
|
creator = (TextView) v.findViewById(R.id.creatorView);
|
||||||
icon = (ImageView) v.findViewById(R.id.icon);
|
|
||||||
info = (TextView) v.findViewById(R.id.info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void bind(MemberListItem item) {
|
protected void bind(MemberListItem item) {
|
||||||
@@ -64,19 +57,6 @@ class MemberListItemHolder extends RecyclerView.ViewHolder {
|
|||||||
} else {
|
} else {
|
||||||
creator.setVisibility(View.GONE);
|
creator.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// visibility information
|
|
||||||
if (item.getStatus() == OURSELVES || item.getStatus() == UNKNOWN) {
|
|
||||||
icon.setVisibility(View.GONE);
|
|
||||||
info.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
icon.setVisibility(View.VISIBLE);
|
|
||||||
icon.setImageResource(getVisibilityIcon(item.getVisibility()));
|
|
||||||
info.setVisibility(View.VISIBLE);
|
|
||||||
info.setText(
|
|
||||||
getVisibilityString(info.getContext(), item.getVisibility(),
|
|
||||||
item.getMember().getName()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ public class BriarReportPrimer implements ReportPrimer {
|
|||||||
NetworkInfo wifi = cm.getNetworkInfo(TYPE_WIFI);
|
NetworkInfo wifi = cm.getNetworkInfo(TYPE_WIFI);
|
||||||
boolean wifiAvailable = wifi != null && wifi.isAvailable();
|
boolean wifiAvailable = wifi != null && wifi.isAvailable();
|
||||||
// Is wifi enabled?
|
// Is wifi enabled?
|
||||||
o = ctx.getSystemService(WIFI_SERVICE);
|
o = ctx.getApplicationContext().getSystemService(WIFI_SERVICE);
|
||||||
WifiManager wm = (WifiManager) o;
|
WifiManager wm = (WifiManager) o;
|
||||||
boolean wifiEnabled = wm != null &&
|
boolean wifiEnabled = wm != null &&
|
||||||
wm.getWifiState() == WIFI_STATE_ENABLED;
|
wm.getWifiState() == WIFI_STATE_ENABLED;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import android.content.Intent;
|
|||||||
import android.media.Ringtone;
|
import android.media.Ringtone;
|
||||||
import android.media.RingtoneManager;
|
import android.media.RingtoneManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v7.preference.CheckBoxPreference;
|
import android.support.v7.preference.CheckBoxPreference;
|
||||||
import android.support.v7.preference.ListPreference;
|
import android.support.v7.preference.ListPreference;
|
||||||
@@ -54,6 +55,7 @@ import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_RINGT
|
|||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_BLOG;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_BLOG;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_FORUM;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_FORUM;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_GROUP;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_GROUP;
|
||||||
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_LOCK_SCREEN;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_PRIVATE;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_PRIVATE;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_RINGTONE_NAME;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_RINGTONE_NAME;
|
||||||
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_RINGTONE_URI;
|
import static org.briarproject.briar.api.android.AndroidNotificationManager.PREF_NOTIFY_RINGTONE_URI;
|
||||||
@@ -81,6 +83,8 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
private CheckBoxPreference notifyForumPosts;
|
private CheckBoxPreference notifyForumPosts;
|
||||||
private CheckBoxPreference notifyBlogPosts;
|
private CheckBoxPreference notifyBlogPosts;
|
||||||
private CheckBoxPreference notifyVibration;
|
private CheckBoxPreference notifyVibration;
|
||||||
|
private CheckBoxPreference notifyLockscreen;
|
||||||
|
|
||||||
private Preference notifySound;
|
private Preference notifySound;
|
||||||
|
|
||||||
// Fields that are accessed from background threads must be volatile
|
// Fields that are accessed from background threads must be volatile
|
||||||
@@ -114,6 +118,8 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
"pref_key_notify_blog_posts");
|
"pref_key_notify_blog_posts");
|
||||||
notifyVibration = (CheckBoxPreference) findPreference(
|
notifyVibration = (CheckBoxPreference) findPreference(
|
||||||
"pref_key_notify_vibration");
|
"pref_key_notify_vibration");
|
||||||
|
notifyLockscreen = (CheckBoxPreference) findPreference(
|
||||||
|
"pref_key_notify_lock_screen");
|
||||||
notifySound = findPreference("pref_key_notify_sound");
|
notifySound = findPreference("pref_key_notify_sound");
|
||||||
|
|
||||||
enableBluetooth.setOnPreferenceChangeListener(this);
|
enableBluetooth.setOnPreferenceChangeListener(this);
|
||||||
@@ -123,7 +129,10 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
notifyForumPosts.setOnPreferenceChangeListener(this);
|
notifyForumPosts.setOnPreferenceChangeListener(this);
|
||||||
notifyBlogPosts.setOnPreferenceChangeListener(this);
|
notifyBlogPosts.setOnPreferenceChangeListener(this);
|
||||||
notifyVibration.setOnPreferenceChangeListener(this);
|
notifyVibration.setOnPreferenceChangeListener(this);
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
notifyLockscreen.setVisible(true);
|
||||||
|
notifyLockscreen.setOnPreferenceChangeListener(this);
|
||||||
|
}
|
||||||
notifySound.setOnPreferenceClickListener(
|
notifySound.setOnPreferenceClickListener(
|
||||||
new Preference.OnPreferenceClickListener() {
|
new Preference.OnPreferenceClickListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -234,6 +243,9 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
notifyVibration.setChecked(settings.getBoolean(
|
notifyVibration.setChecked(settings.getBoolean(
|
||||||
PREF_NOTIFY_VIBRATION, true));
|
PREF_NOTIFY_VIBRATION, true));
|
||||||
|
|
||||||
|
notifyLockscreen.setChecked(settings.getBoolean(
|
||||||
|
PREF_NOTIFY_LOCK_SCREEN, false));
|
||||||
|
|
||||||
String text;
|
String text;
|
||||||
if (settings.getBoolean(PREF_NOTIFY_SOUND, true)) {
|
if (settings.getBoolean(PREF_NOTIFY_SOUND, true)) {
|
||||||
String ringtoneName =
|
String ringtoneName =
|
||||||
@@ -290,6 +302,10 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
Settings s = new Settings();
|
Settings s = new Settings();
|
||||||
s.putBoolean(PREF_NOTIFY_VIBRATION, (Boolean) o);
|
s.putBoolean(PREF_NOTIFY_VIBRATION, (Boolean) o);
|
||||||
storeSettings(s);
|
storeSettings(s);
|
||||||
|
} else if (preference == notifyLockscreen) {
|
||||||
|
Settings s = new Settings();
|
||||||
|
s.putBoolean(PREF_NOTIFY_LOCK_SCREEN, (Boolean) o);
|
||||||
|
storeSettings(s);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.briarproject.briar.android.sharing;
|
|||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
@@ -25,6 +24,7 @@ import java.util.Collection;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|||||||
@@ -4,9 +4,6 @@ import android.content.Intent;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.StrictMode;
|
|
||||||
import android.os.StrictMode.ThreadPolicy;
|
|
||||||
import android.os.StrictMode.VmPolicy;
|
|
||||||
import android.support.v7.preference.PreferenceManager;
|
import android.support.v7.preference.PreferenceManager;
|
||||||
import android.transition.Fade;
|
import android.transition.Fade;
|
||||||
|
|
||||||
@@ -22,27 +19,18 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static org.briarproject.briar.android.TestingConstants.DEFAULT_LOG_LEVEL;
|
import static org.briarproject.briar.android.BriarApplication.EXPIRY_DATE;
|
||||||
import static org.briarproject.briar.android.TestingConstants.TESTING;
|
|
||||||
|
|
||||||
public class SplashScreenActivity extends BaseActivity {
|
public class SplashScreenActivity extends BaseActivity {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(SplashScreenActivity.class.getName());
|
Logger.getLogger(SplashScreenActivity.class.getName());
|
||||||
|
|
||||||
// This build expires on 1 May 2017
|
|
||||||
private static final long EXPIRY_DATE = 1493593200 * 1000L;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected ConfigController configController;
|
protected ConfigController configController;
|
||||||
@Inject
|
@Inject
|
||||||
protected AndroidExecutor androidExecutor;
|
protected AndroidExecutor androidExecutor;
|
||||||
|
|
||||||
public SplashScreenActivity() {
|
|
||||||
Logger.getLogger("").setLevel(DEFAULT_LOG_LEVEL);
|
|
||||||
enableStrictMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
super.onCreate(state);
|
super.onCreate(state);
|
||||||
@@ -83,23 +71,6 @@ public class SplashScreenActivity extends BaseActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void showNewScreenFilterWarning() {
|
|
||||||
}
|
|
||||||
|
|
||||||
private void enableStrictMode() {
|
|
||||||
if (TESTING) {
|
|
||||||
ThreadPolicy.Builder threadPolicy = new ThreadPolicy.Builder();
|
|
||||||
threadPolicy.detectAll();
|
|
||||||
threadPolicy.penaltyLog();
|
|
||||||
StrictMode.setThreadPolicy(threadPolicy.build());
|
|
||||||
VmPolicy.Builder vmPolicy = new VmPolicy.Builder();
|
|
||||||
vmPolicy.detectAll();
|
|
||||||
vmPolicy.penaltyLog();
|
|
||||||
StrictMode.setVmPolicy(vmPolicy.build());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setPreferencesDefaults() {
|
private void setPreferencesDefaults() {
|
||||||
androidExecutor.runOnBackgroundThread(new Runnable() {
|
androidExecutor.runOnBackgroundThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package org.briarproject.briar.android.threaded;
|
package org.briarproject.briar.android.threaded;
|
||||||
|
|
||||||
import android.support.annotation.Nullable;
|
import android.os.Handler;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
@@ -14,6 +14,8 @@ import org.briarproject.briar.android.util.VersionedAdapter;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static android.support.v7.widget.RecyclerView.NO_POSITION;
|
import static android.support.v7.widget.RecyclerView.NO_POSITION;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@@ -26,6 +28,7 @@ public class ThreadItemAdapter<I extends ThreadItem>
|
|||||||
protected final NestedTreeList<I> items = new NestedTreeList<>();
|
protected final NestedTreeList<I> items = new NestedTreeList<>();
|
||||||
private final ThreadItemListener<I> listener;
|
private final ThreadItemListener<I> listener;
|
||||||
private final LinearLayoutManager layoutManager;
|
private final LinearLayoutManager layoutManager;
|
||||||
|
private final Handler handler = new Handler();
|
||||||
|
|
||||||
private volatile int revision = 0;
|
private volatile int revision = 0;
|
||||||
|
|
||||||
@@ -64,6 +67,17 @@ public class ThreadItemAdapter<I extends ThreadItem>
|
|||||||
revision++;
|
revision++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setItemWithIdVisible(MessageId messageId) {
|
||||||
|
int pos = 0;
|
||||||
|
for (I item : items) {
|
||||||
|
if (item.getId().equals(messageId)) {
|
||||||
|
layoutManager.scrollToPosition(pos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setItems(Collection<I> items) {
|
public void setItems(Collection<I> items) {
|
||||||
this.items.clear();
|
this.items.clear();
|
||||||
this.items.addAll(items);
|
this.items.addAll(items);
|
||||||
@@ -144,7 +158,7 @@ public class ThreadItemAdapter<I extends ThreadItem>
|
|||||||
/**
|
/**
|
||||||
* Returns the position of the first unread item below the current viewport
|
* Returns the position of the first unread item below the current viewport
|
||||||
*/
|
*/
|
||||||
public int getVisibleUnreadPosBottom() {
|
int getVisibleUnreadPosBottom() {
|
||||||
final int positionBottom = layoutManager.findLastVisibleItemPosition();
|
final int positionBottom = layoutManager.findLastVisibleItemPosition();
|
||||||
if (positionBottom == NO_POSITION) return NO_POSITION;
|
if (positionBottom == NO_POSITION) return NO_POSITION;
|
||||||
for (int i = positionBottom + 1; i < items.size(); i++) {
|
for (int i = positionBottom + 1; i < items.size(); i++) {
|
||||||
@@ -156,7 +170,7 @@ public class ThreadItemAdapter<I extends ThreadItem>
|
|||||||
/**
|
/**
|
||||||
* Returns the position of the first unread item above the current viewport
|
* Returns the position of the first unread item above the current viewport
|
||||||
*/
|
*/
|
||||||
public int getVisibleUnreadPosTop() {
|
int getVisibleUnreadPosTop() {
|
||||||
final int positionTop = layoutManager.findFirstVisibleItemPosition();
|
final int positionTop = layoutManager.findFirstVisibleItemPosition();
|
||||||
int position = NO_POSITION;
|
int position = NO_POSITION;
|
||||||
for (int i = 0; i < items.size(); i++) {
|
for (int i = 0; i < items.size(); i++) {
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.briarproject.briar.android.threaded;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public interface ThreadItemList<I extends ThreadItem> extends List<I> {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
MessageId getFirstVisibleItemId();
|
||||||
|
|
||||||
|
void setFirstVisibleId(@Nullable MessageId bottomVisibleItemId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package org.briarproject.briar.android.threaded;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class ThreadItemListImpl<I extends ThreadItem> extends ArrayList<I>
|
||||||
|
implements ThreadItemList<I> {
|
||||||
|
|
||||||
|
private MessageId bottomVisibleItemId;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MessageId getFirstVisibleItemId() {
|
||||||
|
return bottomVisibleItemId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFirstVisibleId(@Nullable MessageId bottomVisibleItemId) {
|
||||||
|
this.bottomVisibleItemId = bottomVisibleItemId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@ package org.briarproject.briar.android.threaded;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.CallSuper;
|
import android.support.annotation.CallSuper;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
@@ -26,6 +25,7 @@ import org.briarproject.briar.android.controller.SharingController;
|
|||||||
import org.briarproject.briar.android.controller.SharingController.SharingListener;
|
import org.briarproject.briar.android.controller.SharingController.SharingListener;
|
||||||
import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler;
|
import org.briarproject.briar.android.controller.handler.UiResultExceptionHandler;
|
||||||
import org.briarproject.briar.android.threaded.ThreadItemAdapter.ThreadItemListener;
|
import org.briarproject.briar.android.threaded.ThreadItemAdapter.ThreadItemListener;
|
||||||
|
import org.briarproject.briar.android.threaded.ThreadListController.ThreadListDataSource;
|
||||||
import org.briarproject.briar.android.threaded.ThreadListController.ThreadListListener;
|
import org.briarproject.briar.android.threaded.ThreadListController.ThreadListListener;
|
||||||
import org.briarproject.briar.android.view.BriarRecyclerView;
|
import org.briarproject.briar.android.view.BriarRecyclerView;
|
||||||
import org.briarproject.briar.android.view.TextInputView;
|
import org.briarproject.briar.android.view.TextInputView;
|
||||||
@@ -38,6 +38,7 @@ import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static android.support.design.widget.Snackbar.make;
|
import static android.support.design.widget.Snackbar.make;
|
||||||
@@ -51,7 +52,7 @@ import static org.briarproject.briar.android.threaded.ThreadItemAdapter.UnreadCo
|
|||||||
public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadItemAdapter<I>, I extends ThreadItem, H extends PostHeader>
|
public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadItemAdapter<I>, I extends ThreadItem, H extends PostHeader>
|
||||||
extends BriarActivity
|
extends BriarActivity
|
||||||
implements ThreadListListener<H>, TextInputListener, SharingListener,
|
implements ThreadListListener<H>, TextInputListener, SharingListener,
|
||||||
ThreadItemListener<I> {
|
ThreadItemListener<I>, ThreadListDataSource {
|
||||||
|
|
||||||
protected static final String KEY_REPLY_ID = "replyId";
|
protected static final String KEY_REPLY_ID = "replyId";
|
||||||
|
|
||||||
@@ -68,6 +69,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
|
|||||||
private MessageId replyId;
|
private MessageId replyId;
|
||||||
|
|
||||||
protected abstract ThreadListController<G, I, H> getController();
|
protected abstract ThreadListController<G, I, H> getController();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected SharingController sharingController;
|
protected SharingController sharingController;
|
||||||
|
|
||||||
@@ -104,6 +106,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
|
|||||||
updateUnreadCount();
|
updateUnreadCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onScrollStateChanged(RecyclerView recyclerView,
|
public void onScrollStateChanged(RecyclerView recyclerView,
|
||||||
int newState) {
|
int newState) {
|
||||||
@@ -139,11 +142,22 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
|
|||||||
if (replyIdBytes != null) replyId = new MessageId(replyIdBytes);
|
if (replyIdBytes != null) replyId = new MessageId(replyIdBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadItems();
|
|
||||||
sharingController.setSharingListener(this);
|
sharingController.setSharingListener(this);
|
||||||
loadSharingContacts();
|
loadSharingContacts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public MessageId getFirstVisibleMessageId() {
|
||||||
|
if (layoutManager != null && adapter != null) {
|
||||||
|
int position =
|
||||||
|
layoutManager.findFirstVisibleItemPosition();
|
||||||
|
I i = adapter.getItemAt(position);
|
||||||
|
return i == null ? null : i.getId();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract A createAdapter(LinearLayoutManager layoutManager);
|
protected abstract A createAdapter(LinearLayoutManager layoutManager);
|
||||||
|
|
||||||
protected void loadNamedGroup() {
|
protected void loadNamedGroup() {
|
||||||
@@ -167,16 +181,16 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
|
|||||||
protected void loadItems() {
|
protected void loadItems() {
|
||||||
final int revision = adapter.getRevision();
|
final int revision = adapter.getRevision();
|
||||||
getController().loadItems(
|
getController().loadItems(
|
||||||
new UiResultExceptionHandler<Collection<I>, DbException>(this) {
|
new UiResultExceptionHandler<ThreadItemList<I>, DbException>(
|
||||||
|
this) {
|
||||||
@Override
|
@Override
|
||||||
public void onResultUi(Collection<I> items) {
|
public void onResultUi(ThreadItemList<I> items) {
|
||||||
if (revision == adapter.getRevision()) {
|
if (revision == adapter.getRevision()) {
|
||||||
adapter.incrementRevision();
|
adapter.incrementRevision();
|
||||||
if (items.isEmpty()) {
|
if (items.isEmpty()) {
|
||||||
list.showData();
|
list.showData();
|
||||||
} else {
|
} else {
|
||||||
adapter.setItems(items);
|
initList(items);
|
||||||
list.showData();
|
|
||||||
updateTextInput(replyId);
|
updateTextInput(replyId);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -192,6 +206,15 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initList(final ThreadItemList<I> items) {
|
||||||
|
adapter.setItems(items);
|
||||||
|
MessageId messageId = items.getFirstVisibleItemId();
|
||||||
|
if (messageId != null)
|
||||||
|
adapter.setItemWithIdVisible(messageId);
|
||||||
|
updateUnreadCount();
|
||||||
|
list.showData();
|
||||||
|
}
|
||||||
|
|
||||||
protected void loadSharingContacts() {
|
protected void loadSharingContacts() {
|
||||||
getController().loadSharingContacts(
|
getController().loadSharingContacts(
|
||||||
new UiResultExceptionHandler<Collection<ContactId>, DbException>(
|
new UiResultExceptionHandler<Collection<ContactId>, DbException>(
|
||||||
@@ -215,6 +238,7 @@ public abstract class ThreadListActivity<G extends NamedGroup, A extends ThreadI
|
|||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
sharingController.onStart();
|
sharingController.onStart();
|
||||||
|
loadItems();
|
||||||
list.startPeriodicUpdate();
|
list.startPeriodicUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.contact.ContactId;
|
|||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.briar.android.DestroyableContext;
|
import org.briarproject.briar.android.DestroyableContext;
|
||||||
import org.briarproject.briar.android.controller.ActivityLifecycleController;
|
import org.briarproject.briar.android.controller.ActivityLifecycleController;
|
||||||
import org.briarproject.briar.android.controller.handler.ExceptionHandler;
|
import org.briarproject.briar.android.controller.handler.ExceptionHandler;
|
||||||
@@ -30,7 +31,7 @@ public interface ThreadListController<G extends NamedGroup, I extends ThreadItem
|
|||||||
|
|
||||||
void loadItem(H header, ResultExceptionHandler<I, DbException> handler);
|
void loadItem(H header, ResultExceptionHandler<I, DbException> handler);
|
||||||
|
|
||||||
void loadItems(ResultExceptionHandler<Collection<I>, DbException> handler);
|
void loadItems(ResultExceptionHandler<ThreadItemList<I>, DbException> handler);
|
||||||
|
|
||||||
void markItemRead(I item);
|
void markItemRead(I item);
|
||||||
|
|
||||||
@@ -41,7 +42,7 @@ public interface ThreadListController<G extends NamedGroup, I extends ThreadItem
|
|||||||
|
|
||||||
void deleteNamedGroup(ExceptionHandler<DbException> handler);
|
void deleteNamedGroup(ExceptionHandler<DbException> handler);
|
||||||
|
|
||||||
interface ThreadListListener<H> extends DestroyableContext {
|
interface ThreadListListener<H> extends ThreadListDataSource {
|
||||||
@UiThread
|
@UiThread
|
||||||
void onHeaderReceived(H header);
|
void onHeaderReceived(H header);
|
||||||
|
|
||||||
@@ -52,4 +53,10 @@ public interface ThreadListController<G extends NamedGroup, I extends ThreadItem
|
|||||||
void onInvitationAccepted(ContactId c);
|
void onInvitationAccepted(ContactId c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ThreadListDataSource extends DestroyableContext {
|
||||||
|
|
||||||
|
@UiThread @Nullable
|
||||||
|
MessageId getFirstVisibleMessageId();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,14 +22,13 @@ import org.briarproject.briar.android.controller.handler.ExceptionHandler;
|
|||||||
import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
|
import org.briarproject.briar.android.controller.handler.ResultExceptionHandler;
|
||||||
import org.briarproject.briar.android.threaded.ThreadListController.ThreadListListener;
|
import org.briarproject.briar.android.threaded.ThreadListController.ThreadListListener;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
|
import org.briarproject.briar.api.client.MessageTracker;
|
||||||
import org.briarproject.briar.api.client.NamedGroup;
|
import org.briarproject.briar.api.client.NamedGroup;
|
||||||
import org.briarproject.briar.api.client.PostHeader;
|
import org.briarproject.briar.api.client.PostHeader;
|
||||||
import org.briarproject.briar.api.client.ThreadedMessage;
|
import org.briarproject.briar.api.client.ThreadedMessage;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
@@ -55,18 +54,21 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
|
|||||||
protected final AndroidNotificationManager notificationManager;
|
protected final AndroidNotificationManager notificationManager;
|
||||||
protected final Executor cryptoExecutor;
|
protected final Executor cryptoExecutor;
|
||||||
protected final Clock clock;
|
protected final Clock clock;
|
||||||
|
private final MessageTracker messageTracker;
|
||||||
protected volatile L listener;
|
protected volatile L listener;
|
||||||
|
|
||||||
protected ThreadListControllerImpl(@DatabaseExecutor Executor dbExecutor,
|
protected ThreadListControllerImpl(@DatabaseExecutor Executor dbExecutor,
|
||||||
LifecycleManager lifecycleManager, IdentityManager identityManager,
|
LifecycleManager lifecycleManager, IdentityManager identityManager,
|
||||||
@CryptoExecutor Executor cryptoExecutor, EventBus eventBus,
|
@CryptoExecutor Executor cryptoExecutor, EventBus eventBus,
|
||||||
Clock clock, AndroidNotificationManager notificationManager) {
|
Clock clock, AndroidNotificationManager notificationManager,
|
||||||
|
MessageTracker messageTracker) {
|
||||||
super(dbExecutor, lifecycleManager);
|
super(dbExecutor, lifecycleManager);
|
||||||
this.identityManager = identityManager;
|
this.identityManager = identityManager;
|
||||||
this.cryptoExecutor = cryptoExecutor;
|
this.cryptoExecutor = cryptoExecutor;
|
||||||
this.notificationManager = notificationManager;
|
this.notificationManager = notificationManager;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
|
this.messageTracker = messageTracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -97,6 +99,21 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityDestroy() {
|
public void onActivityDestroy() {
|
||||||
|
final MessageId messageId = listener.getFirstVisibleMessageId();
|
||||||
|
if (messageId != null) {
|
||||||
|
dbExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
messageTracker
|
||||||
|
.storeMessageId(groupId, messageId);
|
||||||
|
} catch (DbException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
@@ -144,7 +161,7 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadItems(
|
public void loadItems(
|
||||||
final ResultExceptionHandler<Collection<I>, DbException> handler) {
|
final ResultExceptionHandler<ThreadItemList<I>, DbException> handler) {
|
||||||
checkGroupId();
|
checkGroupId();
|
||||||
runOnDbThread(new Runnable() {
|
runOnDbThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@@ -293,11 +310,16 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
|
|||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
protected abstract void deleteNamedGroup(G groupItem) throws DbException;
|
protected abstract void deleteNamedGroup(G groupItem) throws DbException;
|
||||||
|
|
||||||
private List<I> buildItems(Collection<H> headers) {
|
private ThreadItemList<I> buildItems(Collection<H> headers)
|
||||||
List<I> items = new ArrayList<>();
|
throws DbException {
|
||||||
|
ThreadItemList<I> items = new ThreadItemListImpl<>();
|
||||||
for (H h : headers) {
|
for (H h : headers) {
|
||||||
items.add(buildItem(h, bodyCache.get(h.getId())));
|
items.add(buildItem(h, bodyCache.get(h.getId())));
|
||||||
}
|
}
|
||||||
|
MessageId msgId = messageTracker.loadStoredMessageId(groupId);
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Loaded last top visible message id " + msgId);
|
||||||
|
items.setFirstVisibleId(msgId);
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.briar.android.util;
|
package org.briarproject.briar.android.util;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.design.widget.TextInputLayout;
|
import android.support.design.widget.TextInputLayout;
|
||||||
import android.support.v4.app.FragmentManager;
|
import android.support.v4.app.FragmentManager;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
@@ -23,6 +22,8 @@ import org.briarproject.briar.R;
|
|||||||
import org.briarproject.briar.android.view.ArticleMovementMethod;
|
import org.briarproject.briar.android.view.ArticleMovementMethod;
|
||||||
import org.briarproject.briar.android.widget.LinkDialogFragment;
|
import org.briarproject.briar.android.widget.LinkDialogFragment;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static android.text.format.DateUtils.DAY_IN_MILLIS;
|
import static android.text.format.DateUtils.DAY_IN_MILLIS;
|
||||||
import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
|
import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
|
||||||
import static android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE;
|
import static android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE;
|
||||||
@@ -30,6 +31,7 @@ import static android.text.format.DateUtils.FORMAT_ABBREV_TIME;
|
|||||||
import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
|
import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
|
||||||
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
|
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
|
||||||
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
|
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
|
||||||
|
import static org.briarproject.briar.android.BriarApplication.EXPIRY_DATE;
|
||||||
|
|
||||||
public class UiUtils {
|
public class UiUtils {
|
||||||
|
|
||||||
@@ -63,6 +65,12 @@ public class UiUtils {
|
|||||||
MIN_DATE_RESOLUTION, flags).toString();
|
MIN_DATE_RESOLUTION, flags).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getDaysUntilExpiry() {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
long daysBeforeExpiry = (EXPIRY_DATE - now) / 1000 / 60 / 60 / 24;
|
||||||
|
return (int) daysBeforeExpiry;
|
||||||
|
}
|
||||||
|
|
||||||
public static SpannableStringBuilder getTeaser(Context ctx, Spanned body) {
|
public static SpannableStringBuilder getTeaser(Context ctx, Spanned body) {
|
||||||
if (body.length() < TEASER_LENGTH)
|
if (body.length() < TEASER_LENGTH)
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.briar.android.view;
|
package org.briarproject.briar.android.view;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.support.annotation.DimenRes;
|
import android.support.annotation.DimenRes;
|
||||||
@@ -16,9 +15,7 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.identity.Author.Status;
|
import org.briarproject.bramble.api.identity.Author.Status;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.blog.BlogActivity;
|
|
||||||
import org.briarproject.briar.android.util.UiUtils;
|
import org.briarproject.briar.android.util.UiUtils;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -27,12 +24,10 @@ import de.hdodenhof.circleimageview.CircleImageView;
|
|||||||
import im.delight.android.identicons.IdenticonDrawable;
|
import im.delight.android.identicons.IdenticonDrawable;
|
||||||
|
|
||||||
import static android.content.Context.LAYOUT_INFLATER_SERVICE;
|
import static android.content.Context.LAYOUT_INFLATER_SERVICE;
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
|
||||||
import static android.graphics.Typeface.BOLD;
|
import static android.graphics.Typeface.BOLD;
|
||||||
import static android.util.TypedValue.COMPLEX_UNIT_PX;
|
import static android.util.TypedValue.COMPLEX_UNIT_PX;
|
||||||
import static org.briarproject.bramble.api.identity.Author.Status.NONE;
|
import static org.briarproject.bramble.api.identity.Author.Status.NONE;
|
||||||
import static org.briarproject.bramble.api.identity.Author.Status.OURSELVES;
|
import static org.briarproject.bramble.api.identity.Author.Status.OURSELVES;
|
||||||
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
public class AuthorView extends RelativeLayout {
|
public class AuthorView extends RelativeLayout {
|
||||||
@@ -110,24 +105,16 @@ public class AuthorView extends RelativeLayout {
|
|||||||
requestLayout();
|
requestLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBlogLink(final GroupId groupId) {
|
public void setAuthorClickable(OnClickListener listener) {
|
||||||
setClickable(true);
|
setClickable(true);
|
||||||
TypedValue outValue = new TypedValue();
|
TypedValue outValue = new TypedValue();
|
||||||
getContext().getTheme().resolveAttribute(
|
getContext().getTheme().resolveAttribute(
|
||||||
android.R.attr.selectableItemBackground, outValue, true);
|
android.R.attr.selectableItemBackground, outValue, true);
|
||||||
setBackgroundResource(outValue.resourceId);
|
setBackgroundResource(outValue.resourceId);
|
||||||
setOnClickListener(new OnClickListener() {
|
setOnClickListener(listener);
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
Intent i = new Intent(getContext(), BlogActivity.class);
|
|
||||||
i.putExtra(GROUP_ID, groupId.getBytes());
|
|
||||||
i.setFlags(FLAG_ACTIVITY_CLEAR_TOP);
|
|
||||||
getContext().startActivity(i);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unsetBlogLink() {
|
public void setAuthorNotClickable() {
|
||||||
setClickable(false);
|
setClickable(false);
|
||||||
setBackgroundResource(android.R.color.transparent);
|
setBackgroundResource(android.R.color.transparent);
|
||||||
setOnClickListener(null);
|
setOnClickListener(null);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.briarproject.briar.android.view;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
import android.support.design.widget.FloatingActionButton;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
@@ -13,6 +12,8 @@ import android.widget.TextView;
|
|||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class UnreadMessageButton extends FrameLayout {
|
public class UnreadMessageButton extends FrameLayout {
|
||||||
@@ -36,8 +37,7 @@ public class UnreadMessageButton extends FrameLayout {
|
|||||||
|
|
||||||
LayoutInflater inflater = (LayoutInflater) context
|
LayoutInflater inflater = (LayoutInflater) context
|
||||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
inflater
|
inflater.inflate(R.layout.unread_message_button, this, true);
|
||||||
.inflate(R.layout.unread_message_button, this, true);
|
|
||||||
|
|
||||||
fab = (FloatingActionButton) findViewById(R.id.fab);
|
fab = (FloatingActionButton) findViewById(R.id.fab);
|
||||||
unread = (TextView) findViewById(R.id.unreadCountView);
|
unread = (TextView) findViewById(R.id.unreadCountView);
|
||||||
@@ -64,15 +64,11 @@ public class UnreadMessageButton extends FrameLayout {
|
|||||||
|
|
||||||
public void setUnreadCount(int count) {
|
public void setUnreadCount(int count) {
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
fab.setVisibility(GONE);
|
setVisibility(INVISIBLE);
|
||||||
// fab.hide();
|
|
||||||
unread.setVisibility(GONE);
|
|
||||||
} else {
|
} else {
|
||||||
// FIXME: Use animations when upgrading to support library 24.2.0
|
// FIXME: Use animations when upgrading to support library 24.2.0
|
||||||
// https://code.google.com/p/android/issues/detail?id=216469
|
// https://code.google.com/p/android/issues/detail?id=216469
|
||||||
fab.setVisibility(VISIBLE);
|
setVisibility(VISIBLE);
|
||||||
// if (!fab.isShown()) fab.show();
|
|
||||||
unread.setVisibility(VISIBLE);
|
|
||||||
unread.setText(String.valueOf(count));
|
unread.setText(String.valueOf(count));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package org.briarproject.briar.android.widget;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.annotation.AttrRes;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static android.view.MotionEvent.FLAG_WINDOW_IS_OBSCURED;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
public class TapSafeFrameLayout extends FrameLayout {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private OnTapFilteredListener listener;
|
||||||
|
|
||||||
|
public TapSafeFrameLayout(Context context) {
|
||||||
|
super(context);
|
||||||
|
setFilterTouchesWhenObscured(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TapSafeFrameLayout(Context context, @Nullable AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
setFilterTouchesWhenObscured(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TapSafeFrameLayout(Context context, @Nullable AttributeSet attrs,
|
||||||
|
@AttrRes int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
setFilterTouchesWhenObscured(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnTapFilteredListener(OnTapFilteredListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onFilterTouchEventForSecurity(MotionEvent e) {
|
||||||
|
boolean filter = (e.getFlags() & FLAG_WINDOW_IS_OBSCURED) != 0;
|
||||||
|
if (filter && listener != null) listener.onTapFiltered();
|
||||||
|
return !filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnTapFilteredListener {
|
||||||
|
void onTapFiltered();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,19 +18,14 @@ public interface AndroidNotificationManager {
|
|||||||
String PREF_NOTIFY_RINGTONE_NAME = "notifyRingtoneName";
|
String PREF_NOTIFY_RINGTONE_NAME = "notifyRingtoneName";
|
||||||
String PREF_NOTIFY_RINGTONE_URI = "notifyRingtoneUri";
|
String PREF_NOTIFY_RINGTONE_URI = "notifyRingtoneUri";
|
||||||
String PREF_NOTIFY_VIBRATION = "notifyVibration";
|
String PREF_NOTIFY_VIBRATION = "notifyVibration";
|
||||||
|
String PREF_NOTIFY_LOCK_SCREEN = "notifyLockScreen";
|
||||||
|
|
||||||
void clearContactNotification(ContactId c);
|
void clearContactNotification(ContactId c);
|
||||||
|
|
||||||
void clearAllContactNotifications();
|
|
||||||
|
|
||||||
void clearGroupMessageNotification(GroupId g);
|
void clearGroupMessageNotification(GroupId g);
|
||||||
|
|
||||||
void clearAllGroupMessageNotifications();
|
|
||||||
|
|
||||||
void clearForumPostNotification(GroupId g);
|
void clearForumPostNotification(GroupId g);
|
||||||
|
|
||||||
void clearAllForumPostNotifications();
|
|
||||||
|
|
||||||
void clearBlogPostNotification(GroupId g);
|
void clearBlogPostNotification(GroupId g);
|
||||||
|
|
||||||
void clearAllBlogPostNotifications();
|
void clearAllBlogPostNotifications();
|
||||||
@@ -43,18 +38,6 @@ public interface AndroidNotificationManager {
|
|||||||
|
|
||||||
void unblockNotification(GroupId g);
|
void unblockNotification(GroupId g);
|
||||||
|
|
||||||
void blockAllContactNotifications();
|
|
||||||
|
|
||||||
void unblockAllContactNotifications();
|
|
||||||
|
|
||||||
void blockAllGroupMessageNotifications();
|
|
||||||
|
|
||||||
void unblockAllGroupMessageNotifications();
|
|
||||||
|
|
||||||
void blockAllForumPostNotifications();
|
|
||||||
|
|
||||||
void unblockAllForumPostNotifications();
|
|
||||||
|
|
||||||
void blockAllBlogPostNotifications();
|
void blockAllBlogPostNotifications();
|
||||||
|
|
||||||
void unblockAllBlogPostNotifications();
|
void unblockAllBlogPostNotifications();
|
||||||
|
|||||||
@@ -2,14 +2,10 @@ package org.briarproject.briar.api.android;
|
|||||||
|
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public interface ScreenFilterMonitor {
|
public interface ScreenFilterMonitor {
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
Set<String> getApps();
|
Set<String> getApps();
|
||||||
|
|
||||||
@UiThread
|
|
||||||
void storeAppsAsShown(Collection<String> s, boolean persistent);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,8 +104,9 @@ public class EmojiPageView extends FrameLayout {
|
|||||||
emojiSize + 2 * pad));
|
emojiSize + 2 * pad));
|
||||||
view = emojiView;
|
view = emojiView;
|
||||||
}
|
}
|
||||||
|
String emoji = model.getEmoji()[position];
|
||||||
|
view.setEmoji(emoji);
|
||||||
|
|
||||||
view.setEmoji(model.getEmoji()[position]);
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,21 @@
|
|||||||
package org.thoughtcrime.securesms.components.emoji;
|
package org.thoughtcrime.securesms.components.emoji;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Paint.FontMetricsInt;
|
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.text.TextUtils;
|
import android.support.v7.widget.AppCompatTextView;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.ViewConfiguration;
|
import android.view.ViewConfiguration;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.components.emoji.EmojiProvider.EmojiDrawable;
|
import org.thoughtcrime.securesms.components.emoji.EmojiProvider.EmojiDrawable;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static android.text.TextUtils.TruncateAt.END;
|
|
||||||
import static android.view.View.MeasureSpec.AT_MOST;
|
|
||||||
import static android.view.View.MeasureSpec.EXACTLY;
|
|
||||||
import static android.widget.TextView.BufferType.SPANNABLE;
|
import static android.widget.TextView.BufferType.SPANNABLE;
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
public class EmojiTextView extends TextView {
|
public class EmojiTextView extends AppCompatTextView {
|
||||||
|
|
||||||
private CharSequence source;
|
|
||||||
private boolean needsEllipsizing;
|
|
||||||
|
|
||||||
public EmojiTextView(Context context) {
|
public EmojiTextView(Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
@@ -42,13 +34,9 @@ public class EmojiTextView extends TextView {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setText(@Nullable CharSequence text, BufferType type) {
|
public void setText(@Nullable CharSequence text, BufferType type) {
|
||||||
source = EmojiProvider.getInstance(getContext()).emojify(text, this);
|
CharSequence source =
|
||||||
|
EmojiProvider.getInstance(getContext()).emojify(text, this);
|
||||||
setTextEllipsized(source);
|
super.setText(source, SPANNABLE);
|
||||||
}
|
|
||||||
|
|
||||||
private void setTextEllipsized(final @Nullable CharSequence source) {
|
|
||||||
super.setText(needsEllipsizing ? ellipsize(source) : source, SPANNABLE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -57,26 +45,6 @@ public class EmojiTextView extends TextView {
|
|||||||
else super.invalidateDrawable(drawable);
|
else super.invalidateDrawable(drawable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
||||||
final int size = MeasureSpec.getSize(widthMeasureSpec);
|
|
||||||
final int mode = MeasureSpec.getMode(widthMeasureSpec);
|
|
||||||
if (getEllipsize() == END &&
|
|
||||||
!TextUtils.isEmpty(source) &&
|
|
||||||
(mode == AT_MOST || mode == EXACTLY) &&
|
|
||||||
getPaint().breakText(source, 0, source.length() - 1, true, size,
|
|
||||||
null) != source.length()) {
|
|
||||||
needsEllipsizing = true;
|
|
||||||
FontMetricsInt font = getPaint().getFontMetricsInt();
|
|
||||||
int height = Math.abs(font.top - font.bottom);
|
|
||||||
super.onMeasure(MeasureSpec.makeMeasureSpec(size, EXACTLY),
|
|
||||||
MeasureSpec.makeMeasureSpec(height, EXACTLY));
|
|
||||||
} else {
|
|
||||||
needsEllipsizing = false;
|
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onLayout(boolean changed, int left, int top, int right,
|
protected void onLayout(boolean changed, int left, int top, int right,
|
||||||
int bottom) {
|
int bottom) {
|
||||||
@@ -89,20 +57,6 @@ public class EmojiTextView extends TextView {
|
|||||||
if (size > drawingCacheSize) {
|
if (size > drawingCacheSize) {
|
||||||
setLayerType(LAYER_TYPE_NONE, null);
|
setLayerType(LAYER_TYPE_NONE, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed) setTextEllipsized(source);
|
|
||||||
super.onLayout(changed, left, top, right, bottom);
|
super.onLayout(changed, left, top, right, bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public CharSequence ellipsize(@Nullable CharSequence text) {
|
|
||||||
if (TextUtils.isEmpty(text) || getWidth() == 0 ||
|
|
||||||
getEllipsize() != END) {
|
|
||||||
return text;
|
|
||||||
} else {
|
|
||||||
return TextUtils.ellipsize(text, getPaint(),
|
|
||||||
getWidth() - getPaddingRight() - getPaddingLeft(), END);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class RecentEmojiPageModel implements EmojiPageModel {
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(RecentEmojiPageModel.class.getName());
|
Logger.getLogger(RecentEmojiPageModel.class.getName());
|
||||||
|
|
||||||
private static final String EMOJI_LRU_PREFERENCE = "pref_emoji_recent";
|
private static final String EMOJI_LRU_PREFERENCE = "pref_emoji_recent2";
|
||||||
private static final int EMOJI_LRU_SIZE = 50;
|
private static final int EMOJI_LRU_SIZE = 50;
|
||||||
|
|
||||||
private final LinkedHashSet<String> recentlyUsed; // UI thread
|
private final LinkedHashSet<String> recentlyUsed; // UI thread
|
||||||
@@ -98,12 +98,12 @@ public class RecentEmojiPageModel implements EmojiPageModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String serialize(LinkedHashSet<String> emojis) {
|
private String serialize(LinkedHashSet<String> emojis) {
|
||||||
return StringUtils.join(emojis, ";");
|
return StringUtils.join(emojis, "\t");
|
||||||
}
|
}
|
||||||
|
|
||||||
private LinkedHashSet<String> deserialize(@Nullable String serialized) {
|
private LinkedHashSet<String> deserialize(@Nullable String serialized) {
|
||||||
if (serialized == null) return new LinkedHashSet<>();
|
if (serialized == null) return new LinkedHashSet<>();
|
||||||
String[] list = serialized.split(";");
|
String[] list = serialized.split("\t");
|
||||||
LinkedHashSet<String> result = new LinkedHashSet<>(list.length);
|
LinkedHashSet<String> result = new LinkedHashSet<>(list.length);
|
||||||
Collections.addAll(result, list);
|
Collections.addAll(result, list);
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
9
briar-android/src/main/res/drawable/ic_close.xml
Normal file
9
briar-android/src/main/res/drawable/ic_close.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="18dp"
|
||||||
|
android:height="18dp"
|
||||||
|
android:viewportHeight="24.0"
|
||||||
|
android:viewportWidth="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||||
|
</vector>
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<path
|
<path
|
||||||
android:fillColor="#ffa500"
|
android:fillColor="#ffa500"
|
||||||
android:pathData="M0,8.88178e-16 L30,8.88178e-16 L30,30 L0,30 L0,8.88178e-16 Z"/>
|
android:pathData="M0,0 L30,0 L30,30 L0,30 L0,0 Z"/>
|
||||||
<path
|
<path
|
||||||
android:fillColor="#ffffff"
|
android:fillColor="#ffffff"
|
||||||
android:pathData="M8.9322,18.0339 C10.6078,18.0339,11.9661,19.3922,11.9661,21.0678
|
android:pathData="M8.9322,18.0339 C10.6078,18.0339,11.9661,19.3922,11.9661,21.0678
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
android:fillColor="#87c214"
|
android:fillColor="#87c214"
|
||||||
android:pathData="M64.9004,0 C55.2004,0,47.1992,7.99922,47.1992,17.6992 L47.1992,40.1992
|
android:pathData="M64.9004,0 C55.2004,0,47.1992,7.99922,47.1992,17.6992 L47.1992,40.1992
|
||||||
L90.8008,40.1992 L90.8008,17.6992
|
L90.8008,40.1992 L90.8008,17.6992
|
||||||
C90.8008,7.99922,82.8992,-4.73695e-15,73.1992,0 L64.9004,0 Z M161.9,0
|
C90.8008,7.99922,82.8992,0,73.1992,0 L64.9004,0 Z M161.9,0
|
||||||
C152.2,0,144.199,7.99922,144.199,17.6992 L144.199,137.199 L187.801,137.199
|
C152.2,0,144.199,7.99922,144.199,17.6992 L144.199,137.199 L187.801,137.199
|
||||||
L187.801,17.6992 C187.801,7.99922,179.899,-4.73695e-15,170.199,0 L161.9,0 Z
|
L187.801,17.6992 C187.801,7.99922,179.899,0,170.199,0 L161.9,0 Z
|
||||||
M47.1992,97.8008 L47.1992,217.301 C47.1992,227.001,55.1004,235,64.9004,235
|
M47.1992,97.8008 L47.1992,217.301 C47.1992,227.001,55.1004,235,64.9004,235
|
||||||
L73.1992,235 C82.8992,235,90.9004,227.001,90.9004,217.301 L90.9004,97.8008
|
L73.1992,235 C82.8992,235,90.9004,227.001,90.9004,217.301 L90.9004,97.8008
|
||||||
L47.1992,97.8008 Z M144.199,194.801 L144.199,217.301
|
L47.1992,97.8008 Z M144.199,194.801 L144.199,217.301
|
||||||
@@ -25,12 +25,12 @@ C179.899,235,187.9,227.001,187.9,217.301 L187.9,194.801 L144.199,194.801 Z"/>
|
|||||||
android:pathData="M144.2,144.2 L187.9,144.2 L187.9,187.9 L144.2,187.9 L144.2,144.2 Z"/>
|
android:pathData="M144.2,144.2 L187.9,144.2 L187.9,187.9 L144.2,187.9 L144.2,144.2 Z"/>
|
||||||
<path
|
<path
|
||||||
android:fillColor="#95d220"
|
android:fillColor="#95d220"
|
||||||
android:pathData="M17.6992,47.1992 C7.99922,47.1992,2.36848e-15,55.1004,0,64.9004 L0,73.1992
|
android:pathData="M17.6992,47.1992 C7.99922,47.1992,0,55.1004,0,64.9004 L0,73.1992
|
||||||
C0,82.8992,7.89922,90.9004,17.6992,90.9004 L137.199,90.9004 L137.199,47.1992
|
C0,82.8992,7.89922,90.9004,17.6992,90.9004 L137.199,90.9004 L137.199,47.1992
|
||||||
L17.6992,47.1992 Z M194.801,47.1992 L194.801,90.9004 L217.301,90.9004
|
L17.6992,47.1992 Z M194.801,47.1992 L194.801,90.9004 L217.301,90.9004
|
||||||
C227.001,90.9004,235,82.9992,235,73.1992 L235,64.9004
|
C227.001,90.9004,235,82.9992,235,73.1992 L235,64.9004
|
||||||
C235,55.1004,227.001,47.1992,217.301,47.1992 L194.801,47.1992 Z M17.6992,144.199
|
C235,55.1004,227.001,47.1992,217.301,47.1992 L194.801,47.1992 Z M17.6992,144.199
|
||||||
C7.99922,144.199,2.36848e-15,152.1,0,161.9 L0,170.199
|
C7.99922,144.199,0,152.1,0,161.9 L0,170.199
|
||||||
C0,179.899,7.89922,187.9,17.6992,187.9 L40.1992,187.9 L40.1992,144.199
|
C0,179.899,7.89922,187.9,17.6992,187.9 L40.1992,187.9 L40.1992,144.199
|
||||||
L17.6992,144.199 Z M97.8008,144.199 L97.8008,187.9 L217.301,187.9
|
L17.6992,144.199 Z M97.8008,144.199 L97.8008,187.9 L217.301,187.9
|
||||||
C227.001,187.9,235,179.899,235,170.199 L235,161.9
|
C227.001,187.9,235,179.899,235,170.199 L235,161.9
|
||||||
|
|||||||
@@ -1,44 +1,42 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:orientation="vertical"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center_horizontal"
|
android:orientation="vertical"
|
||||||
android:padding="20dp" >
|
android:padding="@dimen/margin_large">
|
||||||
|
|
||||||
<TextView
|
<android.support.design.widget.TextInputLayout
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/createForumNameLayout"
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textSize="@dimen/text_size_medium"
|
|
||||||
android:text="@string/choose_forum_name" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/createForumNameEntry"
|
app:errorEnabled="true">
|
||||||
android:maxLines="1"
|
|
||||||
android:inputType="text|textCapSentences" />
|
|
||||||
|
|
||||||
<TextView
|
<EditText
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/createForumNameEntry"
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/createForumFeedback"
|
android:hint="@string/choose_forum_hint"
|
||||||
android:gravity="center"
|
android:inputType="text|textCapSentences"
|
||||||
android:paddingLeft="50dp"
|
android:maxLines="1"/>
|
||||||
android:paddingRight="50dp" />
|
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
style="@style/BriarButton"
|
|
||||||
android:id="@+id/createForumButton"
|
android:id="@+id/createForumButton"
|
||||||
android:text="@string/create_forum_button" />
|
style="@style/BriarButton"
|
||||||
|
android:enabled="false"
|
||||||
|
android:text="@string/create_forum_button"/>
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/createForumProgressBar"
|
android:id="@+id/createForumProgressBar"
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
android:indeterminate="true"
|
android:indeterminate="true"
|
||||||
android:visibility="gone" />
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user