mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 21:59:54 +01:00
Merge branch 'master' into '2277-activity-not-found-exception'
# Conflicts: # briar-android/src/main/java/org/briarproject/briar/android/conversation/ImageActivity.java
This commit is contained in:
@@ -32,13 +32,22 @@ class AndroidRemovableDrivePlugin extends RemovableDrivePlugin {
|
|||||||
InputStream openInputStream(TransportProperties p) throws IOException {
|
InputStream openInputStream(TransportProperties p) throws IOException {
|
||||||
String uri = p.get(PROP_URI);
|
String uri = p.get(PROP_URI);
|
||||||
if (isNullOrEmpty(uri)) throw new IllegalArgumentException();
|
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
|
@Override
|
||||||
OutputStream openOutputStream(TransportProperties p) throws IOException {
|
OutputStream openOutputStream(TransportProperties p) throws IOException {
|
||||||
String uri = p.get(PROP_URI);
|
String uri = p.get(PROP_URI);
|
||||||
if (isNullOrEmpty(uri)) throw new IllegalArgumentException();
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,10 +116,12 @@ class AndroidTaskScheduler implements TaskScheduler, Service, AlarmListener {
|
|||||||
long dueMillis = now + MILLISECONDS.convert(delay, unit);
|
long dueMillis = now + MILLISECONDS.convert(delay, unit);
|
||||||
Runnable wakeful = () ->
|
Runnable wakeful = () ->
|
||||||
wakeLockManager.executeWakefully(task, executor, "TaskHandoff");
|
wakeLockManager.executeWakefully(task, executor, "TaskHandoff");
|
||||||
Future<?> check = scheduleCheckForDueTasks(delay, unit);
|
// Acquire the lock before scheduling the check to ensure the check
|
||||||
ScheduledTask s = new ScheduledTask(wakeful, dueMillis, check,
|
// doesn't access the task queue before the task has been added
|
||||||
cancelled);
|
ScheduledTask s;
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
|
Future<?> check = scheduleCheckForDueTasks(delay, unit);
|
||||||
|
s = new ScheduledTask(wakeful, dueMillis, check, cancelled);
|
||||||
tasks.add(s);
|
tasks.add(s);
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
@@ -136,6 +138,7 @@ class AndroidTaskScheduler implements TaskScheduler, Service, AlarmListener {
|
|||||||
return schedule(wrapped, executor, delay, unit, cancelled);
|
return schedule(wrapped, executor, delay, unit, cancelled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
private Future<?> scheduleCheckForDueTasks(long delay, TimeUnit unit) {
|
private Future<?> scheduleCheckForDueTasks(long delay, TimeUnit unit) {
|
||||||
Runnable wakeful = () -> wakeLockManager.runWakefully(
|
Runnable wakeful = () -> wakeLockManager.runWakefully(
|
||||||
this::runDueTasks, "TaskScheduler");
|
this::runDueTasks, "TaskScheduler");
|
||||||
@@ -206,7 +209,7 @@ class AndroidTaskScheduler implements TaskScheduler, Service, AlarmListener {
|
|||||||
private final Future<?> check;
|
private final Future<?> check;
|
||||||
private final AtomicBoolean cancelled;
|
private final AtomicBoolean cancelled;
|
||||||
|
|
||||||
public ScheduledTask(Runnable task, long dueMillis,
|
private ScheduledTask(Runnable task, long dueMillis,
|
||||||
Future<?> check, AtomicBoolean cancelled) {
|
Future<?> check, AtomicBoolean cancelled) {
|
||||||
this.task = task;
|
this.task = task;
|
||||||
this.dueMillis = dueMillis;
|
this.dueMillis = dueMillis;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.briarproject.bramble.api.plugin;
|
package org.briarproject.bramble.api.plugin;
|
||||||
|
|
||||||
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
|
|
||||||
public interface TorConstants {
|
public interface TorConstants {
|
||||||
|
|
||||||
TransportId ID = new TransportId("org.briarproject.bramble.tor");
|
TransportId ID = new TransportId("org.briarproject.bramble.tor");
|
||||||
@@ -10,8 +12,9 @@ public interface TorConstants {
|
|||||||
int DEFAULT_SOCKS_PORT = 59050;
|
int DEFAULT_SOCKS_PORT = 59050;
|
||||||
int DEFAULT_CONTROL_PORT = 59051;
|
int DEFAULT_CONTROL_PORT = 59051;
|
||||||
|
|
||||||
int CONNECT_TO_PROXY_TIMEOUT = 5000; // Milliseconds
|
int CONNECT_TO_PROXY_TIMEOUT = (int) SECONDS.toMillis(5);
|
||||||
int EXTRA_SOCKET_TIMEOUT = 30000; // Milliseconds
|
int EXTRA_CONNECT_TIMEOUT = (int) SECONDS.toMillis(120);
|
||||||
|
int EXTRA_SOCKET_TIMEOUT = (int) SECONDS.toMillis(30);
|
||||||
|
|
||||||
// Local settings (not shared with contacts)
|
// Local settings (not shared with contacts)
|
||||||
String PREF_TOR_NETWORK = "network2";
|
String PREF_TOR_NETWORK = "network2";
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import dagger.Module;
|
|||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.plugin.TorConstants.CONNECT_TO_PROXY_TIMEOUT;
|
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;
|
import static org.briarproject.bramble.api.plugin.TorConstants.EXTRA_SOCKET_TIMEOUT;
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@@ -20,6 +21,6 @@ public class SocksModule {
|
|||||||
InetSocketAddress proxy = new InetSocketAddress("127.0.0.1",
|
InetSocketAddress proxy = new InetSocketAddress("127.0.0.1",
|
||||||
torSocksPort);
|
torSocksPort);
|
||||||
return new SocksSocketFactory(proxy, CONNECT_TO_PROXY_TIMEOUT,
|
return new SocksSocketFactory(proxy, CONNECT_TO_PROXY_TIMEOUT,
|
||||||
EXTRA_SOCKET_TIMEOUT);
|
EXTRA_CONNECT_TIMEOUT, EXTRA_SOCKET_TIMEOUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,15 +26,18 @@ class SocksSocket extends Socket {
|
|||||||
"Address type not supported"
|
"Address type not supported"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@SuppressWarnings("MismatchedReadAndWriteOfArray")
|
||||||
private static final byte[] UNSPECIFIED_ADDRESS = new byte[4];
|
private static final byte[] UNSPECIFIED_ADDRESS = new byte[4];
|
||||||
|
|
||||||
private final SocketAddress proxy;
|
private final SocketAddress proxy;
|
||||||
private final int connectToProxyTimeout, extraSocketTimeout;
|
private final int connectToProxyTimeout;
|
||||||
|
private final int extraConnectTimeout, extraSocketTimeout;
|
||||||
|
|
||||||
SocksSocket(SocketAddress proxy, int connectToProxyTimeout,
|
SocksSocket(SocketAddress proxy, int connectToProxyTimeout,
|
||||||
int extraSocketTimeout) {
|
int extraConnectTimeout, int extraSocketTimeout) {
|
||||||
this.proxy = proxy;
|
this.proxy = proxy;
|
||||||
this.connectToProxyTimeout = connectToProxyTimeout;
|
this.connectToProxyTimeout = connectToProxyTimeout;
|
||||||
|
this.extraConnectTimeout = extraConnectTimeout;
|
||||||
this.extraSocketTimeout = extraSocketTimeout;
|
this.extraSocketTimeout = extraSocketTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +69,7 @@ class SocksSocket extends Socket {
|
|||||||
|
|
||||||
// Use the supplied timeout temporarily, plus any configured extra
|
// Use the supplied timeout temporarily, plus any configured extra
|
||||||
int oldTimeout = getSoTimeout();
|
int oldTimeout = getSoTimeout();
|
||||||
setSoTimeout(timeout + extraSocketTimeout);
|
setSoTimeout(timeout + extraConnectTimeout);
|
||||||
|
|
||||||
// Connect to the endpoint via the proxy
|
// Connect to the endpoint via the proxy
|
||||||
sendConnectRequest(out, host, port);
|
sendConnectRequest(out, host, port);
|
||||||
|
|||||||
@@ -11,18 +11,21 @@ import javax.net.SocketFactory;
|
|||||||
class SocksSocketFactory extends SocketFactory {
|
class SocksSocketFactory extends SocketFactory {
|
||||||
|
|
||||||
private final SocketAddress proxy;
|
private final SocketAddress proxy;
|
||||||
private final int connectToProxyTimeout, extraSocketTimeout;
|
private final int connectToProxyTimeout;
|
||||||
|
private final int extraConnectTimeout, extraSocketTimeout;
|
||||||
|
|
||||||
SocksSocketFactory(SocketAddress proxy, int connectToProxyTimeout,
|
SocksSocketFactory(SocketAddress proxy, int connectToProxyTimeout,
|
||||||
int extraSocketTimeout) {
|
int extraConnectTimeout, int extraSocketTimeout) {
|
||||||
this.proxy = proxy;
|
this.proxy = proxy;
|
||||||
this.connectToProxyTimeout = connectToProxyTimeout;
|
this.connectToProxyTimeout = connectToProxyTimeout;
|
||||||
|
this.extraConnectTimeout = extraConnectTimeout;
|
||||||
this.extraSocketTimeout = extraSocketTimeout;
|
this.extraSocketTimeout = extraSocketTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Socket createSocket() {
|
public Socket createSocket() {
|
||||||
return new SocksSocket(proxy, connectToProxyTimeout, extraSocketTimeout);
|
return new SocksSocket(proxy, connectToProxyTimeout,
|
||||||
|
extraConnectTimeout, extraSocketTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -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.logDuration;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
import static org.briarproject.briar.android.attachment.media.ImageCompressor.MIME_TYPE;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class AttachmentCreationTask {
|
class AttachmentCreationTask {
|
||||||
@@ -100,14 +101,17 @@ class AttachmentCreationTask {
|
|||||||
if (!asList(getSupportedImageContentTypes()).contains(contentType)) {
|
if (!asList(getSupportedImageContentTypes()).contains(contentType)) {
|
||||||
throw new UnsupportedMimeTypeException(contentType, uri);
|
throw new UnsupportedMimeTypeException(contentType, uri);
|
||||||
}
|
}
|
||||||
InputStream is = contentResolver.openInputStream(uri);
|
InputStream is;
|
||||||
if (is == null) throw new IOException();
|
try {
|
||||||
is = imageCompressor
|
is = contentResolver.openInputStream(uri);
|
||||||
.compressImage(is, contentType);
|
if (is == null) throw new IOException();
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
is = imageCompressor.compressImage(is, contentType);
|
||||||
long timestamp = System.currentTimeMillis();
|
long timestamp = System.currentTimeMillis();
|
||||||
AttachmentHeader h = messagingManager
|
AttachmentHeader h = messagingManager.addLocalAttachment(groupId,
|
||||||
.addLocalAttachment(groupId, timestamp,
|
timestamp, MIME_TYPE, is);
|
||||||
ImageCompressor.MIME_TYPE, is);
|
|
||||||
tryToClose(is, LOG, WARNING);
|
tryToClose(is, LOG, WARNING);
|
||||||
logDuration(LOG, "Storing attachment", start);
|
logDuration(LOG, "Storing attachment", start);
|
||||||
return h;
|
return h;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.briar.android.conversation;
|
package org.briarproject.briar.android.conversation;
|
||||||
|
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.DialogInterface.OnClickListener;
|
import android.content.DialogInterface.OnClickListener;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@@ -259,7 +260,11 @@ public class ImageActivity extends BriarActivity
|
|||||||
if (SDK_INT >= 19) {
|
if (SDK_INT >= 19) {
|
||||||
String name = viewModel.getFileName() + "." +
|
String name = viewModel.getFileName() + "." +
|
||||||
getVisibleAttachment().getExtension();
|
getVisibleAttachment().getExtension();
|
||||||
requireNonNull(launcher).launch(name);
|
try {
|
||||||
|
requireNonNull(launcher).launch(name);
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
viewModel.onSaveImageError();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
viewModel.saveImage(getVisibleAttachment());
|
viewModel.saveImage(getVisibleAttachment());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,12 +180,17 @@ public class ImageViewModel extends DbViewModel implements EventListener {
|
|||||||
@UiThread
|
@UiThread
|
||||||
void saveImage(AttachmentItem attachment, @Nullable Uri uri) {
|
void saveImage(AttachmentItem attachment, @Nullable Uri uri) {
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
saveState.setEvent(true);
|
onSaveImageError();
|
||||||
} else {
|
} else {
|
||||||
saveImage(attachment, () -> getOutputStream(uri), null);
|
saveImage(attachment, () -> getOutputStream(uri), null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
void onSaveImageError() {
|
||||||
|
saveState.setEvent(true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the attachment on external storage,
|
* Saves the attachment on external storage,
|
||||||
* assuming the permission was granted during install time.
|
* assuming the permission was granted during install time.
|
||||||
|
|||||||
@@ -231,9 +231,14 @@ class SettingsViewModel extends DbViewModel implements EventListener {
|
|||||||
if (!asList(getSupportedImageContentTypes()).contains(contentType)) {
|
if (!asList(getSupportedImageContentTypes()).contains(contentType)) {
|
||||||
throw new UnsupportedMimeTypeException(contentType, uri);
|
throw new UnsupportedMimeTypeException(contentType, uri);
|
||||||
}
|
}
|
||||||
InputStream is = contentResolver.openInputStream(uri);
|
InputStream is;
|
||||||
if (is == null) throw new IOException(
|
try {
|
||||||
"ContentResolver returned null when opening InputStream");
|
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);
|
InputStream compressed = imageCompressor.compressImage(is, contentType);
|
||||||
|
|
||||||
runOnDbThread(() -> {
|
runOnDbThread(() -> {
|
||||||
|
|||||||
@@ -320,7 +320,7 @@
|
|||||||
<!-- Introductions -->
|
<!-- Introductions -->
|
||||||
|
|
||||||
<string name="introduction_onboarding_title">Introduce your contacts</string>
|
<string name="introduction_onboarding_title">Introduce your contacts</string>
|
||||||
<string name="introduction_onboarding_text">You can introduce your contacts to each other, so they don\'t need to meet in person to connect on Briar.</string>
|
<string name="introduction_onboarding_text">Introduce your contacts to each other so they can connect on Briar.</string>
|
||||||
<string name="introduction_menu_item">Make Introduction</string>
|
<string name="introduction_menu_item">Make Introduction</string>
|
||||||
<string name="introduction_activity_title">Select Contact</string>
|
<string name="introduction_activity_title">Select Contact</string>
|
||||||
<string name="introduction_not_possible">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.</string>
|
<string name="introduction_not_possible">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.</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user