diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/file/AndroidRemovableDrivePlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/file/AndroidRemovableDrivePlugin.java
index 3d038f145..6d325a02f 100644
--- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/file/AndroidRemovableDrivePlugin.java
+++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/file/AndroidRemovableDrivePlugin.java
@@ -32,13 +32,22 @@ class AndroidRemovableDrivePlugin extends RemovableDrivePlugin {
InputStream openInputStream(TransportProperties p) throws IOException {
String uri = p.get(PROP_URI);
if (isNullOrEmpty(uri)) throw new IllegalArgumentException();
- return app.getContentResolver().openInputStream(Uri.parse(uri));
+ try {
+ return app.getContentResolver().openInputStream(Uri.parse(uri));
+ } catch (SecurityException e) {
+ throw new IOException(e);
+ }
}
@Override
OutputStream openOutputStream(TransportProperties p) throws IOException {
String uri = p.get(PROP_URI);
if (isNullOrEmpty(uri)) throw new IllegalArgumentException();
- return app.getContentResolver().openOutputStream(Uri.parse(uri), "wt");
+ try {
+ return app.getContentResolver()
+ .openOutputStream(Uri.parse(uri), "wt");
+ } catch (SecurityException e) {
+ throw new IOException(e);
+ }
}
}
diff --git a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidTaskScheduler.java b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidTaskScheduler.java
index 639824991..fd0a89c13 100644
--- a/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidTaskScheduler.java
+++ b/bramble-android/src/main/java/org/briarproject/bramble/system/AndroidTaskScheduler.java
@@ -116,10 +116,12 @@ class AndroidTaskScheduler implements TaskScheduler, Service, AlarmListener {
long dueMillis = now + MILLISECONDS.convert(delay, unit);
Runnable wakeful = () ->
wakeLockManager.executeWakefully(task, executor, "TaskHandoff");
- Future> check = scheduleCheckForDueTasks(delay, unit);
- ScheduledTask s = new ScheduledTask(wakeful, dueMillis, check,
- cancelled);
+ // Acquire the lock before scheduling the check to ensure the check
+ // doesn't access the task queue before the task has been added
+ ScheduledTask s;
synchronized (lock) {
+ Future> check = scheduleCheckForDueTasks(delay, unit);
+ s = new ScheduledTask(wakeful, dueMillis, check, cancelled);
tasks.add(s);
}
return s;
@@ -136,6 +138,7 @@ class AndroidTaskScheduler implements TaskScheduler, Service, AlarmListener {
return schedule(wrapped, executor, delay, unit, cancelled);
}
+ @GuardedBy("lock")
private Future> scheduleCheckForDueTasks(long delay, TimeUnit unit) {
Runnable wakeful = () -> wakeLockManager.runWakefully(
this::runDueTasks, "TaskScheduler");
@@ -206,7 +209,7 @@ class AndroidTaskScheduler implements TaskScheduler, Service, AlarmListener {
private final Future> check;
private final AtomicBoolean cancelled;
- public ScheduledTask(Runnable task, long dueMillis,
+ private ScheduledTask(Runnable task, long dueMillis,
Future> check, AtomicBoolean cancelled) {
this.task = task;
this.dueMillis = dueMillis;
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/TorConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/TorConstants.java
index c94fc6755..10e9c557d 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/TorConstants.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/TorConstants.java
@@ -1,5 +1,7 @@
package org.briarproject.bramble.api.plugin;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
public interface TorConstants {
TransportId ID = new TransportId("org.briarproject.bramble.tor");
@@ -10,8 +12,9 @@ public interface TorConstants {
int DEFAULT_SOCKS_PORT = 59050;
int DEFAULT_CONTROL_PORT = 59051;
- int CONNECT_TO_PROXY_TIMEOUT = 5000; // Milliseconds
- int EXTRA_SOCKET_TIMEOUT = 30000; // Milliseconds
+ int CONNECT_TO_PROXY_TIMEOUT = (int) SECONDS.toMillis(5);
+ int EXTRA_CONNECT_TIMEOUT = (int) SECONDS.toMillis(120);
+ int EXTRA_SOCKET_TIMEOUT = (int) SECONDS.toMillis(30);
// Local settings (not shared with contacts)
String PREF_TOR_NETWORK = "network2";
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksModule.java b/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksModule.java
index c74666884..5d4d7939c 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksModule.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksModule.java
@@ -10,6 +10,7 @@ import dagger.Module;
import dagger.Provides;
import static org.briarproject.bramble.api.plugin.TorConstants.CONNECT_TO_PROXY_TIMEOUT;
+import static org.briarproject.bramble.api.plugin.TorConstants.EXTRA_CONNECT_TIMEOUT;
import static org.briarproject.bramble.api.plugin.TorConstants.EXTRA_SOCKET_TIMEOUT;
@Module
@@ -20,6 +21,6 @@ public class SocksModule {
InetSocketAddress proxy = new InetSocketAddress("127.0.0.1",
torSocksPort);
return new SocksSocketFactory(proxy, CONNECT_TO_PROXY_TIMEOUT,
- EXTRA_SOCKET_TIMEOUT);
+ EXTRA_CONNECT_TIMEOUT, EXTRA_SOCKET_TIMEOUT);
}
}
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksSocket.java b/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksSocket.java
index a254026ef..e7b15786e 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksSocket.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksSocket.java
@@ -26,15 +26,18 @@ class SocksSocket extends Socket {
"Address type not supported"
};
+ @SuppressWarnings("MismatchedReadAndWriteOfArray")
private static final byte[] UNSPECIFIED_ADDRESS = new byte[4];
private final SocketAddress proxy;
- private final int connectToProxyTimeout, extraSocketTimeout;
+ private final int connectToProxyTimeout;
+ private final int extraConnectTimeout, extraSocketTimeout;
SocksSocket(SocketAddress proxy, int connectToProxyTimeout,
- int extraSocketTimeout) {
+ int extraConnectTimeout, int extraSocketTimeout) {
this.proxy = proxy;
this.connectToProxyTimeout = connectToProxyTimeout;
+ this.extraConnectTimeout = extraConnectTimeout;
this.extraSocketTimeout = extraSocketTimeout;
}
@@ -66,7 +69,7 @@ class SocksSocket extends Socket {
// Use the supplied timeout temporarily, plus any configured extra
int oldTimeout = getSoTimeout();
- setSoTimeout(timeout + extraSocketTimeout);
+ setSoTimeout(timeout + extraConnectTimeout);
// Connect to the endpoint via the proxy
sendConnectRequest(out, host, port);
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksSocketFactory.java b/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksSocketFactory.java
index fb0b1cd91..6f1edc8a0 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksSocketFactory.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/socks/SocksSocketFactory.java
@@ -11,18 +11,21 @@ import javax.net.SocketFactory;
class SocksSocketFactory extends SocketFactory {
private final SocketAddress proxy;
- private final int connectToProxyTimeout, extraSocketTimeout;
+ private final int connectToProxyTimeout;
+ private final int extraConnectTimeout, extraSocketTimeout;
SocksSocketFactory(SocketAddress proxy, int connectToProxyTimeout,
- int extraSocketTimeout) {
+ int extraConnectTimeout, int extraSocketTimeout) {
this.proxy = proxy;
this.connectToProxyTimeout = connectToProxyTimeout;
+ this.extraConnectTimeout = extraConnectTimeout;
this.extraSocketTimeout = extraSocketTimeout;
}
@Override
public Socket createSocket() {
- return new SocksSocket(proxy, connectToProxyTimeout, extraSocketTimeout);
+ return new SocksSocket(proxy, connectToProxyTimeout,
+ extraConnectTimeout, extraSocketTimeout);
}
@Override
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentCreationTask.java b/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentCreationTask.java
index f9dd759b4..f2451de10 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentCreationTask.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/attachment/AttachmentCreationTask.java
@@ -26,6 +26,7 @@ import static org.briarproject.bramble.util.IoUtils.tryToClose;
import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now;
+import static org.briarproject.briar.android.attachment.media.ImageCompressor.MIME_TYPE;
@NotNullByDefault
class AttachmentCreationTask {
@@ -100,14 +101,17 @@ class AttachmentCreationTask {
if (!asList(getSupportedImageContentTypes()).contains(contentType)) {
throw new UnsupportedMimeTypeException(contentType, uri);
}
- InputStream is = contentResolver.openInputStream(uri);
- if (is == null) throw new IOException();
- is = imageCompressor
- .compressImage(is, contentType);
+ InputStream is;
+ try {
+ is = contentResolver.openInputStream(uri);
+ if (is == null) throw new IOException();
+ } catch (SecurityException e) {
+ throw new IOException(e);
+ }
+ is = imageCompressor.compressImage(is, contentType);
long timestamp = System.currentTimeMillis();
- AttachmentHeader h = messagingManager
- .addLocalAttachment(groupId, timestamp,
- ImageCompressor.MIME_TYPE, is);
+ AttachmentHeader h = messagingManager.addLocalAttachment(groupId,
+ timestamp, MIME_TYPE, is);
tryToClose(is, LOG, WARNING);
logDuration(LOG, "Storing attachment", start);
return h;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageActivity.java
index 46bbfabf2..67db6804a 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageActivity.java
@@ -1,5 +1,6 @@
package org.briarproject.briar.android.conversation;
+import android.content.ActivityNotFoundException;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.net.Uri;
@@ -259,7 +260,11 @@ public class ImageActivity extends BriarActivity
if (SDK_INT >= 19) {
String name = viewModel.getFileName() + "." +
getVisibleAttachment().getExtension();
- requireNonNull(launcher).launch(name);
+ try {
+ requireNonNull(launcher).launch(name);
+ } catch (ActivityNotFoundException e) {
+ viewModel.onSaveImageError();
+ }
} else {
viewModel.saveImage(getVisibleAttachment());
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageViewModel.java
index 823151fca..b8a7ff902 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageViewModel.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageViewModel.java
@@ -180,12 +180,17 @@ public class ImageViewModel extends DbViewModel implements EventListener {
@UiThread
void saveImage(AttachmentItem attachment, @Nullable Uri uri) {
if (uri == null) {
- saveState.setEvent(true);
+ onSaveImageError();
} else {
saveImage(attachment, () -> getOutputStream(uri), null);
}
}
+ @UiThread
+ void onSaveImageError() {
+ saveState.setEvent(true);
+ }
+
/**
* Saves the attachment on external storage,
* assuming the permission was granted during install time.
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsViewModel.java
index 694460934..df1788712 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsViewModel.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsViewModel.java
@@ -231,9 +231,14 @@ class SettingsViewModel extends DbViewModel implements EventListener {
if (!asList(getSupportedImageContentTypes()).contains(contentType)) {
throw new UnsupportedMimeTypeException(contentType, uri);
}
- InputStream is = contentResolver.openInputStream(uri);
- if (is == null) throw new IOException(
- "ContentResolver returned null when opening InputStream");
+ InputStream is;
+ try {
+ is = contentResolver.openInputStream(uri);
+ if (is == null) throw new IOException(
+ "ContentResolver returned null when opening InputStream");
+ } catch (SecurityException e) {
+ throw new IOException(e);
+ }
InputStream compressed = imageCompressor.compressImage(is, contentType);
runOnDbThread(() -> {
diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml
index eb97d2ba0..f3d2ec0ab 100644
--- a/briar-android/src/main/res/values/strings.xml
+++ b/briar-android/src/main/res/values/strings.xml
@@ -320,7 +320,7 @@
Introduce your contacts
- You can introduce your contacts to each other, so they don\'t need to meet in person to connect on Briar.
+ Introduce your contacts to each other so they can connect on Briar.
Make Introduction
Select Contact
You already have one introduction in progress with these contacts. Please allow for this to finish first. If you or your contacts are rarely online, this can take some time.