mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 02:39:05 +01:00
Compare commits
25 Commits
release-1.
...
release-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e83d8bb700 | ||
|
|
d1ce0d0628 | ||
|
|
d73ec3cd88 | ||
|
|
71c66c843b | ||
|
|
bd19272099 | ||
|
|
b77b885a94 | ||
|
|
1fc4f657c7 | ||
|
|
df7d48d54d | ||
|
|
1987dcb936 | ||
|
|
f3b69a26f8 | ||
|
|
5e0ca10dae | ||
|
|
685496fb15 | ||
|
|
1521cdd258 | ||
|
|
80561910b1 | ||
|
|
bffb5c94ed | ||
|
|
c19f7c27b1 | ||
|
|
9a5a1489ef | ||
|
|
648793e092 | ||
|
|
e10742a23d | ||
|
|
32ada51831 | ||
|
|
7734a62c3e | ||
|
|
3c4513b9c7 | ||
|
|
5320737d49 | ||
|
|
ed53544226 | ||
|
|
6da45a4585 |
@@ -14,8 +14,8 @@ android {
|
||||
defaultConfig {
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 26
|
||||
versionCode 10002
|
||||
versionName "1.0.2"
|
||||
versionCode 10003
|
||||
versionName "1.0.3"
|
||||
consumerProguardFiles 'proguard-rules.txt'
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,29 @@
|
||||
package org.briarproject.bramble.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
import static java.util.logging.Level.INFO;
|
||||
|
||||
public class AndroidUtils {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(AndroidUtils.class.getName());
|
||||
|
||||
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
|
||||
private static final String FAKE_BLUETOOTH_ADDRESS = "02:00:00:00:00:00";
|
||||
|
||||
@@ -35,6 +44,7 @@ public class AndroidUtils {
|
||||
public static String getBluetoothAddress(Context ctx,
|
||||
BluetoothAdapter adapter) {
|
||||
// Return the adapter's address if it's valid and not fake
|
||||
@SuppressLint("HardwareIds")
|
||||
String address = adapter.getAddress();
|
||||
if (isValidBluetoothAddress(address)) return address;
|
||||
// Return the address from settings if it's valid and not fake
|
||||
@@ -51,17 +61,77 @@ public class AndroidUtils {
|
||||
&& !address.equals(FAKE_BLUETOOTH_ADDRESS);
|
||||
}
|
||||
|
||||
public static void deleteAppData(Context ctx) {
|
||||
public static void logDataDirContents(Context ctx) {
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
LOG.info("Contents of data directory:");
|
||||
logFileOrDir(new File(ctx.getApplicationInfo().dataDir));
|
||||
}
|
||||
}
|
||||
|
||||
private static void logFileOrDir(File f) {
|
||||
LOG.info(f.getAbsolutePath() + " " + f.length());
|
||||
if (f.isDirectory()) {
|
||||
File[] children = f.listFiles();
|
||||
if (children == null) {
|
||||
LOG.info("Could not list files in " + f.getAbsolutePath());
|
||||
} else {
|
||||
for (File child : children) logFileOrDir(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static File getSharedPrefsFile(Context ctx, String name) {
|
||||
File dataDir = new File(ctx.getApplicationInfo().dataDir);
|
||||
File prefsDir = new File(dataDir, "shared_prefs");
|
||||
return new File(prefsDir, name + ".xml");
|
||||
}
|
||||
|
||||
public static void logFileContents(File f) {
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
LOG.info("Contents of " + f.getAbsolutePath() + ":");
|
||||
try {
|
||||
Scanner s = new Scanner(f);
|
||||
while (s.hasNextLine()) LOG.info(s.nextLine());
|
||||
s.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
LOG.info(f.getAbsolutePath() + " not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
public static void deleteAppData(Context ctx, SharedPreferences... clear) {
|
||||
// Clear and commit shared preferences
|
||||
for (SharedPreferences prefs : clear) {
|
||||
boolean cleared = prefs.edit().clear().commit();
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
if (cleared) LOG.info("Cleared shared preferences");
|
||||
else LOG.info("Could not clear shared preferences");
|
||||
}
|
||||
}
|
||||
// Delete files, except lib and shared_prefs directories
|
||||
File dataDir = new File(ctx.getApplicationInfo().dataDir);
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Deleting app data from " + dataDir.getAbsolutePath());
|
||||
File[] children = dataDir.listFiles();
|
||||
if (children != null) {
|
||||
for (File child : children) {
|
||||
if (!child.getName().equals("lib"))
|
||||
String name = child.getName();
|
||||
if (!name.equals("lib") && !name.equals("shared_prefs")) {
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Deleting " + child.getAbsolutePath());
|
||||
IoUtils.deleteFileOrDir(child);
|
||||
}
|
||||
}
|
||||
} else if (LOG.isLoggable(INFO)) {
|
||||
LOG.info("Could not list files in " + dataDir.getAbsolutePath());
|
||||
}
|
||||
// Recreate the cache dir as some OpenGL drivers expect it to exist
|
||||
new File(dataDir, "cache").mkdir();
|
||||
boolean recreated = new File(dataDir, "cache").mkdir();
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
if (recreated) LOG.info("Recreated cache dir");
|
||||
else LOG.info("Could not recreate cache dir");
|
||||
}
|
||||
}
|
||||
|
||||
public static File getReportDir(Context ctx) {
|
||||
|
||||
@@ -2,9 +2,9 @@ package org.briarproject.bramble.api.sync;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface SyncSessionFactory {
|
||||
@@ -12,8 +12,8 @@ public interface SyncSessionFactory {
|
||||
SyncSession createIncomingSession(ContactId c, InputStream in);
|
||||
|
||||
SyncSession createSimplexOutgoingSession(ContactId c, int maxLatency,
|
||||
OutputStream out);
|
||||
StreamWriter streamWriter);
|
||||
|
||||
SyncSession createDuplexOutgoingSession(ContactId c, int maxLatency,
|
||||
int maxIdleTime, OutputStream out);
|
||||
int maxIdleTime, StreamWriter streamWriter);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.briarproject.bramble.api.transport;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* An interface for writing data to a transport connection. Data will be
|
||||
* encrypted and authenticated before being written to the connection.
|
||||
*/
|
||||
public interface StreamWriter {
|
||||
|
||||
OutputStream getOutputStream();
|
||||
|
||||
/**
|
||||
* Sends the end of stream marker, informing the recipient that no more
|
||||
* data will be sent. The connection is flushed but not closed.
|
||||
*/
|
||||
void sendEndOfStream() throws IOException;
|
||||
}
|
||||
@@ -12,12 +12,12 @@ public interface StreamWriterFactory {
|
||||
* Creates an {@link OutputStream OutputStream} for writing to a
|
||||
* transport stream
|
||||
*/
|
||||
OutputStream createStreamWriter(OutputStream out, StreamContext ctx);
|
||||
StreamWriter createStreamWriter(OutputStream out, StreamContext ctx);
|
||||
|
||||
/**
|
||||
* Creates an {@link OutputStream OutputStream} for writing to a contact
|
||||
* exchange stream.
|
||||
*/
|
||||
OutputStream createContactExchangeStreamWriter(OutputStream out,
|
||||
StreamWriter createContactExchangeStreamWriter(OutputStream out,
|
||||
SecretKey headerKey);
|
||||
}
|
||||
|
||||
@@ -9,25 +9,37 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
|
||||
@NotNullByDefault
|
||||
public class IoUtils {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(IoUtils.class.getName());
|
||||
|
||||
public static void deleteFileOrDir(File f) {
|
||||
if (f.isFile()) {
|
||||
f.delete();
|
||||
delete(f);
|
||||
} else if (f.isDirectory()) {
|
||||
File[] children = f.listFiles();
|
||||
if (children != null)
|
||||
for (File child : children) deleteFileOrDir(child);
|
||||
f.delete();
|
||||
delete(f);
|
||||
}
|
||||
}
|
||||
|
||||
public static void copyAndClose(InputStream in, OutputStream out)
|
||||
throws IOException {
|
||||
private static void delete(File f) {
|
||||
boolean deleted = f.delete();
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
if (deleted) LOG.info("Deleted " + f.getAbsolutePath());
|
||||
else LOG.info("Could not delete " + f.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
public static void copyAndClose(InputStream in, OutputStream out) {
|
||||
byte[] buf = new byte[4096];
|
||||
try {
|
||||
while (true) {
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.briarproject.bramble.api.record.RecordWriter;
|
||||
import org.briarproject.bramble.api.record.RecordWriterFactory;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.api.transport.StreamReaderFactory;
|
||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
||||
|
||||
import java.io.EOFException;
|
||||
@@ -152,11 +153,11 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
recordReaderFactory.createRecordReader(streamReader);
|
||||
|
||||
// Create the writers
|
||||
OutputStream streamWriter =
|
||||
StreamWriter streamWriter =
|
||||
streamWriterFactory.createContactExchangeStreamWriter(out,
|
||||
alice ? aliceHeaderKey : bobHeaderKey);
|
||||
RecordWriter recordWriter =
|
||||
recordWriterFactory.createRecordWriter(streamWriter);
|
||||
recordWriterFactory.createRecordWriter(streamWriter.getOutputStream());
|
||||
|
||||
// Derive the nonces to be signed
|
||||
byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret,
|
||||
@@ -184,8 +185,8 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask {
|
||||
localSignature, localTimestamp);
|
||||
recordWriter.flush();
|
||||
}
|
||||
// Close the outgoing stream
|
||||
recordWriter.close();
|
||||
// Send EOF on the outgoing stream
|
||||
streamWriter.sendEndOfStream();
|
||||
// Skip any remaining records from the incoming stream
|
||||
try {
|
||||
while (true) recordReader.readRecord();
|
||||
|
||||
@@ -14,12 +14,12 @@ import org.briarproject.bramble.api.sync.SyncSessionFactory;
|
||||
import org.briarproject.bramble.api.transport.KeyManager;
|
||||
import org.briarproject.bramble.api.transport.StreamContext;
|
||||
import org.briarproject.bramble.api.transport.StreamReaderFactory;
|
||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -101,7 +101,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
||||
|
||||
private SyncSession createSimplexOutgoingSession(StreamContext ctx,
|
||||
TransportConnectionWriter w) throws IOException {
|
||||
OutputStream streamWriter = streamWriterFactory.createStreamWriter(
|
||||
StreamWriter streamWriter = streamWriterFactory.createStreamWriter(
|
||||
w.getOutputStream(), ctx);
|
||||
return syncSessionFactory.createSimplexOutgoingSession(
|
||||
ctx.getContactId(), w.getMaxLatency(), streamWriter);
|
||||
@@ -109,7 +109,7 @@ class ConnectionManagerImpl implements ConnectionManager {
|
||||
|
||||
private SyncSession createDuplexOutgoingSession(StreamContext ctx,
|
||||
TransportConnectionWriter w) throws IOException {
|
||||
OutputStream streamWriter = streamWriterFactory.createStreamWriter(
|
||||
StreamWriter streamWriter = streamWriterFactory.createStreamWriter(
|
||||
w.getOutputStream(), ctx);
|
||||
return syncSessionFactory.createDuplexOutgoingSession(
|
||||
ctx.getContactId(), w.getMaxLatency(), w.getMaxIdleTime(),
|
||||
@@ -300,8 +300,8 @@ class ConnectionManagerImpl implements ConnectionManager {
|
||||
}
|
||||
|
||||
private void disposeReader(boolean exception, boolean recognised) {
|
||||
if (exception && outgoingSession != null)
|
||||
outgoingSession.interrupt();
|
||||
// Interrupt the outgoing session so it finishes cleanly
|
||||
if (outgoingSession != null) outgoingSession.interrupt();
|
||||
try {
|
||||
reader.dispose(exception, recognised);
|
||||
} catch (IOException e) {
|
||||
@@ -310,6 +310,8 @@ class ConnectionManagerImpl implements ConnectionManager {
|
||||
}
|
||||
|
||||
private void disposeWriter(boolean exception) {
|
||||
// Interrupt the incoming session if an exception occurred,
|
||||
// otherwise wait for the end of stream marker
|
||||
if (exception && incomingSession != null)
|
||||
incomingSession.interrupt();
|
||||
try {
|
||||
@@ -407,8 +409,8 @@ class ConnectionManagerImpl implements ConnectionManager {
|
||||
}
|
||||
|
||||
private void disposeReader(boolean exception, boolean recognised) {
|
||||
if (exception && outgoingSession != null)
|
||||
outgoingSession.interrupt();
|
||||
// Interrupt the outgoing session so it finishes cleanly
|
||||
if (outgoingSession != null) outgoingSession.interrupt();
|
||||
try {
|
||||
reader.dispose(exception, recognised);
|
||||
} catch (IOException e) {
|
||||
@@ -417,6 +419,8 @@ class ConnectionManagerImpl implements ConnectionManager {
|
||||
}
|
||||
|
||||
private void disposeWriter(boolean exception) {
|
||||
// Interrupt the incoming session if an exception occurred,
|
||||
// otherwise wait for the end of stream marker
|
||||
if (exception && incomingSession != null)
|
||||
incomingSession.interrupt();
|
||||
try {
|
||||
|
||||
@@ -106,7 +106,7 @@ class ConnectionRegistryImpl implements ConnectionRegistry {
|
||||
if (m == null) return Collections.emptyList();
|
||||
List<ContactId> ids = new ArrayList<>(m.keySet());
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info(ids.size() + " contacts connected");
|
||||
LOG.info(ids.size() + " contacts connected: " + t);
|
||||
return ids;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.briarproject.bramble.api.sync.event.MessageSharedEvent;
|
||||
import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
|
||||
import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
@@ -67,6 +68,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
||||
private final Clock clock;
|
||||
private final ContactId contactId;
|
||||
private final int maxLatency, maxIdleTime;
|
||||
private final StreamWriter streamWriter;
|
||||
private final SyncRecordWriter recordWriter;
|
||||
private final BlockingQueue<ThrowingRunnable<IOException>> writerTasks;
|
||||
|
||||
@@ -81,7 +83,8 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
||||
|
||||
DuplexOutgoingSession(DatabaseComponent db, Executor dbExecutor,
|
||||
EventBus eventBus, Clock clock, ContactId contactId, int maxLatency,
|
||||
int maxIdleTime, SyncRecordWriter recordWriter) {
|
||||
int maxIdleTime, StreamWriter streamWriter,
|
||||
SyncRecordWriter recordWriter) {
|
||||
this.db = db;
|
||||
this.dbExecutor = dbExecutor;
|
||||
this.eventBus = eventBus;
|
||||
@@ -89,6 +92,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
||||
this.contactId = contactId;
|
||||
this.maxLatency = maxLatency;
|
||||
this.maxIdleTime = maxIdleTime;
|
||||
this.streamWriter = streamWriter;
|
||||
this.recordWriter = recordWriter;
|
||||
writerTasks = new LinkedBlockingQueue<>();
|
||||
}
|
||||
@@ -149,7 +153,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
||||
dataToFlush = true;
|
||||
}
|
||||
}
|
||||
if (dataToFlush) recordWriter.flush();
|
||||
streamWriter.sendEndOfStream();
|
||||
} catch (InterruptedException e) {
|
||||
LOG.info("Interrupted while waiting for a record to write");
|
||||
Thread.currentThread().interrupt();
|
||||
|
||||
@@ -63,7 +63,11 @@ class IncomingSession implements SyncSession, EventListener {
|
||||
eventBus.addListener(this);
|
||||
try {
|
||||
// Read records until interrupted or EOF
|
||||
while (!interrupted && !recordReader.eof()) {
|
||||
while (!interrupted) {
|
||||
if (recordReader.eof()) {
|
||||
LOG.info("End of stream");
|
||||
return;
|
||||
}
|
||||
if (recordReader.hasAck()) {
|
||||
Ack a = recordReader.readAck();
|
||||
dbExecutor.execute(new ReceiveAck(a));
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.Ack;
|
||||
import org.briarproject.bramble.api.sync.SyncRecordWriter;
|
||||
import org.briarproject.bramble.api.sync.SyncSession;
|
||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
@@ -51,6 +52,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
||||
private final EventBus eventBus;
|
||||
private final ContactId contactId;
|
||||
private final int maxLatency;
|
||||
private final StreamWriter streamWriter;
|
||||
private final SyncRecordWriter recordWriter;
|
||||
private final AtomicInteger outstandingQueries;
|
||||
private final BlockingQueue<ThrowingRunnable<IOException>> writerTasks;
|
||||
@@ -58,13 +60,14 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
||||
private volatile boolean interrupted = false;
|
||||
|
||||
SimplexOutgoingSession(DatabaseComponent db, Executor dbExecutor,
|
||||
EventBus eventBus, ContactId contactId,
|
||||
int maxLatency, SyncRecordWriter recordWriter) {
|
||||
EventBus eventBus, ContactId contactId, int maxLatency,
|
||||
StreamWriter streamWriter, SyncRecordWriter recordWriter) {
|
||||
this.db = db;
|
||||
this.dbExecutor = dbExecutor;
|
||||
this.eventBus = eventBus;
|
||||
this.contactId = contactId;
|
||||
this.maxLatency = maxLatency;
|
||||
this.streamWriter = streamWriter;
|
||||
this.recordWriter = recordWriter;
|
||||
outstandingQueries = new AtomicInteger(2); // One per type of record
|
||||
writerTasks = new LinkedBlockingQueue<>();
|
||||
@@ -85,7 +88,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
||||
if (task == CLOSE) break;
|
||||
task.run();
|
||||
}
|
||||
recordWriter.flush();
|
||||
streamWriter.sendEndOfStream();
|
||||
} catch (InterruptedException e) {
|
||||
LOG.info("Interrupted while waiting for a record to write");
|
||||
Thread.currentThread().interrupt();
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.briarproject.bramble.api.sync.SyncRecordWriterFactory;
|
||||
import org.briarproject.bramble.api.sync.SyncSession;
|
||||
import org.briarproject.bramble.api.sync.SyncSessionFactory;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -53,19 +54,21 @@ class SyncSessionFactoryImpl implements SyncSessionFactory {
|
||||
|
||||
@Override
|
||||
public SyncSession createSimplexOutgoingSession(ContactId c,
|
||||
int maxLatency, OutputStream out) {
|
||||
int maxLatency, StreamWriter streamWriter) {
|
||||
OutputStream out = streamWriter.getOutputStream();
|
||||
SyncRecordWriter recordWriter =
|
||||
recordWriterFactory.createRecordWriter(out);
|
||||
return new SimplexOutgoingSession(db, dbExecutor, eventBus, c,
|
||||
maxLatency, recordWriter);
|
||||
maxLatency, streamWriter, recordWriter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SyncSession createDuplexOutgoingSession(ContactId c, int maxLatency,
|
||||
int maxIdleTime, OutputStream out) {
|
||||
int maxIdleTime, StreamWriter streamWriter) {
|
||||
OutputStream out = streamWriter.getOutputStream();
|
||||
SyncRecordWriter recordWriter =
|
||||
recordWriterFactory.createRecordWriter(out);
|
||||
return new DuplexOutgoingSession(db, dbExecutor, eventBus, clock, c,
|
||||
maxLatency, maxIdleTime, recordWriter);
|
||||
maxLatency, maxIdleTime, streamWriter, recordWriter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.crypto.StreamEncrypterFactory;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.transport.StreamContext;
|
||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
||||
|
||||
import java.io.OutputStream;
|
||||
@@ -23,14 +24,14 @@ class StreamWriterFactoryImpl implements StreamWriterFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream createStreamWriter(OutputStream out,
|
||||
public StreamWriter createStreamWriter(OutputStream out,
|
||||
StreamContext ctx) {
|
||||
return new StreamWriterImpl(
|
||||
streamEncrypterFactory.createStreamEncrypter(out, ctx));
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream createContactExchangeStreamWriter(OutputStream out,
|
||||
public StreamWriter createContactExchangeStreamWriter(OutputStream out,
|
||||
SecretKey headerKey) {
|
||||
return new StreamWriterImpl(
|
||||
streamEncrypterFactory.createContactExchangeStreamDecrypter(out,
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.briarproject.bramble.transport;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.StreamEncrypter;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
@@ -17,7 +18,7 @@ import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYL
|
||||
*/
|
||||
@NotThreadSafe
|
||||
@NotNullByDefault
|
||||
class StreamWriterImpl extends OutputStream {
|
||||
class StreamWriterImpl extends OutputStream implements StreamWriter {
|
||||
|
||||
private final StreamEncrypter encrypter;
|
||||
private final byte[] payload;
|
||||
@@ -29,6 +30,17 @@ class StreamWriterImpl extends OutputStream {
|
||||
payload = new byte[MAX_PAYLOAD_LENGTH];
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendEndOfStream() throws IOException {
|
||||
writeFrame(true);
|
||||
encrypter.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
writeFrame(true);
|
||||
|
||||
@@ -7,11 +7,10 @@ import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.sync.Ack;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.sync.SyncRecordWriter;
|
||||
import org.briarproject.bramble.test.BrambleTestCase;
|
||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.ImmediateExecutor;
|
||||
import org.briarproject.bramble.test.TestUtils;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.Mockery;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -19,33 +18,27 @@ import java.util.Collections;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||
|
||||
public class SimplexOutgoingSessionTest extends BrambleTestCase {
|
||||
public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
|
||||
|
||||
private final Mockery context;
|
||||
private final DatabaseComponent db;
|
||||
private final Executor dbExecutor;
|
||||
private final EventBus eventBus;
|
||||
private final ContactId contactId;
|
||||
private final MessageId messageId;
|
||||
private final int maxLatency;
|
||||
private final SyncRecordWriter recordWriter;
|
||||
private static final int MAX_LATENCY = Integer.MAX_VALUE;
|
||||
|
||||
public SimplexOutgoingSessionTest() {
|
||||
context = new Mockery();
|
||||
db = context.mock(DatabaseComponent.class);
|
||||
dbExecutor = new ImmediateExecutor();
|
||||
eventBus = context.mock(EventBus.class);
|
||||
recordWriter = context.mock(SyncRecordWriter.class);
|
||||
contactId = new ContactId(234);
|
||||
messageId = new MessageId(TestUtils.getRandomId());
|
||||
maxLatency = Integer.MAX_VALUE;
|
||||
}
|
||||
private final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||
private final EventBus eventBus = context.mock(EventBus.class);
|
||||
private final StreamWriter streamWriter = context.mock(StreamWriter.class);
|
||||
private final SyncRecordWriter recordWriter =
|
||||
context.mock(SyncRecordWriter.class);
|
||||
|
||||
private final Executor dbExecutor = new ImmediateExecutor();
|
||||
private final ContactId contactId = new ContactId(234);
|
||||
private final MessageId messageId = new MessageId(getRandomId());
|
||||
|
||||
@Test
|
||||
public void testNothingToSend() throws Exception {
|
||||
SimplexOutgoingSession session = new SimplexOutgoingSession(db,
|
||||
dbExecutor, eventBus, contactId, maxLatency, recordWriter);
|
||||
dbExecutor, eventBus, contactId, MAX_LATENCY, streamWriter,
|
||||
recordWriter);
|
||||
Transaction noAckTxn = new Transaction(null, false);
|
||||
Transaction noMsgTxn = new Transaction(null, false);
|
||||
|
||||
@@ -63,19 +56,17 @@ public class SimplexOutgoingSessionTest extends BrambleTestCase {
|
||||
oneOf(db).startTransaction(false);
|
||||
will(returnValue(noMsgTxn));
|
||||
oneOf(db).generateBatch(with(noMsgTxn), with(contactId),
|
||||
with(any(int.class)), with(maxLatency));
|
||||
with(any(int.class)), with(MAX_LATENCY));
|
||||
will(returnValue(null));
|
||||
oneOf(db).commitTransaction(noMsgTxn);
|
||||
oneOf(db).endTransaction(noMsgTxn);
|
||||
// Flush the output stream
|
||||
oneOf(recordWriter).flush();
|
||||
// Send the end of stream marker
|
||||
oneOf(streamWriter).sendEndOfStream();
|
||||
// Remove listener
|
||||
oneOf(eventBus).removeListener(session);
|
||||
}});
|
||||
|
||||
session.run();
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -83,7 +74,8 @@ public class SimplexOutgoingSessionTest extends BrambleTestCase {
|
||||
Ack ack = new Ack(Collections.singletonList(messageId));
|
||||
byte[] raw = new byte[1234];
|
||||
SimplexOutgoingSession session = new SimplexOutgoingSession(db,
|
||||
dbExecutor, eventBus, contactId, maxLatency, recordWriter);
|
||||
dbExecutor, eventBus, contactId, MAX_LATENCY, streamWriter,
|
||||
recordWriter);
|
||||
Transaction ackTxn = new Transaction(null, false);
|
||||
Transaction noAckTxn = new Transaction(null, false);
|
||||
Transaction msgTxn = new Transaction(null, false);
|
||||
@@ -104,7 +96,7 @@ public class SimplexOutgoingSessionTest extends BrambleTestCase {
|
||||
oneOf(db).startTransaction(false);
|
||||
will(returnValue(msgTxn));
|
||||
oneOf(db).generateBatch(with(msgTxn), with(contactId),
|
||||
with(any(int.class)), with(maxLatency));
|
||||
with(any(int.class)), with(MAX_LATENCY));
|
||||
will(returnValue(Arrays.asList(raw)));
|
||||
oneOf(db).commitTransaction(msgTxn);
|
||||
oneOf(db).endTransaction(msgTxn);
|
||||
@@ -120,18 +112,16 @@ public class SimplexOutgoingSessionTest extends BrambleTestCase {
|
||||
oneOf(db).startTransaction(false);
|
||||
will(returnValue(noMsgTxn));
|
||||
oneOf(db).generateBatch(with(noMsgTxn), with(contactId),
|
||||
with(any(int.class)), with(maxLatency));
|
||||
with(any(int.class)), with(MAX_LATENCY));
|
||||
will(returnValue(null));
|
||||
oneOf(db).commitTransaction(noMsgTxn);
|
||||
oneOf(db).endTransaction(noMsgTxn);
|
||||
// Flush the output stream
|
||||
oneOf(recordWriter).flush();
|
||||
// Send the end of stream marker
|
||||
oneOf(streamWriter).sendEndOfStream();
|
||||
// Remove listener
|
||||
oneOf(eventBus).removeListener(session);
|
||||
}});
|
||||
|
||||
session.run();
|
||||
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.briarproject.bramble.api.sync.SyncRecordWriter;
|
||||
import org.briarproject.bramble.api.sync.SyncRecordWriterFactory;
|
||||
import org.briarproject.bramble.api.transport.StreamContext;
|
||||
import org.briarproject.bramble.api.transport.StreamReaderFactory;
|
||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
||||
import org.briarproject.bramble.test.BrambleTestCase;
|
||||
import org.briarproject.bramble.test.TestUtils;
|
||||
@@ -27,7 +28,6 @@ import org.junit.Test;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -102,18 +102,18 @@ public class SyncIntegrationTest extends BrambleTestCase {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamContext ctx = new StreamContext(contactId, transportId, tagKey,
|
||||
headerKey, streamNumber);
|
||||
OutputStream streamWriter = streamWriterFactory.createStreamWriter(out,
|
||||
StreamWriter streamWriter = streamWriterFactory.createStreamWriter(out,
|
||||
ctx);
|
||||
SyncRecordWriter recordWriter = recordWriterFactory.createRecordWriter(
|
||||
streamWriter);
|
||||
streamWriter.getOutputStream());
|
||||
|
||||
recordWriter.writeAck(new Ack(messageIds));
|
||||
recordWriter.writeMessage(message.getRaw());
|
||||
recordWriter.writeMessage(message1.getRaw());
|
||||
recordWriter.writeOffer(new Offer(messageIds));
|
||||
recordWriter.writeRequest(new Request(messageIds));
|
||||
recordWriter.flush();
|
||||
|
||||
streamWriter.sendEndOfStream();
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
@@ -238,12 +238,13 @@ android {
|
||||
defaultConfig {
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 26
|
||||
versionCode 10002
|
||||
versionName "1.0.2"
|
||||
versionCode 10003
|
||||
versionName "1.0.3"
|
||||
applicationId "org.briarproject.briar.android"
|
||||
resValue "string", "app_package", "org.briarproject.briar.android"
|
||||
resValue "string", "app_name", "Briar"
|
||||
buildConfigField "String", "GitHash", "\"${getGitHash()}\""
|
||||
buildConfigField "Long", "BuildTimestamp", "${System.currentTimeMillis()}L"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package org.briarproject.briar.android;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
|
||||
@NotNullByDefault
|
||||
class AndroidDatabaseConfig implements DatabaseConfig {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(AndroidDatabaseConfig.class.getName());
|
||||
|
||||
private final File dir;
|
||||
|
||||
@Nullable
|
||||
private volatile SecretKey key = null;
|
||||
@Nullable
|
||||
private volatile String nickname = null;
|
||||
|
||||
AndroidDatabaseConfig(File dir) {
|
||||
this.dir = dir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean databaseExists() {
|
||||
// FIXME should not run on UiThread #620
|
||||
if (!dir.isDirectory()) {
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info(dir.getAbsolutePath() + " is not a directory");
|
||||
return false;
|
||||
}
|
||||
File[] files = dir.listFiles();
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
if (files == null) {
|
||||
LOG.info("Could not list files in " + dir.getAbsolutePath());
|
||||
} else {
|
||||
LOG.info("Files in " + dir.getAbsolutePath() + ":");
|
||||
for (File f : files) LOG.info(f.getName());
|
||||
}
|
||||
LOG.info("Database exists: " + (files != null && files.length > 0));
|
||||
}
|
||||
return files != null && files.length > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDatabaseDirectory() {
|
||||
File dir = this.dir;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Database directory: " + dir.getAbsolutePath());
|
||||
return dir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEncryptionKey(SecretKey key) {
|
||||
LOG.info("Setting database key");
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocalAuthorName(String nickname) {
|
||||
LOG.info("Setting local author name");
|
||||
this.nickname = nickname;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getLocalAuthorName() {
|
||||
String nickname = this.nickname;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Local author name has been set: " + (nickname != null));
|
||||
return nickname;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public SecretKey getEncryptionKey() {
|
||||
SecretKey key = this.key;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Database key has been set: " + (key != null));
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxSize() {
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import android.content.SharedPreferences;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||
@@ -23,7 +22,6 @@ import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
||||
import java.io.File;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
@@ -87,51 +85,7 @@ public class AppModule {
|
||||
File dir = app.getApplicationContext().getDir("db", MODE_PRIVATE);
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
DatabaseConfig databaseConfig = new DatabaseConfig() {
|
||||
|
||||
private volatile SecretKey key;
|
||||
private volatile String nickname;
|
||||
|
||||
@Override
|
||||
public boolean databaseExists() {
|
||||
// FIXME should not run on UiThread #620
|
||||
if (!dir.isDirectory()) return false;
|
||||
File[] files = dir.listFiles();
|
||||
return files != null && files.length > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDatabaseDirectory() {
|
||||
return dir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEncryptionKey(SecretKey key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLocalAuthorName(String nickname) {
|
||||
this.nickname = nickname;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getLocalAuthorName() {
|
||||
return nickname;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public SecretKey getEncryptionKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxSize() {
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
};
|
||||
DatabaseConfig databaseConfig = new AndroidDatabaseConfig(dir);
|
||||
return databaseConfig;
|
||||
}
|
||||
|
||||
@@ -204,4 +158,5 @@ public class AppModule {
|
||||
lifecycleManager.registerService(dozeWatchdog);
|
||||
return dozeWatchdog;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,9 +6,5 @@ package org.briarproject.briar.android;
|
||||
*/
|
||||
public interface BriarApplication {
|
||||
|
||||
// This build expires on 31 December 2018
|
||||
long EXPIRY_DATE = 1546214400 * 1000L;
|
||||
|
||||
AndroidComponent getApplicationComponent();
|
||||
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.logout.HideUiActivity;
|
||||
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
||||
import org.briarproject.briar.android.splash.SplashScreenActivity;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -44,6 +43,7 @@ import static android.os.Build.VERSION.SDK_INT;
|
||||
import static android.support.v4.app.NotificationCompat.CATEGORY_SERVICE;
|
||||
import static android.support.v4.app.NotificationCompat.PRIORITY_MIN;
|
||||
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
|
||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
|
||||
@@ -221,18 +221,52 @@ public class BriarService extends Service {
|
||||
public void onLowMemory() {
|
||||
super.onLowMemory();
|
||||
LOG.warning("Memory is low");
|
||||
// Clear the UI - this is done in onTrimMemory() if SDK_INT >= 16
|
||||
if (SDK_INT < 16) hideUi();
|
||||
}
|
||||
|
||||
private void shutdownFromBackground() {
|
||||
// Stop the service
|
||||
stopSelf();
|
||||
// Hide the UI
|
||||
@Override
|
||||
public void onTrimMemory(int level) {
|
||||
super.onTrimMemory(level);
|
||||
if (level == TRIM_MEMORY_UI_HIDDEN) {
|
||||
LOG.info("Trim memory: UI hidden");
|
||||
} else if (level == TRIM_MEMORY_BACKGROUND) {
|
||||
LOG.info("Trim memory: added to LRU list");
|
||||
} else if (level == TRIM_MEMORY_MODERATE) {
|
||||
LOG.info("Trim memory: near middle of LRU list");
|
||||
} else if (level == TRIM_MEMORY_COMPLETE) {
|
||||
LOG.info("Trim memory: near end of LRU list");
|
||||
} else if (SDK_INT >= 16) {
|
||||
if (level == TRIM_MEMORY_RUNNING_MODERATE) {
|
||||
LOG.info("Trim memory: running moderately low");
|
||||
} else if (level == TRIM_MEMORY_RUNNING_LOW) {
|
||||
LOG.info("Trim memory: running low");
|
||||
} else if (level == TRIM_MEMORY_RUNNING_CRITICAL) {
|
||||
LOG.info("Trim memory: running critically low");
|
||||
// Clear the UI to save some memory
|
||||
hideUi();
|
||||
} else if (LOG.isLoggable(INFO)) {
|
||||
LOG.info("Trim memory: unknown level " + level);
|
||||
}
|
||||
} else if (LOG.isLoggable(INFO)) {
|
||||
LOG.info("Trim memory: unknown level " + level);
|
||||
}
|
||||
}
|
||||
|
||||
private void hideUi() {
|
||||
Intent i = new Intent(this, HideUiActivity.class);
|
||||
i.addFlags(FLAG_ACTIVITY_NEW_TASK
|
||||
| FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
|
||||
| FLAG_ACTIVITY_NO_ANIMATION
|
||||
| FLAG_ACTIVITY_CLEAR_TASK);
|
||||
startActivity(i);
|
||||
}
|
||||
|
||||
private void shutdownFromBackground() {
|
||||
// Stop the service
|
||||
stopSelf();
|
||||
// Hide the UI
|
||||
hideUi();
|
||||
// Wait for shutdown to complete, then exit
|
||||
new Thread(() -> {
|
||||
try {
|
||||
@@ -245,25 +279,6 @@ public class BriarService extends Service {
|
||||
}).start();
|
||||
}
|
||||
|
||||
// TODO: Remove if low memory shutdowns are not appropriate
|
||||
private void showLowMemoryShutdownNotification() {
|
||||
androidExecutor.runOnUiThread(() -> {
|
||||
NotificationCompat.Builder b = new NotificationCompat.Builder(
|
||||
BriarService.this, FAILURE_CHANNEL_ID);
|
||||
b.setSmallIcon(android.R.drawable.stat_notify_error);
|
||||
b.setContentTitle(getText(
|
||||
R.string.low_memory_shutdown_notification_title));
|
||||
b.setContentText(getText(
|
||||
R.string.low_memory_shutdown_notification_text));
|
||||
Intent i = new Intent(this, SplashScreenActivity.class);
|
||||
b.setContentIntent(PendingIntent.getActivity(this, 0, i, 0));
|
||||
b.setAutoCancel(true);
|
||||
Object o = getSystemService(NOTIFICATION_SERVICE);
|
||||
NotificationManager nm = (NotificationManager) o;
|
||||
nm.notify(FAILURE_NOTIFICATION_ID, b.build());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for all services to start before returning.
|
||||
*/
|
||||
|
||||
@@ -14,7 +14,6 @@ import android.content.pm.Signature;
|
||||
import android.support.annotation.UiThread;
|
||||
|
||||
import org.briarproject.bramble.api.lifecycle.Service;
|
||||
import org.briarproject.bramble.api.lifecycle.ServiceException;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||
import org.briarproject.bramble.util.StringUtils;
|
||||
@@ -196,7 +195,7 @@ class ScreenFilterMonitorImpl implements ScreenFilterMonitor, Service {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startService() throws ServiceException {
|
||||
public void startService() {
|
||||
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||
androidExecutor.runOnUiThread(() -> {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
@@ -212,7 +211,7 @@ class ScreenFilterMonitorImpl implements ScreenFilterMonitor, Service {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopService() throws ServiceException {
|
||||
public void stopService() {
|
||||
androidExecutor.runOnUiThread(() -> {
|
||||
if (receiver != null) app.unregisterReceiver(receiver);
|
||||
});
|
||||
|
||||
@@ -33,4 +33,12 @@ public interface TestingConstants {
|
||||
* intentionally.
|
||||
*/
|
||||
boolean PREVENT_SCREENSHOTS = !IS_DEBUG_BUILD;
|
||||
|
||||
/**
|
||||
* Debug and beta builds expire after 90 days. Final release builds expire
|
||||
* after 292 million years.
|
||||
*/
|
||||
long EXPIRY_DATE = IS_DEBUG_BUILD || IS_BETA_BUILD ?
|
||||
BuildConfig.BuildTimestamp + 90 * 24 * 60 * 60 * 1000L :
|
||||
Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,27 @@
|
||||
package org.briarproject.briar.android.controller;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.support.v7.preference.PreferenceManager;
|
||||
|
||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.util.AndroidUtils;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
|
||||
@NotNullByDefault
|
||||
public class ConfigControllerImpl implements ConfigController {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ConfigControllerImpl.class.getName());
|
||||
|
||||
private static final String PREF_DB_KEY = "key";
|
||||
|
||||
private final SharedPreferences briarPrefs;
|
||||
@@ -23,39 +32,46 @@ public class ConfigControllerImpl implements ConfigController {
|
||||
DatabaseConfig databaseConfig) {
|
||||
this.briarPrefs = briarPrefs;
|
||||
this.databaseConfig = databaseConfig;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getEncryptedDatabaseKey() {
|
||||
return briarPrefs.getString(PREF_DB_KEY, null);
|
||||
String key = briarPrefs.getString(PREF_DB_KEY, null);
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Got database key from preferences: " + (key != null));
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressLint("ApplySharedPref")
|
||||
public void storeEncryptedDatabaseKey(String hex) {
|
||||
SharedPreferences.Editor editor = briarPrefs.edit();
|
||||
editor.putString(PREF_DB_KEY, hex);
|
||||
editor.apply();
|
||||
LOG.info("Storing database key in preferences");
|
||||
briarPrefs.edit().putString(PREF_DB_KEY, hex).commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAccount(Context ctx) {
|
||||
SharedPreferences.Editor editor = briarPrefs.edit();
|
||||
editor.clear();
|
||||
editor.apply();
|
||||
AndroidUtils.deleteAppData(ctx);
|
||||
LOG.info("Deleting account");
|
||||
SharedPreferences defaultPrefs =
|
||||
PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
AndroidUtils.deleteAppData(ctx, briarPrefs, defaultPrefs);
|
||||
AndroidUtils.logDataDirContents(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accountExists() {
|
||||
String hex = getEncryptedDatabaseKey();
|
||||
return hex != null && databaseConfig.databaseExists();
|
||||
boolean exists = hex != null && databaseConfig.databaseExists();
|
||||
if (LOG.isLoggable(INFO)) LOG.info("Account exists: " + exists);
|
||||
return exists;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accountSignedIn() {
|
||||
return databaseConfig.getEncryptionKey() != null;
|
||||
boolean signedIn = databaseConfig.getEncryptionKey() != null;
|
||||
if (LOG.isLoggable(INFO)) LOG.info("Signed in: " + signedIn);
|
||||
return signedIn;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,15 +8,21 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.bramble.util.StringUtils;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static android.view.inputmethod.EditorInfo.IME_ACTION_NEXT;
|
||||
import static android.view.inputmethod.EditorInfo.IME_ACTION_NONE;
|
||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||
import static org.briarproject.briar.android.util.UiUtils.setError;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class AuthorNameFragment extends SetupFragment {
|
||||
|
||||
private final static String TAG = AuthorNameFragment.class.getName();
|
||||
@@ -30,8 +36,9 @@ public class AuthorNameFragment extends SetupFragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
public View onCreateView(LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
getActivity().setTitle(getString(R.string.setup_title));
|
||||
View v = inflater.inflate(R.layout.fragment_setup_author_name,
|
||||
container, false);
|
||||
@@ -75,6 +82,7 @@ public class AuthorNameFragment extends SetupFragment {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
setupController.setAuthorName(authorNameInput.getText().toString());
|
||||
setupController.showPasswordFragment();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
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.ActivityComponent;
|
||||
import org.briarproject.briar.android.login.PowerView.OnCheckedChangedListener;
|
||||
@@ -21,7 +22,8 @@ import static android.view.View.VISIBLE;
|
||||
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING;
|
||||
import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog;
|
||||
|
||||
@NotNullByDefault
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class DozeFragment extends SetupFragment
|
||||
implements OnCheckedChangedListener {
|
||||
|
||||
|
||||
@@ -11,15 +11,21 @@ import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
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.ActivityComponent;
|
||||
import org.briarproject.briar.android.util.UiUtils;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static android.content.Context.INPUT_METHOD_SERVICE;
|
||||
import static android.view.View.INVISIBLE;
|
||||
import static android.view.View.VISIBLE;
|
||||
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class PasswordFragment extends SetupFragment {
|
||||
|
||||
private final static String TAG = PasswordFragment.class.getName();
|
||||
@@ -37,8 +43,9 @@ public class PasswordFragment extends SetupFragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
public View onCreateView(LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
getActivity().setTitle(getString(R.string.setup_password_intro));
|
||||
View v = inflater.inflate(R.layout.fragment_setup_password, container,
|
||||
false);
|
||||
@@ -105,16 +112,17 @@ public class PasswordFragment extends SetupFragment {
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (!setupController.needToShowDozeFragment()) {
|
||||
nextButton.setVisibility(INVISIBLE);
|
||||
progressBar.setVisibility(VISIBLE);
|
||||
}
|
||||
String password = passwordEntry.getText().toString();
|
||||
IBinder token = passwordEntry.getWindowToken();
|
||||
Object o = getContext().getSystemService(INPUT_METHOD_SERVICE);
|
||||
((InputMethodManager) o).hideSoftInputFromWindow(token, 0);
|
||||
setupController.setPassword(password);
|
||||
setupController.showDozeOrCreateAccount();
|
||||
setupController.setPassword(passwordEntry.getText().toString());
|
||||
if (setupController.needToShowDozeFragment()) {
|
||||
setupController.showDozeFragment();
|
||||
} else {
|
||||
nextButton.setVisibility(INVISIBLE);
|
||||
progressBar.setVisibility(VISIBLE);
|
||||
setupController.createAccount();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,30 +4,46 @@ import android.annotation.TargetApi;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
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.ActivityComponent;
|
||||
import org.briarproject.briar.android.activity.BaseActivity;
|
||||
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class SetupActivity extends BaseActivity
|
||||
implements BaseFragmentListener {
|
||||
|
||||
private static final String STATE_KEY_AUTHOR_NAME = "authorName";
|
||||
private static final String STATE_KEY_PASSWORD = "password";
|
||||
|
||||
@Inject
|
||||
SetupController setupController;
|
||||
|
||||
@Nullable
|
||||
private String authorName, password;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle state) {
|
||||
public void onCreate(@Nullable Bundle state) {
|
||||
super.onCreate(state);
|
||||
// fade-in after splash screen instead of default animation
|
||||
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
|
||||
setContentView(R.layout.activity_fragment_container);
|
||||
|
||||
if (state == null) {
|
||||
if (setupController.accountExists())
|
||||
throw new AssertionError();
|
||||
showInitialFragment(AuthorNameFragment.newInstance());
|
||||
} else {
|
||||
authorName = state.getString(STATE_KEY_AUTHOR_NAME);
|
||||
password = state.getString(STATE_KEY_PASSWORD);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,16 +53,46 @@ public class SetupActivity extends BaseActivity
|
||||
setupController.setSetupActivity(this);
|
||||
}
|
||||
|
||||
public void showPasswordFragment() {
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle state) {
|
||||
super.onSaveInstanceState(state);
|
||||
if (authorName != null)
|
||||
state.putString(STATE_KEY_AUTHOR_NAME, authorName);
|
||||
if (password != null)
|
||||
state.putString(STATE_KEY_PASSWORD, password);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
String getAuthorName() {
|
||||
return authorName;
|
||||
}
|
||||
|
||||
void setAuthorName(String authorName) {
|
||||
this.authorName = authorName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
void showPasswordFragment() {
|
||||
if (authorName == null) throw new IllegalStateException();
|
||||
showNextFragment(PasswordFragment.newInstance());
|
||||
}
|
||||
|
||||
@TargetApi(23)
|
||||
public void showDozeFragment() {
|
||||
void showDozeFragment() {
|
||||
if (authorName == null) throw new IllegalStateException();
|
||||
if (password == null) throw new IllegalStateException();
|
||||
showNextFragment(DozeFragment.newInstance());
|
||||
}
|
||||
|
||||
public void showApp() {
|
||||
void showApp() {
|
||||
Intent i = new Intent(this, OpenDatabaseActivity.class);
|
||||
i.setFlags(FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(i);
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package org.briarproject.briar.android.login;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.android.controller.handler.ResultHandler;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface SetupController {
|
||||
public interface SetupController extends PasswordController {
|
||||
|
||||
void setSetupActivity(SetupActivity setupActivity);
|
||||
|
||||
@@ -14,17 +13,20 @@ public interface SetupController {
|
||||
|
||||
void setPassword(String password);
|
||||
|
||||
float estimatePasswordStrength(String password);
|
||||
/**
|
||||
* This should be called after the author name has been set.
|
||||
*/
|
||||
void showPasswordFragment();
|
||||
|
||||
/**
|
||||
* This should be called after the author name and the password have been
|
||||
* set. It decides whether to ask for doze exception or create the account
|
||||
* right away.
|
||||
* set.
|
||||
*/
|
||||
void showDozeOrCreateAccount();
|
||||
void showDozeFragment();
|
||||
|
||||
/**
|
||||
* This should be called after the author name and the password have been
|
||||
* set.
|
||||
*/
|
||||
void createAccount();
|
||||
|
||||
void createAccount(ResultHandler<Void> resultHandler);
|
||||
|
||||
}
|
||||
|
||||
@@ -9,10 +9,12 @@ import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.util.AndroidUtils;
|
||||
import org.briarproject.briar.android.controller.handler.ResultHandler;
|
||||
import org.briarproject.briar.android.controller.handler.UiResultHandler;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@@ -20,10 +22,11 @@ import javax.inject.Inject;
|
||||
public class SetupControllerImpl extends PasswordControllerImpl
|
||||
implements SetupController {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(SetupControllerImpl.class.getName());
|
||||
|
||||
@Nullable
|
||||
private String authorName, password;
|
||||
@Nullable
|
||||
private SetupActivity setupActivity;
|
||||
private volatile SetupActivity setupActivity;
|
||||
|
||||
@Inject
|
||||
SetupControllerImpl(SharedPreferences briarPrefs,
|
||||
@@ -41,6 +44,7 @@ public class SetupControllerImpl extends PasswordControllerImpl
|
||||
|
||||
@Override
|
||||
public boolean needToShowDozeFragment() {
|
||||
SetupActivity setupActivity = this.setupActivity;
|
||||
if (setupActivity == null) throw new IllegalStateException();
|
||||
return DozeView.needsToBeShown(setupActivity) ||
|
||||
HuaweiView.needsToBeShown(setupActivity);
|
||||
@@ -48,28 +52,35 @@ public class SetupControllerImpl extends PasswordControllerImpl
|
||||
|
||||
@Override
|
||||
public void setAuthorName(String authorName) {
|
||||
this.authorName = authorName;
|
||||
SetupActivity setupActivity = this.setupActivity;
|
||||
if (setupActivity == null) throw new IllegalStateException();
|
||||
setupActivity.setAuthorName(authorName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPassword(String password) {
|
||||
SetupActivity setupActivity = this.setupActivity;
|
||||
if (setupActivity == null) throw new IllegalStateException();
|
||||
setupActivity.setPassword(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPasswordFragment() {
|
||||
SetupActivity setupActivity = this.setupActivity;
|
||||
if (setupActivity == null) throw new IllegalStateException();
|
||||
setupActivity.showPasswordFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showDozeOrCreateAccount() {
|
||||
public void showDozeFragment() {
|
||||
SetupActivity setupActivity = this.setupActivity;
|
||||
if (setupActivity == null) throw new IllegalStateException();
|
||||
if (needToShowDozeFragment()) {
|
||||
setupActivity.showDozeFragment();
|
||||
} else {
|
||||
createAccount();
|
||||
}
|
||||
setupActivity.showDozeFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createAccount() {
|
||||
SetupActivity setupActivity = this.setupActivity;
|
||||
UiResultHandler<Void> resultHandler =
|
||||
new UiResultHandler<Void>(setupActivity) {
|
||||
@Override
|
||||
@@ -82,16 +93,24 @@ public class SetupControllerImpl extends PasswordControllerImpl
|
||||
createAccount(resultHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createAccount(ResultHandler<Void> resultHandler) {
|
||||
if (authorName == null || password == null)
|
||||
throw new IllegalStateException();
|
||||
// Package access for testing
|
||||
void createAccount(ResultHandler<Void> resultHandler) {
|
||||
SetupActivity setupActivity = this.setupActivity;
|
||||
if (setupActivity == null) throw new IllegalStateException();
|
||||
String authorName = setupActivity.getAuthorName();
|
||||
if (authorName == null) throw new IllegalStateException();
|
||||
String password = setupActivity.getPassword();
|
||||
if (password == null) throw new IllegalStateException();
|
||||
cryptoExecutor.execute(() -> {
|
||||
LOG.info("Creating account");
|
||||
AndroidUtils.logDataDirContents(setupActivity);
|
||||
databaseConfig.setLocalAuthorName(authorName);
|
||||
SecretKey key = crypto.generateSecretKey();
|
||||
databaseConfig.setEncryptionKey(key);
|
||||
String hex = encryptDatabaseKey(key, password);
|
||||
storeEncryptedDatabaseKey(hex);
|
||||
LOG.info("Created account");
|
||||
AndroidUtils.logDataDirContents(setupActivity);
|
||||
resultHandler.onResult(null);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.briar.android.BriarApplication.EXPIRY_DATE;
|
||||
import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE;
|
||||
import static org.briarproject.briar.android.TestingConstants.IS_BETA_BUILD;
|
||||
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
|
||||
import static org.briarproject.briar.android.controller.BriarControllerImpl.DOZE_ASK_AGAIN;
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.support.v7.preference.PreferenceManager;
|
||||
import android.transition.Fade;
|
||||
|
||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||
import org.briarproject.bramble.util.AndroidUtils;
|
||||
import org.briarproject.briar.R;
|
||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||
import org.briarproject.briar.android.activity.BaseActivity;
|
||||
@@ -19,7 +20,7 @@ import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.briarproject.briar.android.BriarApplication.EXPIRY_DATE;
|
||||
import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE;
|
||||
|
||||
public class SplashScreenActivity extends BaseActivity {
|
||||
|
||||
@@ -44,9 +45,11 @@ public class SplashScreenActivity extends BaseActivity {
|
||||
setContentView(R.layout.splash);
|
||||
|
||||
if (configController.accountSignedIn()) {
|
||||
LOG.info("Already signed in, not showing splash screen");
|
||||
startActivity(new Intent(this, OpenDatabaseActivity.class));
|
||||
finish();
|
||||
} else {
|
||||
LOG.info("Showing splash screen");
|
||||
new Handler().postDelayed(() -> {
|
||||
startNextActivity();
|
||||
supportFinishAfterTransition();
|
||||
@@ -64,9 +67,12 @@ public class SplashScreenActivity extends BaseActivity {
|
||||
LOG.info("Expired");
|
||||
startActivity(new Intent(this, ExpiredActivity.class));
|
||||
} else {
|
||||
AndroidUtils.logDataDirContents(this);
|
||||
if (configController.accountExists()) {
|
||||
LOG.info("Account exists");
|
||||
startActivity(new Intent(this, OpenDatabaseActivity.class));
|
||||
} else {
|
||||
LOG.info("Account does not exist");
|
||||
configController.deleteAccount(this);
|
||||
startActivity(new Intent(this, SetupActivity.class));
|
||||
}
|
||||
@@ -74,8 +80,10 @@ public class SplashScreenActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
private void setPreferencesDefaults() {
|
||||
androidExecutor.runOnBackgroundThread(() ->
|
||||
PreferenceManager.setDefaultValues(SplashScreenActivity.this,
|
||||
R.xml.panic_preferences, false));
|
||||
androidExecutor.runOnBackgroundThread(() -> {
|
||||
PreferenceManager.setDefaultValues(SplashScreenActivity.this,
|
||||
R.xml.panic_preferences, false);
|
||||
LOG.info("Finished setting panic preference defaults");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
|
||||
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
|
||||
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
|
||||
import static org.briarproject.briar.BuildConfig.APPLICATION_ID;
|
||||
import static org.briarproject.briar.android.BriarApplication.EXPIRY_DATE;
|
||||
import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
|
||||
@@ -421,8 +421,4 @@
|
||||
<string name="permission_camera_denied_toast">Camera permission was not granted</string>
|
||||
<string name="qr_code">QR code</string>
|
||||
<string name="show_qr_code_fullscreen">Show QR code fullscreen</string>
|
||||
|
||||
<!-- Low Memory Notification -->
|
||||
<string name="low_memory_shutdown_notification_title">Signed out of Briar</string>
|
||||
<string name="low_memory_shutdown_notification_text">Signed out due to lack of memory.</string>
|
||||
</resources>
|
||||
|
||||
@@ -54,7 +54,8 @@ public class PasswordControllerImplTest extends BrambleMockTestCase {
|
||||
oneOf(briarPrefs).edit();
|
||||
will(returnValue(editor));
|
||||
oneOf(editor).putString("key", newEncryptedHex);
|
||||
oneOf(editor).apply();
|
||||
will(returnValue(editor));
|
||||
oneOf(editor).commit();
|
||||
}});
|
||||
|
||||
PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs,
|
||||
|
||||
@@ -73,7 +73,7 @@ public class PasswordFragmentTest {
|
||||
|
||||
// assert controller has been called properly
|
||||
verify(setupController, times(1)).setPassword(safePass);
|
||||
verify(setupController, times(1)).showDozeOrCreateAccount();
|
||||
verify(setupController, times(1)).createAccount();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -15,22 +15,8 @@ import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.NONE;
|
||||
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_STRONG;
|
||||
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK;
|
||||
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.STRONG;
|
||||
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.WEAK;
|
||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.timeout;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(sdk = 21, application = TestBriarApplication.class,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.briarproject.briar.android.login;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
|
||||
@@ -8,10 +9,13 @@ import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.ImmediateExecutor;
|
||||
import org.briarproject.bramble.test.TestUtils;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.lib.legacy.ClassImposteriser;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@@ -40,6 +44,7 @@ public class SetupControllerImplTest extends BrambleMockTestCase {
|
||||
private final String encryptedHex = "010203";
|
||||
private final byte[] encryptedBytes = new byte[] {1, 2, 3};
|
||||
private final SecretKey key = getSecretKey();
|
||||
private final File testDir = TestUtils.getTestDirectory();
|
||||
|
||||
public SetupControllerImplTest() {
|
||||
context.setImposteriser(ClassImposteriser.INSTANCE);
|
||||
@@ -47,10 +52,22 @@ public class SetupControllerImplTest extends BrambleMockTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
public void testCreateAccount() {
|
||||
context.checking(new Expectations() {{
|
||||
// Setting the author name shows the password fragment
|
||||
oneOf(setupActivity).showPasswordFragment();
|
||||
// Allow the contents of the data directory to be logged
|
||||
allowing(setupActivity).getApplicationInfo();
|
||||
will(returnValue(new ApplicationInfo() {{
|
||||
dataDir = testDir.getAbsolutePath();
|
||||
}}));
|
||||
// Set the author name and password
|
||||
oneOf(setupActivity).setAuthorName(authorName);
|
||||
oneOf(setupActivity).setPassword(password);
|
||||
// Get the author name and password
|
||||
oneOf(setupActivity).getAuthorName();
|
||||
will(returnValue(authorName));
|
||||
oneOf(setupActivity).getPassword();
|
||||
will(returnValue(password));
|
||||
// Generate a database key
|
||||
oneOf(crypto).generateSecretKey();
|
||||
will(returnValue(key));
|
||||
@@ -64,7 +81,8 @@ public class SetupControllerImplTest extends BrambleMockTestCase {
|
||||
oneOf(briarPrefs).edit();
|
||||
will(returnValue(editor));
|
||||
oneOf(editor).putString("key", encryptedHex);
|
||||
oneOf(editor).apply();
|
||||
will(returnValue(editor));
|
||||
oneOf(editor).commit();
|
||||
}});
|
||||
|
||||
SetupControllerImpl s = new SetupControllerImpl(briarPrefs,
|
||||
@@ -77,4 +95,9 @@ public class SetupControllerImplTest extends BrambleMockTestCase {
|
||||
s.createAccount(result -> called.set(true));
|
||||
assertTrue(called.get());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
TestUtils.deleteTestDirectory(testDir);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import org.briarproject.bramble.api.sync.SyncSessionFactory;
|
||||
import org.briarproject.bramble.api.transport.KeyManager;
|
||||
import org.briarproject.bramble.api.transport.StreamContext;
|
||||
import org.briarproject.bramble.api.transport.StreamReaderFactory;
|
||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
||||
import org.briarproject.bramble.contact.ContactModule;
|
||||
import org.briarproject.bramble.identity.IdentityModule;
|
||||
@@ -39,7 +40,6 @@ import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH;
|
||||
import static org.briarproject.bramble.test.TestPluginConfigModule.MAX_LATENCY;
|
||||
@@ -69,7 +69,6 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
|
||||
alice = DaggerSimplexMessagingIntegrationTestComponent.builder()
|
||||
.testDatabaseModule(new TestDatabaseModule(aliceDir)).build();
|
||||
injectEagerSingletons(alice);
|
||||
alice.inject(new SystemModule.EagerSingletons());
|
||||
bob = DaggerSimplexMessagingIntegrationTestComponent.builder()
|
||||
.testDatabaseModule(new TestDatabaseModule(bobDir)).build();
|
||||
injectEagerSingletons(bob);
|
||||
@@ -159,7 +158,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
|
||||
// Create a stream writer
|
||||
StreamWriterFactory streamWriterFactory =
|
||||
device.getStreamWriterFactory();
|
||||
OutputStream streamWriter =
|
||||
StreamWriter streamWriter =
|
||||
streamWriterFactory.createStreamWriter(out, ctx);
|
||||
// Create an outgoing sync session
|
||||
SyncSessionFactory syncSessionFactory = device.getSyncSessionFactory();
|
||||
@@ -167,7 +166,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
|
||||
contactId, MAX_LATENCY, streamWriter);
|
||||
// Write whatever needs to be written
|
||||
session.run();
|
||||
streamWriter.close();
|
||||
streamWriter.sendEndOfStream();
|
||||
// Return the contents of the stream
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.briarproject.bramble.api.sync.SyncSession;
|
||||
import org.briarproject.bramble.api.sync.SyncSessionFactory;
|
||||
import org.briarproject.bramble.api.sync.event.MessageStateChangedEvent;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||
import org.briarproject.bramble.contact.ContactModule;
|
||||
import org.briarproject.bramble.crypto.CryptoExecutorModule;
|
||||
import org.briarproject.bramble.identity.IdentityModule;
|
||||
@@ -340,9 +341,10 @@ public abstract class BriarIntegrationTest<C extends BriarIntegrationTestCompone
|
||||
LOG.info("TEST: Sending message from " + from + " to " + to);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamWriter streamWriter = new TestStreamWriter(out);
|
||||
// Create an outgoing sync session
|
||||
SyncSession sessionFrom =
|
||||
fromSync.createSimplexOutgoingSession(toId, MAX_LATENCY, out);
|
||||
SyncSession sessionFrom = fromSync.createSimplexOutgoingSession(toId,
|
||||
MAX_LATENCY, streamWriter);
|
||||
// Write whatever needs to be written
|
||||
sessionFrom.run();
|
||||
out.close();
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.briarproject.briar.test;
|
||||
|
||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
class TestStreamWriter implements StreamWriter {
|
||||
|
||||
private final OutputStream out;
|
||||
|
||||
TestStreamWriter(OutputStream out) {
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream() {
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendEndOfStream() throws IOException {
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user