mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Compare commits
6 Commits
network-lo
...
bluetooth-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbb65ec807 | ||
|
|
53b38d83e8 | ||
|
|
692db742cf | ||
|
|
5b177c9901 | ||
|
|
c00bf2b2cd | ||
|
|
55150fe02a |
@@ -21,6 +21,8 @@ import org.briarproject.bramble.util.AndroidUtils;
|
|||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
@@ -37,7 +39,16 @@ import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERA
|
|||||||
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE;
|
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE;
|
||||||
import static android.bluetooth.BluetoothAdapter.STATE_OFF;
|
import static android.bluetooth.BluetoothAdapter.STATE_OFF;
|
||||||
import static android.bluetooth.BluetoothAdapter.STATE_ON;
|
import static android.bluetooth.BluetoothAdapter.STATE_ON;
|
||||||
|
import static android.bluetooth.BluetoothDevice.ACTION_BOND_STATE_CHANGED;
|
||||||
|
import static android.bluetooth.BluetoothDevice.BOND_BONDED;
|
||||||
|
import static android.bluetooth.BluetoothDevice.BOND_BONDING;
|
||||||
|
import static android.bluetooth.BluetoothDevice.BOND_NONE;
|
||||||
|
import static android.bluetooth.BluetoothDevice.EXTRA_BOND_STATE;
|
||||||
|
import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
|
||||||
|
import static android.bluetooth.BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE;
|
||||||
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -55,10 +66,12 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
|||||||
// Non-null if the plugin started successfully
|
// Non-null if the plugin started successfully
|
||||||
private volatile BluetoothAdapter adapter = null;
|
private volatile BluetoothAdapter adapter = null;
|
||||||
|
|
||||||
AndroidBluetoothPlugin(Executor ioExecutor, AndroidExecutor androidExecutor,
|
AndroidBluetoothPlugin(BluetoothConnectionManager connectionManager,
|
||||||
|
Executor ioExecutor, AndroidExecutor androidExecutor,
|
||||||
Context appContext, SecureRandom secureRandom, Backoff backoff,
|
Context appContext, SecureRandom secureRandom, Backoff backoff,
|
||||||
DuplexPluginCallback callback, int maxLatency) {
|
DuplexPluginCallback callback, int maxLatency) {
|
||||||
super(ioExecutor, secureRandom, backoff, callback, maxLatency);
|
super(connectionManager, ioExecutor, secureRandom, backoff, callback,
|
||||||
|
maxLatency);
|
||||||
this.androidExecutor = androidExecutor;
|
this.androidExecutor = androidExecutor;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
}
|
}
|
||||||
@@ -70,6 +83,7 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
|||||||
IntentFilter filter = new IntentFilter();
|
IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(ACTION_STATE_CHANGED);
|
filter.addAction(ACTION_STATE_CHANGED);
|
||||||
filter.addAction(ACTION_SCAN_MODE_CHANGED);
|
filter.addAction(ACTION_SCAN_MODE_CHANGED);
|
||||||
|
filter.addAction(ACTION_BOND_STATE_CHANGED);
|
||||||
receiver = new BluetoothStateReceiver();
|
receiver = new BluetoothStateReceiver();
|
||||||
appContext.registerReceiver(receiver, filter);
|
appContext.registerReceiver(receiver, filter);
|
||||||
}
|
}
|
||||||
@@ -154,7 +168,8 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private DuplexTransportConnection wrapSocket(BluetoothSocket s) {
|
private DuplexTransportConnection wrapSocket(BluetoothSocket s) {
|
||||||
return new AndroidBluetoothTransportConnection(this, s);
|
return new AndroidBluetoothTransportConnection(this,
|
||||||
|
connectionManager, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -165,6 +180,17 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
|||||||
@Override
|
@Override
|
||||||
DuplexTransportConnection connectTo(String address, String uuid)
|
DuplexTransportConnection connectTo(String address, String uuid)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
if (LOG.isLoggable(INFO)) {
|
||||||
|
boolean found = false;
|
||||||
|
List<String> addresses = new ArrayList<>();
|
||||||
|
for (BluetoothDevice d : adapter.getBondedDevices()) {
|
||||||
|
addresses.add(scrubMacAddress(d.getAddress()));
|
||||||
|
if (d.getAddress().equals(address)) found = true;
|
||||||
|
}
|
||||||
|
LOG.info("Bonded devices: " + addresses);
|
||||||
|
if (found) LOG.info("Connecting to bonded device");
|
||||||
|
else LOG.info("Connecting to unbonded device");
|
||||||
|
}
|
||||||
BluetoothDevice d = adapter.getRemoteDevice(address);
|
BluetoothDevice d = adapter.getRemoteDevice(address);
|
||||||
UUID u = UUID.fromString(uuid);
|
UUID u = UUID.fromString(uuid);
|
||||||
BluetoothSocket s = null;
|
BluetoothSocket s = null;
|
||||||
@@ -190,16 +216,42 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context ctx, Intent intent) {
|
public void onReceive(Context ctx, Intent intent) {
|
||||||
int state = intent.getIntExtra(EXTRA_STATE, 0);
|
String action = intent.getAction();
|
||||||
if (state == STATE_ON) onAdapterEnabled();
|
if (ACTION_STATE_CHANGED.equals(action)) {
|
||||||
else if (state == STATE_OFF) onAdapterDisabled();
|
int state = intent.getIntExtra(EXTRA_STATE, 0);
|
||||||
int scanMode = intent.getIntExtra(EXTRA_SCAN_MODE, 0);
|
if (state == STATE_ON) onAdapterEnabled();
|
||||||
if (scanMode == SCAN_MODE_NONE) {
|
else if (state == STATE_OFF) onAdapterDisabled();
|
||||||
LOG.info("Scan mode: None");
|
} else if (ACTION_SCAN_MODE_CHANGED.equals(action)) {
|
||||||
} else if (scanMode == SCAN_MODE_CONNECTABLE) {
|
int scanMode = intent.getIntExtra(EXTRA_SCAN_MODE, 0);
|
||||||
LOG.info("Scan mode: Connectable");
|
if (scanMode == SCAN_MODE_NONE) {
|
||||||
} else if (scanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
|
LOG.info("Scan mode: None");
|
||||||
LOG.info("Scan mode: Discoverable");
|
} else if (scanMode == SCAN_MODE_CONNECTABLE) {
|
||||||
|
LOG.info("Scan mode: Connectable");
|
||||||
|
} else if (scanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
|
||||||
|
LOG.info("Scan mode: Discoverable");
|
||||||
|
}
|
||||||
|
} else if (ACTION_BOND_STATE_CHANGED.equals(action)) {
|
||||||
|
BluetoothDevice d = intent.getParcelableExtra(EXTRA_DEVICE);
|
||||||
|
if (LOG.isLoggable(INFO)) {
|
||||||
|
LOG.info("Bond state changed for "
|
||||||
|
+ scrubMacAddress(d.getAddress()));
|
||||||
|
}
|
||||||
|
int oldState = intent.getIntExtra(EXTRA_PREVIOUS_BOND_STATE, 0);
|
||||||
|
if (oldState == BOND_NONE) {
|
||||||
|
LOG.info("Old state: none");
|
||||||
|
} else if (oldState == BOND_BONDING) {
|
||||||
|
LOG.info("Old state: bonding");
|
||||||
|
} else if (oldState == BOND_BONDED) {
|
||||||
|
LOG.info("Old state: bonded");
|
||||||
|
}
|
||||||
|
int state = intent.getIntExtra(EXTRA_BOND_STATE, 0);
|
||||||
|
if (state == BOND_NONE) {
|
||||||
|
LOG.info("New state: none");
|
||||||
|
} else if (state == BOND_BONDING) {
|
||||||
|
LOG.info("New state: bonding");
|
||||||
|
} else if (state == BOND_BONDED) {
|
||||||
|
LOG.info("New state: bonded");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,11 +59,13 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
||||||
|
BluetoothConnectionManager connectionManager =
|
||||||
|
new BluetoothConnectionManagerImpl();
|
||||||
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(ioExecutor,
|
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(
|
||||||
androidExecutor, appContext, secureRandom, backoff, callback,
|
connectionManager, ioExecutor, androidExecutor, appContext,
|
||||||
MAX_LATENCY);
|
secureRandom, backoff, callback, MAX_LATENCY);
|
||||||
eventBus.addListener(plugin);
|
eventBus.addListener(plugin);
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,14 @@ import java.io.OutputStream;
|
|||||||
class AndroidBluetoothTransportConnection
|
class AndroidBluetoothTransportConnection
|
||||||
extends AbstractDuplexTransportConnection {
|
extends AbstractDuplexTransportConnection {
|
||||||
|
|
||||||
|
private final BluetoothConnectionManager connectionManager;
|
||||||
private final BluetoothSocket socket;
|
private final BluetoothSocket socket;
|
||||||
|
|
||||||
AndroidBluetoothTransportConnection(Plugin plugin, BluetoothSocket socket) {
|
AndroidBluetoothTransportConnection(Plugin plugin,
|
||||||
|
BluetoothConnectionManager connectionManager,
|
||||||
|
BluetoothSocket socket) {
|
||||||
super(plugin);
|
super(plugin);
|
||||||
|
this.connectionManager = connectionManager;
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +37,10 @@ class AndroidBluetoothTransportConnection
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void closeConnection(boolean exception) throws IOException {
|
protected void closeConnection(boolean exception) throws IOException {
|
||||||
socket.close();
|
try {
|
||||||
|
socket.close();
|
||||||
|
} finally {
|
||||||
|
connectionManager.connectionClosed(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import android.content.Intent;
|
|||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Backoff;
|
import org.briarproject.bramble.api.plugin.Backoff;
|
||||||
@@ -20,15 +19,10 @@ import javax.annotation.Nullable;
|
|||||||
import static android.content.Context.CONNECTIVITY_SERVICE;
|
import static android.content.Context.CONNECTIVITY_SERVICE;
|
||||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
||||||
import static android.net.ConnectivityManager.TYPE_WIFI;
|
import static android.net.ConnectivityManager.TYPE_WIFI;
|
||||||
import static android.net.wifi.WifiManager.EXTRA_WIFI_STATE;
|
|
||||||
import static java.util.logging.Level.INFO;
|
|
||||||
import static org.briarproject.bramble.util.AndroidUtils.logNetworkState;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class AndroidLanTcpPlugin extends LanTcpPlugin {
|
class AndroidLanTcpPlugin extends LanTcpPlugin {
|
||||||
|
|
||||||
private static final String WIFI_AP_STATE_ACTION =
|
|
||||||
"android.net.wifi.WIFI_AP_STATE_CHANGED";
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(AndroidLanTcpPlugin.class.getName());
|
Logger.getLogger(AndroidLanTcpPlugin.class.getName());
|
||||||
|
|
||||||
@@ -50,11 +44,8 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
running = true;
|
running = true;
|
||||||
// Register to receive network status events
|
// Register to receive network status events
|
||||||
networkStateReceiver = new NetworkStateReceiver();
|
networkStateReceiver = new NetworkStateReceiver();
|
||||||
IntentFilter filter = new IntentFilter();
|
IntentFilter filter = new IntentFilter(CONNECTIVITY_ACTION);
|
||||||
filter.addAction(CONNECTIVITY_ACTION);
|
|
||||||
filter.addAction(WIFI_AP_STATE_ACTION);
|
|
||||||
appContext.registerReceiver(networkStateReceiver, filter);
|
appContext.registerReceiver(networkStateReceiver, filter);
|
||||||
if (LOG.isLoggable(INFO)) logNetworkState(appContext, LOG);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -70,27 +61,10 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context ctx, Intent i) {
|
public void onReceive(Context ctx, Intent i) {
|
||||||
if (!running) return;
|
if (!running) return;
|
||||||
if (LOG.isLoggable(INFO)) {
|
|
||||||
if (CONNECTIVITY_ACTION.equals(i.getAction())) {
|
|
||||||
LOG.info("Connectivity change");
|
|
||||||
Bundle extras = i.getExtras();
|
|
||||||
if (extras != null) {
|
|
||||||
LOG.info("Extras:");
|
|
||||||
for (String key : extras.keySet())
|
|
||||||
LOG.info("\t" + key + ": " + extras.get(key));
|
|
||||||
}
|
|
||||||
} else if (WIFI_AP_STATE_ACTION.equals(i.getAction())) {
|
|
||||||
int state = i.getIntExtra(EXTRA_WIFI_STATE, 0);
|
|
||||||
if (state == 13) LOG.info("Wifi AP enabled");
|
|
||||||
else LOG.info("Wifi AP state " + state);
|
|
||||||
}
|
|
||||||
logNetworkState(appContext, LOG);
|
|
||||||
}
|
|
||||||
Object o = ctx.getSystemService(CONNECTIVITY_SERVICE);
|
Object o = ctx.getSystemService(CONNECTIVITY_SERVICE);
|
||||||
ConnectivityManager cm = (ConnectivityManager) o;
|
ConnectivityManager cm = (ConnectivityManager) o;
|
||||||
NetworkInfo net = cm.getActiveNetworkInfo();
|
NetworkInfo net = cm.getActiveNetworkInfo();
|
||||||
if (net != null && net.getType() == TYPE_WIFI
|
if (net != null && net.getType() == TYPE_WIFI && net.isConnected()) {
|
||||||
&& net.isConnected()) {
|
|
||||||
LOG.info("Connected to Wi-Fi");
|
LOG.info("Connected to Wi-Fi");
|
||||||
if (socket == null || socket.isClosed()) bind();
|
if (socket == null || socket.isClosed()) bind();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -716,7 +716,8 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
boolean online = net != null && net.isConnected();
|
boolean online = net != null && net.isConnected();
|
||||||
boolean wifi = online && net.getType() == TYPE_WIFI;
|
boolean wifi = online && net.getType() == TYPE_WIFI;
|
||||||
String country = locationUtils.getCurrentCountry();
|
String country = locationUtils.getCurrentCountry();
|
||||||
boolean blocked = TorNetworkMetadata.isTorProbablyBlocked(country);
|
boolean blocked = TorNetworkMetadata.isTorProbablyBlocked(
|
||||||
|
country);
|
||||||
Settings s = callback.getSettings();
|
Settings s = callback.getSettings();
|
||||||
int network = s.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_ALWAYS);
|
int network = s.getInt(PREF_TOR_NETWORK, PREF_TOR_NETWORK_ALWAYS);
|
||||||
|
|
||||||
|
|||||||
@@ -1,41 +1,18 @@
|
|||||||
package org.briarproject.bramble.util;
|
package org.briarproject.bramble.util;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.net.Network;
|
|
||||||
import android.net.NetworkInfo;
|
|
||||||
import android.net.wifi.WifiInfo;
|
|
||||||
import android.net.wifi.WifiManager;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.InterfaceAddress;
|
|
||||||
import java.net.NetworkInterface;
|
|
||||||
import java.net.SocketException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import static android.content.Context.CONNECTIVITY_SERVICE;
|
|
||||||
import static android.content.Context.MODE_PRIVATE;
|
import static android.content.Context.MODE_PRIVATE;
|
||||||
import static android.content.Context.WIFI_SERVICE;
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static java.net.NetworkInterface.getNetworkInterfaces;
|
|
||||||
import static java.util.Collections.list;
|
|
||||||
import static java.util.logging.Level.INFO;
|
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
import static org.briarproject.bramble.util.StringUtils.ipToString;
|
|
||||||
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
|
||||||
|
|
||||||
@SuppressLint("HardwareIds")
|
|
||||||
public class AndroidUtils {
|
public class AndroidUtils {
|
||||||
|
|
||||||
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
|
// Fake Bluetooth address returned by BluetoothAdapter on API 23 and later
|
||||||
@@ -46,7 +23,7 @@ public class AndroidUtils {
|
|||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public static Collection<String> getSupportedArchitectures() {
|
public static Collection<String> getSupportedArchitectures() {
|
||||||
List<String> abis = new ArrayList<>();
|
List<String> abis = new ArrayList<>();
|
||||||
if (SDK_INT >= 21) {
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS));
|
abis.addAll(Arrays.asList(Build.SUPPORTED_ABIS));
|
||||||
} else {
|
} else {
|
||||||
abis.add(Build.CPU_ABI);
|
abis.add(Build.CPU_ABI);
|
||||||
@@ -90,123 +67,4 @@ public class AndroidUtils {
|
|||||||
public static File getReportDir(Context ctx) {
|
public static File getReportDir(Context ctx) {
|
||||||
return ctx.getDir(STORED_REPORTS, MODE_PRIVATE);
|
return ctx.getDir(STORED_REPORTS, MODE_PRIVATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void logNetworkState(Context ctx, Logger logger) {
|
|
||||||
if (!logger.isLoggable(INFO)) return;
|
|
||||||
|
|
||||||
Object o = ctx.getSystemService(CONNECTIVITY_SERVICE);
|
|
||||||
if (o == null) throw new AssertionError();
|
|
||||||
ConnectivityManager cm = (ConnectivityManager) o;
|
|
||||||
o = ctx.getApplicationContext().getSystemService(WIFI_SERVICE);
|
|
||||||
if (o == null) throw new AssertionError();
|
|
||||||
WifiManager wm = (WifiManager) o;
|
|
||||||
|
|
||||||
StringBuilder s = new StringBuilder();
|
|
||||||
logWifiInfo(s, wm.getConnectionInfo());
|
|
||||||
logNetworkInfo(s, cm.getActiveNetworkInfo(), true);
|
|
||||||
if (SDK_INT >= 21) {
|
|
||||||
for (Network network : cm.getAllNetworks())
|
|
||||||
logNetworkInfo(s, cm.getNetworkInfo(network), false);
|
|
||||||
} else {
|
|
||||||
for (NetworkInfo info : cm.getAllNetworkInfo())
|
|
||||||
logNetworkInfo(s, info, false);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
for (NetworkInterface iface : list(getNetworkInterfaces()))
|
|
||||||
logNetworkInterface(s, iface);
|
|
||||||
} catch (SocketException e) {
|
|
||||||
logger.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
logger.log(INFO, s.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void logWifiInfo(StringBuilder s, @Nullable WifiInfo info) {
|
|
||||||
if (info == null) {
|
|
||||||
s.append("Wifi info: null\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
s.append("Wifi info:\n");
|
|
||||||
s.append("\tSSID: ").append(info.getSSID()).append("\n");
|
|
||||||
s.append("\tBSSID: ").append(info.getBSSID()).append("\n");
|
|
||||||
s.append("\tMAC address: ").append(info.getMacAddress()).append("\n");
|
|
||||||
s.append("\tIP address: ")
|
|
||||||
.append(ipToString(info.getIpAddress())).append("\n");
|
|
||||||
s.append("\tSupplicant state: ")
|
|
||||||
.append(info.getSupplicantState()).append("\n");
|
|
||||||
s.append("\tNetwork ID: ").append(info.getNetworkId()).append("\n");
|
|
||||||
s.append("\tLink speed: ").append(info.getLinkSpeed()).append("\n");
|
|
||||||
s.append("\tRSSI: ").append(info.getRssi()).append("\n");
|
|
||||||
if (info.getHiddenSSID()) s.append("\tHidden SSID\n");
|
|
||||||
if (SDK_INT >= 21)
|
|
||||||
s.append("\tFrequency: ").append(info.getFrequency()).append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void logNetworkInfo(StringBuilder s,
|
|
||||||
@Nullable NetworkInfo info, boolean active) {
|
|
||||||
if (info == null) {
|
|
||||||
if (active) s.append("Active network info: null\n");
|
|
||||||
else s.append("Network info: null\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (active) s.append("Active network info:\n");
|
|
||||||
else s.append("Network info:\n");
|
|
||||||
s.append("\tType: ").append(info.getTypeName())
|
|
||||||
.append(" (").append(info.getType()).append(")\n");
|
|
||||||
s.append("\tSubtype: ").append(info.getSubtypeName())
|
|
||||||
.append(" (").append(info.getSubtype()).append(")\n");
|
|
||||||
s.append("\tState: ").append(info.getState()).append("\n");
|
|
||||||
s.append("\tDetailed state: ")
|
|
||||||
.append(info.getDetailedState()).append("\n");
|
|
||||||
s.append("\tReason: ").append(info.getReason()).append("\n");
|
|
||||||
s.append("\tExtra info: ").append(info.getExtraInfo()).append("\n");
|
|
||||||
if (info.isAvailable()) s.append("\tAvailable\n");
|
|
||||||
if (info.isConnected()) s.append("\tConnected\n");
|
|
||||||
if (info.isConnectedOrConnecting())
|
|
||||||
s.append("\tConnected or connecting\n");
|
|
||||||
if (info.isFailover()) s.append("\tFailover\n");
|
|
||||||
if (info.isRoaming()) s.append("\tRoaming\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void logNetworkInterface(StringBuilder s,
|
|
||||||
NetworkInterface iface) throws SocketException {
|
|
||||||
s.append("Network interface:\n");
|
|
||||||
s.append("\tName: ").append(iface.getName()).append("\n");
|
|
||||||
s.append("\tDisplay name: ")
|
|
||||||
.append(iface.getDisplayName()).append("\n");
|
|
||||||
s.append("\tHardware address: ")
|
|
||||||
.append(hexOrNull(iface.getHardwareAddress())).append("\n");
|
|
||||||
if (iface.isLoopback()) s.append("\tLoopback\n");
|
|
||||||
if (iface.isPointToPoint()) s.append("\tPoint-to-point\n");
|
|
||||||
if (iface.isVirtual()) s.append("\tVirtual\n");
|
|
||||||
if (iface.isUp()) s.append("\tUp\n");
|
|
||||||
if (SDK_INT >= 19)
|
|
||||||
s.append("\tIndex: ").append(iface.getIndex()).append("\n");
|
|
||||||
for (InterfaceAddress addr : iface.getInterfaceAddresses()) {
|
|
||||||
s.append("\tInterface address:\n");
|
|
||||||
logInetAddress(s, addr.getAddress());
|
|
||||||
s.append("\t\tPrefix length: ")
|
|
||||||
.append(addr.getNetworkPrefixLength()).append("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void logInetAddress(StringBuilder s, InetAddress addr) {
|
|
||||||
s.append("\t\tAddress: ")
|
|
||||||
.append(hexOrNull(addr.getAddress())).append("\n");
|
|
||||||
s.append("\t\tHost address: ")
|
|
||||||
.append(addr.getHostAddress()).append("\n");
|
|
||||||
if (addr.isLoopbackAddress()) s.append("\t\tLoopback\n");
|
|
||||||
if (addr.isLinkLocalAddress()) s.append("\t\tLink-local\n");
|
|
||||||
if (addr.isSiteLocalAddress()) s.append("\t\tSite-local\n");
|
|
||||||
if (addr.isAnyLocalAddress()) s.append("\t\tAny local (wildcard)\n");
|
|
||||||
if (addr.isMCNodeLocal()) s.append("\t\tMulticast node-local\n");
|
|
||||||
if (addr.isMCLinkLocal()) s.append("\t\tMulticast link-local\n");
|
|
||||||
if (addr.isMCSiteLocal()) s.append("\t\tMulticast site-local\n");
|
|
||||||
if (addr.isMCOrgLocal()) s.append("\t\tMulticast org-local\n");
|
|
||||||
if (addr.isMCGlobal()) s.append("\t\tMulticast global\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static String hexOrNull(@Nullable byte[] b) {
|
|
||||||
return b == null ? null : toHexString(b);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public interface DatabaseComponent {
|
|||||||
* @throws DataTooOldException if the data uses an older schema than the
|
* @throws DataTooOldException if the data uses an older schema than the
|
||||||
* current code and cannot be migrated
|
* current code and cannot be migrated
|
||||||
*/
|
*/
|
||||||
boolean open(@Nullable MigrationListener listener) throws DbException;
|
boolean open() throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for any open transactions to finish and closes the database.
|
* Waits for any open transactions to finish and closes the database.
|
||||||
@@ -259,30 +259,31 @@ public interface DatabaseComponent {
|
|||||||
Collection<LocalAuthor> getLocalAuthors(Transaction txn) throws DbException;
|
Collection<LocalAuthor> getLocalAuthors(Transaction txn) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the IDs of any messages that need to be validated.
|
* Returns the IDs of any messages that need to be validated by the given
|
||||||
|
* client.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<MessageId> getMessagesToValidate(Transaction txn)
|
Collection<MessageId> getMessagesToValidate(Transaction txn, ClientId c)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the IDs of any messages that are pending delivery due to
|
* Returns the IDs of any messages that are valid but pending delivery due
|
||||||
* dependencies on other messages.
|
* to dependencies on other messages for the given client.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<MessageId> getPendingMessages(Transaction txn)
|
Collection<MessageId> getPendingMessages(Transaction txn, ClientId c)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the IDs of any messages that have shared dependents but have
|
* Returns the IDs of any messages from the given client
|
||||||
* not yet been shared themselves.
|
* that have a shared dependent, but are still not shared themselves.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<MessageId> getMessagesToShare(Transaction txn)
|
Collection<MessageId> getMessagesToShare(Transaction txn,
|
||||||
throws DbException;
|
ClientId c) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the message with the given ID, in serialised form, or null if
|
* Returns the message with the given ID, in serialised form, or null if
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
package org.briarproject.bramble.api.db;
|
|
||||||
|
|
||||||
public interface MigrationListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is called when a migration is started while opening the database.
|
|
||||||
* It will be called once for each migration being applied.
|
|
||||||
*/
|
|
||||||
void onMigrationRun();
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -21,25 +21,7 @@ public interface LifecycleManager {
|
|||||||
* The result of calling {@link #startServices(String)}.
|
* The result of calling {@link #startServices(String)}.
|
||||||
*/
|
*/
|
||||||
enum StartResult {
|
enum StartResult {
|
||||||
ALREADY_RUNNING,
|
ALREADY_RUNNING, DB_ERROR, SERVICE_ERROR, SUCCESS
|
||||||
DB_ERROR,
|
|
||||||
DATA_TOO_OLD_ERROR,
|
|
||||||
DATA_TOO_NEW_ERROR,
|
|
||||||
SERVICE_ERROR,
|
|
||||||
SUCCESS
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The state the lifecycle can be in.
|
|
||||||
* Returned by {@link #getLifecycleState()}
|
|
||||||
*/
|
|
||||||
enum LifecycleState {
|
|
||||||
|
|
||||||
STARTING, MIGRATING_DATABASE, STARTING_SERVICES, RUNNING, STOPPING;
|
|
||||||
|
|
||||||
public boolean isAfter(LifecycleState state) {
|
|
||||||
return ordinal() > state.ordinal();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,10 +71,4 @@ public interface LifecycleManager {
|
|||||||
* the {@link DatabaseComponent} to be closed before returning.
|
* the {@link DatabaseComponent} to be closed before returning.
|
||||||
*/
|
*/
|
||||||
void waitForShutdown() throws InterruptedException;
|
void waitForShutdown() throws InterruptedException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current state of the lifecycle.
|
|
||||||
*/
|
|
||||||
LifecycleState getLifecycleState();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package org.briarproject.bramble.api.lifecycle.event;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.event.Event;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An event that is broadcast when the app enters a new lifecycle state.
|
|
||||||
*/
|
|
||||||
public class LifecycleEvent extends Event {
|
|
||||||
|
|
||||||
private final LifecycleState state;
|
|
||||||
|
|
||||||
public LifecycleEvent(LifecycleState state) {
|
|
||||||
this.state = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LifecycleState getLifecycleState() {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.briarproject.bramble.api.lifecycle.event;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.event.Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event that is broadcast when the app is shutting down.
|
||||||
|
*/
|
||||||
|
public class ShutdownEvent extends Event {
|
||||||
|
}
|
||||||
@@ -146,14 +146,6 @@ public class StringUtils {
|
|||||||
return s.toString();
|
return s.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String ipToString(int ip) {
|
|
||||||
int ip1 = ip & 0xFF;
|
|
||||||
int ip2 = (ip >> 8) & 0xFF;
|
|
||||||
int ip3 = (ip >> 16) & 0xFF;
|
|
||||||
int ip4 = (ip >> 24) & 0xFF;
|
|
||||||
return ip1 + "." + ip2 + "." + ip3 + "." + ip4;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getRandomString(int length) {
|
public static String getRandomString(int length) {
|
||||||
char[] c = new char[length];
|
char[] c = new char[length];
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import org.briarproject.bramble.api.db.DataTooNewException;
|
|||||||
import org.briarproject.bramble.api.db.DataTooOldException;
|
import org.briarproject.bramble.api.db.DataTooOldException;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Metadata;
|
import org.briarproject.bramble.api.db.Metadata;
|
||||||
import org.briarproject.bramble.api.db.MigrationListener;
|
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.identity.AuthorId;
|
import org.briarproject.bramble.api.identity.AuthorId;
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
@@ -46,7 +45,7 @@ interface Database<T> {
|
|||||||
* @throws DataTooOldException if the data uses an older schema than the
|
* @throws DataTooOldException if the data uses an older schema than the
|
||||||
* current code and cannot be migrated
|
* current code and cannot be migrated
|
||||||
*/
|
*/
|
||||||
boolean open(@Nullable MigrationListener listener) throws DbException;
|
boolean open() throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevents new transactions from starting, waits for all current
|
* Prevents new transactions from starting, waits for all current
|
||||||
@@ -424,27 +423,31 @@ interface Database<T> {
|
|||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the IDs of any messages that need to be validated.
|
* Returns the IDs of any messages that need to be validated by the given
|
||||||
|
* client.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<MessageId> getMessagesToValidate(T txn) throws DbException;
|
Collection<MessageId> getMessagesToValidate(T txn, ClientId c)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the IDs of any messages that are pending delivery due to
|
* Returns the IDs of any messages that are still pending due to
|
||||||
* dependencies on other messages.
|
* dependencies to other messages for the given client.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<MessageId> getPendingMessages(T txn) throws DbException;
|
Collection<MessageId> getPendingMessages(T txn, ClientId c)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the IDs of any messages that have a shared dependent but have
|
* Returns the IDs of any messages from the given client
|
||||||
* not yet been shared themselves.
|
* that have a shared dependent, but are still not shared themselves.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<MessageId> getMessagesToShare(T txn) throws DbException;
|
Collection<MessageId> getMessagesToShare(T txn, ClientId c)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the next time (in milliseconds since the Unix epoch) when a
|
* Returns the next time (in milliseconds since the Unix epoch) when a
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import org.briarproject.bramble.api.db.ContactExistsException;
|
|||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Metadata;
|
import org.briarproject.bramble.api.db.Metadata;
|
||||||
import org.briarproject.bramble.api.db.MigrationListener;
|
|
||||||
import org.briarproject.bramble.api.db.NoSuchContactException;
|
import org.briarproject.bramble.api.db.NoSuchContactException;
|
||||||
import org.briarproject.bramble.api.db.NoSuchGroupException;
|
import org.briarproject.bramble.api.db.NoSuchGroupException;
|
||||||
import org.briarproject.bramble.api.db.NoSuchLocalAuthorException;
|
import org.briarproject.bramble.api.db.NoSuchLocalAuthorException;
|
||||||
@@ -101,9 +100,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean open(@Nullable MigrationListener listener)
|
public boolean open() throws DbException {
|
||||||
throws DbException {
|
boolean reopened = db.open();
|
||||||
boolean reopened = db.open(listener);
|
|
||||||
shutdown.addShutdownHook(() -> {
|
shutdown.addShutdownHook(() -> {
|
||||||
try {
|
try {
|
||||||
close();
|
close();
|
||||||
@@ -455,24 +453,24 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<MessageId> getMessagesToValidate(Transaction transaction)
|
public Collection<MessageId> getMessagesToValidate(Transaction transaction,
|
||||||
throws DbException {
|
ClientId c) throws DbException {
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
return db.getMessagesToValidate(txn);
|
return db.getMessagesToValidate(txn, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<MessageId> getPendingMessages(Transaction transaction)
|
public Collection<MessageId> getPendingMessages(Transaction transaction,
|
||||||
throws DbException {
|
ClientId c) throws DbException {
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
return db.getPendingMessages(txn);
|
return db.getPendingMessages(txn, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<MessageId> getMessagesToShare(Transaction transaction)
|
public Collection<MessageId> getMessagesToShare(
|
||||||
throws DbException {
|
Transaction transaction, ClientId c) throws DbException {
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
return db.getMessagesToShare(txn);
|
return db.getMessagesToShare(txn, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -573,7 +571,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getNextSendTime(Transaction transaction, ContactId c)
|
public long getNextSendTime(Transaction transaction, ContactId c)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
T txn = unbox(transaction);
|
T txn = unbox(transaction);
|
||||||
return db.getNextSendTime(txn, c);
|
return db.getNextSendTime(txn, c);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.briarproject.bramble.db;
|
|||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.MigrationListener;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
@@ -14,7 +13,6 @@ import java.sql.DriverManager;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,11 +42,10 @@ class H2Database extends JdbcDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean open(@Nullable MigrationListener listener)
|
public boolean open() throws DbException {
|
||||||
throws DbException {
|
|
||||||
boolean reopen = config.databaseExists();
|
boolean reopen = config.databaseExists();
|
||||||
if (!reopen) config.getDatabaseDirectory().mkdirs();
|
if (!reopen) config.getDatabaseDirectory().mkdirs();
|
||||||
super.open("org.h2.Driver", reopen, listener);
|
super.open("org.h2.Driver", reopen);
|
||||||
return reopen;
|
return reopen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.briarproject.bramble.db;
|
|||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.MigrationListener;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
@@ -14,7 +13,6 @@ import java.sql.DriverManager;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,10 +44,10 @@ class HyperSqlDatabase extends JdbcDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean open(@Nullable MigrationListener listener) throws DbException {
|
public boolean open() throws DbException {
|
||||||
boolean reopen = config.databaseExists();
|
boolean reopen = config.databaseExists();
|
||||||
if (!reopen) config.getDatabaseDirectory().mkdirs();
|
if (!reopen) config.getDatabaseDirectory().mkdirs();
|
||||||
super.open("org.hsqldb.jdbc.JDBCDriver", reopen, listener);
|
super.open("org.hsqldb.jdbc.JDBCDriver", reopen);
|
||||||
return reopen;
|
return reopen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import org.briarproject.bramble.api.db.DataTooOldException;
|
|||||||
import org.briarproject.bramble.api.db.DbClosedException;
|
import org.briarproject.bramble.api.db.DbClosedException;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.Metadata;
|
import org.briarproject.bramble.api.db.Metadata;
|
||||||
import org.briarproject.bramble.api.db.MigrationListener;
|
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.identity.AuthorId;
|
import org.briarproject.bramble.api.identity.AuthorId;
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
@@ -302,8 +301,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void open(String driverClass, boolean reopen,
|
protected void open(String driverClass, boolean reopen) throws DbException {
|
||||||
@Nullable MigrationListener listener) throws DbException {
|
|
||||||
// Load the JDBC driver
|
// Load the JDBC driver
|
||||||
try {
|
try {
|
||||||
Class.forName(driverClass);
|
Class.forName(driverClass);
|
||||||
@@ -314,7 +312,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
Connection txn = startTransaction();
|
Connection txn = startTransaction();
|
||||||
try {
|
try {
|
||||||
if (reopen) {
|
if (reopen) {
|
||||||
checkSchemaVersion(txn, listener);
|
checkSchemaVersion(txn);
|
||||||
} else {
|
} else {
|
||||||
createTables(txn);
|
createTables(txn);
|
||||||
storeSchemaVersion(txn, CODE_SCHEMA_VERSION);
|
storeSchemaVersion(txn, CODE_SCHEMA_VERSION);
|
||||||
@@ -337,8 +335,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
* @throws DataTooOldException if the data uses an older schema than the
|
* @throws DataTooOldException if the data uses an older schema than the
|
||||||
* current code and cannot be migrated
|
* current code and cannot be migrated
|
||||||
*/
|
*/
|
||||||
private void checkSchemaVersion(Connection txn,
|
private void checkSchemaVersion(Connection txn) throws DbException {
|
||||||
@Nullable MigrationListener listener) throws DbException {
|
|
||||||
Settings s = getSettings(txn, DB_SETTINGS_NAMESPACE);
|
Settings s = getSettings(txn, DB_SETTINGS_NAMESPACE);
|
||||||
int dataSchemaVersion = s.getInt(SCHEMA_VERSION_KEY, -1);
|
int dataSchemaVersion = s.getInt(SCHEMA_VERSION_KEY, -1);
|
||||||
if (dataSchemaVersion == -1) throw new DbException();
|
if (dataSchemaVersion == -1) throw new DbException();
|
||||||
@@ -351,7 +348,6 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
if (start == dataSchemaVersion) {
|
if (start == dataSchemaVersion) {
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Migrating from schema " + start + " to " + end);
|
LOG.info("Migrating from schema " + start + " to " + end);
|
||||||
if (listener != null) listener.onMigrationRun();
|
|
||||||
// Apply the migration
|
// Apply the migration
|
||||||
m.migrate(txn);
|
m.migrate(txn);
|
||||||
// Store the new schema version
|
// Store the new schema version
|
||||||
@@ -1868,26 +1864,28 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<MessageId> getMessagesToValidate(Connection txn)
|
public Collection<MessageId> getMessagesToValidate(Connection txn,
|
||||||
throws DbException {
|
ClientId c) throws DbException {
|
||||||
return getMessagesInState(txn, UNKNOWN);
|
return getMessagesInState(txn, c, UNKNOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<MessageId> getPendingMessages(Connection txn)
|
public Collection<MessageId> getPendingMessages(Connection txn,
|
||||||
throws DbException {
|
ClientId c) throws DbException {
|
||||||
return getMessagesInState(txn, PENDING);
|
return getMessagesInState(txn, c, PENDING);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<MessageId> getMessagesInState(Connection txn,
|
private Collection<MessageId> getMessagesInState(Connection txn, ClientId c,
|
||||||
State state) throws DbException {
|
State state) throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
String sql = "SELECT messageId FROM messages"
|
String sql = "SELECT messageId FROM messages AS m"
|
||||||
+ " WHERE state = ? AND raw IS NOT NULL";
|
+ " JOIN groups AS g ON m.groupId = g.groupId"
|
||||||
|
+ " WHERE state = ? AND clientId = ? AND raw IS NOT NULL";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, state.getValue());
|
ps.setInt(1, state.getValue());
|
||||||
|
ps.setString(2, c.getString());
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
List<MessageId> ids = new ArrayList<>();
|
List<MessageId> ids = new ArrayList<>();
|
||||||
while (rs.next()) ids.add(new MessageId(rs.getBytes(1)));
|
while (rs.next()) ids.add(new MessageId(rs.getBytes(1)));
|
||||||
@@ -1902,7 +1900,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<MessageId> getMessagesToShare(Connection txn)
|
public Collection<MessageId> getMessagesToShare(Connection txn, ClientId c)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
@@ -1912,10 +1910,12 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " ON m.messageId = d.dependencyId"
|
+ " ON m.messageId = d.dependencyId"
|
||||||
+ " JOIN messages AS m1"
|
+ " JOIN messages AS m1"
|
||||||
+ " ON d.messageId = m1.messageId"
|
+ " ON d.messageId = m1.messageId"
|
||||||
+ " WHERE m.state = ?"
|
+ " JOIN groups AS g"
|
||||||
+ " AND m.shared = FALSE AND m1.shared = TRUE";
|
+ " ON m.groupId = g.groupId"
|
||||||
|
+ " WHERE m.shared = FALSE AND m1.shared = TRUE"
|
||||||
|
+ " AND g.clientId = ?";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setInt(1, DELIVERED.getValue());
|
ps.setString(1, c.getString());
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
List<MessageId> ids = new ArrayList<>();
|
List<MessageId> ids = new ArrayList<>();
|
||||||
while (rs.next()) ids.add(new MessageId(rs.getBytes(1)));
|
while (rs.next()) ids.add(new MessageId(rs.getBytes(1)));
|
||||||
|
|||||||
@@ -2,35 +2,38 @@ package org.briarproject.bramble.keyagreement;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
interface ConnectionChooser {
|
interface ConnectionChooser {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submits a connection task to the chooser.
|
* Adds a connection to the set of connections that may be chosen. If
|
||||||
|
* {@link #stop()} has already been called, the connection will be closed
|
||||||
|
* immediately.
|
||||||
*/
|
*/
|
||||||
void submit(Callable<KeyAgreementConnection> task);
|
void addConnection(KeyAgreementConnection c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a connection returned by any of the tasks submitted to the
|
* Chooses one of the connections passed to
|
||||||
* chooser, waiting up to the given amount of time for a connection if
|
* {@link #addConnection(KeyAgreementConnection)} and returns it,
|
||||||
* necessary. Returns null if the time elapses without a connection
|
* waiting up to the given amount of time for a suitable connection to
|
||||||
* becoming available.
|
* become available. Returns null if the time elapses without a suitable
|
||||||
|
* connection becoming available.
|
||||||
*
|
*
|
||||||
|
* @param alice true if the local party is Alice
|
||||||
* @param timeout the timeout in milliseconds
|
* @param timeout the timeout in milliseconds
|
||||||
* @throws InterruptedException if the thread is interrupted while waiting
|
* @throws InterruptedException if the thread is interrupted while waiting
|
||||||
* for a connection to become available
|
* for a suitable connection to become available
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
KeyAgreementConnection poll(long timeout) throws InterruptedException;
|
KeyAgreementConnection chooseConnection(boolean alice, long timeout)
|
||||||
|
throws InterruptedException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops the chooser. Any connections already returned to the chooser are
|
* Stops the chooser from accepting new connections. Closes any connections
|
||||||
* closed unless they have been removed from the chooser by calling
|
* already passed to {@link #addConnection(KeyAgreementConnection)}
|
||||||
* {@link #poll(long)}. Any connections subsequently returned to the
|
* and not chosen. Any connections subsequently passed to
|
||||||
* chooser will also be closed.
|
* {@link #addConnection(KeyAgreementConnection)} will be closed.
|
||||||
*/
|
*/
|
||||||
void stop();
|
void stop();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
package org.briarproject.bramble.keyagreement;
|
package org.briarproject.bramble.keyagreement;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementWaitingEvent;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedList;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -20,6 +18,7 @@ import javax.annotation.concurrent.ThreadSafe;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@@ -28,54 +27,114 @@ class ConnectionChooserImpl implements ConnectionChooser {
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(ConnectionChooserImpl.class.getName());
|
Logger.getLogger(ConnectionChooserImpl.class.getName());
|
||||||
|
|
||||||
|
private final EventBus eventBus;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final Executor ioExecutor;
|
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
|
private final List<KeyAgreementConnection> connections =
|
||||||
// The following are locking: lock
|
new ArrayList<>(); // Locking: lock
|
||||||
private boolean stopped = false;
|
private boolean stopped = false; // Locking: lock
|
||||||
private final Queue<KeyAgreementConnection> results = new LinkedList<>();
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ConnectionChooserImpl(Clock clock, @IoExecutor Executor ioExecutor) {
|
ConnectionChooserImpl(EventBus eventBus, Clock clock) {
|
||||||
|
this.eventBus = eventBus;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
this.ioExecutor = ioExecutor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void submit(Callable<KeyAgreementConnection> task) {
|
public void addConnection(KeyAgreementConnection conn) {
|
||||||
ioExecutor.execute(() -> {
|
boolean close = false;
|
||||||
try {
|
synchronized (lock) {
|
||||||
KeyAgreementConnection c = task.call();
|
if (stopped) {
|
||||||
if (c != null) addResult(c);
|
// Already stopped, close the connection
|
||||||
} catch (Exception e) {
|
close = true;
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
|
} else {
|
||||||
|
connections.add(conn);
|
||||||
|
lock.notifyAll();
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
if (close) tryToClose(conn.getConnection());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public KeyAgreementConnection poll(long timeout)
|
public KeyAgreementConnection chooseConnection(boolean alice, long timeout)
|
||||||
throws InterruptedException {
|
throws InterruptedException {
|
||||||
|
if (alice) return chooseConnectionAlice(timeout);
|
||||||
|
else return chooseConnectionBob(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private KeyAgreementConnection chooseConnectionAlice(long timeout)
|
||||||
|
throws InterruptedException {
|
||||||
|
LOG.info("Choosing connection for Alice");
|
||||||
long now = clock.currentTimeMillis();
|
long now = clock.currentTimeMillis();
|
||||||
long end = now + timeout;
|
long end = now + timeout;
|
||||||
|
KeyAgreementConnection chosen;
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
while (!stopped && results.isEmpty() && now < end) {
|
// Wait until we're stopped, a connection is added, or we time out
|
||||||
|
while (!stopped && connections.isEmpty() && now < end) {
|
||||||
lock.wait(end - now);
|
lock.wait(end - now);
|
||||||
now = clock.currentTimeMillis();
|
now = clock.currentTimeMillis();
|
||||||
}
|
}
|
||||||
return results.poll();
|
if (connections.isEmpty()) {
|
||||||
|
LOG.info("No suitable connection for Alice");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// Choose the first connection
|
||||||
|
chosen = connections.remove(0);
|
||||||
}
|
}
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Choosing " + chosen.getTransportId());
|
||||||
|
return chosen;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private KeyAgreementConnection chooseConnectionBob(long timeout)
|
||||||
|
throws InterruptedException {
|
||||||
|
LOG.info("Choosing connection for Bob");
|
||||||
|
// Bob waits here for Alice to scan his QR code, determine her role,
|
||||||
|
// choose a connection and send her key
|
||||||
|
eventBus.broadcast(new KeyAgreementWaitingEvent());
|
||||||
|
long now = clock.currentTimeMillis();
|
||||||
|
long end = now + timeout;
|
||||||
|
synchronized (lock) {
|
||||||
|
while (!stopped && now < end) {
|
||||||
|
// Check whether any connection has data available
|
||||||
|
Iterator<KeyAgreementConnection> it = connections.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
KeyAgreementConnection c = it.next();
|
||||||
|
try {
|
||||||
|
int available = c.getConnection().getReader()
|
||||||
|
.getInputStream().available();
|
||||||
|
if (available > 0) {
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Choosing " + c.getTransportId());
|
||||||
|
it.remove();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
tryToClose(c.getConnection());
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Wait for 1 second before checking again
|
||||||
|
lock.wait(Math.min(1000, end - now));
|
||||||
|
now = clock.currentTimeMillis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG.info("No suitable connection for Bob");
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
List<KeyAgreementConnection> unused;
|
List<KeyAgreementConnection> unused;
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
unused = new ArrayList<>(results);
|
|
||||||
results.clear();
|
|
||||||
stopped = true;
|
stopped = true;
|
||||||
|
unused = new ArrayList<>(connections);
|
||||||
|
connections.clear();
|
||||||
lock.notifyAll();
|
lock.notifyAll();
|
||||||
}
|
}
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
@@ -83,24 +142,6 @@ class ConnectionChooserImpl implements ConnectionChooser {
|
|||||||
for (KeyAgreementConnection c : unused) tryToClose(c.getConnection());
|
for (KeyAgreementConnection c : unused) tryToClose(c.getConnection());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addResult(KeyAgreementConnection c) {
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Got connection for " + c.getTransportId());
|
|
||||||
boolean close = false;
|
|
||||||
synchronized (lock) {
|
|
||||||
if (stopped) {
|
|
||||||
close = true;
|
|
||||||
} else {
|
|
||||||
results.add(c);
|
|
||||||
lock.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (close) {
|
|
||||||
LOG.info("Already stopped");
|
|
||||||
tryToClose(c.getConnection());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void tryToClose(DuplexTransportConnection conn) {
|
private void tryToClose(DuplexTransportConnection conn) {
|
||||||
try {
|
try {
|
||||||
conn.getReader().dispose(false, true);
|
conn.getReader().dispose(false, true);
|
||||||
|
|||||||
@@ -7,21 +7,20 @@ import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
|
|||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.bramble.api.keyagreement.Payload;
|
import org.briarproject.bramble.api.keyagreement.Payload;
|
||||||
import org.briarproject.bramble.api.keyagreement.TransportDescriptor;
|
import org.briarproject.bramble.api.keyagreement.TransportDescriptor;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Plugin;
|
import org.briarproject.bramble.api.plugin.Plugin;
|
||||||
import org.briarproject.bramble.api.plugin.PluginManager;
|
import org.briarproject.bramble.api.plugin.PluginManager;
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -33,31 +32,27 @@ import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.CO
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class KeyAgreementConnector {
|
class KeyAgreementConnector {
|
||||||
|
|
||||||
interface Callbacks {
|
|
||||||
void connectionWaiting();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(KeyAgreementConnector.class.getName());
|
Logger.getLogger(KeyAgreementConnector.class.getName());
|
||||||
|
|
||||||
private final Callbacks callbacks;
|
private final Clock clock;
|
||||||
private final KeyAgreementCrypto keyAgreementCrypto;
|
private final KeyAgreementCrypto keyAgreementCrypto;
|
||||||
private final PluginManager pluginManager;
|
private final PluginManager pluginManager;
|
||||||
|
private final Executor ioExecutor;
|
||||||
private final ConnectionChooser connectionChooser;
|
private final ConnectionChooser connectionChooser;
|
||||||
|
|
||||||
private final List<KeyAgreementListener> listeners =
|
private final List<KeyAgreementListener> listeners =
|
||||||
new CopyOnWriteArrayList<>();
|
new CopyOnWriteArrayList<>();
|
||||||
private final CountDownLatch aliceLatch = new CountDownLatch(1);
|
|
||||||
private final AtomicBoolean waitingSent = new AtomicBoolean(false);
|
|
||||||
|
|
||||||
private volatile boolean alice = false, stopped = false;
|
private volatile boolean stopped = false;
|
||||||
|
|
||||||
KeyAgreementConnector(Callbacks callbacks,
|
KeyAgreementConnector(Clock clock, KeyAgreementCrypto keyAgreementCrypto,
|
||||||
KeyAgreementCrypto keyAgreementCrypto, PluginManager pluginManager,
|
PluginManager pluginManager, Executor ioExecutor,
|
||||||
ConnectionChooser connectionChooser) {
|
ConnectionChooser connectionChooser) {
|
||||||
this.callbacks = callbacks;
|
this.clock = clock;
|
||||||
this.keyAgreementCrypto = keyAgreementCrypto;
|
this.keyAgreementCrypto = keyAgreementCrypto;
|
||||||
this.pluginManager = pluginManager;
|
this.pluginManager = pluginManager;
|
||||||
|
this.ioExecutor = ioExecutor;
|
||||||
this.connectionChooser = connectionChooser;
|
this.connectionChooser = connectionChooser;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +71,14 @@ class KeyAgreementConnector {
|
|||||||
descriptors.add(new TransportDescriptor(id, l.getDescriptor()));
|
descriptors.add(new TransportDescriptor(id, l.getDescriptor()));
|
||||||
if (LOG.isLoggable(INFO)) LOG.info("Listening via " + id);
|
if (LOG.isLoggable(INFO)) LOG.info("Listening via " + id);
|
||||||
listeners.add(l);
|
listeners.add(l);
|
||||||
connectionChooser.submit(new ReadableTask(l::accept));
|
ioExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
connectionChooser.addConnection(l.accept());
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Payload(commitment, descriptors);
|
return new Payload(commitment, descriptors);
|
||||||
@@ -85,17 +87,13 @@ class KeyAgreementConnector {
|
|||||||
void stopListening() {
|
void stopListening() {
|
||||||
LOG.info("Stopping BQP listeners");
|
LOG.info("Stopping BQP listeners");
|
||||||
stopped = true;
|
stopped = true;
|
||||||
aliceLatch.countDown();
|
|
||||||
for (KeyAgreementListener l : listeners) l.close();
|
for (KeyAgreementListener l : listeners) l.close();
|
||||||
|
listeners.clear();
|
||||||
connectionChooser.stop();
|
connectionChooser.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public KeyAgreementTransport connect(Payload remotePayload, boolean alice) {
|
public KeyAgreementTransport connect(Payload remotePayload, boolean alice) {
|
||||||
// Let the ReadableTasks know if we are Alice
|
|
||||||
this.alice = alice;
|
|
||||||
aliceLatch.countDown();
|
|
||||||
|
|
||||||
// Start connecting over supported transports
|
// Start connecting over supported transports
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("Starting outgoing BQP connections as "
|
LOG.info("Starting outgoing BQP connections as "
|
||||||
@@ -109,16 +107,23 @@ class KeyAgreementConnector {
|
|||||||
DuplexPlugin plugin = (DuplexPlugin) p;
|
DuplexPlugin plugin = (DuplexPlugin) p;
|
||||||
byte[] commitment = remotePayload.getCommitment();
|
byte[] commitment = remotePayload.getCommitment();
|
||||||
BdfList descriptor = d.getDescriptor();
|
BdfList descriptor = d.getDescriptor();
|
||||||
connectionChooser.submit(new ReadableTask(
|
ioExecutor.execute(() -> {
|
||||||
new ConnectorTask(plugin, commitment, descriptor)));
|
try {
|
||||||
|
KeyAgreementConnection c =
|
||||||
|
connect(plugin, commitment, descriptor);
|
||||||
|
if (c != null) connectionChooser.addConnection(c);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
LOG.info("Interrupted while waiting to connect");
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get chosen connection
|
// Get chosen connection
|
||||||
try {
|
try {
|
||||||
KeyAgreementConnection chosen =
|
KeyAgreementConnection chosen = connectionChooser.chooseConnection(
|
||||||
connectionChooser.poll(CONNECTION_TIMEOUT);
|
alice, CONNECTION_TIMEOUT);
|
||||||
if (chosen == null) return null;
|
if (chosen == null) return null; // No suitable connection
|
||||||
return new KeyAgreementTransport(chosen);
|
return new KeyAgreementTransport(chosen);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.info("Interrupted while waiting for connection");
|
LOG.info("Interrupted while waiting for connection");
|
||||||
@@ -132,70 +137,20 @@ class KeyAgreementConnector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void waitingForAlice() {
|
@Nullable
|
||||||
if (!waitingSent.getAndSet(true)) callbacks.connectionWaiting();
|
@IoExecutor
|
||||||
}
|
private KeyAgreementConnection connect(DuplexPlugin plugin,
|
||||||
|
byte[] commitment, BdfList descriptor) throws InterruptedException {
|
||||||
private class ConnectorTask implements Callable<KeyAgreementConnection> {
|
// Repeat attempts until we time out, get stopped, or get interrupted
|
||||||
|
long end = clock.currentTimeMillis() + CONNECTION_TIMEOUT;
|
||||||
private final byte[] commitment;
|
while (!stopped && clock.currentTimeMillis() < end) {
|
||||||
private final BdfList descriptor;
|
DuplexTransportConnection conn =
|
||||||
private final DuplexPlugin plugin;
|
plugin.createKeyAgreementConnection(commitment, descriptor);
|
||||||
|
if (conn != null)
|
||||||
private ConnectorTask(DuplexPlugin plugin, byte[] commitment,
|
return new KeyAgreementConnection(conn, plugin.getId());
|
||||||
BdfList descriptor) {
|
// Wait 2s before retry (to circumvent transient failures)
|
||||||
this.plugin = plugin;
|
Thread.sleep(2000);
|
||||||
this.commitment = commitment;
|
|
||||||
this.descriptor = descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public KeyAgreementConnection call() throws Exception {
|
|
||||||
// Repeat attempts until we connect, get stopped, or get interrupted
|
|
||||||
while (!stopped) {
|
|
||||||
DuplexTransportConnection conn =
|
|
||||||
plugin.createKeyAgreementConnection(commitment,
|
|
||||||
descriptor);
|
|
||||||
if (conn != null) {
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info(plugin.getId() + ": Outgoing connection");
|
|
||||||
return new KeyAgreementConnection(conn, plugin.getId());
|
|
||||||
}
|
|
||||||
// Wait 2s before retry (to circumvent transient failures)
|
|
||||||
Thread.sleep(2000);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ReadableTask implements Callable<KeyAgreementConnection> {
|
|
||||||
|
|
||||||
private final Callable<KeyAgreementConnection> connectionTask;
|
|
||||||
|
|
||||||
private ReadableTask(Callable<KeyAgreementConnection> connectionTask) {
|
|
||||||
this.connectionTask = connectionTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public KeyAgreementConnection call() throws Exception {
|
|
||||||
KeyAgreementConnection c = connectionTask.call();
|
|
||||||
if (c == null) return null;
|
|
||||||
aliceLatch.await();
|
|
||||||
if (alice || stopped) return c;
|
|
||||||
// Bob waits here for Alice to scan his QR code, determine her
|
|
||||||
// role, and send her key
|
|
||||||
InputStream in = c.getConnection().getReader().getInputStream();
|
|
||||||
while (!stopped && in.available() == 0) {
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info(c.getTransportId() + ": Waiting for data");
|
|
||||||
waitingForAlice();
|
|
||||||
Thread.sleep(500);
|
|
||||||
}
|
|
||||||
if (!stopped && LOG.isLoggable(INFO))
|
|
||||||
LOG.info(c.getTransportId().getString() + ": Data available");
|
|
||||||
return c;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,11 +15,14 @@ import org.briarproject.bramble.api.keyagreement.event.KeyAgreementFinishedEvent
|
|||||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementListeningEvent;
|
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementListeningEvent;
|
||||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementStartedEvent;
|
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementStartedEvent;
|
||||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementWaitingEvent;
|
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementWaitingEvent;
|
||||||
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.PluginManager;
|
import org.briarproject.bramble.api.plugin.PluginManager;
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -28,8 +31,8 @@ import static java.util.logging.Level.WARNING;
|
|||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
class KeyAgreementTaskImpl extends Thread implements KeyAgreementTask,
|
class KeyAgreementTaskImpl extends Thread implements
|
||||||
KeyAgreementProtocol.Callbacks, KeyAgreementConnector.Callbacks {
|
KeyAgreementTask, KeyAgreementProtocol.Callbacks {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(KeyAgreementTaskImpl.class.getName());
|
Logger.getLogger(KeyAgreementTaskImpl.class.getName());
|
||||||
@@ -45,17 +48,18 @@ class KeyAgreementTaskImpl extends Thread implements KeyAgreementTask,
|
|||||||
private Payload remotePayload;
|
private Payload remotePayload;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
KeyAgreementTaskImpl(CryptoComponent crypto,
|
KeyAgreementTaskImpl(Clock clock, CryptoComponent crypto,
|
||||||
KeyAgreementCrypto keyAgreementCrypto, EventBus eventBus,
|
KeyAgreementCrypto keyAgreementCrypto, EventBus eventBus,
|
||||||
PayloadEncoder payloadEncoder, PluginManager pluginManager,
|
PayloadEncoder payloadEncoder, PluginManager pluginManager,
|
||||||
|
@IoExecutor Executor ioExecutor,
|
||||||
ConnectionChooser connectionChooser) {
|
ConnectionChooser connectionChooser) {
|
||||||
this.crypto = crypto;
|
this.crypto = crypto;
|
||||||
this.keyAgreementCrypto = keyAgreementCrypto;
|
this.keyAgreementCrypto = keyAgreementCrypto;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.payloadEncoder = payloadEncoder;
|
this.payloadEncoder = payloadEncoder;
|
||||||
localKeyPair = crypto.generateAgreementKeyPair();
|
localKeyPair = crypto.generateAgreementKeyPair();
|
||||||
connector = new KeyAgreementConnector(this, keyAgreementCrypto,
|
connector = new KeyAgreementConnector(clock, keyAgreementCrypto,
|
||||||
pluginManager, connectionChooser);
|
pluginManager, ioExecutor, connectionChooser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -2,11 +2,8 @@ package org.briarproject.bramble.lifecycle;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
import org.briarproject.bramble.api.crypto.KeyPair;
|
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||||
import org.briarproject.bramble.api.db.DataTooNewException;
|
|
||||||
import org.briarproject.bramble.api.db.DataTooOldException;
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.MigrationListener;
|
|
||||||
import org.briarproject.bramble.api.db.Transaction;
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.identity.AuthorFactory;
|
import org.briarproject.bramble.api.identity.AuthorFactory;
|
||||||
@@ -15,7 +12,7 @@ import org.briarproject.bramble.api.identity.LocalAuthor;
|
|||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.lifecycle.Service;
|
import org.briarproject.bramble.api.lifecycle.Service;
|
||||||
import org.briarproject.bramble.api.lifecycle.ServiceException;
|
import org.briarproject.bramble.api.lifecycle.ServiceException;
|
||||||
import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
|
import org.briarproject.bramble.api.lifecycle.event.ShutdownEvent;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.Client;
|
import org.briarproject.bramble.api.sync.Client;
|
||||||
|
|
||||||
@@ -32,21 +29,14 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE;
|
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING;
|
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING;
|
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING_SERVICES;
|
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
|
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.DATA_TOO_NEW_ERROR;
|
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.DATA_TOO_OLD_ERROR;
|
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.DB_ERROR;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.DB_ERROR;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SERVICE_ERROR;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SERVICE_ERROR;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
|
||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
class LifecycleManagerImpl implements LifecycleManager {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(LifecycleManagerImpl.class.getName());
|
Logger.getLogger(LifecycleManagerImpl.class.getName());
|
||||||
@@ -64,8 +54,6 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
private final CountDownLatch startupLatch = new CountDownLatch(1);
|
private final CountDownLatch startupLatch = new CountDownLatch(1);
|
||||||
private final CountDownLatch shutdownLatch = new CountDownLatch(1);
|
private final CountDownLatch shutdownLatch = new CountDownLatch(1);
|
||||||
|
|
||||||
private volatile LifecycleState state = STARTING;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
LifecycleManagerImpl(DatabaseComponent db, EventBus eventBus,
|
LifecycleManagerImpl(DatabaseComponent db, EventBus eventBus,
|
||||||
CryptoComponent crypto, AuthorFactory authorFactory,
|
CryptoComponent crypto, AuthorFactory authorFactory,
|
||||||
@@ -131,7 +119,7 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
LOG.info("Starting services");
|
LOG.info("Starting services");
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
|
|
||||||
boolean reopened = db.open(this);
|
boolean reopened = db.open();
|
||||||
long duration = System.currentTimeMillis() - start;
|
long duration = System.currentTimeMillis() - start;
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
if (reopened)
|
if (reopened)
|
||||||
@@ -143,10 +131,7 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
registerLocalAuthor(createLocalAuthor(nickname));
|
registerLocalAuthor(createLocalAuthor(nickname));
|
||||||
}
|
}
|
||||||
|
|
||||||
state = STARTING_SERVICES;
|
|
||||||
dbLatch.countDown();
|
dbLatch.countDown();
|
||||||
eventBus.broadcast(new LifecycleEvent(STARTING_SERVICES));
|
|
||||||
|
|
||||||
Transaction txn = db.startTransaction(false);
|
Transaction txn = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
for (Client c : clients) {
|
for (Client c : clients) {
|
||||||
@@ -172,17 +157,8 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
+ " took " + duration + " ms");
|
+ " took " + duration + " ms");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state = RUNNING;
|
|
||||||
startupLatch.countDown();
|
startupLatch.countDown();
|
||||||
eventBus.broadcast(new LifecycleEvent(RUNNING));
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
} catch (DataTooOldException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
return DATA_TOO_OLD_ERROR;
|
|
||||||
} catch (DataTooNewException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
return DATA_TOO_NEW_ERROR;
|
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
return DB_ERROR;
|
return DB_ERROR;
|
||||||
@@ -194,12 +170,6 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMigrationRun() {
|
|
||||||
state = MIGRATING_DATABASE;
|
|
||||||
eventBus.broadcast(new LifecycleEvent(MIGRATING_DATABASE));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stopServices() {
|
public void stopServices() {
|
||||||
try {
|
try {
|
||||||
@@ -210,8 +180,7 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
LOG.info("Stopping services");
|
LOG.info("Stopping services");
|
||||||
state = STOPPING;
|
eventBus.broadcast(new ShutdownEvent());
|
||||||
eventBus.broadcast(new LifecycleEvent(STOPPING));
|
|
||||||
for (Service s : services) {
|
for (Service s : services) {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
s.stopService();
|
s.stopService();
|
||||||
@@ -256,8 +225,4 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
shutdownLatch.await();
|
shutdownLatch.await();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public LifecycleState getLifecycleState() {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -247,12 +247,12 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
ctx = keyManager.getStreamContext(transportId, tag);
|
ctx = keyManager.getStreamContext(transportId, tag);
|
||||||
} catch (IOException | DbException e) {
|
} catch (IOException | DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
disposeReader(true, false);
|
dispose(true, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ctx == null) {
|
if (ctx == null) {
|
||||||
LOG.info("Unrecognised tag");
|
LOG.info("Unrecognised tag");
|
||||||
disposeReader(false, false);
|
dispose(false, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
contactId = ctx.getContactId();
|
contactId = ctx.getContactId();
|
||||||
@@ -263,10 +263,10 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
// Create and run the incoming session
|
// Create and run the incoming session
|
||||||
incomingSession = createIncomingSession(ctx, reader);
|
incomingSession = createIncomingSession(ctx, reader);
|
||||||
incomingSession.run();
|
incomingSession.run();
|
||||||
disposeReader(false, true);
|
dispose(false, true);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
disposeReader(true, true);
|
dispose(true, true);
|
||||||
} finally {
|
} finally {
|
||||||
connectionRegistry.unregisterConnection(contactId, transportId,
|
connectionRegistry.unregisterConnection(contactId, transportId,
|
||||||
true);
|
true);
|
||||||
@@ -280,39 +280,28 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
ctx = keyManager.getStreamContext(contactId, transportId);
|
ctx = keyManager.getStreamContext(contactId, transportId);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
disposeWriter(true);
|
dispose(true, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ctx == null) {
|
if (ctx == null) {
|
||||||
LOG.warning("Could not allocate stream context");
|
LOG.warning("Could not allocate stream context");
|
||||||
disposeWriter(true);
|
dispose(true, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// Create and run the outgoing session
|
// Create and run the outgoing session
|
||||||
outgoingSession = createDuplexOutgoingSession(ctx, writer);
|
outgoingSession = createDuplexOutgoingSession(ctx, writer);
|
||||||
outgoingSession.run();
|
outgoingSession.run();
|
||||||
disposeWriter(false);
|
dispose(false, true);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
disposeWriter(true);
|
dispose(true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void disposeReader(boolean exception, boolean recognised) {
|
private void dispose(boolean exception, boolean recognised) {
|
||||||
if (exception && outgoingSession != null)
|
|
||||||
outgoingSession.interrupt();
|
|
||||||
try {
|
try {
|
||||||
reader.dispose(exception, recognised);
|
reader.dispose(exception, recognised);
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void disposeWriter(boolean exception) {
|
|
||||||
if (exception && incomingSession != null)
|
|
||||||
incomingSession.interrupt();
|
|
||||||
try {
|
|
||||||
writer.dispose(exception);
|
writer.dispose(exception);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
@@ -346,12 +335,12 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
ctx = keyManager.getStreamContext(contactId, transportId);
|
ctx = keyManager.getStreamContext(contactId, transportId);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
disposeWriter(true);
|
dispose(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ctx == null) {
|
if (ctx == null) {
|
||||||
LOG.warning("Could not allocate stream context");
|
LOG.warning("Could not allocate stream context");
|
||||||
disposeWriter(true);
|
dispose(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Start the incoming session on another thread
|
// Start the incoming session on another thread
|
||||||
@@ -360,10 +349,10 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
// Create and run the outgoing session
|
// Create and run the outgoing session
|
||||||
outgoingSession = createDuplexOutgoingSession(ctx, writer);
|
outgoingSession = createDuplexOutgoingSession(ctx, writer);
|
||||||
outgoingSession.run();
|
outgoingSession.run();
|
||||||
disposeWriter(false);
|
dispose(false);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
disposeWriter(true);
|
dispose(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,19 +364,19 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
ctx = keyManager.getStreamContext(transportId, tag);
|
ctx = keyManager.getStreamContext(transportId, tag);
|
||||||
} catch (IOException | DbException e) {
|
} catch (IOException | DbException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
disposeReader(true, false);
|
dispose(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Unrecognised tags are suspicious in this case
|
// Unrecognised tags are suspicious in this case
|
||||||
if (ctx == null) {
|
if (ctx == null) {
|
||||||
LOG.warning("Unrecognised tag for returning stream");
|
LOG.warning("Unrecognised tag for returning stream");
|
||||||
disposeReader(true, false);
|
dispose(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Check that the stream comes from the expected contact
|
// Check that the stream comes from the expected contact
|
||||||
if (!ctx.getContactId().equals(contactId)) {
|
if (!ctx.getContactId().equals(contactId)) {
|
||||||
LOG.warning("Wrong contact ID for returning stream");
|
LOG.warning("Wrong contact ID for returning stream");
|
||||||
disposeReader(true, true);
|
dispose(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
connectionRegistry.registerConnection(contactId, transportId,
|
connectionRegistry.registerConnection(contactId, transportId,
|
||||||
@@ -396,30 +385,20 @@ class ConnectionManagerImpl implements ConnectionManager {
|
|||||||
// Create and run the incoming session
|
// Create and run the incoming session
|
||||||
incomingSession = createIncomingSession(ctx, reader);
|
incomingSession = createIncomingSession(ctx, reader);
|
||||||
incomingSession.run();
|
incomingSession.run();
|
||||||
disposeReader(false, true);
|
dispose(false);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
disposeReader(true, true);
|
dispose(true);
|
||||||
} finally {
|
} finally {
|
||||||
connectionRegistry.unregisterConnection(contactId, transportId,
|
connectionRegistry.unregisterConnection(contactId, transportId,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void disposeReader(boolean exception, boolean recognised) {
|
private void dispose(boolean exception) {
|
||||||
if (exception && outgoingSession != null)
|
|
||||||
outgoingSession.interrupt();
|
|
||||||
try {
|
|
||||||
reader.dispose(exception, recognised);
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void disposeWriter(boolean exception) {
|
|
||||||
if (exception && incomingSession != null)
|
|
||||||
incomingSession.interrupt();
|
|
||||||
try {
|
try {
|
||||||
|
// 'Recognised' is always true because we opened the connection
|
||||||
|
reader.dispose(exception, true);
|
||||||
writer.dispose(exception);
|
writer.dispose(exception);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package org.briarproject.bramble.plugin.bluetooth;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
interface BluetoothConnectionManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if a contact connection can be opened without exceeding
|
||||||
|
* the connection limit. This method does not need to be called for key
|
||||||
|
* exchange connections.
|
||||||
|
*/
|
||||||
|
boolean canOpenConnection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Passes a newly opened connection to the manager. The manager may close
|
||||||
|
* the new connection or another connection to stay within the connection
|
||||||
|
* limit.
|
||||||
|
* <p/>
|
||||||
|
* Returns false if the manager has closed the new connection (this will
|
||||||
|
* never be the case for key exchange connections).
|
||||||
|
*/
|
||||||
|
boolean connectionOpened(DuplexTransportConnection conn,
|
||||||
|
boolean isForKeyExchange);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Informs the manager that the given connection has been closed.
|
||||||
|
*/
|
||||||
|
void connectionClosed(DuplexTransportConnection conn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Informs the manager that all connections have been closed.
|
||||||
|
*/
|
||||||
|
void allConnectionsClosed();
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package org.briarproject.bramble.plugin.bluetooth;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.INFO;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
@ThreadSafe
|
||||||
|
class BluetoothConnectionManagerImpl implements BluetoothConnectionManager {
|
||||||
|
|
||||||
|
private static final int MAX_OPEN_CONNECTIONS = 5;
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(BluetoothConnectionManagerImpl.class.getName());
|
||||||
|
|
||||||
|
private final Object lock = new Object();
|
||||||
|
private final LinkedList<DuplexTransportConnection> connections =
|
||||||
|
new LinkedList<>(); // Locking: lock
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canOpenConnection() {
|
||||||
|
synchronized (lock) {
|
||||||
|
int open = connections.size();
|
||||||
|
if (LOG.isLoggable(INFO)) LOG.info(open + " open connections");
|
||||||
|
return open < MAX_OPEN_CONNECTIONS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean connectionOpened(DuplexTransportConnection conn,
|
||||||
|
boolean isForKeyExchange) {
|
||||||
|
DuplexTransportConnection close = null;
|
||||||
|
synchronized (lock) {
|
||||||
|
int open = connections.size();
|
||||||
|
boolean accept = isForKeyExchange || open < MAX_OPEN_CONNECTIONS;
|
||||||
|
if (accept) {
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Accepting connection, " + (open + 1) + " open");
|
||||||
|
connections.add(conn);
|
||||||
|
if (open == MAX_OPEN_CONNECTIONS) {
|
||||||
|
LOG.info("Closing old connection to stay within limit");
|
||||||
|
close = connections.poll();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Refusing connection, " + open + " open");
|
||||||
|
close = conn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (close != null) tryToClose(close);
|
||||||
|
return close != conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryToClose(DuplexTransportConnection conn) {
|
||||||
|
try {
|
||||||
|
conn.getReader().dispose(false, true);
|
||||||
|
conn.getWriter().dispose(false);
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (LOG.isLoggable(INFO)) LOG.log(INFO, e.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connectionClosed(DuplexTransportConnection conn) {
|
||||||
|
synchronized (lock) {
|
||||||
|
connections.remove(conn);
|
||||||
|
if (LOG.isLoggable(INFO)) {
|
||||||
|
int open = connections.size();
|
||||||
|
LOG.info("Connection closed, " + open + " open");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void allConnectionsClosed() {
|
||||||
|
synchronized (lock) {
|
||||||
|
connections.clear();
|
||||||
|
LOG.info("All connections closed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -51,6 +51,8 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(BluetoothPlugin.class.getName());
|
Logger.getLogger(BluetoothPlugin.class.getName());
|
||||||
|
|
||||||
|
protected final BluetoothConnectionManager connectionManager;
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
private final SecureRandom secureRandom;
|
private final SecureRandom secureRandom;
|
||||||
private final Backoff backoff;
|
private final Backoff backoff;
|
||||||
@@ -91,8 +93,10 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
abstract DuplexTransportConnection connectTo(String address, String uuid)
|
abstract DuplexTransportConnection connectTo(String address, String uuid)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
BluetoothPlugin(Executor ioExecutor, SecureRandom secureRandom,
|
BluetoothPlugin(BluetoothConnectionManager connectionManager,
|
||||||
|
Executor ioExecutor, SecureRandom secureRandom,
|
||||||
Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
|
Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
|
||||||
|
this.connectionManager = connectionManager;
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.secureRandom = secureRandom;
|
this.secureRandom = secureRandom;
|
||||||
this.backoff = backoff;
|
this.backoff = backoff;
|
||||||
@@ -110,6 +114,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
void onAdapterDisabled() {
|
void onAdapterDisabled() {
|
||||||
LOG.info("Bluetooth disabled");
|
LOG.info("Bluetooth disabled");
|
||||||
tryToClose(socket);
|
tryToClose(socket);
|
||||||
|
connectionManager.allConnectionsClosed();
|
||||||
callback.transportDisabled();
|
callback.transportDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +218,8 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
callback.incomingConnectionCreated(conn);
|
if (connectionManager.connectionOpened(conn, false))
|
||||||
|
callback.incomingConnectionCreated(conn);
|
||||||
if (!running) return;
|
if (!running) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,10 +263,15 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
if (!isRunning() || !shouldAllowContactConnections()) return;
|
if (!isRunning() || !shouldAllowContactConnections()) return;
|
||||||
|
if (!connectionManager.canOpenConnection()) {
|
||||||
|
LOG.info("Not connecting, too many open connections");
|
||||||
|
return;
|
||||||
|
}
|
||||||
DuplexTransportConnection conn = connect(address, uuid);
|
DuplexTransportConnection conn = connect(address, uuid);
|
||||||
if (conn != null) {
|
if (conn != null) {
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
callback.outgoingConnectionCreated(c, conn);
|
if (connectionManager.connectionOpened(conn, false))
|
||||||
|
callback.outgoingConnectionCreated(c, conn);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -300,12 +311,19 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(ContactId c) {
|
||||||
if (!isRunning() || !shouldAllowContactConnections()) return null;
|
if (!isRunning() || !shouldAllowContactConnections()) return null;
|
||||||
|
if (!connectionManager.canOpenConnection()) {
|
||||||
|
LOG.info("Not connecting, too many open connections");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
TransportProperties p = callback.getRemoteProperties(c);
|
TransportProperties p = callback.getRemoteProperties(c);
|
||||||
String address = p.get(PROP_ADDRESS);
|
String address = p.get(PROP_ADDRESS);
|
||||||
if (StringUtils.isNullOrEmpty(address)) return null;
|
if (StringUtils.isNullOrEmpty(address)) return null;
|
||||||
String uuid = p.get(PROP_UUID);
|
String uuid = p.get(PROP_UUID);
|
||||||
if (StringUtils.isNullOrEmpty(uuid)) return null;
|
if (StringUtils.isNullOrEmpty(uuid)) return null;
|
||||||
return connect(address, uuid);
|
DuplexTransportConnection conn = connect(address, uuid);
|
||||||
|
if (conn == null) return null;
|
||||||
|
// TODO: Why don't we reset the backoff here?
|
||||||
|
return connectionManager.connectionOpened(conn, false) ? conn : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -355,7 +373,10 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
String uuid = UUID.nameUUIDFromBytes(commitment).toString();
|
String uuid = UUID.nameUUIDFromBytes(commitment).toString();
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Connecting to key agreement UUID " + uuid);
|
LOG.info("Connecting to key agreement UUID " + uuid);
|
||||||
return connect(address, uuid);
|
DuplexTransportConnection conn = connect(address, uuid);
|
||||||
|
// The connection limit doesn't apply to key agreement
|
||||||
|
if (conn != null) connectionManager.connectionOpened(conn, true);
|
||||||
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String parseAddress(BdfList descriptor) throws FormatException {
|
private String parseAddress(BdfList descriptor) throws FormatException {
|
||||||
@@ -408,6 +429,8 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
public KeyAgreementConnection accept() throws IOException {
|
public KeyAgreementConnection accept() throws IOException {
|
||||||
DuplexTransportConnection conn = acceptConnection(ss);
|
DuplexTransportConnection conn = acceptConnection(ss);
|
||||||
if (LOG.isLoggable(INFO)) LOG.info(ID + ": Incoming connection");
|
if (LOG.isLoggable(INFO)) LOG.info(ID + ": Incoming connection");
|
||||||
|
// The connection limit doesn't apply to key agreement
|
||||||
|
connectionManager.connectionOpened(conn, true);
|
||||||
return new KeyAgreementConnection(conn, ID);
|
return new KeyAgreementConnection(conn, ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import org.briarproject.bramble.api.event.Event;
|
|||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
|
import org.briarproject.bramble.api.lifecycle.event.ShutdownEvent;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.Ack;
|
import org.briarproject.bramble.api.sync.Ack;
|
||||||
import org.briarproject.bramble.api.sync.Offer;
|
import org.briarproject.bramble.api.sync.Offer;
|
||||||
@@ -38,7 +38,6 @@ import javax.annotation.concurrent.ThreadSafe;
|
|||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
|
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_RECORD_PAYLOAD_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_RECORD_PAYLOAD_LENGTH;
|
||||||
|
|
||||||
@@ -210,9 +209,8 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
} else if (e instanceof MessageToRequestEvent) {
|
} else if (e instanceof MessageToRequestEvent) {
|
||||||
if (((MessageToRequestEvent) e).getContactId().equals(contactId))
|
if (((MessageToRequestEvent) e).getContactId().equals(contactId))
|
||||||
generateRequest();
|
generateRequest();
|
||||||
} else if (e instanceof LifecycleEvent) {
|
} else if (e instanceof ShutdownEvent) {
|
||||||
LifecycleEvent l = (LifecycleEvent) e;
|
interrupt();
|
||||||
if (l.getLifecycleState() == STOPPING) interrupt();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import org.briarproject.bramble.api.event.Event;
|
|||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
|
import org.briarproject.bramble.api.lifecycle.event.ShutdownEvent;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.Ack;
|
import org.briarproject.bramble.api.sync.Ack;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
@@ -27,7 +27,6 @@ import java.util.logging.Logger;
|
|||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An incoming {@link SyncSession}.
|
* An incoming {@link SyncSession}.
|
||||||
@@ -97,9 +96,8 @@ class IncomingSession implements SyncSession, EventListener {
|
|||||||
if (e instanceof ContactRemovedEvent) {
|
if (e instanceof ContactRemovedEvent) {
|
||||||
ContactRemovedEvent c = (ContactRemovedEvent) e;
|
ContactRemovedEvent c = (ContactRemovedEvent) e;
|
||||||
if (c.getContactId().equals(contactId)) interrupt();
|
if (c.getContactId().equals(contactId)) interrupt();
|
||||||
} else if (e instanceof LifecycleEvent) {
|
} else if (e instanceof ShutdownEvent) {
|
||||||
LifecycleEvent l = (LifecycleEvent) e;
|
interrupt();
|
||||||
if (l.getLifecycleState() == STOPPING) interrupt();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import org.briarproject.bramble.api.event.Event;
|
|||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
|
import org.briarproject.bramble.api.lifecycle.event.ShutdownEvent;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.Ack;
|
import org.briarproject.bramble.api.sync.Ack;
|
||||||
import org.briarproject.bramble.api.sync.RecordWriter;
|
import org.briarproject.bramble.api.sync.RecordWriter;
|
||||||
@@ -28,7 +28,6 @@ import javax.annotation.concurrent.ThreadSafe;
|
|||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
|
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_RECORD_PAYLOAD_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_RECORD_PAYLOAD_LENGTH;
|
||||||
|
|
||||||
@@ -110,9 +109,8 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
if (e instanceof ContactRemovedEvent) {
|
if (e instanceof ContactRemovedEvent) {
|
||||||
ContactRemovedEvent c = (ContactRemovedEvent) e;
|
ContactRemovedEvent c = (ContactRemovedEvent) e;
|
||||||
if (c.getContactId().equals(contactId)) interrupt();
|
if (c.getContactId().equals(contactId)) interrupt();
|
||||||
} else if (e instanceof LifecycleEvent) {
|
} else if (e instanceof ShutdownEvent) {
|
||||||
LifecycleEvent l = (LifecycleEvent) e;
|
interrupt();
|
||||||
if (l.getLifecycleState() == STOPPING) interrupt();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,9 +71,11 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
@Override
|
@Override
|
||||||
public void startService() {
|
public void startService() {
|
||||||
if (used.getAndSet(true)) throw new IllegalStateException();
|
if (used.getAndSet(true)) throw new IllegalStateException();
|
||||||
validateOutstandingMessagesAsync();
|
for (ClientId c : validators.keySet()) {
|
||||||
deliverOutstandingMessagesAsync();
|
validateOutstandingMessagesAsync(c);
|
||||||
shareOutstandingMessagesAsync();
|
deliverOutstandingMessagesAsync(c);
|
||||||
|
shareOutstandingMessagesAsync(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -91,17 +93,17 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
hooks.put(c, hook);
|
hooks.put(c, hook);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateOutstandingMessagesAsync() {
|
private void validateOutstandingMessagesAsync(ClientId c) {
|
||||||
dbExecutor.execute(this::validateOutstandingMessages);
|
dbExecutor.execute(() -> validateOutstandingMessages(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
private void validateOutstandingMessages() {
|
private void validateOutstandingMessages(ClientId c) {
|
||||||
try {
|
try {
|
||||||
Queue<MessageId> unvalidated = new LinkedList<>();
|
Queue<MessageId> unvalidated = new LinkedList<>();
|
||||||
Transaction txn = db.startTransaction(true);
|
Transaction txn = db.startTransaction(true);
|
||||||
try {
|
try {
|
||||||
unvalidated.addAll(db.getMessagesToValidate(txn));
|
unvalidated.addAll(db.getMessagesToValidate(txn, c));
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction(txn);
|
db.endTransaction(txn);
|
||||||
@@ -146,17 +148,17 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deliverOutstandingMessagesAsync() {
|
private void deliverOutstandingMessagesAsync(ClientId c) {
|
||||||
dbExecutor.execute(this::deliverOutstandingMessages);
|
dbExecutor.execute(() -> deliverOutstandingMessages(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
private void deliverOutstandingMessages() {
|
private void deliverOutstandingMessages(ClientId c) {
|
||||||
try {
|
try {
|
||||||
Queue<MessageId> pending = new LinkedList<>();
|
Queue<MessageId> pending = new LinkedList<>();
|
||||||
Transaction txn = db.startTransaction(true);
|
Transaction txn = db.startTransaction(true);
|
||||||
try {
|
try {
|
||||||
pending.addAll(db.getPendingMessages(txn));
|
pending.addAll(db.getPendingMessages(txn, c));
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction(txn);
|
db.endTransaction(txn);
|
||||||
@@ -351,17 +353,17 @@ class ValidationManagerImpl implements ValidationManager, Service,
|
|||||||
return pending;
|
return pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void shareOutstandingMessagesAsync() {
|
private void shareOutstandingMessagesAsync(ClientId c) {
|
||||||
dbExecutor.execute(this::shareOutstandingMessages);
|
dbExecutor.execute(() -> shareOutstandingMessages(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
private void shareOutstandingMessages() {
|
private void shareOutstandingMessages(ClientId c) {
|
||||||
try {
|
try {
|
||||||
Queue<MessageId> toShare = new LinkedList<>();
|
Queue<MessageId> toShare = new LinkedList<>();
|
||||||
Transaction txn = db.startTransaction(true);
|
Transaction txn = db.startTransaction(true);
|
||||||
try {
|
try {
|
||||||
toShare.addAll(db.getMessagesToShare(txn));
|
toShare.addAll(db.getMessagesToShare(txn, c));
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction(txn);
|
db.endTransaction(txn);
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
int shutdownHandle = 12345;
|
int shutdownHandle = 12345;
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// open()
|
// open()
|
||||||
oneOf(database).open(null);
|
oneOf(database).open();
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
|
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
|
||||||
will(returnValue(shutdownHandle));
|
will(returnValue(shutdownHandle));
|
||||||
@@ -201,7 +201,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
shutdown);
|
shutdown);
|
||||||
|
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open());
|
||||||
Transaction transaction = db.startTransaction(false);
|
Transaction transaction = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
db.addLocalAuthor(transaction, localAuthor);
|
db.addLocalAuthor(transaction, localAuthor);
|
||||||
@@ -1501,7 +1501,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
MessageId messageId2 = new MessageId(TestUtils.getRandomId());
|
MessageId messageId2 = new MessageId(TestUtils.getRandomId());
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// open()
|
// open()
|
||||||
oneOf(database).open(null);
|
oneOf(database).open();
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
|
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
|
||||||
will(returnValue(shutdownHandle));
|
will(returnValue(shutdownHandle));
|
||||||
@@ -1543,7 +1543,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
shutdown);
|
shutdown);
|
||||||
|
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open());
|
||||||
Transaction transaction = db.startTransaction(false);
|
Transaction transaction = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
db.addLocalMessage(transaction, message, metadata, true);
|
db.addLocalMessage(transaction, message, metadata, true);
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
public void testDoesNotRunMigrationsWhenCreatingDatabase()
|
public void testDoesNotRunMigrationsWhenCreatingDatabase()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Database<Connection> db = createDatabase(singletonList(migration));
|
Database<Connection> db = createDatabase(singletonList(migration));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open());
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
@@ -72,14 +72,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open());
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
// Override the data schema version
|
// Override the data schema version
|
||||||
setDataSchemaVersion(db, -1);
|
setDataSchemaVersion(db, -1);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - an exception should be thrown
|
// Reopen the DB - an exception should be thrown
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
db.open(null);
|
db.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -87,12 +87,12 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open());
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - migrations should not be run
|
// Reopen the DB - migrations should not be run
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
assertTrue(db.open(null));
|
assertTrue(db.open());
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
@@ -101,14 +101,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
public void testThrowsExceptionIfDataIsNewerThanCode() throws Exception {
|
public void testThrowsExceptionIfDataIsNewerThanCode() throws Exception {
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open());
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
// Override the data schema version
|
// Override the data schema version
|
||||||
setDataSchemaVersion(db, CODE_SCHEMA_VERSION + 1);
|
setDataSchemaVersion(db, CODE_SCHEMA_VERSION + 1);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - an exception should be thrown
|
// Reopen the DB - an exception should be thrown
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
db.open(null);
|
db.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = DataTooOldException.class)
|
@Test(expected = DataTooOldException.class)
|
||||||
@@ -116,13 +116,13 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(emptyList());
|
Database<Connection> db = createDatabase(emptyList());
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open());
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 1);
|
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 1);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - an exception should be thrown
|
// Reopen the DB - an exception should be thrown
|
||||||
db = createDatabase(emptyList());
|
db = createDatabase(emptyList());
|
||||||
db.open(null);
|
db.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = DataTooOldException.class)
|
@Test(expected = DataTooOldException.class)
|
||||||
@@ -141,14 +141,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open());
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
// Override the data schema version
|
// Override the data schema version
|
||||||
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 3);
|
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 3);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - an exception should be thrown
|
// Reopen the DB - an exception should be thrown
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
db.open(null);
|
db.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -170,14 +170,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open());
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
// Override the data schema version
|
// Override the data schema version
|
||||||
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 2);
|
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 2);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - the first migration should be run
|
// Reopen the DB - the first migration should be run
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
assertTrue(db.open(null));
|
assertTrue(db.open());
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
@@ -202,14 +202,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open());
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
// Override the data schema version
|
// Override the data schema version
|
||||||
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 2);
|
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 2);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - both migrations should be run
|
// Reopen the DB - both migrations should be run
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
assertTrue(db.open(null));
|
assertTrue(db.open());
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ public abstract class DatabasePerformanceComparisonTest
|
|||||||
throws DbException {
|
throws DbException {
|
||||||
Database<Connection> db = createDatabase(conditionA,
|
Database<Connection> db = createDatabase(conditionA,
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
||||||
db.open(null);
|
db.open();
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -477,30 +477,30 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetMessagesToShare() throws Exception {
|
public void testGetMessagesToShare() throws Exception {
|
||||||
String name = "getMessagesToShare(T)";
|
String name = "getMessagesToShare(T, ClientId)";
|
||||||
benchmark(name, db -> {
|
benchmark(name, db -> {
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
db.getMessagesToShare(txn);
|
db.getMessagesToShare(txn, pickRandom(clientIds));
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetMessagesToValidate() throws Exception {
|
public void testGetMessagesToValidate() throws Exception {
|
||||||
String name = "getMessagesToValidate(T)";
|
String name = "getMessagesToValidate(T, ClientId)";
|
||||||
benchmark(name, db -> {
|
benchmark(name, db -> {
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
db.getMessagesToValidate(txn);
|
db.getMessagesToValidate(txn, pickRandom(clientIds));
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetPendingMessages() throws Exception {
|
public void testGetPendingMessages() throws Exception {
|
||||||
String name = "getPendingMessages(T)";
|
String name = "getPendingMessages(T, ClientId)";
|
||||||
benchmark(name, db -> {
|
benchmark(name, db -> {
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
db.getPendingMessages(txn);
|
db.getPendingMessages(txn, pickRandom(clientIds));
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
|
|||||||
private Database<Connection> openDatabase() throws DbException {
|
private Database<Connection> openDatabase() throws DbException {
|
||||||
Database<Connection> db = createDatabase(
|
Database<Connection> db = createDatabase(
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
||||||
db.open(null);
|
db.open();
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1376,12 +1376,12 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Collection<MessageId> result;
|
Collection<MessageId> result;
|
||||||
|
|
||||||
// Retrieve messages to be validated
|
// Retrieve messages to be validated
|
||||||
result = db.getMessagesToValidate(txn);
|
result = db.getMessagesToValidate(txn, clientId);
|
||||||
assertEquals(1, result.size());
|
assertEquals(1, result.size());
|
||||||
assertTrue(result.contains(mId1));
|
assertTrue(result.contains(mId1));
|
||||||
|
|
||||||
// Retrieve pending messages
|
// Retrieve pending messages
|
||||||
result = db.getPendingMessages(txn);
|
result = db.getPendingMessages(txn, clientId);
|
||||||
assertEquals(1, result.size());
|
assertEquals(1, result.size());
|
||||||
assertTrue(result.contains(mId3));
|
assertTrue(result.contains(mId3));
|
||||||
|
|
||||||
@@ -1416,7 +1416,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
db.addMessageDependency(txn, groupId, mId4, mId3);
|
db.addMessageDependency(txn, groupId, mId4, mId3);
|
||||||
|
|
||||||
// Retrieve messages to be shared
|
// Retrieve messages to be shared
|
||||||
Collection<MessageId> result = db.getMessagesToShare(txn);
|
Collection<MessageId> result =
|
||||||
|
db.getMessagesToShare(txn, clientId);
|
||||||
assertEquals(2, result.size());
|
assertEquals(2, result.size());
|
||||||
assertTrue(result.contains(mId2));
|
assertTrue(result.contains(mId2));
|
||||||
assertTrue(result.contains(mId3));
|
assertTrue(result.contains(mId3));
|
||||||
@@ -1699,7 +1700,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Database<Connection> db = createDatabase(
|
Database<Connection> db = createDatabase(
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), clock);
|
new TestDatabaseConfig(testDir, MAX_SIZE), clock);
|
||||||
if (!resume) TestUtils.deleteTestDirectory(testDir);
|
if (!resume) TestUtils.deleteTestDirectory(testDir);
|
||||||
db.open(null);
|
db.open();
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public abstract class SingleDatabasePerformanceTest
|
|||||||
private Database<Connection> openDatabase() throws DbException {
|
private Database<Connection> openDatabase() throws DbException {
|
||||||
Database<Connection> db = createDatabase(
|
Database<Connection> db = createDatabase(
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
||||||
db.open(null);
|
db.open();
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,21 +100,21 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
|
|||||||
// validateOutstandingMessages()
|
// validateOutstandingMessages()
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
oneOf(db).getMessagesToValidate(txn);
|
oneOf(db).getMessagesToValidate(txn, clientId);
|
||||||
will(returnValue(Collections.emptyList()));
|
will(returnValue(Collections.emptyList()));
|
||||||
oneOf(db).commitTransaction(txn);
|
oneOf(db).commitTransaction(txn);
|
||||||
oneOf(db).endTransaction(txn);
|
oneOf(db).endTransaction(txn);
|
||||||
// deliverOutstandingMessages()
|
// deliverOutstandingMessages()
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn1));
|
will(returnValue(txn1));
|
||||||
oneOf(db).getPendingMessages(txn1);
|
oneOf(db).getPendingMessages(txn1, clientId);
|
||||||
will(returnValue(Collections.emptyList()));
|
will(returnValue(Collections.emptyList()));
|
||||||
oneOf(db).commitTransaction(txn1);
|
oneOf(db).commitTransaction(txn1);
|
||||||
oneOf(db).endTransaction(txn1);
|
oneOf(db).endTransaction(txn1);
|
||||||
// shareOutstandingMessages()
|
// shareOutstandingMessages()
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn2));
|
will(returnValue(txn2));
|
||||||
oneOf(db).getMessagesToShare(txn2);
|
oneOf(db).getMessagesToShare(txn2, clientId);
|
||||||
will(returnValue(Collections.emptyList()));
|
will(returnValue(Collections.emptyList()));
|
||||||
oneOf(db).commitTransaction(txn2);
|
oneOf(db).commitTransaction(txn2);
|
||||||
oneOf(db).endTransaction(txn2);
|
oneOf(db).endTransaction(txn2);
|
||||||
@@ -138,7 +138,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
|
|||||||
// Get messages to validate
|
// Get messages to validate
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
oneOf(db).getMessagesToValidate(txn);
|
oneOf(db).getMessagesToValidate(txn, clientId);
|
||||||
will(returnValue(Arrays.asList(messageId, messageId1)));
|
will(returnValue(Arrays.asList(messageId, messageId1)));
|
||||||
oneOf(db).commitTransaction(txn);
|
oneOf(db).commitTransaction(txn);
|
||||||
oneOf(db).endTransaction(txn);
|
oneOf(db).endTransaction(txn);
|
||||||
@@ -199,14 +199,14 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
|
|||||||
// Get pending messages to deliver
|
// Get pending messages to deliver
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn5));
|
will(returnValue(txn5));
|
||||||
oneOf(db).getPendingMessages(txn5);
|
oneOf(db).getPendingMessages(txn5, clientId);
|
||||||
will(returnValue(Collections.emptyList()));
|
will(returnValue(Collections.emptyList()));
|
||||||
oneOf(db).commitTransaction(txn5);
|
oneOf(db).commitTransaction(txn5);
|
||||||
oneOf(db).endTransaction(txn5);
|
oneOf(db).endTransaction(txn5);
|
||||||
// Get messages to share
|
// Get messages to share
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn6));
|
will(returnValue(txn6));
|
||||||
oneOf(db).getMessagesToShare(txn6);
|
oneOf(db).getMessagesToShare(txn6, clientId);
|
||||||
will(returnValue(Collections.emptyList()));
|
will(returnValue(Collections.emptyList()));
|
||||||
oneOf(db).commitTransaction(txn6);
|
oneOf(db).commitTransaction(txn6);
|
||||||
oneOf(db).endTransaction(txn6);
|
oneOf(db).endTransaction(txn6);
|
||||||
@@ -227,14 +227,14 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
|
|||||||
// Get messages to validate
|
// Get messages to validate
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
oneOf(db).getMessagesToValidate(txn);
|
oneOf(db).getMessagesToValidate(txn, clientId);
|
||||||
will(returnValue(Collections.emptyList()));
|
will(returnValue(Collections.emptyList()));
|
||||||
oneOf(db).commitTransaction(txn);
|
oneOf(db).commitTransaction(txn);
|
||||||
oneOf(db).endTransaction(txn);
|
oneOf(db).endTransaction(txn);
|
||||||
// Get pending messages to deliver
|
// Get pending messages to deliver
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn1));
|
will(returnValue(txn1));
|
||||||
oneOf(db).getPendingMessages(txn1);
|
oneOf(db).getPendingMessages(txn1, clientId);
|
||||||
will(returnValue(Collections.singletonList(messageId)));
|
will(returnValue(Collections.singletonList(messageId)));
|
||||||
oneOf(db).commitTransaction(txn1);
|
oneOf(db).commitTransaction(txn1);
|
||||||
oneOf(db).endTransaction(txn1);
|
oneOf(db).endTransaction(txn1);
|
||||||
@@ -292,7 +292,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
|
|||||||
// Get messages to share
|
// Get messages to share
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn4));
|
will(returnValue(txn4));
|
||||||
oneOf(db).getMessagesToShare(txn4);
|
oneOf(db).getMessagesToShare(txn4, clientId);
|
||||||
will(returnValue(Collections.emptyList()));
|
will(returnValue(Collections.emptyList()));
|
||||||
oneOf(db).commitTransaction(txn4);
|
oneOf(db).commitTransaction(txn4);
|
||||||
oneOf(db).endTransaction(txn4);
|
oneOf(db).endTransaction(txn4);
|
||||||
@@ -313,14 +313,14 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
|
|||||||
// No messages to validate
|
// No messages to validate
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
oneOf(db).getMessagesToValidate(txn);
|
oneOf(db).getMessagesToValidate(txn, clientId);
|
||||||
will(returnValue(Collections.emptyList()));
|
will(returnValue(Collections.emptyList()));
|
||||||
oneOf(db).commitTransaction(txn);
|
oneOf(db).commitTransaction(txn);
|
||||||
oneOf(db).endTransaction(txn);
|
oneOf(db).endTransaction(txn);
|
||||||
// No pending messages to deliver
|
// No pending messages to deliver
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn1));
|
will(returnValue(txn1));
|
||||||
oneOf(db).getPendingMessages(txn1);
|
oneOf(db).getPendingMessages(txn1, clientId);
|
||||||
will(returnValue(Collections.emptyList()));
|
will(returnValue(Collections.emptyList()));
|
||||||
oneOf(db).commitTransaction(txn1);
|
oneOf(db).commitTransaction(txn1);
|
||||||
oneOf(db).endTransaction(txn1);
|
oneOf(db).endTransaction(txn1);
|
||||||
@@ -328,7 +328,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
|
|||||||
// Get messages to share
|
// Get messages to share
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn2));
|
will(returnValue(txn2));
|
||||||
oneOf(db).getMessagesToShare(txn2);
|
oneOf(db).getMessagesToShare(txn2, clientId);
|
||||||
will(returnValue(Collections.singletonList(messageId)));
|
will(returnValue(Collections.singletonList(messageId)));
|
||||||
oneOf(db).commitTransaction(txn2);
|
oneOf(db).commitTransaction(txn2);
|
||||||
oneOf(db).endTransaction(txn2);
|
oneOf(db).endTransaction(txn2);
|
||||||
@@ -416,7 +416,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
|
|||||||
// Get messages to validate
|
// Get messages to validate
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
oneOf(db).getMessagesToValidate(txn);
|
oneOf(db).getMessagesToValidate(txn, clientId);
|
||||||
will(returnValue(Arrays.asList(messageId, messageId1)));
|
will(returnValue(Arrays.asList(messageId, messageId1)));
|
||||||
oneOf(db).commitTransaction(txn);
|
oneOf(db).commitTransaction(txn);
|
||||||
oneOf(db).endTransaction(txn);
|
oneOf(db).endTransaction(txn);
|
||||||
@@ -457,14 +457,14 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
|
|||||||
// Get pending messages to deliver
|
// Get pending messages to deliver
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn4));
|
will(returnValue(txn4));
|
||||||
oneOf(db).getPendingMessages(txn4);
|
oneOf(db).getPendingMessages(txn4, clientId);
|
||||||
will(returnValue(Collections.emptyList()));
|
will(returnValue(Collections.emptyList()));
|
||||||
oneOf(db).commitTransaction(txn4);
|
oneOf(db).commitTransaction(txn4);
|
||||||
oneOf(db).endTransaction(txn4);
|
oneOf(db).endTransaction(txn4);
|
||||||
// Get messages to share
|
// Get messages to share
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn5));
|
will(returnValue(txn5));
|
||||||
oneOf(db).getMessagesToShare(txn5);
|
oneOf(db).getMessagesToShare(txn5, clientId);
|
||||||
will(returnValue(Collections.emptyList()));
|
will(returnValue(Collections.emptyList()));
|
||||||
oneOf(db).commitTransaction(txn5);
|
oneOf(db).commitTransaction(txn5);
|
||||||
oneOf(db).endTransaction(txn5);
|
oneOf(db).endTransaction(txn5);
|
||||||
@@ -487,7 +487,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
|
|||||||
// Get messages to validate
|
// Get messages to validate
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn));
|
will(returnValue(txn));
|
||||||
oneOf(db).getMessagesToValidate(txn);
|
oneOf(db).getMessagesToValidate(txn, clientId);
|
||||||
will(returnValue(Arrays.asList(messageId, messageId1)));
|
will(returnValue(Arrays.asList(messageId, messageId1)));
|
||||||
oneOf(db).commitTransaction(txn);
|
oneOf(db).commitTransaction(txn);
|
||||||
oneOf(db).endTransaction(txn);
|
oneOf(db).endTransaction(txn);
|
||||||
@@ -533,14 +533,14 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
|
|||||||
// Get pending messages to deliver
|
// Get pending messages to deliver
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn4));
|
will(returnValue(txn4));
|
||||||
oneOf(db).getPendingMessages(txn4);
|
oneOf(db).getPendingMessages(txn4, clientId);
|
||||||
will(returnValue(Collections.emptyList()));
|
will(returnValue(Collections.emptyList()));
|
||||||
oneOf(db).commitTransaction(txn4);
|
oneOf(db).commitTransaction(txn4);
|
||||||
oneOf(db).endTransaction(txn4);
|
oneOf(db).endTransaction(txn4);
|
||||||
// Get messages to share
|
// Get messages to share
|
||||||
oneOf(db).startTransaction(true);
|
oneOf(db).startTransaction(true);
|
||||||
will(returnValue(txn5));
|
will(returnValue(txn5));
|
||||||
oneOf(db).getMessagesToShare(txn5);
|
oneOf(db).getMessagesToShare(txn5, clientId);
|
||||||
will(returnValue(Collections.emptyList()));
|
will(returnValue(Collections.emptyList()));
|
||||||
oneOf(db).commitTransaction(txn5);
|
oneOf(db).commitTransaction(txn5);
|
||||||
oneOf(db).endTransaction(txn5);
|
oneOf(db).endTransaction(txn5);
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ import javax.inject.Singleton;
|
|||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING;
|
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
public class TestLifecycleModule {
|
public class TestLifecycleModule {
|
||||||
|
|
||||||
@@ -59,11 +57,6 @@ public class TestLifecycleModule {
|
|||||||
@Override
|
@Override
|
||||||
public void waitForShutdown() throws InterruptedException {
|
public void waitForShutdown() throws InterruptedException {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public LifecycleState getLifecycleState() {
|
|
||||||
return RUNNING;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
return lifecycleManager;
|
return lifecycleManager;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,9 +31,11 @@ class JavaBluetoothPlugin extends BluetoothPlugin<StreamConnectionNotifier> {
|
|||||||
// Non-null if the plugin started successfully
|
// Non-null if the plugin started successfully
|
||||||
private volatile LocalDevice localDevice = null;
|
private volatile LocalDevice localDevice = null;
|
||||||
|
|
||||||
JavaBluetoothPlugin(Executor ioExecutor, SecureRandom secureRandom,
|
JavaBluetoothPlugin(BluetoothConnectionManager connectionManager,
|
||||||
|
Executor ioExecutor, SecureRandom secureRandom,
|
||||||
Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
|
Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
|
||||||
super(ioExecutor, secureRandom, backoff, callback, maxLatency);
|
super(connectionManager, ioExecutor, secureRandom, backoff, callback,
|
||||||
|
maxLatency);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -110,6 +112,6 @@ class JavaBluetoothPlugin extends BluetoothPlugin<StreamConnectionNotifier> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private DuplexTransportConnection wrapSocket(StreamConnection s) {
|
private DuplexTransportConnection wrapSocket(StreamConnection s) {
|
||||||
return new JavaBluetoothTransportConnection(this, s);
|
return new JavaBluetoothTransportConnection(this, connectionManager, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,10 +51,12 @@ public class JavaBluetoothPluginFactory implements DuplexPluginFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
||||||
|
BluetoothConnectionManager connectionManager =
|
||||||
|
new BluetoothConnectionManagerImpl();
|
||||||
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
JavaBluetoothPlugin plugin = new JavaBluetoothPlugin(ioExecutor,
|
JavaBluetoothPlugin plugin = new JavaBluetoothPlugin(connectionManager,
|
||||||
secureRandom, backoff, callback, MAX_LATENCY);
|
ioExecutor, secureRandom, backoff, callback, MAX_LATENCY);
|
||||||
eventBus.addListener(plugin);
|
eventBus.addListener(plugin);
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,11 +14,15 @@ import javax.microedition.io.StreamConnection;
|
|||||||
class JavaBluetoothTransportConnection
|
class JavaBluetoothTransportConnection
|
||||||
extends AbstractDuplexTransportConnection {
|
extends AbstractDuplexTransportConnection {
|
||||||
|
|
||||||
|
private final BluetoothConnectionManager connectionManager;
|
||||||
private final StreamConnection stream;
|
private final StreamConnection stream;
|
||||||
|
|
||||||
JavaBluetoothTransportConnection(Plugin plugin, StreamConnection stream) {
|
JavaBluetoothTransportConnection(Plugin plugin,
|
||||||
|
BluetoothConnectionManager connectionManager,
|
||||||
|
StreamConnection stream) {
|
||||||
super(plugin);
|
super(plugin);
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
|
this.connectionManager = connectionManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -33,6 +37,10 @@ class JavaBluetoothTransportConnection
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void closeConnection(boolean exception) throws IOException {
|
protected void closeConnection(boolean exception) throws IOException {
|
||||||
stream.close();
|
try {
|
||||||
|
stream.close();
|
||||||
|
} finally {
|
||||||
|
connectionManager.connectionClosed(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[main]
|
[main]
|
||||||
host = https://www.transifex.com
|
host = https://www.transifex.com
|
||||||
lang_map = pt_BR: pt-rBR, nb_NO: nb, zh-Hans: zh-rCN
|
lang_map = pt_BR: pt-rBR, fr_FR: fr, nb_NO: nb, zh-Hans: zh-rCN
|
||||||
|
|
||||||
[briar.stringsxml-5]
|
[briar.stringsxml-5]
|
||||||
file_filter = src/main/res/values-<lang>/strings.xml
|
file_filter = src/main/res/values-<lang>/strings.xml
|
||||||
|
|||||||
@@ -77,11 +77,6 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name=".android.login.OpenDatabaseActivity"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:launchMode="singleTop"/>
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
android:name="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
|
||||||
android:theme="@style/BriarTheme.NoActionBar"
|
android:theme="@style/BriarTheme.NoActionBar"
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import android.net.Uri;
|
|||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.support.v4.app.TaskStackBuilder;
|
import android.support.v4.app.TaskStackBuilder;
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.Multiset;
|
import org.briarproject.bramble.api.Multiset;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
@@ -171,13 +170,9 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
@TargetApi(26)
|
@TargetApi(26)
|
||||||
private void createNotificationChannel(String channelId,
|
private void createNotificationChannel(String channelId,
|
||||||
@StringRes int name) {
|
@StringRes int name) {
|
||||||
NotificationChannel nc =
|
notificationManager.createNotificationChannel(
|
||||||
new NotificationChannel(channelId, appContext.getString(name),
|
new NotificationChannel(channelId, appContext.getString(name),
|
||||||
IMPORTANCE_DEFAULT);
|
IMPORTANCE_DEFAULT));
|
||||||
nc.enableLights(true);
|
|
||||||
nc.setLightColor(
|
|
||||||
ContextCompat.getColor(appContext, R.color.briar_green_light));
|
|
||||||
notificationManager.createNotificationChannel(nc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -94,7 +94,6 @@ public class AppModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean databaseExists() {
|
public boolean databaseExists() {
|
||||||
// FIXME should not run on UiThread #620
|
|
||||||
if (!dir.isDirectory()) return false;
|
if (!dir.isDirectory()) return false;
|
||||||
File[] files = dir.listFiles();
|
File[] files = dir.listFiles();
|
||||||
return files != null && files.length > 0;
|
return files != null && files.length > 0;
|
||||||
|
|||||||
@@ -88,7 +88,6 @@ public class BriarService extends Service {
|
|||||||
stopSelf();
|
stopSelf();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create notification channels
|
// Create notification channels
|
||||||
if (SDK_INT >= 26) {
|
if (SDK_INT >= 26) {
|
||||||
NotificationManager nm = (NotificationManager)
|
NotificationManager nm = (NotificationManager)
|
||||||
|
|||||||
@@ -3,31 +3,29 @@ package org.briarproject.briar.android;
|
|||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.activity.BaseActivity;
|
import org.briarproject.briar.android.activity.BaseActivity;
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
|
||||||
import org.briarproject.briar.android.fragment.ErrorFragment;
|
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult;
|
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult;
|
||||||
import static org.briarproject.briar.android.BriarService.EXTRA_NOTIFICATION_ID;
|
import static org.briarproject.briar.android.BriarService.EXTRA_NOTIFICATION_ID;
|
||||||
import static org.briarproject.briar.android.BriarService.EXTRA_START_RESULT;
|
import static org.briarproject.briar.android.BriarService.EXTRA_START_RESULT;
|
||||||
|
|
||||||
public class StartupFailureActivity extends BaseActivity implements
|
public class StartupFailureActivity extends BaseActivity {
|
||||||
BaseFragmentListener {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
super.onCreate(state);
|
super.onCreate(state);
|
||||||
|
|
||||||
setContentView(R.layout.activity_fragment_container);
|
setContentView(R.layout.activity_startup_failure);
|
||||||
handleIntent(getIntent());
|
handleIntent(getIntent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectActivity(ActivityComponent component) {
|
public void injectActivity(ActivityComponent component) {
|
||||||
component.inject(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleIntent(Intent i) {
|
private void handleIntent(Intent i) {
|
||||||
@@ -43,31 +41,12 @@ public class StartupFailureActivity extends BaseActivity implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
// show proper error message
|
// show proper error message
|
||||||
String errorMsg;
|
TextView view = findViewById(R.id.errorView);
|
||||||
switch (result) {
|
if (result.equals(StartResult.DB_ERROR)) {
|
||||||
case DATA_TOO_OLD_ERROR:
|
view.setText(getText(R.string.startup_failed_db_error));
|
||||||
errorMsg = getString(R.string.startup_failed_db_error);
|
} else if (result.equals(StartResult.SERVICE_ERROR)) {
|
||||||
break;
|
view.setText(getText(R.string.startup_failed_service_error));
|
||||||
case DATA_TOO_NEW_ERROR:
|
|
||||||
errorMsg =
|
|
||||||
getString(R.string.startup_failed_data_too_new_error);
|
|
||||||
break;
|
|
||||||
case DB_ERROR:
|
|
||||||
errorMsg =
|
|
||||||
getString(R.string.startup_failed_data_too_old_error);
|
|
||||||
break;
|
|
||||||
case SERVICE_ERROR:
|
|
||||||
errorMsg = getString(R.string.startup_failed_service_error);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
}
|
||||||
showInitialFragment(ErrorFragment.newInstance(errorMsg));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void runOnDbThread(Runnable runnable) {
|
|
||||||
throw new AssertionError("Deprecated and should not be used");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.briarproject.briar.android.activity;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
|
||||||
import org.briarproject.briar.android.AndroidComponent;
|
import org.briarproject.briar.android.AndroidComponent;
|
||||||
import org.briarproject.briar.android.StartupFailureActivity;
|
|
||||||
import org.briarproject.briar.android.blog.BlogActivity;
|
import org.briarproject.briar.android.blog.BlogActivity;
|
||||||
import org.briarproject.briar.android.blog.BlogFragment;
|
import org.briarproject.briar.android.blog.BlogFragment;
|
||||||
import org.briarproject.briar.android.blog.BlogModule;
|
import org.briarproject.briar.android.blog.BlogModule;
|
||||||
@@ -32,7 +31,6 @@ import org.briarproject.briar.android.keyagreement.ShowQrCodeFragment;
|
|||||||
import org.briarproject.briar.android.login.AuthorNameFragment;
|
import org.briarproject.briar.android.login.AuthorNameFragment;
|
||||||
import org.briarproject.briar.android.login.ChangePasswordActivity;
|
import org.briarproject.briar.android.login.ChangePasswordActivity;
|
||||||
import org.briarproject.briar.android.login.DozeFragment;
|
import org.briarproject.briar.android.login.DozeFragment;
|
||||||
import org.briarproject.briar.android.login.OpenDatabaseActivity;
|
|
||||||
import org.briarproject.briar.android.login.PasswordActivity;
|
import org.briarproject.briar.android.login.PasswordActivity;
|
||||||
import org.briarproject.briar.android.login.PasswordFragment;
|
import org.briarproject.briar.android.login.PasswordFragment;
|
||||||
import org.briarproject.briar.android.login.SetupActivity;
|
import org.briarproject.briar.android.login.SetupActivity;
|
||||||
@@ -89,8 +87,6 @@ public interface ActivityComponent {
|
|||||||
|
|
||||||
void inject(SetupActivity activity);
|
void inject(SetupActivity activity);
|
||||||
|
|
||||||
void inject(OpenDatabaseActivity activity);
|
|
||||||
|
|
||||||
void inject(NavDrawerActivity activity);
|
void inject(NavDrawerActivity activity);
|
||||||
|
|
||||||
void inject(PasswordActivity activity);
|
void inject(PasswordActivity activity);
|
||||||
@@ -155,8 +151,6 @@ public interface ActivityComponent {
|
|||||||
|
|
||||||
void inject(RssFeedManageActivity activity);
|
void inject(RssFeedManageActivity activity);
|
||||||
|
|
||||||
void inject(StartupFailureActivity activity);
|
|
||||||
|
|
||||||
// Fragments
|
// Fragments
|
||||||
void inject(AuthorNameFragment fragment);
|
void inject(AuthorNameFragment fragment);
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ abstract class BasePostFragment extends BaseFragment {
|
|||||||
i.setFlags(FLAG_ACTIVITY_CLEAR_TOP);
|
i.setFlags(FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
getContext().startActivity(i);
|
getContext().startActivity(i);
|
||||||
}
|
}
|
||||||
}, getFragmentManager());
|
});
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,8 +91,7 @@ public class BlogFragment extends BaseFragment
|
|||||||
|
|
||||||
View v = inflater.inflate(R.layout.fragment_blog, container, false);
|
View v = inflater.inflate(R.layout.fragment_blog, container, false);
|
||||||
|
|
||||||
adapter =
|
adapter = new BlogPostAdapter(getActivity(), this);
|
||||||
new BlogPostAdapter(getActivity(), this, getFragmentManager());
|
|
||||||
list = v.findViewById(R.id.postList);
|
list = v.findViewById(R.id.postList);
|
||||||
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||||
list.setAdapter(adapter);
|
list.setAdapter(adapter);
|
||||||
|
|||||||
@@ -1,30 +1,21 @@
|
|||||||
package org.briarproject.briar.android.blog;
|
package org.briarproject.briar.android.blog;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.v4.app.FragmentManager;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.util.BriarAdapter;
|
import org.briarproject.briar.android.util.BriarAdapter;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
class BlogPostAdapter
|
||||||
@ParametersNotNullByDefault
|
extends BriarAdapter<BlogPostItem, BlogPostViewHolder> {
|
||||||
class BlogPostAdapter extends BriarAdapter<BlogPostItem, BlogPostViewHolder> {
|
|
||||||
|
|
||||||
private final OnBlogPostClickListener listener;
|
private final OnBlogPostClickListener listener;
|
||||||
@Nullable
|
|
||||||
private final FragmentManager fragmentManager;
|
|
||||||
|
|
||||||
BlogPostAdapter(Context ctx, OnBlogPostClickListener listener,
|
BlogPostAdapter(Context ctx, OnBlogPostClickListener listener) {
|
||||||
@Nullable FragmentManager fragmentManager) {
|
|
||||||
super(ctx, BlogPostItem.class);
|
super(ctx, BlogPostItem.class);
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
this.fragmentManager = fragmentManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -32,7 +23,8 @@ class BlogPostAdapter extends BriarAdapter<BlogPostItem, BlogPostViewHolder> {
|
|||||||
int viewType) {
|
int viewType) {
|
||||||
View v = LayoutInflater.from(ctx).inflate(
|
View v = LayoutInflater.from(ctx).inflate(
|
||||||
R.layout.list_item_blog_post, parent, false);
|
R.layout.list_item_blog_post, parent, false);
|
||||||
return new BlogPostViewHolder(v, false, listener, fragmentManager);
|
BlogPostViewHolder ui = new BlogPostViewHolder(v, false, listener);
|
||||||
|
return ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import android.support.annotation.NonNull;
|
|||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v4.app.ActivityOptionsCompat;
|
import android.support.v4.app.ActivityOptionsCompat;
|
||||||
import android.support.v4.app.FragmentManager;
|
|
||||||
import android.support.v4.view.ViewCompat;
|
import android.support.v4.view.ViewCompat;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
@@ -53,16 +52,12 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final OnBlogPostClickListener listener;
|
private final OnBlogPostClickListener listener;
|
||||||
@Nullable
|
|
||||||
private final FragmentManager fragmentManager;
|
|
||||||
|
|
||||||
BlogPostViewHolder(View v, boolean fullText,
|
BlogPostViewHolder(View v, boolean fullText,
|
||||||
@NonNull OnBlogPostClickListener listener,
|
@NonNull OnBlogPostClickListener listener) {
|
||||||
@Nullable FragmentManager fragmentManager) {
|
|
||||||
super(v);
|
super(v);
|
||||||
this.fullText = fullText;
|
this.fullText = fullText;
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
this.fragmentManager = fragmentManager;
|
|
||||||
|
|
||||||
ctx = v.getContext();
|
ctx = v.getContext();
|
||||||
layout = v.findViewById(R.id.postLayout);
|
layout = v.findViewById(R.id.postLayout);
|
||||||
@@ -122,7 +117,7 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
|
|||||||
if (fullText) {
|
if (fullText) {
|
||||||
body.setText(bodyText);
|
body.setText(bodyText);
|
||||||
body.setTextIsSelectable(true);
|
body.setTextIsSelectable(true);
|
||||||
makeLinksClickable(body, fragmentManager);
|
makeLinksClickable(body);
|
||||||
} else {
|
} else {
|
||||||
body.setTextIsSelectable(false);
|
body.setTextIsSelectable(false);
|
||||||
if (bodyText.length() > TEASER_LENGTH)
|
if (bodyText.length() > TEASER_LENGTH)
|
||||||
|
|||||||
@@ -74,8 +74,7 @@ public class FeedFragment extends BaseFragment implements
|
|||||||
|
|
||||||
View v = inflater.inflate(R.layout.fragment_blog, container, false);
|
View v = inflater.inflate(R.layout.fragment_blog, container, false);
|
||||||
|
|
||||||
adapter =
|
adapter = new BlogPostAdapter(getActivity(), this);
|
||||||
new BlogPostAdapter(getActivity(), this, getFragmentManager());
|
|
||||||
|
|
||||||
layoutManager = new LinearLayoutManager(getActivity());
|
layoutManager = new LinearLayoutManager(getActivity());
|
||||||
list = v.findViewById(R.id.postList);
|
list = v.findViewById(R.id.postList);
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ public class ReblogFragment extends BaseFragment implements TextInputListener {
|
|||||||
ui.input.setVisibility(VISIBLE);
|
ui.input.setVisibility(VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ViewHolder {
|
private static class ViewHolder {
|
||||||
|
|
||||||
private final ScrollView scrollView;
|
private final ScrollView scrollView;
|
||||||
private final ProgressBar progressBar;
|
private final ProgressBar progressBar;
|
||||||
@@ -167,7 +167,7 @@ public class ReblogFragment extends BaseFragment implements TextInputListener {
|
|||||||
public void onAuthorClick(BlogPostItem post) {
|
public void onAuthorClick(BlogPostItem post) {
|
||||||
// probably don't want to allow author clicks here
|
// probably don't want to allow author clicks here
|
||||||
}
|
}
|
||||||
}, getFragmentManager());
|
});
|
||||||
input = v.findViewById(R.id.inputText);
|
input = v.findViewById(R.id.inputText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,4 @@ public interface ConfigController {
|
|||||||
void deleteAccount(Context ctx);
|
void deleteAccount(Context ctx);
|
||||||
|
|
||||||
boolean accountExists();
|
boolean accountExists();
|
||||||
|
|
||||||
boolean accountSignedIn();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,10 +52,4 @@ public class ConfigControllerImpl implements ConfigController {
|
|||||||
String hex = getEncryptedDatabaseKey();
|
String hex = getEncryptedDatabaseKey();
|
||||||
return hex != null && databaseConfig.databaseExists();
|
return hex != null && databaseConfig.databaseExists();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean accountSignedIn() {
|
|
||||||
return databaseConfig.getEncryptionKey() != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import android.content.IntentFilter;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v4.app.FragmentManager;
|
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.support.v7.app.AlertDialog.Builder;
|
import android.support.v7.app.AlertDialog.Builder;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
@@ -207,14 +206,11 @@ public class KeyAgreementActivity extends BriarActivity implements
|
|||||||
|
|
||||||
private void showQrCodeFragment() {
|
private void showQrCodeFragment() {
|
||||||
// FIXME #824
|
// FIXME #824
|
||||||
FragmentManager fm = getSupportFragmentManager();
|
BaseFragment f = ShowQrCodeFragment.newInstance();
|
||||||
if (fm.findFragmentByTag(ShowQrCodeFragment.TAG) == null) {
|
getSupportFragmentManager().beginTransaction()
|
||||||
BaseFragment f = ShowQrCodeFragment.newInstance();
|
.replace(R.id.fragmentContainer, f, f.getUniqueTag())
|
||||||
fm.beginTransaction()
|
.addToBackStack(f.getUniqueTag())
|
||||||
.replace(R.id.fragmentContainer, f, f.getUniqueTag())
|
.commit();
|
||||||
.addToBackStack(f.getUniqueTag())
|
|
||||||
.commit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkPermissions() {
|
private boolean checkPermissions() {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import static com.google.zxing.DecodeHintType.CHARACTER_SET;
|
import static com.google.zxing.DecodeHintType.CHARACTER_SET;
|
||||||
import static java.util.Collections.singletonMap;
|
import static java.util.Collections.singletonMap;
|
||||||
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
@@ -66,6 +67,7 @@ class QrCodeDecoder implements PreviewConsumer, PreviewCallback {
|
|||||||
@Override
|
@Override
|
||||||
public void onPreviewFrame(byte[] data, Camera camera) {
|
public void onPreviewFrame(byte[] data, Camera camera) {
|
||||||
if (camera == this.camera) {
|
if (camera == this.camera) {
|
||||||
|
LOG.info("Got preview frame");
|
||||||
try {
|
try {
|
||||||
Size size = camera.getParameters().getPreviewSize();
|
Size size = camera.getParameters().getPreviewSize();
|
||||||
// The preview should be in NV21 format: width * height bytes of
|
// The preview should be in NV21 format: width * height bytes of
|
||||||
@@ -103,13 +105,20 @@ class QrCodeDecoder implements PreviewConsumer, PreviewCallback {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... params) {
|
protected Void doInBackground(Void... params) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
BinaryBitmap bitmap = binarize(data, width, height, orientation);
|
BinaryBitmap bitmap = binarize(data, width, height, orientation);
|
||||||
Result result;
|
Result result;
|
||||||
try {
|
try {
|
||||||
result = reader.decode(bitmap,
|
result = reader.decode(bitmap,
|
||||||
singletonMap(CHARACTER_SET, "ISO8859_1"));
|
singletonMap(CHARACTER_SET, "ISO8859_1"));
|
||||||
|
long duration = System.currentTimeMillis() - now;
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Decoding barcode took " + duration + " ms");
|
||||||
} catch (ReaderException e) {
|
} catch (ReaderException e) {
|
||||||
// No barcode found
|
// No barcode found
|
||||||
|
long duration = System.currentTimeMillis() - now;
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("No barcode found after " + duration + " ms");
|
||||||
return null;
|
return null;
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
LOG.warning("Invalid preview frame");
|
LOG.warning("Invalid preview frame");
|
||||||
|
|||||||
@@ -61,8 +61,7 @@ import static java.util.logging.Level.WARNING;
|
|||||||
public class ShowQrCodeFragment extends BaseEventFragment
|
public class ShowQrCodeFragment extends BaseEventFragment
|
||||||
implements QrCodeDecoder.ResultCallback {
|
implements QrCodeDecoder.ResultCallback {
|
||||||
|
|
||||||
static final String TAG = ShowQrCodeFragment.class.getName();
|
private static final String TAG = ShowQrCodeFragment.class.getName();
|
||||||
|
|
||||||
private static final Logger LOG = Logger.getLogger(TAG);
|
private static final Logger LOG = Logger.getLogger(TAG);
|
||||||
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
|
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
|
||||||
|
|
||||||
@@ -208,15 +207,6 @@ public class ShowQrCodeFragment extends BaseEventFragment
|
|||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void reset() {
|
private void reset() {
|
||||||
// If we've stopped the camera view, restart it
|
|
||||||
if (gotRemotePayload) {
|
|
||||||
try {
|
|
||||||
cameraView.start(getScreenRotationDegrees());
|
|
||||||
} catch (CameraException e) {
|
|
||||||
logCameraExceptionAndFinish(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
statusView.setVisibility(INVISIBLE);
|
statusView.setVisibility(INVISIBLE);
|
||||||
cameraView.setVisibility(VISIBLE);
|
cameraView.setVisibility(VISIBLE);
|
||||||
gotRemotePayload = false;
|
gotRemotePayload = false;
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
package org.briarproject.briar.android.login;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.event.Event;
|
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
|
|
||||||
import org.briarproject.briar.R;
|
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
|
||||||
import org.briarproject.briar.android.activity.BriarActivity;
|
|
||||||
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
|
||||||
|
|
||||||
import javax.annotation.ParametersAreNonnullByDefault;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE;
|
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING_SERVICES;
|
|
||||||
|
|
||||||
@ParametersAreNonnullByDefault
|
|
||||||
public class OpenDatabaseActivity extends BriarActivity
|
|
||||||
implements EventListener {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
LifecycleManager lifecycleManager;
|
|
||||||
@Inject
|
|
||||||
EventBus eventBus;
|
|
||||||
|
|
||||||
private TextView textView;
|
|
||||||
private ImageView imageView;
|
|
||||||
private boolean showingMigration = false;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@Nullable Bundle state) {
|
|
||||||
super.onCreate(state);
|
|
||||||
setContentView(R.layout.activity_open_database);
|
|
||||||
textView = findViewById(R.id.textView);
|
|
||||||
imageView = findViewById(R.id.imageView);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void injectActivity(ActivityComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
LifecycleState state = lifecycleManager.getLifecycleState();
|
|
||||||
if (state.isAfter(STARTING_SERVICES)) {
|
|
||||||
finishAndStartApp();
|
|
||||||
} else {
|
|
||||||
if (state == MIGRATING_DATABASE) showMigration();
|
|
||||||
eventBus.addListener(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onStop() {
|
|
||||||
super.onStop();
|
|
||||||
eventBus.removeListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void eventOccurred(Event e) {
|
|
||||||
if (e instanceof LifecycleEvent) {
|
|
||||||
LifecycleState state = ((LifecycleEvent) e).getLifecycleState();
|
|
||||||
if (state.isAfter(STARTING_SERVICES))
|
|
||||||
runOnUiThreadUnlessDestroyed(this::finishAndStartApp);
|
|
||||||
else if (state == MIGRATING_DATABASE)
|
|
||||||
runOnUiThreadUnlessDestroyed(this::showMigration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showMigration() {
|
|
||||||
if (showingMigration) return;
|
|
||||||
textView.setText(R.string.startup_migrate_database);
|
|
||||||
imageView.setImageResource(R.drawable.startup_migration);
|
|
||||||
showingMigration = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void finishAndStartApp() {
|
|
||||||
startActivity(new Intent(this, NavDrawerActivity.class));
|
|
||||||
supportFinishAfterTransition();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -8,6 +8,7 @@ import org.briarproject.briar.R;
|
|||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.activity.BaseActivity;
|
import org.briarproject.briar.android.activity.BaseActivity;
|
||||||
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
||||||
|
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ public class SetupActivity extends BaseActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void showApp() {
|
public void showApp() {
|
||||||
Intent i = new Intent(this, OpenDatabaseActivity.class);
|
Intent i = new Intent(this, NavDrawerActivity.class);
|
||||||
i.setFlags(FLAG_ACTIVITY_NEW_TASK);
|
i.setFlags(FLAG_ACTIVITY_NEW_TASK);
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
supportFinishAfterTransition();
|
supportFinishAfterTransition();
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static android.os.Build.MANUFACTURER;
|
||||||
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static android.support.v4.app.FragmentManager.POP_BACK_STACK_INCLUSIVE;
|
import static android.support.v4.app.FragmentManager.POP_BACK_STACK_INCLUSIVE;
|
||||||
import static android.support.v4.view.GravityCompat.START;
|
import static android.support.v4.view.GravityCompat.START;
|
||||||
import static android.support.v4.widget.DrawerLayout.LOCK_MODE_LOCKED_CLOSED;
|
import static android.support.v4.widget.DrawerLayout.LOCK_MODE_LOCKED_CLOSED;
|
||||||
@@ -212,6 +214,18 @@ public class NavDrawerActivity extends BriarActivity implements
|
|||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
if (drawerLayout.isDrawerOpen(START)) {
|
if (drawerLayout.isDrawerOpen(START)) {
|
||||||
drawerLayout.closeDrawer(START);
|
drawerLayout.closeDrawer(START);
|
||||||
|
} else if (getSupportFragmentManager().getBackStackEntryCount() == 0 &&
|
||||||
|
getSupportFragmentManager()
|
||||||
|
.findFragmentByTag(ContactListFragment.TAG) != null) {
|
||||||
|
if (SDK_INT == 19 && MANUFACTURER.equalsIgnoreCase("Samsung")) {
|
||||||
|
// workaround for #1116 causes splash screen to show again
|
||||||
|
super.onBackPressed();
|
||||||
|
} else {
|
||||||
|
Intent i = new Intent(Intent.ACTION_MAIN);
|
||||||
|
i.addCategory(Intent.CATEGORY_HOME);
|
||||||
|
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
startActivity(i);
|
||||||
|
}
|
||||||
} else if (getSupportFragmentManager().getBackStackEntryCount() == 0 &&
|
} else if (getSupportFragmentManager().getBackStackEntryCount() == 0 &&
|
||||||
getSupportFragmentManager()
|
getSupportFragmentManager()
|
||||||
.findFragmentByTag(ContactListFragment.TAG) == null) {
|
.findFragmentByTag(ContactListFragment.TAG) == null) {
|
||||||
|
|||||||
@@ -173,7 +173,12 @@ public class BriarReportPrimer implements ReportPrimer {
|
|||||||
WifiInfo wifiInfo = wm.getConnectionInfo();
|
WifiInfo wifiInfo = wm.getConnectionInfo();
|
||||||
if (wifiInfo != null) {
|
if (wifiInfo != null) {
|
||||||
int ip = wifiInfo.getIpAddress(); // Nice API, Google
|
int ip = wifiInfo.getIpAddress(); // Nice API, Google
|
||||||
customData.put("Wi-Fi address", StringUtils.ipToString(ip));
|
int ip1 = ip & 0xFF;
|
||||||
|
int ip2 = (ip >> 8) & 0xFF;
|
||||||
|
int ip3 = (ip >> 16) & 0xFF;
|
||||||
|
int ip4 = (ip >> 24) & 0xFF;
|
||||||
|
String address = ip1 + "." + ip2 + "." + ip3 + "." + ip4;
|
||||||
|
customData.put("Wi-Fi address", address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,8 +128,6 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
"pref_key_notify_lock_screen");
|
"pref_key_notify_lock_screen");
|
||||||
notifySound = findPreference("pref_key_notify_sound");
|
notifySound = findPreference("pref_key_notify_sound");
|
||||||
|
|
||||||
setSettingsEnabled(false);
|
|
||||||
|
|
||||||
enableBluetooth.setOnPreferenceChangeListener(this);
|
enableBluetooth.setOnPreferenceChangeListener(this);
|
||||||
torNetwork.setOnPreferenceChangeListener(this);
|
torNetwork.setOnPreferenceChangeListener(this);
|
||||||
notifyPrivateMessages.setOnPreferenceChangeListener(this);
|
notifyPrivateMessages.setOnPreferenceChangeListener(this);
|
||||||
@@ -250,22 +248,9 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
|||||||
text = getString(R.string.notify_sound_setting_disabled);
|
text = getString(R.string.notify_sound_setting_disabled);
|
||||||
}
|
}
|
||||||
notifySound.setSummary(text);
|
notifySound.setSummary(text);
|
||||||
setSettingsEnabled(true);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setSettingsEnabled(boolean enabled) {
|
|
||||||
enableBluetooth.setEnabled(enabled);
|
|
||||||
torNetwork.setEnabled(enabled);
|
|
||||||
notifyPrivateMessages.setEnabled(enabled);
|
|
||||||
notifyGroupMessages.setEnabled(enabled);
|
|
||||||
notifyForumPosts.setEnabled(enabled);
|
|
||||||
notifyBlogPosts.setEnabled(enabled);
|
|
||||||
notifyVibration.setEnabled(enabled);
|
|
||||||
notifyLockscreen.setEnabled(enabled);
|
|
||||||
notifySound.setEnabled(enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void triggerFeedback() {
|
private void triggerFeedback() {
|
||||||
androidExecutor.runOnBackgroundThread(() -> ACRA.getErrorReporter()
|
androidExecutor.runOnBackgroundThread(() -> ACRA.getErrorReporter()
|
||||||
.handleException(new UserFeedback(), false));
|
.handleException(new UserFeedback(), false));
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import org.briarproject.briar.R;
|
|||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
import org.briarproject.briar.android.activity.ActivityComponent;
|
||||||
import org.briarproject.briar.android.activity.BaseActivity;
|
import org.briarproject.briar.android.activity.BaseActivity;
|
||||||
import org.briarproject.briar.android.controller.ConfigController;
|
import org.briarproject.briar.android.controller.ConfigController;
|
||||||
import org.briarproject.briar.android.login.OpenDatabaseActivity;
|
|
||||||
import org.briarproject.briar.android.login.SetupActivity;
|
import org.briarproject.briar.android.login.SetupActivity;
|
||||||
|
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -43,15 +43,10 @@ public class SplashScreenActivity extends BaseActivity {
|
|||||||
|
|
||||||
setContentView(R.layout.splash);
|
setContentView(R.layout.splash);
|
||||||
|
|
||||||
if (configController.accountSignedIn()) {
|
new Handler().postDelayed(() -> {
|
||||||
startActivity(new Intent(this, OpenDatabaseActivity.class));
|
startNextActivity();
|
||||||
finish();
|
supportFinishAfterTransition();
|
||||||
} else {
|
}, 500);
|
||||||
new Handler().postDelayed(() -> {
|
|
||||||
startNextActivity();
|
|
||||||
supportFinishAfterTransition();
|
|
||||||
}, 500);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -65,7 +60,7 @@ public class SplashScreenActivity extends BaseActivity {
|
|||||||
startActivity(new Intent(this, ExpiredActivity.class));
|
startActivity(new Intent(this, ExpiredActivity.class));
|
||||||
} else {
|
} else {
|
||||||
if (configController.accountExists()) {
|
if (configController.accountExists()) {
|
||||||
startActivity(new Intent(this, OpenDatabaseActivity.class));
|
startActivity(new Intent(this, NavDrawerActivity.class));
|
||||||
} else {
|
} else {
|
||||||
configController.deleteAccount(this);
|
configController.deleteAccount(this);
|
||||||
startActivity(new Intent(this, SetupActivity.class));
|
startActivity(new Intent(this, SetupActivity.class));
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import android.support.annotation.ColorRes;
|
|||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
|
||||||
|
|
||||||
import static android.support.v4.app.NotificationCompat.VISIBILITY_PRIVATE;
|
import static android.support.v4.app.NotificationCompat.VISIBILITY_PRIVATE;
|
||||||
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
|
import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
|
||||||
|
|
||||||
@@ -19,9 +17,6 @@ public class BriarNotificationBuilder extends NotificationCompat.Builder {
|
|||||||
// Auto-cancel does not fire the delete intent, see
|
// Auto-cancel does not fire the delete intent, see
|
||||||
// https://issuetracker.google.com/issues/36961721
|
// https://issuetracker.google.com/issues/36961721
|
||||||
setAutoCancel(true);
|
setAutoCancel(true);
|
||||||
|
|
||||||
setLights(ContextCompat.getColor(context, R.color.briar_green_light),
|
|
||||||
750, 500);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BriarNotificationBuilder setColorRes(@ColorRes int res) {
|
public BriarNotificationBuilder setColorRes(@ColorRes int res) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import android.support.design.widget.TextInputLayout;
|
|||||||
import android.support.v4.app.FragmentManager;
|
import android.support.v4.app.FragmentManager;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
@@ -24,8 +25,6 @@ import android.view.View;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.view.ArticleMovementMethod;
|
import org.briarproject.briar.android.view.ArticleMovementMethod;
|
||||||
import org.briarproject.briar.android.widget.LinkDialogFragment;
|
import org.briarproject.briar.android.widget.LinkDialogFragment;
|
||||||
@@ -48,8 +47,6 @@ import static android.text.format.DateUtils.WEEK_IN_MILLIS;
|
|||||||
import static org.briarproject.briar.BuildConfig.APPLICATION_ID;
|
import static org.briarproject.briar.BuildConfig.APPLICATION_ID;
|
||||||
import static org.briarproject.briar.android.BriarApplication.EXPIRY_DATE;
|
import static org.briarproject.briar.android.BriarApplication.EXPIRY_DATE;
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
|
||||||
@ParametersNotNullByDefault
|
|
||||||
public class UiUtils {
|
public class UiUtils {
|
||||||
|
|
||||||
public static final long MIN_DATE_RESOLUTION = MINUTE_IN_MILLIS;
|
public static final long MIN_DATE_RESOLUTION = MINUTE_IN_MILLIS;
|
||||||
@@ -113,9 +110,7 @@ public class UiUtils {
|
|||||||
return Html.fromHtml(s);
|
return Html.fromHtml(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void makeLinksClickable(TextView v,
|
public static void makeLinksClickable(TextView v) {
|
||||||
@Nullable FragmentManager fm) {
|
|
||||||
if (fm == null) return;
|
|
||||||
SpannableStringBuilder ssb = new SpannableStringBuilder(v.getText());
|
SpannableStringBuilder ssb = new SpannableStringBuilder(v.getText());
|
||||||
URLSpan[] spans = ssb.getSpans(0, ssb.length(), URLSpan.class);
|
URLSpan[] spans = ssb.getSpans(0, ssb.length(), URLSpan.class);
|
||||||
for (URLSpan span : spans) {
|
for (URLSpan span : spans) {
|
||||||
@@ -127,6 +122,8 @@ public class UiUtils {
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(View v2) {
|
public void onClick(View v2) {
|
||||||
LinkDialogFragment f = LinkDialogFragment.newInstance(url);
|
LinkDialogFragment f = LinkDialogFragment.newInstance(url);
|
||||||
|
FragmentManager fm = ((AppCompatActivity) v2.getContext())
|
||||||
|
.getSupportFragmentManager();
|
||||||
f.show(fm, f.getUniqueTag());
|
f.show(fm, f.getUniqueTag());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="64dp"
|
|
||||||
android:height="64dp"
|
|
||||||
android:viewportHeight="24.0"
|
|
||||||
android:viewportWidth="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="64dp"
|
|
||||||
android:height="64dp"
|
|
||||||
android:viewportHeight="24.0"
|
|
||||||
android:viewportWidth="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="M21,10.12h-6.78l2.74,-2.82c-2.73,-2.7 -7.15,-2.8 -9.88,-0.1 -2.73,2.71 -2.73,7.08 0,9.79 2.73,2.71 7.15,2.71 9.88,0C18.32,15.65 19,14.08 19,12.1h2c0,1.98 -0.88,4.55 -2.64,6.29 -3.51,3.48 -9.21,3.48 -12.72,0 -3.5,-3.47 -3.53,-9.11 -0.02,-12.58 3.51,-3.47 9.14,-3.47 12.65,0L21,3v7.12zM12.5,8v4.25l3.5,2.08 -0.72,1.21L11,13V8h1.5z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingBottom="@dimen/margin_activity_vertical"
|
||||||
|
android:paddingEnd="@dimen/margin_activity_horizontal"
|
||||||
|
android:paddingLeft="@dimen/margin_activity_horizontal"
|
||||||
|
android:paddingRight="@dimen/margin_activity_horizontal"
|
||||||
|
android:paddingStart="@dimen/margin_activity_horizontal"
|
||||||
|
android:paddingTop="@dimen/margin_activity_vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageView"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginEnd="@dimen/margin_medium"
|
||||||
|
android:layout_marginRight="@dimen/margin_medium"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:src="@drawable/bluetooth"/>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/BriarTextBody"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/your_nickname"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinner"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/margin_medium"
|
||||||
|
android:background="@drawable/border_spinner"
|
||||||
|
android:spinnerMode="dropdown"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/BriarTextBody"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/margin_medium"
|
||||||
|
android:text="@string/face_to_face"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/continueButton"
|
||||||
|
style="@style/BriarButton.Default"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginTop="@dimen/margin_medium"
|
||||||
|
android:text="@string/continue_button"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<android.support.constraint.ConstraintLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/imageView"
|
|
||||||
android:layout_width="128dp"
|
|
||||||
android:layout_height="128dp"
|
|
||||||
android:scaleType="center"
|
|
||||||
android:src="@drawable/startup_lock"
|
|
||||||
android:tint="@color/briar_primary"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/textView"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintVertical_bias="0.5"
|
|
||||||
app:layout_constraintVertical_chainStyle="packed"
|
|
||||||
tools:ignore="ContentDescription"/>
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/progressBar"
|
|
||||||
style="?android:attr/progressBarStyleLarge"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/imageView"
|
|
||||||
app:layout_constraintEnd_toEndOf="@+id/imageView"
|
|
||||||
app:layout_constraintStart_toStartOf="@+id/imageView"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/imageView"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/textView"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="8dp"
|
|
||||||
android:text="@string/startup_open_database"
|
|
||||||
android:textSize="@dimen/text_size_large"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/imageView"/>
|
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="@dimen/margin_activity_horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/BriarTextTitle"
|
||||||
|
android:text="@string/startup_failed_notification_title"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginTop="7dp"
|
||||||
|
android:layout_marginBottom="7dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/errorView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/startup_failed_notification_text"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -17,64 +17,58 @@
|
|||||||
android:id="@+id/diagram"
|
android:id="@+id/diagram"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:paddingBottom="@dimen/margin_large"
|
android:paddingBottom="@dimen/margin_large"
|
||||||
android:scaleType="fitCenter"
|
android:scaleType="fitCenter"
|
||||||
android:src="@drawable/qr_code_intro"
|
android:src="@drawable/qr_code_intro"
|
||||||
app:layout_constraintBottom_toTopOf="@id/explanationImage"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintBottom_toTopOf="@id/explanationImage"/>
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"/>
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/explanationImage"
|
android:id="@+id/explanationImage"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
|
android:paddingTop="@dimen/margin_large"
|
||||||
android:paddingLeft="@dimen/margin_large"
|
android:paddingLeft="@dimen/margin_large"
|
||||||
android:paddingRight="@dimen/margin_large"
|
android:paddingRight="@dimen/margin_large"
|
||||||
android:paddingTop="@dimen/margin_large"
|
|
||||||
android:scaleType="fitCenter"
|
android:scaleType="fitCenter"
|
||||||
android:src="@drawable/qr_code_explanation"
|
android:src="@drawable/qr_code_explanation"
|
||||||
app:layout_constraintBottom_toTopOf="@id/explanationText"
|
tools:ignore="ContentDescription"
|
||||||
app:layout_constraintEnd_toEndOf="@id/diagram"
|
|
||||||
app:layout_constraintStart_toStartOf="@id/diagram"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/diagram"
|
app:layout_constraintTop_toBottomOf="@id/diagram"
|
||||||
tools:ignore="ContentDescription"/>
|
app:layout_constraintBottom_toTopOf="@id/explanationText"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/explanationText"
|
android:id="@+id/explanationText"
|
||||||
style="@style/BriarTextBody"
|
style="@style/BriarTextBody"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:padding="@dimen/margin_large"
|
android:padding="@dimen/margin_large"
|
||||||
android:text="@string/face_to_face"
|
android:text="@string/face_to_face"
|
||||||
app:layout_constrainedWidth="true"
|
app:layout_constraintTop_toBottomOf="@id/explanationImage"
|
||||||
app:layout_constraintEnd_toEndOf="@id/explanationImage"
|
app:layout_constraintBottom_toTopOf="@id/continueButton"/>
|
||||||
app:layout_constraintStart_toStartOf="@id/explanationImage"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/explanationImage"/>
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/explanationBorder"
|
android:id="@+id/explanationBorder"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:background="@drawable/border_explanation"
|
android:background="@drawable/border_explanation"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/explanationText"
|
app:layout_constraintTop_toTopOf="@id/explanationImage"
|
||||||
app:layout_constraintEnd_toEndOf="@id/explanationImage"
|
|
||||||
app:layout_constraintStart_toStartOf="@id/explanationImage"
|
app:layout_constraintStart_toStartOf="@id/explanationImage"
|
||||||
app:layout_constraintTop_toTopOf="@id/explanationImage"/>
|
app:layout_constraintEnd_toEndOf="@id/explanationImage"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/explanationText"/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/continueButton"
|
android:id="@+id/continueButton"
|
||||||
style="@style/BriarButton.Default"
|
style="@style/BriarButton.Default"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
android:layout_marginTop="@dimen/margin_medium"
|
android:layout_marginTop="@dimen/margin_medium"
|
||||||
android:text="@string/continue_button"
|
android:text="@string/continue_button"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintTop_toBottomOf="@id/explanationText"
|
||||||
app:layout_constraintEnd_toEndOf="@id/explanationImage"
|
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||||
app:layout_constraintStart_toStartOf="@id/explanationImage"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/explanationText"/>
|
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
</android.support.constraint.ConstraintLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
|
||||||
tools:showIn="@layout/navigation_menu">
|
tools:showIn="@layout/navigation_menu">
|
||||||
|
|
||||||
<View style="@style/Divider.Horizontal"/>
|
<View style="@style/Divider.Horizontal"/>
|
||||||
@@ -13,9 +13,8 @@
|
|||||||
android:id="@+id/transportsView"
|
android:id="@+id/transportsView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:listSelector="@android:color/transparent"
|
|
||||||
android:numColumns="3"
|
|
||||||
android:padding="@dimen/margin_medium"
|
android:padding="@dimen/margin_medium"
|
||||||
|
android:numColumns="3"
|
||||||
tools:listitem="@layout/list_item_transport"/>
|
tools:listitem="@layout/list_item_transport"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<?xml version='1.0' encoding='UTF-8'?>
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
<resources>
|
<resources>
|
||||||
<!--Setup-->
|
<!--Setup-->
|
||||||
<string name="setup_title">Добре дошли в Briar</string>
|
|
||||||
<string name="setup_next">Следващ</string>
|
<string name="setup_next">Следващ</string>
|
||||||
<string name="choose_nickname">Изберете име</string>
|
<string name="choose_nickname">Изберете име</string>
|
||||||
<string name="choose_password">Изберете парола</string>
|
<string name="choose_password">Изберете парола</string>
|
||||||
@@ -18,6 +17,7 @@
|
|||||||
<string name="dialog_title_lost_password">Забравена парола</string>
|
<string name="dialog_title_lost_password">Забравена парола</string>
|
||||||
<string name="dialog_message_lost_password">Briar профилът се съхранява криптиран във вашето устройство, не в облака, така че не можем да зададем нова парола. Искате ли да изтриете профила си и да започнете отначало?\n\nВнимание: Вашият профил, контакти и съобщения ще бъдат изтрити завинаги.</string>
|
<string name="dialog_message_lost_password">Briar профилът се съхранява криптиран във вашето устройство, не в облака, така че не можем да зададем нова парола. Искате ли да изтриете профила си и да започнете отначало?\n\nВнимание: Вашият профил, контакти и съобщения ще бъдат изтрити завинаги.</string>
|
||||||
<string name="startup_failed_notification_title">Briar не можа да стартира</string>
|
<string name="startup_failed_notification_title">Briar не можа да стартира</string>
|
||||||
|
<string name="startup_failed_notification_text">Може да се наложи да преинсталирате Briar.</string>
|
||||||
<string name="startup_failed_activity_title">Неуспешно стартиране</string>
|
<string name="startup_failed_activity_title">Неуспешно стартиране</string>
|
||||||
<string name="startup_failed_service_error">Briar не успя да стартира задължителен плъгин. Обикновено преинсталирането на Briar решава този проблем. Моля, имайте предвид, че ще изгубите профила си и всички данни, асоциирани с него, тъй като Briar не съхранява данните ви в централни сървъри.</string>
|
<string name="startup_failed_service_error">Briar не успя да стартира задължителен плъгин. Обикновено преинсталирането на Briar решава този проблем. Моля, имайте предвид, че ще изгубите профила си и всички данни, асоциирани с него, тъй като Briar не съхранява данните ви в централни сървъри.</string>
|
||||||
<string name="expiry_date_reached">Софтуерът е невалиден.\nБлагодарим ви за тестването!</string>
|
<string name="expiry_date_reached">Софтуерът е невалиден.\nБлагодарим ви за тестването!</string>
|
||||||
@@ -345,5 +345,6 @@
|
|||||||
<string name="progress_title_logout">Отписване от Briar...</string>
|
<string name="progress_title_logout">Отписване от Briar...</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">Открит е овърлей на екрана</string>
|
<string name="screen_filter_title">Открит е овърлей на екрана</string>
|
||||||
|
<string name="screen_filter_body">Друго приложение чертае върху Briar. За да защити вашата сигурност, Briar няма да реагира на докосване, докато друго приложение чертае отгоре.\n\nОпитайте да изключите следните приложения, когато използвате Briar:\n\n%1$s</string>
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
<string name="forgotten_password">Ankoueet em eus ma ger-tremen</string>
|
<string name="forgotten_password">Ankoueet em eus ma ger-tremen</string>
|
||||||
<string name="dialog_title_lost_password">Kollet em eus ma ger-tremen</string>
|
<string name="dialog_title_lost_password">Kollet em eus ma ger-tremen</string>
|
||||||
<string name="startup_failed_notification_title">N\'hall ket loc\'hañ Briar</string>
|
<string name="startup_failed_notification_title">N\'hall ket loc\'hañ Briar</string>
|
||||||
|
<string name="startup_failed_notification_text">Rankout a rit staliañ a nevez Briar.</string>
|
||||||
<!--Navigation Drawer-->
|
<!--Navigation Drawer-->
|
||||||
<string name="contact_list_button">Darempredoù</string>
|
<string name="contact_list_button">Darempredoù</string>
|
||||||
<string name="groups_button">Strolladoù prevez</string>
|
<string name="groups_button">Strolladoù prevez</string>
|
||||||
@@ -143,7 +144,6 @@
|
|||||||
<!--Settings Feedback-->
|
<!--Settings Feedback-->
|
||||||
<!--Link Warning-->
|
<!--Link Warning-->
|
||||||
<!--Crash Reporter-->
|
<!--Crash Reporter-->
|
||||||
<string name="close">Serriñ</string>
|
|
||||||
<!--Sign Out-->
|
<!--Sign Out-->
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
|
|||||||
@@ -31,12 +31,10 @@
|
|||||||
<string name="dialog_title_lost_password">Contrasenya perduda</string>
|
<string name="dialog_title_lost_password">Contrasenya perduda</string>
|
||||||
<string name="dialog_message_lost_password">El vostre compte de Briar s\'emmagatzema xifrat al vostre dispositiu, no al núvol; per tant no podem restaurar-ne la contrasenya. Voleu esborrar el compte i tornar a començar?\n\nAlerta: les vostres identitats, contactes i missatges es perdran per sempre.</string>
|
<string name="dialog_message_lost_password">El vostre compte de Briar s\'emmagatzema xifrat al vostre dispositiu, no al núvol; per tant no podem restaurar-ne la contrasenya. Voleu esborrar el compte i tornar a començar?\n\nAlerta: les vostres identitats, contactes i missatges es perdran per sempre.</string>
|
||||||
<string name="startup_failed_notification_title">Briar no s\'ha pogut iniciar</string>
|
<string name="startup_failed_notification_title">Briar no s\'ha pogut iniciar</string>
|
||||||
<string name="startup_failed_notification_text">Toqueu per obtenir més informació.</string>
|
<string name="startup_failed_notification_text">Potser us caldrà reinstal·lar Briar.</string>
|
||||||
<string name="startup_failed_activity_title">Error iniciant Briar</string>
|
<string name="startup_failed_activity_title">Error iniciant Briar</string>
|
||||||
<string name="startup_failed_db_error">Per alguna raó, la vostra base de dades de Briar està malmesa més enllà de la reparació. El vostre compte, les vostres dades i tots els vostres contactes es perdran. Malauradament, necessiteu tornar a instal·lar Briar i configurar un nou compte escollint «He oblidat la meva contrasenya» quan se us demani la contrasenya.</string>
|
<string name="startup_failed_db_error">Per alguna raó, la vostra base de dades de Briar està malmesa més enllà de la reparació. El vostre compte, les vostres dades i tots els vostres contactes es perdran. Malauradament, necessiteu tornar a instal·lar Briar i configurar un compte nou.</string>
|
||||||
<string name="startup_failed_data_too_old_error">El vostre compte s\'ha creat amb una versió anterior d\'aquesta aplicació i no es pot obrir amb aquesta versió. Heu de tornar a instal·lar la versió antiga o eliminar el vostre antic compte escollint «He oblidat la meva contrasenya» quan se us demani la contrasenya.</string>
|
<string name="startup_failed_service_error">Briar no ha pogut engegar un plugin necessari. La sol.lució sol ser reinstal.lar Briar. De tota manera, tingueu en compte que si ho feu perdreu el vostre compte i totes les dades associades, doncs Briar no usa servidors centrals per desar les vostres dades.</string>
|
||||||
<string name="startup_failed_data_too_new_error">Aquesta versió de l\'aplicació és massa antiga. Actualitzeu a la versió més recent i torneu-ho a provar.</string>
|
|
||||||
<string name="startup_failed_service_error">Briar no ha pogut engegar un connector necessari. La solució sol ser reinstal·lar Briar. De tota manera, tingueu en compte que si ho feu perdreu el vostre compte i totes les dades associades, doncs Briar no usa servidors centrals per desar les vostres dades.</string>
|
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Aquesta és una versió de prova de Briar. El vostre compte expira en %d dia i no es pot renovar.</item>
|
<item quantity="one">Aquesta és una versió de prova de Briar. El vostre compte expira en %d dia i no es pot renovar.</item>
|
||||||
<item quantity="other">Aquesta és una versió de prova de Briar. El vostre compte expira en %d dies i no es pot renovar.</item>
|
<item quantity="other">Aquesta és una versió de prova de Briar. El vostre compte expira en %d dies i no es pot renovar.</item>
|
||||||
@@ -73,7 +71,7 @@
|
|||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="blog_post_notification_text">
|
<plurals name="blog_post_notification_text">
|
||||||
<item quantity="one">Una nova publicacions al bloc.</item>
|
<item quantity="one">Una nova publicacions al bloc.</item>
|
||||||
<item quantity="other">%d noves publicacions al blog.</item>
|
<item quantity="other">%d noves publicacions al bloc.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<!--Misc-->
|
<!--Misc-->
|
||||||
<string name="now">Ara</string>
|
<string name="now">Ara</string>
|
||||||
@@ -97,9 +95,8 @@
|
|||||||
<string name="show_onboarding">Mostra el diàleg d\'ajuda.</string>
|
<string name="show_onboarding">Mostra el diàleg d\'ajuda.</string>
|
||||||
<string name="fix">Corregeix</string>
|
<string name="fix">Corregeix</string>
|
||||||
<string name="help">Ajuda</string>
|
<string name="help">Ajuda</string>
|
||||||
<string name="sorry">Ens sap greu</string>
|
|
||||||
<!--Contacts and Private Conversations-->
|
<!--Contacts and Private Conversations-->
|
||||||
<string name="no_contacts">Sembla que sou nouvingut i no teniu contactes encara.\n\nToqueu la icona + en la part superior i seguiu les instruccions per a afegir amics a la llista.\n\nRecordeu: afegiu només contactes cara a cara per a evitar que algú es faci passar per vós o pugui llegir els vostres missatges en el futur. </string>
|
<string name="no_contacts">Sembla que sou nouvingut i no teniu contactes encara.\n\nToqueu la icona + en la part superior i seguiu les instruccions per a afegir amics a la llista.\n\nRecordeu: afegiu només contactes cara a cara per a evitar que algú es faça passar per vós o pugui llegir els vostres missatges en el futur. </string>
|
||||||
<string name="date_no_private_messages">Sense missatges.</string>
|
<string name="date_no_private_messages">Sense missatges.</string>
|
||||||
<string name="no_private_messages">Aquesta és la vista de conversa.\n\nSembla que hi manca una part de la conversa.\n\nNomés cal que toqueu el camp d\'entrada a la part inferior per iniciar una conversa.</string>
|
<string name="no_private_messages">Aquesta és la vista de conversa.\n\nSembla que hi manca una part de la conversa.\n\nNomés cal que toqueu el camp d\'entrada a la part inferior per iniciar una conversa.</string>
|
||||||
<string name="message_hint">Escriu el missatge.</string>
|
<string name="message_hint">Escriu el missatge.</string>
|
||||||
@@ -119,7 +116,6 @@
|
|||||||
<string name="contact_already_exists">El contacte %s ja existeix</string>
|
<string name="contact_already_exists">El contacte %s ja existeix</string>
|
||||||
<string name="contact_exchange_failed">L\'intercanvi de contactes ha fallat</string>
|
<string name="contact_exchange_failed">L\'intercanvi de contactes ha fallat</string>
|
||||||
<string name="qr_code_invalid">El codi QR és invàlid</string>
|
<string name="qr_code_invalid">El codi QR és invàlid</string>
|
||||||
<string name="qr_code_unsupported">El codi QR que intenteu escanejar pertany a una versió antiga de %s que ja no és compatible.\n\nAssegureu-vos que tots dos estiguin executant la versió més recent i torneu-ho a provar.</string>
|
|
||||||
<string name="camera_error">Error de la càmera</string>
|
<string name="camera_error">Error de la càmera</string>
|
||||||
<string name="connecting_to_device">Connectant al dispositiu\u2026</string>
|
<string name="connecting_to_device">Connectant al dispositiu\u2026</string>
|
||||||
<string name="authenticating_with_device">Autenticant-se amb el dispositiu\u2026</string>
|
<string name="authenticating_with_device">Autenticant-se amb el dispositiu\u2026</string>
|
||||||
@@ -133,7 +129,7 @@
|
|||||||
<string name="introduction_message_hint">Afegir un missatge (opcional)</string>
|
<string name="introduction_message_hint">Afegir un missatge (opcional)</string>
|
||||||
<string name="introduction_button">Presentar contactes entre si</string>
|
<string name="introduction_button">Presentar contactes entre si</string>
|
||||||
<string name="introduction_sent">S\'ha enviat la teva presentació.</string>
|
<string name="introduction_sent">S\'ha enviat la teva presentació.</string>
|
||||||
<string name="introduction_error">Hi ha hagut un error en fer la presentació de contactes.</string>
|
<string name="introduction_error">Hi ha hagut un error al fer la presentació de contactes.</string>
|
||||||
<string name="introduction_response_error">Error en respondre a la presentació</string>
|
<string name="introduction_response_error">Error en respondre a la presentació</string>
|
||||||
<string name="introduction_request_sent">Heu demanat que introduïu %1$s a %2$s.</string>
|
<string name="introduction_request_sent">Heu demanat que introduïu %1$s a %2$s.</string>
|
||||||
<string name="introduction_request_received">%1$s ha demanat que us presenteu a %2$s. Voleu afegir a%2$s a la vostra llista de contactes?</string>
|
<string name="introduction_request_received">%1$s ha demanat que us presenteu a %2$s. Voleu afegir a%2$s a la vostra llista de contactes?</string>
|
||||||
@@ -185,10 +181,6 @@
|
|||||||
<string name="groups_invitations_invitation_received">1%1$s us ha convidat a unir-vos al grup \" 2%2$s \".</string>
|
<string name="groups_invitations_invitation_received">1%1$s us ha convidat a unir-vos al grup \" 2%2$s \".</string>
|
||||||
<string name="groups_invitations_joined">Us heu unit al grup</string>
|
<string name="groups_invitations_joined">Us heu unit al grup</string>
|
||||||
<string name="groups_invitations_declined">S\'ha rebutjat la invitació al grup</string>
|
<string name="groups_invitations_declined">S\'ha rebutjat la invitació al grup</string>
|
||||||
<plurals name="groups_invitations_open">
|
|
||||||
<item quantity="one">%d invitació a un grup obert</item>
|
|
||||||
<item quantity="other">%d invitacions a grups oberts</item>
|
|
||||||
</plurals>
|
|
||||||
<string name="groups_invitations_response_accepted_sent">Heu acceptat la invitació del grup de %s.</string>
|
<string name="groups_invitations_response_accepted_sent">Heu acceptat la invitació del grup de %s.</string>
|
||||||
<string name="groups_invitations_response_declined_sent">Heu rebutjat la invitació del grup de %s.</string>
|
<string name="groups_invitations_response_declined_sent">Heu rebutjat la invitació del grup de %s.</string>
|
||||||
<string name="groups_invitations_response_accepted_received">%s va acceptar la invitació del grup.</string>
|
<string name="groups_invitations_response_accepted_received">%s va acceptar la invitació del grup.</string>
|
||||||
@@ -219,7 +211,7 @@
|
|||||||
<string name="btn_reply">Respon</string>
|
<string name="btn_reply">Respon</string>
|
||||||
<string name="forum_leave">Abandona el fòrum</string>
|
<string name="forum_leave">Abandona el fòrum</string>
|
||||||
<string name="dialog_title_leave_forum">Confirmeu la sortida del Forum</string>
|
<string name="dialog_title_leave_forum">Confirmeu la sortida del Forum</string>
|
||||||
<string name="dialog_message_leave_forum">Esteu segur que voleu sortir del fòrum? Els contactes amb qui heu compartit aquest fòrum podrien deixar de rebre\'n actualitzacions.</string>
|
<string name="dialog_message_leave_forum">Esteu segur que voleu sotir del fòrum? Els contactes amb qui heu compartit aquest fòrum podrien deixar de rebre\'n actualitzacions</string>
|
||||||
<string name="dialog_button_leave">Abandona</string>
|
<string name="dialog_button_leave">Abandona</string>
|
||||||
<string name="forum_left_toast">Abandona el fòrum</string>
|
<string name="forum_left_toast">Abandona el fòrum</string>
|
||||||
<!--Forum Sharing-->
|
<!--Forum Sharing-->
|
||||||
@@ -234,15 +226,12 @@
|
|||||||
<string name="forum_invitation_sent">Heu compartit el fòrum «%1$s» amb %2$s.</string>
|
<string name="forum_invitation_sent">Heu compartit el fòrum «%1$s» amb %2$s.</string>
|
||||||
<string name="forum_invitations_title">Invitacions al fòrum</string>
|
<string name="forum_invitations_title">Invitacions al fòrum</string>
|
||||||
<string name="forum_invitation_exists">Ja heu acceptat una invitació a aquest fòrum. L\'acceptació de més invitacions augmentarà i enfortirà la comunicació al fòrum.</string>
|
<string name="forum_invitation_exists">Ja heu acceptat una invitació a aquest fòrum. L\'acceptació de més invitacions augmentarà i enfortirà la comunicació al fòrum.</string>
|
||||||
<string name="forum_joined_toast">Us hi heu unit al fòrum</string>
|
|
||||||
<string name="forum_declined_toast">S\'ha rebutjat la invitació al fòrum</string>
|
<string name="forum_declined_toast">S\'ha rebutjat la invitació al fòrum</string>
|
||||||
<string name="shared_by_format">Compartit per 1%s</string>
|
<string name="shared_by_format">Compartit per 1%s</string>
|
||||||
<string name="forum_invitation_already_sharing">Ja esteu compartint</string>
|
|
||||||
<string name="forum_invitation_response_accepted_sent">Heu acceptat la invitació del fòrum de %s.</string>
|
<string name="forum_invitation_response_accepted_sent">Heu acceptat la invitació del fòrum de %s.</string>
|
||||||
<string name="forum_invitation_response_declined_sent">Heu rebutjat la invitació del fòrum de %s.</string>
|
<string name="forum_invitation_response_declined_sent">Heu rebutjat la invitació del fòrum de %s.</string>
|
||||||
<string name="forum_invitation_response_accepted_received">%s va acceptar la invitació del fòrum.</string>
|
<string name="forum_invitation_response_accepted_received">%s va acceptar la invitació del fòrum.</string>
|
||||||
<string name="forum_invitation_response_declined_received">%s va rebutjar la invitació del fòrum.</string>
|
<string name="forum_invitation_response_declined_received">%s va rebutjar la invitació del fòrum.</string>
|
||||||
<string name="sharing_status">Estat de la compartició</string>
|
|
||||||
<string name="sharing_status_forum">Qualsevol membre d\'un fòrum pot compartir-lo amb els seus contactes. Esteu compartint aquest fòrum amb els següents contactes. També hi pot haver altres membres que no pugueu veure.</string>
|
<string name="sharing_status_forum">Qualsevol membre d\'un fòrum pot compartir-lo amb els seus contactes. Esteu compartint aquest fòrum amb els següents contactes. També hi pot haver altres membres que no pugueu veure.</string>
|
||||||
<string name="shared_with">Compartit amb %1$d (%2$d en línia)</string>
|
<string name="shared_with">Compartit amb %1$d (%2$d en línia)</string>
|
||||||
<plurals name="forums_shared">
|
<plurals name="forums_shared">
|
||||||
@@ -251,60 +240,18 @@
|
|||||||
</plurals>
|
</plurals>
|
||||||
<string name="nobody">Ningú</string>
|
<string name="nobody">Ningú</string>
|
||||||
<!--Blogs-->
|
<!--Blogs-->
|
||||||
<string name="blogs_other_blog_empty_state">Aquest blog està buit.\n\nPotser l\'autor encara no hi ha escrit res o que la persona que us ha compartit aquest blog hagi de connectar-se, llavors es podran sincronitzar les publicacions.</string>
|
|
||||||
<string name="read_more">llegir més</string>
|
<string name="read_more">llegir més</string>
|
||||||
<string name="blogs_write_blog_post">Escriviu una publicació de blog</string>
|
|
||||||
<string name="blogs_write_blog_post_body_hint">Escriviu la vostra publicació al blog aquí</string>
|
|
||||||
<string name="blogs_publish_blog_post">Publica</string>
|
|
||||||
<string name="blogs_blog_post_created">S\'ha creat la publicació al blog</string>
|
|
||||||
<string name="blogs_blog_post_received">S\'ha rebut una nova publicació al blog</string>
|
|
||||||
<string name="blogs_blog_post_scroll_to">Desplaça</string>
|
|
||||||
<string name="blogs_feed_empty_state">Aquestes són totes les entrades del blog.\n\nSembla que ningú ha publicat res encara.\n\nSigueu el primer i premeu la icona del llapis per escriure una publicació nova al blog.</string>
|
|
||||||
<string name="blogs_remove_blog">Elimina el blog</string>
|
|
||||||
<string name="blogs_remove_blog_dialog_message">Esteu segur que voleu esborrar aquest blog i totes les seves publicacions?\nTingueu present que això no esborrarà el blog dels dispositius d\'altres persones.</string>
|
|
||||||
<string name="blogs_remove_blog_ok">Elimina el blog</string>
|
|
||||||
<string name="blogs_blog_removed">S\'ha eliminat el blog</string>
|
|
||||||
<string name="blogs_reblog_comment_hint">Afegiu un comentari (opcional)</string>
|
|
||||||
<string name="blogs_reblog_button">Rebloga</string>
|
|
||||||
<!--Blog Sharing-->
|
<!--Blog Sharing-->
|
||||||
<string name="blogs_sharing_share">Compartiu el blog</string>
|
|
||||||
<string name="blogs_sharing_error">S\'ha produït un error en compartir aquest blog.</string>
|
|
||||||
<string name="blogs_sharing_button">Compartiu el blog</string>
|
|
||||||
<string name="blogs_sharing_snackbar">S\'ha compartit el blog amb els contactes seleccionats</string>
|
|
||||||
<string name="blogs_sharing_response_accepted_sent">Heu acceptat la invitació al blog de %s.</string>
|
|
||||||
<string name="blogs_sharing_response_declined_sent">Heu refusat la invitació al blog de %s.</string>
|
|
||||||
<string name="blogs_sharing_response_accepted_received">%s ha acceptat la invitació al blog.</string>
|
|
||||||
<string name="blogs_sharing_response_declined_received">%s ha refusat la invitació al blog.</string>
|
|
||||||
<string name="blogs_sharing_invitation_received">%1$s us ha compartit el blog \"%2$s\".</string>
|
|
||||||
<string name="blogs_sharing_invitation_sent">Heu compartit el blog \"%1$s\" amb %2$s.</string>
|
|
||||||
<string name="blogs_sharing_invitations_title">Invitacions al blog</string>
|
|
||||||
<string name="blogs_sharing_joined_toast">Subscrit al blog</string>
|
|
||||||
<string name="blogs_sharing_declined_toast">Invitació al blog refusada</string>
|
|
||||||
<string name="sharing_status_blog">Qualsevol subscrit a un blog el pot compartir amb els seus contactes. Esteu compartint aquest blog amb els següents contactes. També hi pot haver altres subscrits que no veieu.</string>
|
|
||||||
<!--RSS Feeds-->
|
<!--RSS Feeds-->
|
||||||
<string name="blogs_rss_feeds_import">Importa canal RSS</string>
|
|
||||||
<string name="blogs_rss_feeds_import_button">Importa</string>
|
<string name="blogs_rss_feeds_import_button">Importa</string>
|
||||||
<string name="blogs_rss_feeds_import_hint">Introduïu l\'URL del canal RSS</string>
|
|
||||||
<string name="blogs_rss_feeds_import_error">Ens sap greu! S\'ha produït un error en importar el vostre canal.</string>
|
|
||||||
<string name="blogs_rss_feeds_manage">Gestiona els canals RSS</string>
|
|
||||||
<string name="blogs_rss_feeds_manage_imported">Importat:</string>
|
<string name="blogs_rss_feeds_manage_imported">Importat:</string>
|
||||||
<string name="blogs_rss_feeds_manage_author">Autor:</string>
|
<string name="blogs_rss_feeds_manage_author">Autor:</string>
|
||||||
<string name="blogs_rss_feeds_manage_updated">Darrera actualització:</string>
|
<string name="blogs_rss_feeds_manage_updated">Darrera actualització:</string>
|
||||||
<string name="blogs_rss_remove_feed">Elimina el canal</string>
|
|
||||||
<string name="blogs_rss_remove_feed_dialog_message">Esteu segurs que voleu eliminar aquest canal i totes les seves publicacions?\nLes publicacions que hàgiu compartit no se suprimiran dels dispositius d\'altres persones.</string>
|
|
||||||
<string name="blogs_rss_remove_feed_ok">Elimina el canal</string>
|
|
||||||
<string name="blogs_rss_feeds_manage_delete_error">El canal no s\'ha pogut esborrar.</string>
|
|
||||||
<string name="blogs_rss_feeds_manage_empty_state">No heu importat cap canal RSS.\n\nPer què no feu clic al botó més de la part superior dreta per afegir el primer?</string>
|
|
||||||
<string name="blogs_rss_feeds_manage_error">S\'ha produït un problema en carregar els vostres canals. Torneu-ho a provar més tard.</string>
|
|
||||||
<!--Settings Network-->
|
<!--Settings Network-->
|
||||||
<string name="network_settings_title">Xarxes</string>
|
|
||||||
<string name="bluetooth_setting">Connecta via bluetooth</string>
|
<string name="bluetooth_setting">Connecta via bluetooth</string>
|
||||||
<string name="bluetooth_setting_enabled">Sempre que hi hagi contactes propers</string>
|
|
||||||
<string name="bluetooth_setting_disabled">Només quan s\'afegeixen contactes</string>
|
|
||||||
<string name="tor_network_setting">Connecta via Tor</string>
|
<string name="tor_network_setting">Connecta via Tor</string>
|
||||||
<string name="tor_network_setting_never">Mai</string>
|
<string name="tor_network_setting_never">Mai</string>
|
||||||
<string name="tor_network_setting_wifi">Només amb WiFi</string>
|
<string name="tor_network_setting_wifi">Només amb WiFi</string>
|
||||||
<string name="tor_network_setting_always">Quan s\'utilitzi la WiFi o les dades mòbils</string>
|
|
||||||
<!--Settings Security and Panic-->
|
<!--Settings Security and Panic-->
|
||||||
<string name="security_settings_title">Seguretat</string>
|
<string name="security_settings_title">Seguretat</string>
|
||||||
<string name="change_password">Canvia la contrasenya</string>
|
<string name="change_password">Canvia la contrasenya</string>
|
||||||
@@ -315,69 +262,28 @@
|
|||||||
<string name="panic_setting">Configuració del botó del pànic</string>
|
<string name="panic_setting">Configuració del botó del pànic</string>
|
||||||
<string name="panic_setting_title">Botó de pànic</string>
|
<string name="panic_setting_title">Botó de pànic</string>
|
||||||
<string name="panic_setting_hint">Configureu com reaccionarà Briar quan feu servir una aplicació del pànic</string>
|
<string name="panic_setting_hint">Configureu com reaccionarà Briar quan feu servir una aplicació del pànic</string>
|
||||||
<string name="panic_app_setting_title">Aplicació de botó de pànic</string>
|
|
||||||
<string name="unknown_app">una aplicació desconeguda</string>
|
|
||||||
<string name="panic_app_setting_summary">No s\'ha definit cap aplicació</string>
|
|
||||||
<string name="panic_app_setting_none">Cap</string>
|
<string name="panic_app_setting_none">Cap</string>
|
||||||
<string name="dialog_title_connect_panic_app">Confirmeu l\'aplicació del pànic</string>
|
|
||||||
<string name="dialog_message_connect_panic_app">Esteu segurs que voleu permetre que %1$s activi accions destructives del botó del pànic?</string>
|
|
||||||
<string name="lock_setting_title">Tanca la sessió</string>
|
<string name="lock_setting_title">Tanca la sessió</string>
|
||||||
<string name="lock_setting_summary">Tanca la sessió de Briar si es prem un botó del pànic</string>
|
|
||||||
<string name="purge_setting_title">Esborra el compte</string>
|
<string name="purge_setting_title">Esborra el compte</string>
|
||||||
<string name="purge_setting_summary">Suprimeix el compte de Briar si es prem un botó del pànic. Precaució: s\'eliminarà permanentment les vostres identitats, contactes i missatges</string>
|
|
||||||
<string name="uninstall_setting_title">Desinstal·la Briar</string>
|
<string name="uninstall_setting_title">Desinstal·la Briar</string>
|
||||||
<string name="uninstall_setting_summary">Això requereix confirmació manual en una situació de pànic</string>
|
|
||||||
<!--Settings Notifications-->
|
<!--Settings Notifications-->
|
||||||
<string name="notification_settings_title">Notificacions</string>
|
<string name="notification_settings_title">Notificacions</string>
|
||||||
<string name="notify_private_messages_setting_title">Missatges privats</string>
|
<string name="notify_private_messages_setting_title">Missatges privats</string>
|
||||||
<string name="notify_private_messages_setting_summary">Mostra els avisos per als missatges privats</string>
|
|
||||||
<string name="notify_group_messages_setting_title">Missatges grupals</string>
|
|
||||||
<string name="notify_group_messages_setting_summary">Mostra alertes per als missatges grupals</string>
|
|
||||||
<string name="notify_forum_posts_setting_title">Publicacions del fòrum</string>
|
|
||||||
<string name="notify_forum_posts_setting_summary">Mostra alertes per a les publicacions del fòrum</string>
|
|
||||||
<string name="notify_blog_posts_setting_title">Publicacions al blog</string>
|
|
||||||
<string name="notify_blog_posts_setting_summary">Mostra alertes per les publicacions al blog</string>
|
|
||||||
<string name="notify_vibration_setting">Vibra</string>
|
<string name="notify_vibration_setting">Vibra</string>
|
||||||
<string name="notify_lock_screen_setting_title">Bloca la pantalla</string>
|
<string name="notify_lock_screen_setting_title">Bloca la pantalla</string>
|
||||||
<string name="notify_lock_screen_setting_summary">Mostra notificacions a la pantalla de bloqueig</string>
|
|
||||||
<string name="notify_sound_setting">So</string>
|
<string name="notify_sound_setting">So</string>
|
||||||
<string name="notify_sound_setting_default">To de trucada predeterminat</string>
|
|
||||||
<string name="notify_sound_setting_disabled">Cap</string>
|
<string name="notify_sound_setting_disabled">Cap</string>
|
||||||
<string name="choose_ringtone_title">Trieu el to de trucada</string>
|
|
||||||
<string name="cannot_load_ringtone">No s\'ha pogut carregar el to de trucada</string>
|
|
||||||
<!--Settings Feedback-->
|
<!--Settings Feedback-->
|
||||||
<string name="feedback_settings_title">Comentaris</string>
|
|
||||||
<string name="send_feedback">Envieu comentaris</string>
|
|
||||||
<!--Link Warning-->
|
<!--Link Warning-->
|
||||||
<string name="link_warning_title">Avís d\'enllaç</string>
|
|
||||||
<string name="link_warning_intro">L\'enllaç s\'obrirà amb una aplicació externa.</string>
|
<string name="link_warning_intro">L\'enllaç s\'obrirà amb una aplicació externa.</string>
|
||||||
<string name="link_warning_text">Açò podria usar-se per a identificar-vos. Penseu si confieu prou en la persona que us ha enviat l\'enllaç i si convindria obrir-lo amb Orfox.</string>
|
<string name="link_warning_text">Açò podria usar-se per a identificar-vos. Penseu si confieu prou en la persona que us ha enviat l\'enllaç i si convindria obrir-lo amb Orfox.</string>
|
||||||
<string name="link_warning_open_link">Obri l\'enllaç</string>
|
<string name="link_warning_open_link">Obri l\'enllaç</string>
|
||||||
<!--Crash Reporter-->
|
<!--Crash Reporter-->
|
||||||
<string name="crash_report_title">Informe de bloqueig de Briar</string>
|
|
||||||
<string name="briar_crashed">Ens sap greu, el Briar s\'ha tancat inesperadament.</string>
|
|
||||||
<string name="not_your_fault">Això no és culpa vostra.</string>
|
|
||||||
<string name="please_send_report">Ajuda\'ns a construir un Briar millor enviant-nos un informe de fallida.</string>
|
|
||||||
<string name="report_is_encrypted">Ens comprometem a què l\'informe es xifra i s\'envia de manera segura.</string>
|
|
||||||
<string name="feedback_title">Comentaris</string>
|
|
||||||
<string name="describe_crash">Descriu el que hi ha succeït (opcional)</string>
|
|
||||||
<string name="enter_feedback">Introduïu els vostres comentaris</string>
|
|
||||||
<string name="optional_contact_email">La vostra adreça de correu (opcional)</string>
|
<string name="optional_contact_email">La vostra adreça de correu (opcional)</string>
|
||||||
<string name="include_debug_report_crash">Inclou dades anònimes sobre el bloqueig</string>
|
|
||||||
<string name="include_debug_report_feedback">Inclou dades anònimes sobre el dispositiu</string>
|
<string name="include_debug_report_feedback">Inclou dades anònimes sobre el dispositiu</string>
|
||||||
<string name="could_not_load_report_data">No s\'han pogut carregar les dades de l\'informe.</string>
|
|
||||||
<string name="send_report">Envia l\'informe</string>
|
<string name="send_report">Envia l\'informe</string>
|
||||||
<string name="close">Tanca</string>
|
<string name="close">Tanca</string>
|
||||||
<string name="dev_report_saved">S\'ha desat l\'informe. Se us enviarà la propera vegada que inicieu sessió a Briar.</string>
|
|
||||||
<!--Sign Out-->
|
<!--Sign Out-->
|
||||||
<string name="progress_title_logout">S\'està sortint del Briar...</string>
|
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">S\'ha detectat superposició de la pantalla</string>
|
|
||||||
<string name="screen_filter_body">Una altra aplicació es troba damunt de Briar. Per protegir la vostra seguretat, Briar no respondrà als tocs quan s\'aprovi una altra aplicació.\n\nLes següents aplicacions poden estar dibuixant a la part superior:\n\n%1$s</string>
|
|
||||||
<string name="screen_filter_allow">Permet que aquestes aplicacions dibuixin a la part superior</string>
|
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<string name="permission_camera_title">Permís de la càmera</string>
|
|
||||||
<string name="permission_camera_request_body">Per escanejar el codi QR, Briar necessita accés a la càmera.</string>
|
|
||||||
<string name="permission_camera_denied_body">Heu denegat l\'accés a la càmera, però l\'addició de contactes requereix utilitzar la càmera.\n\nTingueu en compte permetre l\'accés.</string>
|
|
||||||
<string name="permission_camera_denied_toast">No s\'ha concedit el permís de la càmera</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -31,7 +31,9 @@
|
|||||||
<string name="dialog_title_lost_password">Ztracené heslo</string>
|
<string name="dialog_title_lost_password">Ztracené heslo</string>
|
||||||
<string name="dialog_message_lost_password">Váš Briar účet je šifrován a uložen ve vašem zařízení, nikoli v cloudu, z tohoto důvodu není možné obnovit Vaše heslo. Chcete odstranit svůj účet a začít znovu?\n\nUpozornění: Vaše identita, kontakty a zprávy budou permanentně ztraceny.</string>
|
<string name="dialog_message_lost_password">Váš Briar účet je šifrován a uložen ve vašem zařízení, nikoli v cloudu, z tohoto důvodu není možné obnovit Vaše heslo. Chcete odstranit svůj účet a začít znovu?\n\nUpozornění: Vaše identita, kontakty a zprávy budou permanentně ztraceny.</string>
|
||||||
<string name="startup_failed_notification_title">Briar nemohl být spuštěn</string>
|
<string name="startup_failed_notification_title">Briar nemohl být spuštěn</string>
|
||||||
|
<string name="startup_failed_notification_text">Můžete zkusit Briar přeinstalovat.</string>
|
||||||
<string name="startup_failed_activity_title">Spuštění Briar selhalo.</string>
|
<string name="startup_failed_activity_title">Spuštění Briar selhalo.</string>
|
||||||
|
<string name="startup_failed_db_error">Z nějakého důvodu je Briar databáze poškozena a není možná její obnova. Váš účet, data a všechny vaše kontakty jsou ztraceny. Bohužel musíte Briar přeinstalovat a nastavit nový účet.</string>
|
||||||
<string name="startup_failed_service_error">Briar nemohl spustit vyžadovaný plugin. Tento problém vyřeší přeinstalování Briar. Mějte prosím na vědomí, že přeinstalováním ztratíte veškerá data pro váš účet, protože Briar nepoužívá centralizované ukládání vašich dat na serverech.</string>
|
<string name="startup_failed_service_error">Briar nemohl spustit vyžadovaný plugin. Tento problém vyřeší přeinstalování Briar. Mějte prosím na vědomí, že přeinstalováním ztratíte veškerá data pro váš účet, protože Briar nepoužívá centralizované ukládání vašich dat na serverech.</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Toto je testovací verze Briar. Váš účet a jeho platnost vyprší po %d dnech a není možné ho obnovit.</item>
|
<item quantity="one">Toto je testovací verze Briar. Váš účet a jeho platnost vyprší po %d dnech a není možné ho obnovit.</item>
|
||||||
@@ -377,6 +379,7 @@
|
|||||||
<string name="progress_title_logout">Odhlásit se z Briar...</string>
|
<string name="progress_title_logout">Odhlásit se z Briar...</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">Bylo zjištěno překrytí obrazovky</string>
|
<string name="screen_filter_title">Bylo zjištěno překrytí obrazovky</string>
|
||||||
|
<string name="screen_filter_body">Jiná aplikace překrývá Briar. Pro vaši bezpečnost, Briar nebude odpovídat na kliknutí, pokud jej bude jiná aplikace překrývat.\n\nZkuste vypnout následující aplikace, když používáte Briar:\n\n%1$s</string>
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<string name="permission_camera_title">Oprávnění pro přístup k fotoaparátu</string>
|
<string name="permission_camera_title">Oprávnění pro přístup k fotoaparátu</string>
|
||||||
<string name="permission_camera_request_body">Pro scan QR kódu, Briar vyžaduje přístup k fotoaparátu.</string>
|
<string name="permission_camera_request_body">Pro scan QR kódu, Briar vyžaduje přístup k fotoaparátu.</string>
|
||||||
|
|||||||
@@ -31,7 +31,9 @@
|
|||||||
<string name="dialog_title_lost_password">Passwort vergessen</string>
|
<string name="dialog_title_lost_password">Passwort vergessen</string>
|
||||||
<string name="dialog_message_lost_password">Dein Briar-Konto ist auf deinem Gerät verschlüsselt und nicht in der Cloud gespeichert, deshalb kannst du dein Passwort nicht zurücksetzen. Willst du dein Konto löschen und neu beginnen?\n\nAchtung: Deine bestehenden Identitäten, Kontakte und Nachrichten gehen dann für immer verloren.</string>
|
<string name="dialog_message_lost_password">Dein Briar-Konto ist auf deinem Gerät verschlüsselt und nicht in der Cloud gespeichert, deshalb kannst du dein Passwort nicht zurücksetzen. Willst du dein Konto löschen und neu beginnen?\n\nAchtung: Deine bestehenden Identitäten, Kontakte und Nachrichten gehen dann für immer verloren.</string>
|
||||||
<string name="startup_failed_notification_title">Briar konnte nicht gestartet werden</string>
|
<string name="startup_failed_notification_title">Briar konnte nicht gestartet werden</string>
|
||||||
|
<string name="startup_failed_notification_text">Möglicherweise hilft eine Neuinstallation von Briar.</string>
|
||||||
<string name="startup_failed_activity_title">Fehler beim Starten von Briar</string>
|
<string name="startup_failed_activity_title">Fehler beim Starten von Briar</string>
|
||||||
|
<string name="startup_failed_db_error">Aus irgendeinem Grund ist deine Briar-Datenbank irreparabel beschädigt. Dein Konto, deine Daten und alle deinen Kontakte sind verloren. Leider musst du Briar neu installieren und ein neues Konto einrichten.</string>
|
||||||
<string name="startup_failed_service_error">Briar konnte ein benötigtes Plugin nicht starten. Normalerweise kann das Problem durch eine Neuinstallation von Briar gelöst werden. Eine Neuinstallation führt jedoch zum Verlust deines Kontos und aller dazugehörigen Daten, da Briar deine Daten nicht auf zentralen Servern speichert.</string>
|
<string name="startup_failed_service_error">Briar konnte ein benötigtes Plugin nicht starten. Normalerweise kann das Problem durch eine Neuinstallation von Briar gelöst werden. Eine Neuinstallation führt jedoch zum Verlust deines Kontos und aller dazugehörigen Daten, da Briar deine Daten nicht auf zentralen Servern speichert.</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Dies ist eine Testversion von Briar. Dein Konto läuft in %d Tag ab und kann nicht verlängert werden.</item>
|
<item quantity="one">Dies ist eine Testversion von Briar. Dein Konto läuft in %d Tag ab und kann nicht verlängert werden.</item>
|
||||||
@@ -367,8 +369,7 @@
|
|||||||
<string name="progress_title_logout">Von Briar abmelden...</string>
|
<string name="progress_title_logout">Von Briar abmelden...</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">Bildschirmüberlagerung erkannt</string>
|
<string name="screen_filter_title">Bildschirmüberlagerung erkannt</string>
|
||||||
<string name="screen_filter_body">Eine andere App überlagert Briar. Um deine Sicherheit zu gewährleisten, reagiert Briar in diesem Fall nicht auf deine Eingaben.\n\nDie folgenden Apps könnten überlagern:\n\n%1$s</string>
|
<string name="screen_filter_body">Eine andere App überlagert Briar. Um deine Sicherheit zu gewährleisten, reagiert Briar in diesem Fall nicht auf deine Eingaben.\n\nBeende deswegen die folgenden Apps während der Verwendung von Briar:\n\n%1$s</string>
|
||||||
<string name="screen_filter_allow">Erlauben diesen Apps die Bildschirmüberlagerung</string>
|
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<string name="permission_camera_title">Berechtigung Kamera</string>
|
<string name="permission_camera_title">Berechtigung Kamera</string>
|
||||||
<string name="permission_camera_request_body">Um den QR-Code zu scannen, benötigt Briar Zugriff auf die Kamera.</string>
|
<string name="permission_camera_request_body">Um den QR-Code zu scannen, benötigt Briar Zugriff auf die Kamera.</string>
|
||||||
|
|||||||
@@ -31,11 +31,9 @@
|
|||||||
<string name="dialog_title_lost_password">Contraseña olvidada</string>
|
<string name="dialog_title_lost_password">Contraseña olvidada</string>
|
||||||
<string name="dialog_message_lost_password">Tu cuenta de Briar se almacena de manera cifrada en tu dispositivo y no en ninguna nube, así que no podemos reiniciar tu contraseña. ¿Deseas eliminar tu cuenta y empezar de nuevo?\n\nAdvertencia: tus identidades, contactos y mensajes se perderán para siempre.</string>
|
<string name="dialog_message_lost_password">Tu cuenta de Briar se almacena de manera cifrada en tu dispositivo y no en ninguna nube, así que no podemos reiniciar tu contraseña. ¿Deseas eliminar tu cuenta y empezar de nuevo?\n\nAdvertencia: tus identidades, contactos y mensajes se perderán para siempre.</string>
|
||||||
<string name="startup_failed_notification_title">Briar no pudo iniciarse</string>
|
<string name="startup_failed_notification_title">Briar no pudo iniciarse</string>
|
||||||
<string name="startup_failed_notification_text">Toca para más información.</string>
|
<string name="startup_failed_notification_text">Quizá tengas que reinstalar Briar.</string>
|
||||||
<string name="startup_failed_activity_title">Fallo al iniciar Briar</string>
|
<string name="startup_failed_activity_title">Fallo al iniciar Briar</string>
|
||||||
<string name="startup_failed_db_error">Por alguna razón, la base de datos de Briar se ha dañada irreparablemente. Tu cuenta, tus datos y tus contactos se han perdido. Lamentablemente, necesitas reinstalar Briar y configurar una nueva cuenta. Puedes hacerlo seleccionando «He olvidado mi contraseña» al arrancar Briar.</string>
|
<string name="startup_failed_db_error">Por alguna razón, su base de datos Briar está dañada irreparablemente. Su cuenta, sus datos y todos sus contactos están perdidos. Desafortunadamente, necesita reinstalar Briar y configurar una nueva cuenta.</string>
|
||||||
<string name="startup_failed_data_too_old_error">Tu cuenta se creó en una versión antigua de esta apli y no puede abrirse con la versión actual. Debes instalar la versión anterior o eliminar tu cuenta eligiendo «He olvidado mi contraseña» al arrancar Briar.</string>
|
|
||||||
<string name="startup_failed_data_too_new_error">La versión de esta apli es demasiado antigua. Por favor, actualiza a la última versión y prueba de nuevo.</string>
|
|
||||||
<string name="startup_failed_service_error">Briar no pudo iniciar un complemento necesario. Reinstalar Briar suele solucionar el problema. Sin embargo, ten en cuenta que perderás tu cuenta y todos los datos asociados ya que Briar no almacena esta información en ningún servidor central.</string>
|
<string name="startup_failed_service_error">Briar no pudo iniciar un complemento necesario. Reinstalar Briar suele solucionar el problema. Sin embargo, ten en cuenta que perderás tu cuenta y todos los datos asociados ya que Briar no almacena esta información en ningún servidor central.</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Esta es una versión de prueba de Briar. Su cuenta expirará en %d día y no podrá ser renovada.</item>
|
<item quantity="one">Esta es una versión de prueba de Briar. Su cuenta expirará en %d día y no podrá ser renovada.</item>
|
||||||
@@ -97,7 +95,6 @@
|
|||||||
<string name="show_onboarding">Mostrar diálogo de ayuda</string>
|
<string name="show_onboarding">Mostrar diálogo de ayuda</string>
|
||||||
<string name="fix">Reparar</string>
|
<string name="fix">Reparar</string>
|
||||||
<string name="help">Ayuda</string>
|
<string name="help">Ayuda</string>
|
||||||
<string name="sorry">Disculpe</string>
|
|
||||||
<!--Contacts and Private Conversations-->
|
<!--Contacts and Private Conversations-->
|
||||||
<string name="no_contacts">Parece que eres nuevo por aquí y no tienes aún contactos.\n\nPulsa el signo + en la parte superior y sigue las instrucciones para añadir amigos a tu lista.\n\nPor favor, recuerda: sólo puedes añadir nuevos contactos cara a cara para evitar que nadie suplante tu identidad o lea tus mensajes en el futuro. </string>
|
<string name="no_contacts">Parece que eres nuevo por aquí y no tienes aún contactos.\n\nPulsa el signo + en la parte superior y sigue las instrucciones para añadir amigos a tu lista.\n\nPor favor, recuerda: sólo puedes añadir nuevos contactos cara a cara para evitar que nadie suplante tu identidad o lea tus mensajes en el futuro. </string>
|
||||||
<string name="date_no_private_messages">Sin mensajes.</string>
|
<string name="date_no_private_messages">Sin mensajes.</string>
|
||||||
@@ -119,7 +116,6 @@
|
|||||||
<string name="contact_already_exists">El contacto %s ya existe</string>
|
<string name="contact_already_exists">El contacto %s ya existe</string>
|
||||||
<string name="contact_exchange_failed">El intercambio del contacto falló</string>
|
<string name="contact_exchange_failed">El intercambio del contacto falló</string>
|
||||||
<string name="qr_code_invalid">El código QR no es válido</string>
|
<string name="qr_code_invalid">El código QR no es válido</string>
|
||||||
<string name="qr_code_unsupported">El código QR que intenta escanear pertenece a una versión anterior de %s que ya no es compatible.\n\nAsegúrese de que ambos estén ejecutando la última versión y luego inténtelo de nuevo.</string>
|
|
||||||
<string name="camera_error">Error de cámara</string>
|
<string name="camera_error">Error de cámara</string>
|
||||||
<string name="connecting_to_device">Conectando al dispositivo\u2026</string>
|
<string name="connecting_to_device">Conectando al dispositivo\u2026</string>
|
||||||
<string name="authenticating_with_device">Autentificándose con el dispositivo\u2026</string>
|
<string name="authenticating_with_device">Autentificándose con el dispositivo\u2026</string>
|
||||||
@@ -373,8 +369,7 @@
|
|||||||
<string name="progress_title_logout">Saliendo de Briar…</string>
|
<string name="progress_title_logout">Saliendo de Briar…</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">Superposición de pantalla detectada</string>
|
<string name="screen_filter_title">Superposición de pantalla detectada</string>
|
||||||
<string name="screen_filter_body">Otra aplicación se está mostrando por encima de Briar. Por seguridad, Briar no reaccionará a los toques mientras otras aplicaciones se muestren por encima.\n\nLas siguientes aplis pueden ser las causantes:\n\n%1$s</string>
|
<string name="screen_filter_body">Otra aplicación se está mostrando encima de Briar. Por seguridad, Briar no responderá a los toques mientras se muestre otra aplicación encima.\n\nIntenta apagar las siguientes aplicaciones cuando uses Briar:\n\n%1$s</string>
|
||||||
<string name="screen_filter_allow">Permitir a estas aplicaciones a mostrarse por encima</string>
|
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<string name="permission_camera_title">Permiso de cámara</string>
|
<string name="permission_camera_title">Permiso de cámara</string>
|
||||||
<string name="permission_camera_request_body">Para escanear el código QR, Briar necesita acceso a la cámara.</string>
|
<string name="permission_camera_request_body">Para escanear el código QR, Briar necesita acceso a la cámara.</string>
|
||||||
|
|||||||
@@ -31,7 +31,9 @@
|
|||||||
<string name="dialog_title_lost_password">Pasahitz galdua</string>
|
<string name="dialog_title_lost_password">Pasahitz galdua</string>
|
||||||
<string name="dialog_message_lost_password">Zure Briar kontua zure gailuan zifratuta gordetzen da, ez hodeian, beraz ezin dugu zure pasahitza berrezarri. Zure kontua ezabatu eta berriro hasi nahi duzu?\n\nKontuz: Zure identitateak, kontaktuak eta mezuak betirako galduko dira.</string>
|
<string name="dialog_message_lost_password">Zure Briar kontua zure gailuan zifratuta gordetzen da, ez hodeian, beraz ezin dugu zure pasahitza berrezarri. Zure kontua ezabatu eta berriro hasi nahi duzu?\n\nKontuz: Zure identitateak, kontaktuak eta mezuak betirako galduko dira.</string>
|
||||||
<string name="startup_failed_notification_title">Ezin izan da Briar abiatu</string>
|
<string name="startup_failed_notification_title">Ezin izan da Briar abiatu</string>
|
||||||
|
<string name="startup_failed_notification_text">Agian Briar berrinstalatu behar duzu.</string>
|
||||||
<string name="startup_failed_activity_title">Briar abio-hutsegitea</string>
|
<string name="startup_failed_activity_title">Briar abio-hutsegitea</string>
|
||||||
|
<string name="startup_failed_db_error">Dena delakoagatik, zure Briar datu-basea hondatuta dago eta ezin da konpondu. Zure kontua, zure datuak eta zure kontaktuak galdu dira. Zoritxarrez Briar berrinstalatu behar duzu eta kontu berria sortu.</string>
|
||||||
<string name="startup_failed_service_error">Briar aplikazioak ezin izan du ezinbesteko plugin bat abiatu. Briar berrinstalatzeak arazoa konpondu ohi du. Hala ere, jakin zure kontua eta datuak galduko dituzula Briar aplikazioak ez baititu zerbitzari zentralak erabiltzen zure datuak gordetzeko.</string>
|
<string name="startup_failed_service_error">Briar aplikazioak ezin izan du ezinbesteko plugin bat abiatu. Briar berrinstalatzeak arazoa konpondu ohi du. Hala ere, jakin zure kontua eta datuak galduko dituzula Briar aplikazioak ez baititu zerbitzari zentralak erabiltzen zure datuak gordetzeko.</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Hau Briar-en probetarako bertsio bat da. Zure kontua egun %d barru iraungituko da eta ezin da berriztu.</item>
|
<item quantity="one">Hau Briar-en probetarako bertsio bat da. Zure kontua egun %d barru iraungituko da eta ezin da berriztu.</item>
|
||||||
@@ -93,7 +95,6 @@
|
|||||||
<string name="show_onboarding">Erakutsi laguntza elkarrizketa-koadroa</string>
|
<string name="show_onboarding">Erakutsi laguntza elkarrizketa-koadroa</string>
|
||||||
<string name="fix">Konpondu</string>
|
<string name="fix">Konpondu</string>
|
||||||
<string name="help">Laguntza</string>
|
<string name="help">Laguntza</string>
|
||||||
<string name="sorry">Sentitzen dugu</string>
|
|
||||||
<!--Contacts and Private Conversations-->
|
<!--Contacts and Private Conversations-->
|
||||||
<string name="no_contacts">Badirudi heldu berria zarela eta ez duzula kontakturik hemen oraindik.\n\nSakatu goiko + ikonoa eta jarraitu argibideak lagunak zure zerrendara gehitzeko.\nGogoratu: Kontaktu berriak aurrez aurre besterik ezin dira gehitu beste inork zure itxurak ez egiteko edo zure mezuak ez irakurtzeko.</string>
|
<string name="no_contacts">Badirudi heldu berria zarela eta ez duzula kontakturik hemen oraindik.\n\nSakatu goiko + ikonoa eta jarraitu argibideak lagunak zure zerrendara gehitzeko.\nGogoratu: Kontaktu berriak aurrez aurre besterik ezin dira gehitu beste inork zure itxurak ez egiteko edo zure mezuak ez irakurtzeko.</string>
|
||||||
<string name="date_no_private_messages">Mezurik ez.</string>
|
<string name="date_no_private_messages">Mezurik ez.</string>
|
||||||
@@ -115,7 +116,6 @@
|
|||||||
<string name="contact_already_exists">%s kontaktua badago aurretik</string>
|
<string name="contact_already_exists">%s kontaktua badago aurretik</string>
|
||||||
<string name="contact_exchange_failed">Kontaktuen trukeak huts egin du</string>
|
<string name="contact_exchange_failed">Kontaktuen trukeak huts egin du</string>
|
||||||
<string name="qr_code_invalid">QR kodea baliogabea da</string>
|
<string name="qr_code_invalid">QR kodea baliogabea da</string>
|
||||||
<string name="qr_code_unsupported">Eskaneatzen saiatu zaren QR kodea %s programaren bertsio zahar bati dagokio eta ez du euskarririk jada.\n\nZiurtatu biak azken bertsioa erabiltzen duzuela eta saiatu berriro.</string>
|
|
||||||
<string name="camera_error">Kameraren errorea</string>
|
<string name="camera_error">Kameraren errorea</string>
|
||||||
<string name="connecting_to_device">Gailura konektatzen\u2026</string>
|
<string name="connecting_to_device">Gailura konektatzen\u2026</string>
|
||||||
<string name="authenticating_with_device">Gailuarekin autentifikatzen\u2026</string>
|
<string name="authenticating_with_device">Gailuarekin autentifikatzen\u2026</string>
|
||||||
@@ -294,7 +294,7 @@
|
|||||||
<string name="blogs_rss_feeds_manage_error">Arazo bat egon da zure jarioak kargatzean. Saiatu berriro geroago.</string>
|
<string name="blogs_rss_feeds_manage_error">Arazo bat egon da zure jarioak kargatzean. Saiatu berriro geroago.</string>
|
||||||
<!--Settings Network-->
|
<!--Settings Network-->
|
||||||
<string name="network_settings_title">Sareak</string>
|
<string name="network_settings_title">Sareak</string>
|
||||||
<string name="bluetooth_setting">Konektatu Bluetooth bidez</string>
|
<string name="bluetooth_setting">Bluetooth bidez konektatuta</string>
|
||||||
<string name="bluetooth_setting_enabled">Kontaktuak hurbil daudeneak</string>
|
<string name="bluetooth_setting_enabled">Kontaktuak hurbil daudeneak</string>
|
||||||
<string name="bluetooth_setting_disabled">Kontaktuak gehitzean besterik ez</string>
|
<string name="bluetooth_setting_disabled">Kontaktuak gehitzean besterik ez</string>
|
||||||
<string name="tor_network_setting">Konektatu Tor bidez</string>
|
<string name="tor_network_setting">Konektatu Tor bidez</string>
|
||||||
@@ -334,7 +334,7 @@
|
|||||||
<string name="notify_blog_posts_setting_title">Blog sarrerak</string>
|
<string name="notify_blog_posts_setting_title">Blog sarrerak</string>
|
||||||
<string name="notify_blog_posts_setting_summary">Erakutsi blog sarreren alertak</string>
|
<string name="notify_blog_posts_setting_summary">Erakutsi blog sarreren alertak</string>
|
||||||
<string name="notify_vibration_setting">Bibratu</string>
|
<string name="notify_vibration_setting">Bibratu</string>
|
||||||
<string name="notify_lock_screen_setting_title">Blokeo-pantaila</string>
|
<string name="notify_lock_screen_setting_title">Blokeatu pantaila</string>
|
||||||
<string name="notify_lock_screen_setting_summary">Erakutsi jakinarazpenak blokeo-pantailan</string>
|
<string name="notify_lock_screen_setting_summary">Erakutsi jakinarazpenak blokeo-pantailan</string>
|
||||||
<string name="notify_sound_setting">Soinua</string>
|
<string name="notify_sound_setting">Soinua</string>
|
||||||
<string name="notify_sound_setting_default">Lehenetsitako dei-doinua</string>
|
<string name="notify_sound_setting_default">Lehenetsitako dei-doinua</string>
|
||||||
@@ -369,8 +369,7 @@
|
|||||||
<string name="progress_title_logout">Briar saioa amaitzen...</string>
|
<string name="progress_title_logout">Briar saioa amaitzen...</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">Pantaila gainjartzea antzeman da</string>
|
<string name="screen_filter_title">Pantaila gainjartzea antzeman da</string>
|
||||||
<string name="screen_filter_body">Briar aplikazioaren gainean marrazten ari den beste aplikazio bat dago, Briar aplikazioak ez dio ukimenari erantzungo beste aplikazio bat gainean marrazten dagoen bitartean.\n\nHauek dira gainean marrazten egon daitezkeen aplikazioak:\n\n%1$s</string>
|
<string name="screen_filter_body">Briar aplikazioaren gainean marrazten ari den beste aplikazio bat dago. Zure segurtasuna babesteko Briar aplikazioak ez dio ukimenari erantzungo beste aplikazio bat gainean marrazten dagoen bitartean.\n\nSaiatu honako aplikazioak ixten Briar erabiltzean:\n\n%1$s</string>
|
||||||
<string name="screen_filter_allow">Baimendu aplikazio hauei gainean idazten</string>
|
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<string name="permission_camera_title">Kamera baimena</string>
|
<string name="permission_camera_title">Kamera baimena</string>
|
||||||
<string name="permission_camera_request_body">QR kodea eskaneatzeko Briar-ek kamera atzitu behar du.</string>
|
<string name="permission_camera_request_body">QR kodea eskaneatzeko Briar-ek kamera atzitu behar du.</string>
|
||||||
|
|||||||
@@ -31,8 +31,9 @@
|
|||||||
<string name="dialog_title_lost_password">Unohtunut salasana</string>
|
<string name="dialog_title_lost_password">Unohtunut salasana</string>
|
||||||
<string name="dialog_message_lost_password">Sinun Briar tili on tallennettu salattuna sinun laitteelle, ei pilvipalvelimelle, joten emme voi palauttaa salasanaasi. Haluatko poistaa tilisi ja aloittaa alusta?\n\nVaroitus: Tulet menettämään tunnuksesi, yhteystietosi ja viestisi lopullisesti.</string>
|
<string name="dialog_message_lost_password">Sinun Briar tili on tallennettu salattuna sinun laitteelle, ei pilvipalvelimelle, joten emme voi palauttaa salasanaasi. Haluatko poistaa tilisi ja aloittaa alusta?\n\nVaroitus: Tulet menettämään tunnuksesi, yhteystietosi ja viestisi lopullisesti.</string>
|
||||||
<string name="startup_failed_notification_title">Briarin käynnistys epäonnistui</string>
|
<string name="startup_failed_notification_title">Briarin käynnistys epäonnistui</string>
|
||||||
<string name="startup_failed_notification_text">Napauta nähdäksesi lisätietoja.</string>
|
<string name="startup_failed_notification_text">Sinun täytyy ehkä uudelleenasentaa Briar.</string>
|
||||||
<string name="startup_failed_activity_title">Briarin käynnistys epäonnistui</string>
|
<string name="startup_failed_activity_title">Briarin käynnistys epäonnistui</string>
|
||||||
|
<string name="startup_failed_db_error">Jostain syystä sinun Briar tietokanta on korruptoitunut korjauskelvottomaksi. Tilisi, tietosi ja kaikki yhteystietosi on menetetty. Valitettavasti, sinun täytyy asentaa Briar uudelleen ja luoda uusi tili.</string>
|
||||||
<string name="startup_failed_service_error">Briar ei kyennyt käynnistämään vaadittua liitännäistä. Briarin uudelleenasennus yleensä korjaa ongelman. Huomaa kuitenkin, että tulet menettämään tilisi ja kaikki siihen liittyvä data koska Briar ei käytä palvelimia sinun tietojesi säilyttämiseen.</string>
|
<string name="startup_failed_service_error">Briar ei kyennyt käynnistämään vaadittua liitännäistä. Briarin uudelleenasennus yleensä korjaa ongelman. Huomaa kuitenkin, että tulet menettämään tilisi ja kaikki siihen liittyvä data koska Briar ei käytä palvelimia sinun tietojesi säilyttämiseen.</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Tämä on Briarin testiversio. Sinun tilisi tulee vanhentumaan %d päivän päästä eikä sitä voi uusia.</item>
|
<item quantity="one">Tämä on Briarin testiversio. Sinun tilisi tulee vanhentumaan %d päivän päästä eikä sitä voi uusia.</item>
|
||||||
@@ -94,7 +95,6 @@
|
|||||||
<string name="show_onboarding">Näytä apudialogi</string>
|
<string name="show_onboarding">Näytä apudialogi</string>
|
||||||
<string name="fix">Korjaa</string>
|
<string name="fix">Korjaa</string>
|
||||||
<string name="help">Ohje</string>
|
<string name="help">Ohje</string>
|
||||||
<string name="sorry">Anteeksi</string>
|
|
||||||
<!--Contacts and Private Conversations-->
|
<!--Contacts and Private Conversations-->
|
||||||
<string name="no_contacts">Näyttää siltä, että olet uusi täällä, eikä sinulla vielä ole yhteyshenkilöitä.\n\nNapauta yllä olevaa + -kuvaketta ja seuraa ohjeita lisätäksesi kavereita luetteloon.\n\nMuista: Voit ainoastaan lisätä uusia yhteyshenkilöitä tapaamalla heidät kasvokkain. Tämä estää sen, että joku voisi esittää olevansa sinä tai lukea viestejäsi tulevaisuudessa.</string>
|
<string name="no_contacts">Näyttää siltä, että olet uusi täällä, eikä sinulla vielä ole yhteyshenkilöitä.\n\nNapauta yllä olevaa + -kuvaketta ja seuraa ohjeita lisätäksesi kavereita luetteloon.\n\nMuista: Voit ainoastaan lisätä uusia yhteyshenkilöitä tapaamalla heidät kasvokkain. Tämä estää sen, että joku voisi esittää olevansa sinä tai lukea viestejäsi tulevaisuudessa.</string>
|
||||||
<string name="date_no_private_messages">Ei viestejä.</string>
|
<string name="date_no_private_messages">Ei viestejä.</string>
|
||||||
@@ -369,8 +369,7 @@
|
|||||||
<string name="progress_title_logout">Kirjaudutaan ulos Briarista...</string>
|
<string name="progress_title_logout">Kirjaudutaan ulos Briarista...</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">Näyttökerros havaittu</string>
|
<string name="screen_filter_title">Näyttökerros havaittu</string>
|
||||||
<string name="screen_filter_body">Toinen sovellus on piirtämässä Briarin päälle. Suojellakseen sinun turvallisuutta, Briar ei tule vastaamaan kosketuksiin silloin kun toinen sovellus on piirtämässä Briarin päälle.\n\nOn mahdollista, että seuraavat sovellukset piirtävät päälle:\n\n%1$s</string>
|
<string name="screen_filter_body">Toinen sovellus on piirtämässä Briarin päälle. Suojellakseen sinun turvallisuutta, Briar ei tule vastaamaan kosketuksiin silloin kun toinen sovellus on piirtämässä Briarin päälle.\n\nYritä sulkea seuraavat sovellukset silloin kun käytät Briaria:\n\n%1$s</string>
|
||||||
<string name="screen_filter_allow">Salli näiden sovellusten piirtää päälle</string>
|
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<string name="permission_camera_title">Kameralupa</string>
|
<string name="permission_camera_title">Kameralupa</string>
|
||||||
<string name="permission_camera_request_body">Skannatakseen QR koodin, Briar tarvitsee luvan käyttää kameraa.</string>
|
<string name="permission_camera_request_body">Skannatakseen QR koodin, Briar tarvitsee luvan käyttää kameraa.</string>
|
||||||
|
|||||||
@@ -1,15 +1,8 @@
|
|||||||
<?xml version='1.0' encoding='UTF-8'?>
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
<resources>
|
<resources>
|
||||||
<!--Setup-->
|
<!--Setup-->
|
||||||
<string name="setup_title">Bienvenue à Briar</string>
|
<string name="setup_title">Configuration de Briar</string>
|
||||||
<string name="setup_name_explanation">Votre pseudonyme sera affiché à côté de tout contenu que vous publierez. Vous pourrez le modifier après avoir créé votre compte.</string>
|
<string name="setup_explanation">Votre compte Briar est enregistré chiffré sur votre appareil et non sur le nuage. Si vous désinstallez Briar ou oubliez votre mot de passe, votre compte et vos données sont irrécupérables.</string>
|
||||||
<string name="setup_next">Suivant</string>
|
|
||||||
<string name="setup_password_intro">Choisir un mot de passe</string>
|
|
||||||
<string name="setup_password_explanation">Votre compte Briar est enregistré chiffré sur votre appareil et non dans le nuage. Si vous désinstallez Briar ou oubliez votre mot de passe, il n’existe aucune façon de récupérer votre compte.\n\nChoisissez un mot de passe long qui sera difficile à deviner, par exemple quatre mots au hasard ou dix lettres, chiffres et symboles au hasard.</string>
|
|
||||||
<string name="setup_doze_title">Connexions d’arrière-plan</string>
|
|
||||||
<string name="setup_doze_intro">Pour recevoir des messages, Briar a besoin de rester connectée en arrière-plan.</string>
|
|
||||||
<string name="setup_doze_explanation">Pour recevoir des messages, Briar a besoin de rester connectée en arrière-plan. Veuillez désactiver les optimisations de la batterie afin que Briar puisse rester connectée.</string>
|
|
||||||
<string name="setup_doze_button">Autoriser les connexions</string>
|
|
||||||
<string name="choose_nickname">Choisir votre pseudonyme</string>
|
<string name="choose_nickname">Choisir votre pseudonyme</string>
|
||||||
<string name="choose_password">Choisir votre mot de passe</string>
|
<string name="choose_password">Choisir votre mot de passe</string>
|
||||||
<string name="confirm_password">Confirmer votre mot de passe</string>
|
<string name="confirm_password">Confirmer votre mot de passe</string>
|
||||||
@@ -17,12 +10,6 @@
|
|||||||
<string name="password_too_weak">Le mot de passe est trop faible</string>
|
<string name="password_too_weak">Le mot de passe est trop faible</string>
|
||||||
<string name="passwords_do_not_match">Les mots de passe ne correspondent pas</string>
|
<string name="passwords_do_not_match">Les mots de passe ne correspondent pas</string>
|
||||||
<string name="create_account_button">Créer un compte</string>
|
<string name="create_account_button">Créer un compte</string>
|
||||||
<string name="more_info">Plus d’informations</string>
|
|
||||||
<string name="don_t_ask_again">Ne plus demander</string>
|
|
||||||
<string name="setup_huawei_text">Veuillez toucher le bouton ci-dessous et vous assurer que Briar est protégée dans l’écran « Applis protégées ».</string>
|
|
||||||
<string name="setup_huawei_button">Protéger Briar</string>
|
|
||||||
<string name="setup_huawei_help">Si Briar n’est pas ajoutée à la liste des applis protégées, elle ne pourra pas fonctionner en arrière-plan.</string>
|
|
||||||
<string name="warning_dozed">%s n’a pas pu fonctionner en arrière-plan</string>
|
|
||||||
<!--Login-->
|
<!--Login-->
|
||||||
<string name="enter_password">Saisir votre mot de passe :</string>
|
<string name="enter_password">Saisir votre mot de passe :</string>
|
||||||
<string name="try_again">Le mot de passe est erroné, ressayez</string>
|
<string name="try_again">Le mot de passe est erroné, ressayez</string>
|
||||||
@@ -31,17 +18,14 @@
|
|||||||
<string name="dialog_title_lost_password">Mot de passe oublié</string>
|
<string name="dialog_title_lost_password">Mot de passe oublié</string>
|
||||||
<string name="dialog_message_lost_password">Votre compte Briar est enregistré chiffré sur votre appareil, pas dans le nuage, et nous ne pouvons donc pas réinitialiser votre mot de passe. Voulez-vous supprimer votre compte et recommencer ?\n\nAttention : vos identités, contacts et messages seront perdus irrémédiablement.</string>
|
<string name="dialog_message_lost_password">Votre compte Briar est enregistré chiffré sur votre appareil, pas dans le nuage, et nous ne pouvons donc pas réinitialiser votre mot de passe. Voulez-vous supprimer votre compte et recommencer ?\n\nAttention : vos identités, contacts et messages seront perdus irrémédiablement.</string>
|
||||||
<string name="startup_failed_notification_title">Impossible de démarrer Briar</string>
|
<string name="startup_failed_notification_title">Impossible de démarrer Briar</string>
|
||||||
<string name="startup_failed_notification_text">Toucher pour plus d’informations.</string>
|
<string name="startup_failed_notification_text">Il vous faudra peut-être réinstaller Briar.</string>
|
||||||
<string name="startup_failed_activity_title">Échec de démarrage de Briar</string>
|
<string name="startup_failed_activity_title">Échec de démarrage de Briar</string>
|
||||||
<string name="startup_failed_db_error">Pour quelque raison, votre base de données Briar est corrompue sans espoir de réparation. Votre compte, vos données et tous vos contacts sont perdus. Malheureusement, vous devez réinstaller Briar et créer un nouveau compte en choisissant « J’ai oublié mon mot de passe » dans l’invite de mot de passe.</string>
|
<string name="startup_failed_db_error">Pour une raison indéterminée, votre base de données Briar est corrompue sans espoir de récupération. Vos comptes, données et contacts sont perdus. Vous devez malheureusement réinstaller Briar et configurer un nouveau compte.</string>
|
||||||
<string name="startup_failed_data_too_old_error">Votre compte a été créé avec une ancienne version de cette appli et ne peut pas être ouvert avec cette version. Vous devez soit installer l’ancienne version soit supprimer votre compte en choisissant « J’ai oublié mon mot de passe » dans l’invite de mot de passe.</string>
|
|
||||||
<string name="startup_failed_data_too_new_error">Cette version de l’appli est trop ancienne. Veuillez la mettre à niveau vers la dernière version et ressayer.</string>
|
|
||||||
<string name="startup_failed_service_error">Briar n’a pas pu démarrer un greffon exigé. Réinstaller Briar résout généralement ce problème. Veuillez cependant noter que vous perdrez votre compte et toutes données relatives puisque Briar n’utilise pas de serveurs centralisés sur lesquels enregistrer vos données.</string>
|
<string name="startup_failed_service_error">Briar n’a pas pu démarrer un greffon exigé. Réinstaller Briar résout généralement ce problème. Veuillez cependant noter que vous perdrez votre compte et toutes données relatives puisque Briar n’utilise pas de serveurs centralisés sur lesquels enregistrer vos données.</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Ceci est une version de test de Briar. Votre compte arrivera à expiration dans %d jour et ne peut pas être renouvelé.</item>
|
<item quantity="one">Ceci est une version bêta de Briar. Votre compte arrivera à expiration dans %d jour et ne peut pas être renouvelé.</item>
|
||||||
<item quantity="other">Ceci est une version de test de Briar. Votre compte arrivera à expiration dans %d jours et ne peut pas être renouvelé.</item>
|
<item quantity="other">Ceci est une version bêta de Briar. Votre compte arrivera à expiration dans %d jours et ne peut pas être renouvelé.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="expiry_update">La date de fin de test a été repoussée. Votre compte arrivera maintenant à expiration dans %d jours.</string>
|
|
||||||
<string name="expiry_date_reached">Ce logiciel est arrivé à expiration.\nMerci de l’avoir testé !</string>
|
<string name="expiry_date_reached">Ce logiciel est arrivé à expiration.\nMerci de l’avoir testé !</string>
|
||||||
<!--Navigation Drawer-->
|
<!--Navigation Drawer-->
|
||||||
<string name="nav_drawer_open_description">Ouvrir le tiroir de navigation</string>
|
<string name="nav_drawer_open_description">Ouvrir le tiroir de navigation</string>
|
||||||
@@ -95,9 +79,6 @@
|
|||||||
<string name="ellipsis">...</string>
|
<string name="ellipsis">...</string>
|
||||||
<string name="text_too_long">Le texte saisi est trop long</string>
|
<string name="text_too_long">Le texte saisi est trop long</string>
|
||||||
<string name="show_onboarding">Afficher la fenêtre d’aide</string>
|
<string name="show_onboarding">Afficher la fenêtre d’aide</string>
|
||||||
<string name="fix">Corriger</string>
|
|
||||||
<string name="help">Aide</string>
|
|
||||||
<string name="sorry">Désolé</string>
|
|
||||||
<!--Contacts and Private Conversations-->
|
<!--Contacts and Private Conversations-->
|
||||||
<string name="no_contacts">Il semble que soyez nouveau ici, sans encore aucun contact.\n\nTouchez l’icône + en haut et suivez les instructions pour ajouter des amis à votre liste.\n\nVeuillez ne pas oublier que vous pouvez seulement ajouter des contacts en les rencontrant directement, afin d’éviter que quelqu’un se fasse passer pour vous et puisse lire vos messages à l’avenir.</string>
|
<string name="no_contacts">Il semble que soyez nouveau ici, sans encore aucun contact.\n\nTouchez l’icône + en haut et suivez les instructions pour ajouter des amis à votre liste.\n\nVeuillez ne pas oublier que vous pouvez seulement ajouter des contacts en les rencontrant directement, afin d’éviter que quelqu’un se fasse passer pour vous et puisse lire vos messages à l’avenir.</string>
|
||||||
<string name="date_no_private_messages">Aucun message.</string>
|
<string name="date_no_private_messages">Aucun message.</string>
|
||||||
@@ -109,21 +90,31 @@
|
|||||||
<string name="contact_deleted_toast">Le contact a été supprimé</string>
|
<string name="contact_deleted_toast">Le contact a été supprimé</string>
|
||||||
<!--Adding Contacts-->
|
<!--Adding Contacts-->
|
||||||
<string name="add_contact_title">Ajouter un contact</string>
|
<string name="add_contact_title">Ajouter un contact</string>
|
||||||
|
<string name="your_nickname">Choisir l’identité que vous souhaitez utiliser :</string>
|
||||||
<string name="face_to_face">Vous devez rencontrer la personne que vous voulez ajouter comme contact, afin d’éviter que quelqu’un se fasse passer pour vous et puisse lire vos messages à l’avenir.</string>
|
<string name="face_to_face">Vous devez rencontrer la personne que vous voulez ajouter comme contact, afin d’éviter que quelqu’un se fasse passer pour vous et puisse lire vos messages à l’avenir.</string>
|
||||||
<string name="continue_button">Continuer</string>
|
<string name="continue_button">Continuer</string>
|
||||||
|
<string name="your_invitation_code">Votre code d’invitation est</string>
|
||||||
|
<string name="enter_invitation_code">Veuillez saisir le code d’invitation de votre contact :</string>
|
||||||
|
<string name="searching_format">Recherche de contacts avec le code d’invitation %06d\u2026</string>
|
||||||
<string name="connection_failed">Échec de connexion</string>
|
<string name="connection_failed">Échec de connexion</string>
|
||||||
|
<string name="could_not_find_contact">Briar n’a pas trouvé votre contact à proximité</string>
|
||||||
<string name="try_again_button">Ressayer</string>
|
<string name="try_again_button">Ressayer</string>
|
||||||
|
<string name="connected_to_contact">Connecté au contact</string>
|
||||||
|
<string name="calculating_confirmation_code">Calcul du code de confirmation\u2026</string>
|
||||||
|
<string name="your_confirmation_code">Votre code de confirmation est</string>
|
||||||
|
<string name="enter_confirmation_code">Veuillez saisir le code de confirmation de votre contact :</string>
|
||||||
|
<string name="waiting_for_contact">En attente du contact\u2026</string>
|
||||||
<string name="waiting_for_contact_to_scan">En attente de lecture du code QR par le contact et de sa connexion\u2026</string>
|
<string name="waiting_for_contact_to_scan">En attente de lecture du code QR par le contact et de sa connexion\u2026</string>
|
||||||
<string name="exchanging_contact_details">Échange des renseignements de contact\u2026</string>
|
<string name="exchanging_contact_details">Échange des renseignements de contact\u2026</string>
|
||||||
|
<string name="codes_do_not_match">Les codes ne correspondent pas</string>
|
||||||
|
<string name="interfering">Cela pourrait signifier que quelqu’un tente d’interférer avec votre connexion</string>
|
||||||
<string name="contact_added_toast">Contact ajouté : %s</string>
|
<string name="contact_added_toast">Contact ajouté : %s</string>
|
||||||
<string name="contact_already_exists">Le contact %s existe déjà</string>
|
<string name="contact_already_exists">Le contact %s existe déjà</string>
|
||||||
<string name="contact_exchange_failed">Échec d’échange de contacts</string>
|
<string name="contact_exchange_failed">Échec d’échange de contacts</string>
|
||||||
<string name="qr_code_invalid">Le code QR est invalide</string>
|
<string name="qr_code_invalid">Le code QR est invalide</string>
|
||||||
<string name="qr_code_unsupported">Le code QR que vous tentez de lire appartient à une ancienne version de %s qui n’est plus prise en charge.\n\nVeuillez vous assurer d’utiliser tous les deux la dernière version et ressayer.</string>
|
|
||||||
<string name="camera_error">Erreur de la caméra</string>
|
|
||||||
<string name="connecting_to_device">Connexion à l’appareil\u2026</string>
|
<string name="connecting_to_device">Connexion à l’appareil\u2026</string>
|
||||||
<string name="authenticating_with_device">Autentification avec l’appareil\u2026</string>
|
<string name="authenticating_with_device">Autentification avec l’appareil\u2026</string>
|
||||||
<string name="connection_aborted_local">La connexion a été interrompue ! Cela pourrait signifier que quelqu’un tente d’interférer avec votre connexion.</string>
|
<string name="connection_aborted_local">Nous avons interrompu la connexion ! Cela pourrait signer que quelqu’un tente d’interférer avec votre connexion</string>
|
||||||
<string name="connection_aborted_remote">Votre contact a interrompu la connexion ! Cela pourrait signer que quelqu’un tente d’interférer avec votre connexion</string>
|
<string name="connection_aborted_remote">Votre contact a interrompu la connexion ! Cela pourrait signer que quelqu’un tente d’interférer avec votre connexion</string>
|
||||||
<!--Introductions-->
|
<!--Introductions-->
|
||||||
<string name="introduction_onboarding_title">Présenter vos contacts</string>
|
<string name="introduction_onboarding_title">Présenter vos contacts</string>
|
||||||
@@ -344,7 +335,6 @@
|
|||||||
<string name="notify_sound_setting_default">Sonnerie par défaut</string>
|
<string name="notify_sound_setting_default">Sonnerie par défaut</string>
|
||||||
<string name="notify_sound_setting_disabled">Aucun</string>
|
<string name="notify_sound_setting_disabled">Aucun</string>
|
||||||
<string name="choose_ringtone_title">Choisir une sonnerie</string>
|
<string name="choose_ringtone_title">Choisir une sonnerie</string>
|
||||||
<string name="cannot_load_ringtone">Impossible de charger la sonnerie</string>
|
|
||||||
<!--Settings Feedback-->
|
<!--Settings Feedback-->
|
||||||
<string name="feedback_settings_title">Rétroaction</string>
|
<string name="feedback_settings_title">Rétroaction</string>
|
||||||
<string name="send_feedback">Envoyer une rétroaction</string>
|
<string name="send_feedback">Envoyer une rétroaction</string>
|
||||||
@@ -373,11 +363,5 @@
|
|||||||
<string name="progress_title_logout">Déconnexion de Briar…</string>
|
<string name="progress_title_logout">Déconnexion de Briar…</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">Une superposition d’écran a été détectée</string>
|
<string name="screen_filter_title">Une superposition d’écran a été détectée</string>
|
||||||
<string name="screen_filter_body">Une autre appli s’affiche par-dessus Briar. Pour protéger votre sécurité, Briar ne répondra pas au toucher si une autre appli s’affiche par-dessus.\n\nLes applis suivantes pourraient s’afficher par-dessus Briar : \n\n%1$s</string>
|
<string name="screen_filter_body">Une autre appli s’affiche par dessus Briar. Pour protéger votre sécurité, Briar ne répondra pas au toucher si autre appli s’affiche par dessus.\n\nEssayez de fermer les applis suivantes lorsque vous utilisez Briar :\n\n%1$s</string>
|
||||||
<string name="screen_filter_allow">Permettre à ces applis de s’afficher par-dessus</string>
|
|
||||||
<!--Permission Requests-->
|
|
||||||
<string name="permission_camera_title">Accès à la caméra</string>
|
|
||||||
<string name="permission_camera_request_body">Pour lire le code QR, Briar doit accéder à la caméra.</string>
|
|
||||||
<string name="permission_camera_denied_body">Vous avez refusé l’accès à la caméra, mais l’ajout de contacts exige l’utilisation de celle-ci.\n\nVeuillez envisager d’y accorder l’accès.</string>
|
|
||||||
<string name="permission_camera_denied_toast">L’accès à la caméra n’a pas été accordé</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
<string name="dialog_title_lost_password">Clave perdida</string>
|
<string name="dialog_title_lost_password">Clave perdida</string>
|
||||||
<string name="dialog_message_lost_password">Briar almacena a súa configuración encriptada no dispositivo, non na nube, así que non podemos restabelecer a súa clave. Querrías borrar a túa conta e empezar de novo?\n\nPrecaución: As túas identidades, contactos e mensaxes serán eliminadas de forma permanente.</string>
|
<string name="dialog_message_lost_password">Briar almacena a súa configuración encriptada no dispositivo, non na nube, así que non podemos restabelecer a súa clave. Querrías borrar a túa conta e empezar de novo?\n\nPrecaución: As túas identidades, contactos e mensaxes serán eliminadas de forma permanente.</string>
|
||||||
<string name="startup_failed_notification_title">Briar non puido iniciarse</string>
|
<string name="startup_failed_notification_title">Briar non puido iniciarse</string>
|
||||||
|
<string name="startup_failed_notification_text">Pode que precises instalar Briar de novo</string>
|
||||||
<string name="startup_failed_activity_title">Fallo de Inicio de Briar</string>
|
<string name="startup_failed_activity_title">Fallo de Inicio de Briar</string>
|
||||||
<string name="startup_failed_service_error"> Briar non puido iniciar un complemento necesario. Xeralmente reinstalar Briar resolve este problema. Teña en conta que entón perderá a súa conta e todos os datos asociados a esta pois Briar non está a utilizar servidores centrais para almacenar os seus datos.</string>
|
<string name="startup_failed_service_error"> Briar non puido iniciar un complemento necesario. Xeralmente reinstalar Briar resolve este problema. Teña en conta que entón perderá a súa conta e todos os datos asociados a esta pois Briar non está a utilizar servidores centrais para almacenar os seus datos.</string>
|
||||||
<string name="expiry_date_reached">Este software caducou.\nGrazas por probalo!</string>
|
<string name="expiry_date_reached">Este software caducou.\nGrazas por probalo!</string>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
זהירות: הזהויות שלכם, אנשי הקשר וההודעות יאבדו לצמיתות.</string>
|
זהירות: הזהויות שלכם, אנשי הקשר וההודעות יאבדו לצמיתות.</string>
|
||||||
<string name="startup_failed_notification_title">אפליקציית בריאר נכשלה באיתחול</string>
|
<string name="startup_failed_notification_title">אפליקציית בריאר נכשלה באיתחול</string>
|
||||||
|
<string name="startup_failed_notification_text">יכול להיות שתאלצו להתקין מחדש את אפליקציית בריאר.</string>
|
||||||
<string name="startup_failed_activity_title">איתחול בריאר נכשל</string>
|
<string name="startup_failed_activity_title">איתחול בריאר נכשל</string>
|
||||||
<string name="startup_failed_service_error">בריאר לא הצליח לאתחל תוסף הכרחי. התקנת בריאר מחדש לרוב פותרת בעייה זו. שימו לב שאז תאבדו את חשבונכם וכל המידע המשוייך אליו כיוון שבריאר לא משתמש בשרתים מרכזיים לשמירת המידע שלכם עליהם.</string>
|
<string name="startup_failed_service_error">בריאר לא הצליח לאתחל תוסף הכרחי. התקנת בריאר מחדש לרוב פותרת בעייה זו. שימו לב שאז תאבדו את חשבונכם וכל המידע המשוייך אליו כיוון שבריאר לא משתמש בשרתים מרכזיים לשמירת המידע שלכם עליהם.</string>
|
||||||
<string name="expiry_date_reached">פג תוקפה של תוכנה זו.
|
<string name="expiry_date_reached">פג תוקפה של תוכנה זו.
|
||||||
|
|||||||
@@ -1,15 +1,7 @@
|
|||||||
<?xml version='1.0' encoding='UTF-8'?>
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
<resources>
|
<resources>
|
||||||
<!--Setup-->
|
<!--Setup-->
|
||||||
<string name="setup_title">Briar में आपका स्वागत है</string>
|
|
||||||
<string name="setup_name_explanation">आपके उपनाम आप पोस्ट किसी भी सामग्री के बगल में दिखाया जाएगा। आप अपना खाता बनाने के बाद इसे बदल नहीं सकते</string>
|
|
||||||
<string name="setup_next">अगला</string>
|
<string name="setup_next">अगला</string>
|
||||||
<string name="setup_password_intro">अपना पासवर्ड चुनें</string>
|
|
||||||
<string name="setup_password_explanation">आपका ब्रियर खाता आपके डिवाइस पर एन्क्रिप्ट किया गया है, न कि क्लाउड में। यदि आप अपना पासवर्ड भूल जाते हैं या बियर को अनइंस्टॉल करते हैं, तो आपका खाता पुनर्प्राप्त करने का कोई तरीका नहीं है। \ N \ n एक लंबे पासवर्ड चुनें जो अनुमान लगाने में मुश्किल हो, जैसे चार यादृच्छिक शब्द, या दस यादृच्छिक वर्ण, संख्याएं और प्रतीकों।</string>
|
|
||||||
<string name="setup_doze_title">पृष्ठभूमि कनेक्शन</string>
|
|
||||||
<string name="setup_doze_intro">संदेश प्राप्त करने के लिए, बैर को पृष्ठभूमि में जुड़े रहने की आवश्यकता है।</string>
|
|
||||||
<string name="setup_doze_explanation">संदेश प्राप्त करने के लिए, बैर को पृष्ठभूमि में जुड़े रहने की आवश्यकता है। कृपया बैटरी ऑप्टिमाइजेशन अक्षम करें ताकि ब्रियर कनेक्ट रह सकें।</string>
|
|
||||||
<string name="setup_doze_button">कनेक्शन की अनुमति दें</string>
|
|
||||||
<string name="choose_nickname">आपका मुंहबोला नाम चुनें</string>
|
<string name="choose_nickname">आपका मुंहबोला नाम चुनें</string>
|
||||||
<string name="choose_password">अपना पासवर्ड चुनें</string>
|
<string name="choose_password">अपना पासवर्ड चुनें</string>
|
||||||
<string name="confirm_password">अपने पासवर्ड की पुष्टि करें</string>
|
<string name="confirm_password">अपने पासवर्ड की पुष्टि करें</string>
|
||||||
@@ -18,11 +10,6 @@
|
|||||||
<string name="passwords_do_not_match">पासवर्ड मेल नहीं खाते</string>
|
<string name="passwords_do_not_match">पासवर्ड मेल नहीं खाते</string>
|
||||||
<string name="create_account_button">खाता बनाएं</string>
|
<string name="create_account_button">खाता बनाएं</string>
|
||||||
<string name="more_info">अधिक जानकारी</string>
|
<string name="more_info">अधिक जानकारी</string>
|
||||||
<string name="don_t_ask_again">फिर से मत पूछो</string>
|
|
||||||
<string name="setup_huawei_text">कृपया नीचे दिए गए बटन को टैप करें और सुनिश्चित करें कि \"संरक्षित ऐप्स\" स्क्रीन पर बियर सुरक्षित है</string>
|
|
||||||
<string name="setup_huawei_button">Briar की रक्षा करें</string>
|
|
||||||
<string name="setup_huawei_help">अगर Briar संरक्षित ऐप्स सूची में नहीं जोड़ा गया है, तो यह पृष्ठभूमि में चलने में असमर्थ होगा।</string>
|
|
||||||
<string name="warning_dozed">%sपृष्ठभूमि में चलाने में असमर्थ था</string>
|
|
||||||
<!--Login-->
|
<!--Login-->
|
||||||
<string name="enter_password">अपना पासवर्ड डालें:</string>
|
<string name="enter_password">अपना पासवर्ड डालें:</string>
|
||||||
<string name="try_again">गलत पासवर्ड, फिर से प्रयास करें</string>
|
<string name="try_again">गलत पासवर्ड, फिर से प्रयास करें</string>
|
||||||
@@ -31,13 +18,9 @@
|
|||||||
<string name="dialog_title_lost_password">पासवर्ड खो गया</string>
|
<string name="dialog_title_lost_password">पासवर्ड खो गया</string>
|
||||||
<string name="dialog_message_lost_password">आपका ब्रियर खाता आपके डिवाइस पर एन्क्रिप्ट किया गया है, बादल में नहीं, इसलिए हम आपका पासवर्ड रीसेट नहीं कर सकते। क्या आप अपना खाता हटाना चाहते हैं और फिर से शुरू करना चाहते हैं? \ N \ n सावधानी: आपकी पहचान, संपर्क और संदेश स्थायी रूप से खो जाएंगे</string>
|
<string name="dialog_message_lost_password">आपका ब्रियर खाता आपके डिवाइस पर एन्क्रिप्ट किया गया है, बादल में नहीं, इसलिए हम आपका पासवर्ड रीसेट नहीं कर सकते। क्या आप अपना खाता हटाना चाहते हैं और फिर से शुरू करना चाहते हैं? \ N \ n सावधानी: आपकी पहचान, संपर्क और संदेश स्थायी रूप से खो जाएंगे</string>
|
||||||
<string name="startup_failed_notification_title">बियर शुरू नहीं हो सका</string>
|
<string name="startup_failed_notification_title">बियर शुरू नहीं हो सका</string>
|
||||||
|
<string name="startup_failed_notification_text">आपको ब्रियर को पुनर्स्थापित करने की आवश्यकता हो सकती है</string>
|
||||||
<string name="startup_failed_activity_title">ब्रियर स्टार्टअप विफलता</string>
|
<string name="startup_failed_activity_title">ब्रियर स्टार्टअप विफलता</string>
|
||||||
<string name="startup_failed_service_error">ब्रियर एक आवश्यक प्लगइन प्रारंभ करने में असमर्थ था बरिअर को पुनः स्थापित करना आमतौर पर इस समस्या को हल करता है हालांकि, कृपया ध्यान दें कि बियर आपके डेटा को स्टोर करने के लिए केंद्रीय सर्वर का उपयोग नहीं कर रहा है, इसके बाद आप अपने खाता और उसके साथ जुड़े सभी डेटा खो देंगे।</string>
|
<string name="startup_failed_service_error">ब्रियर एक आवश्यक प्लगइन प्रारंभ करने में असमर्थ था बरिअर को पुनः स्थापित करना आमतौर पर इस समस्या को हल करता है हालांकि, कृपया ध्यान दें कि बियर आपके डेटा को स्टोर करने के लिए केंद्रीय सर्वर का उपयोग नहीं कर रहा है, इसके बाद आप अपने खाता और उसके साथ जुड़े सभी डेटा खो देंगे।</string>
|
||||||
<plurals name="expiry_warning">
|
|
||||||
<item quantity="one">यह Briar का एक परीक्षण संस्करण है आपका खाता %dदिनों में समाप्त हो जाएगा और नवीनीकरण नहीं किया जा सकता है</item>
|
|
||||||
<item quantity="other">यह Briar का एक परीक्षण संस्करण है आपका खाता %dदिनों में समाप्त हो जाएगा और नवीनीकरण नहीं किया जा सकता है</item>
|
|
||||||
</plurals>
|
|
||||||
<string name="expiry_update">परीक्षण समाप्ति तिथि बढ़ा दी गई है। आपका खाता अब %d दिनों में समाप्त हो जाएगा</string>
|
|
||||||
<string name="expiry_date_reached">यह सॉफ्टवेयर समाप्त हो गया है। \n परीक्षण के लिए धन्यवाद!</string>
|
<string name="expiry_date_reached">यह सॉफ्टवेयर समाप्त हो गया है। \n परीक्षण के लिए धन्यवाद!</string>
|
||||||
<!--Navigation Drawer-->
|
<!--Navigation Drawer-->
|
||||||
<string name="nav_drawer_open_description">नेविगेशन ड्रॉवर खोलें</string>
|
<string name="nav_drawer_open_description">नेविगेशन ड्रॉवर खोलें</string>
|
||||||
@@ -91,7 +74,6 @@
|
|||||||
<string name="ellipsis">…</string>
|
<string name="ellipsis">…</string>
|
||||||
<string name="text_too_long">प्रवेश किया हुआ पाठ बहुत लंबा है</string>
|
<string name="text_too_long">प्रवेश किया हुआ पाठ बहुत लंबा है</string>
|
||||||
<string name="show_onboarding">सहायता संवाद दिखाएं</string>
|
<string name="show_onboarding">सहायता संवाद दिखाएं</string>
|
||||||
<string name="fix">ठीक कर</string>
|
|
||||||
<string name="help">सहायता</string>
|
<string name="help">सहायता</string>
|
||||||
<!--Contacts and Private Conversations-->
|
<!--Contacts and Private Conversations-->
|
||||||
<string name="no_contacts">ऐसा लगता है कि आप यहां नए हैं और अभी तक कोई संपर्क नहीं है। \ N \ n शीर्ष पर + आइकन टैप करें और कुछ मित्रों को अपनी सूची में जोड़ने के लिए निर्देशों का पालन करें। \ N \ n कृपया याद रखें: आप केवल नए संपर्कों को आमने-सामने जोड़ सकते हैं किसी भी व्यक्ति को भविष्य में आपके प्रतिरूपण या पढ़ने से रोकने के लिए -फाइल</string>
|
<string name="no_contacts">ऐसा लगता है कि आप यहां नए हैं और अभी तक कोई संपर्क नहीं है। \ N \ n शीर्ष पर + आइकन टैप करें और कुछ मित्रों को अपनी सूची में जोड़ने के लिए निर्देशों का पालन करें। \ N \ n कृपया याद रखें: आप केवल नए संपर्कों को आमने-सामने जोड़ सकते हैं किसी भी व्यक्ति को भविष्य में आपके प्रतिरूपण या पढ़ने से रोकने के लिए -फाइल</string>
|
||||||
@@ -114,10 +96,8 @@
|
|||||||
<string name="contact_already_exists">संपर्क%s पहले से मौजूद है</string>
|
<string name="contact_already_exists">संपर्क%s पहले से मौजूद है</string>
|
||||||
<string name="contact_exchange_failed">संपर्क विनिमय विफल</string>
|
<string name="contact_exchange_failed">संपर्क विनिमय विफल</string>
|
||||||
<string name="qr_code_invalid">QR कोड अमान्य है</string>
|
<string name="qr_code_invalid">QR कोड अमान्य है</string>
|
||||||
<string name="camera_error">कैमरा त्रुटि</string>
|
|
||||||
<string name="connecting_to_device">उपकरण \ u2026 से कनेक्ट हो रहा है</string>
|
<string name="connecting_to_device">उपकरण \ u2026 से कनेक्ट हो रहा है</string>
|
||||||
<string name="authenticating_with_device">डिवाइस के साथ प्रमाणीकरण \ u2026</string>
|
<string name="authenticating_with_device">डिवाइस के साथ प्रमाणीकरण \ u2026</string>
|
||||||
<string name="connection_aborted_local">कनेक्शन निरस्त कर दिया गया! इसका मतलब यह हो सकता है कि कोई आपके कनेक्शन में हस्तक्षेप करने का प्रयास कर रहा है</string>
|
|
||||||
<string name="connection_aborted_remote">आपके संपर्क से कनेक्शन निरस्त! इसका मतलब यह हो सकता है कि कोई आपके कनेक्शन में हस्तक्षेप करने का प्रयास कर रहा है</string>
|
<string name="connection_aborted_remote">आपके संपर्क से कनेक्शन निरस्त! इसका मतलब यह हो सकता है कि कोई आपके कनेक्शन में हस्तक्षेप करने का प्रयास कर रहा है</string>
|
||||||
<!--Introductions-->
|
<!--Introductions-->
|
||||||
<string name="introduction_onboarding_title">अपने संपर्कों का परिचय दें</string>
|
<string name="introduction_onboarding_title">अपने संपर्कों का परिचय दें</string>
|
||||||
@@ -338,7 +318,6 @@
|
|||||||
<string name="notify_sound_setting_default">बकाया घंटी</string>
|
<string name="notify_sound_setting_default">बकाया घंटी</string>
|
||||||
<string name="notify_sound_setting_disabled">कोई नहीं</string>
|
<string name="notify_sound_setting_disabled">कोई नहीं</string>
|
||||||
<string name="choose_ringtone_title">रिंगटोन चुनें</string>
|
<string name="choose_ringtone_title">रिंगटोन चुनें</string>
|
||||||
<string name="cannot_load_ringtone">रिंगटोन लोड नहीं कर सकता</string>
|
|
||||||
<!--Settings Feedback-->
|
<!--Settings Feedback-->
|
||||||
<string name="feedback_settings_title">प्रतिक्रिया</string>
|
<string name="feedback_settings_title">प्रतिक्रिया</string>
|
||||||
<string name="send_feedback">प्रतिक्रिया भेजें</string>
|
<string name="send_feedback">प्रतिक्रिया भेजें</string>
|
||||||
@@ -367,11 +346,6 @@
|
|||||||
<string name="progress_title_logout">ब्रियर से साइन आउट हो रहा है ...</string>
|
<string name="progress_title_logout">ब्रियर से साइन आउट हो रहा है ...</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">स्क्रीन ओवरले का पता लगाया</string>
|
<string name="screen_filter_title">स्क्रीन ओवरले का पता लगाया</string>
|
||||||
<string name="screen_filter_body">एक और ऐप ब्रियर के शीर्ष पर है। आपकी सुरक्षा की रक्षा के लिए, ब्रियर स्पर्श करने का जवाब नहीं देगा, जब किसी अन्य ऐप को शीर्ष पर आ रही है। \ N \ n निम्न एप्लिकेशन शीर्ष पर ड्राइंग कर सकते हैं: \ n \ n%1$s</string>
|
<string name="screen_filter_body">एक और ऐप ब्रियर के शीर्ष पर है। आपकी सुरक्षा की सुरक्षा के लिए, ब्रियर किसी अन्य ऐप को शीर्ष पर खींचने पर स्पर्श का जवाब नहीं देगा। \ N \ n बरिआर का उपयोग करते समय निम्नलिखित ऐप्स बंद कर दें: \ n \ n%1$s</string>
|
||||||
<string name="screen_filter_allow">इन ऐप्स को शीर्ष पर आकर्षित करने की अनुमति दें</string>
|
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<string name="permission_camera_title">कैमरा अनुमति</string>
|
|
||||||
<string name="permission_camera_request_body">QR कोड को स्कैन करने के लिए, Briar को कैमरे तक पहुंच की आवश्यकता है।</string>
|
|
||||||
<string name="permission_camera_denied_body">आपने कैमरे तक पहुंच से वंचित किया है, लेकिन संपर्क जोड़ने के लिए कैमरे का उपयोग करने की आवश्यकता है। \ N \ n कृपया पहुंच प्रदान करने पर विचार करें।</string>
|
|
||||||
<string name="permission_camera_denied_toast">कैमरा अनुमति नहीं दी गई थी</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -31,11 +31,9 @@
|
|||||||
<string name="dialog_title_lost_password">Password persa</string>
|
<string name="dialog_title_lost_password">Password persa</string>
|
||||||
<string name="dialog_message_lost_password">Il tuo account Briar si trova cifrato sul tuo dispositivo e non nel cloud, quindi non possiamo resettarti la tua password. Vorresti cancellare il tuo account e partire di nuovo?\n\nAttenzione: Le tue identità, contatti e messaggi verranno persi permanentemente.</string>
|
<string name="dialog_message_lost_password">Il tuo account Briar si trova cifrato sul tuo dispositivo e non nel cloud, quindi non possiamo resettarti la tua password. Vorresti cancellare il tuo account e partire di nuovo?\n\nAttenzione: Le tue identità, contatti e messaggi verranno persi permanentemente.</string>
|
||||||
<string name="startup_failed_notification_title">Briar non è riuscito a partire</string>
|
<string name="startup_failed_notification_title">Briar non è riuscito a partire</string>
|
||||||
<string name="startup_failed_notification_text">Tocca per maggiori informazioni.</string>
|
<string name="startup_failed_notification_text">Potresti dover reinstallare Briar</string>
|
||||||
<string name="startup_failed_activity_title">Fallimento Avvio Briar</string>
|
<string name="startup_failed_activity_title">Fallimento Avvio Briar</string>
|
||||||
<string name="startup_failed_db_error">Per qualche motivo, il tuo database di Briar è danneggiato in modo irreparabile. Il tuo account, i tuoi dati e tutti i tuoi contatti sono perduti. Sfortunatamente devi reinstallare Briar e registrare un nuovo account scegliendo \'Ho dimenticato la password\'.</string>
|
<string name="startup_failed_db_error">Per qualche motivo il tuo database di Briar è danneggiato in modo irreversibile. Il tuo account, i tuoi dati e tutti i contatti sono persi. Sfortunatamente devi reinstallare Briar e creare un nuovo account.</string>
|
||||||
<string name="startup_failed_data_too_old_error">Il tuo account è stato creato con una vecchia versione dell\'app e non può essere aperto in questa versione. Devi reinstallare la vecchia versione oppure eliminare l\'account vecchio scegliendo \'Ho dimenticato la password\'.</string>
|
|
||||||
<string name="startup_failed_data_too_new_error">Questa versione dell\'app è troppo vecchia. Aggiornala alla versione più recente e riprova.</string>
|
|
||||||
<string name="startup_failed_service_error">Briar non è stato in grado di caricare un plugin richiesto. Reinstallare Briar di solito sistema questo problema. Però ricorda che perderai il tuo account e tutti i dati ad esso associati poichè Briar non usa server centralizzati per mantenere i tuoi dati.</string>
|
<string name="startup_failed_service_error">Briar non è stato in grado di caricare un plugin richiesto. Reinstallare Briar di solito sistema questo problema. Però ricorda che perderai il tuo account e tutti i dati ad esso associati poichè Briar non usa server centralizzati per mantenere i tuoi dati.</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Questa è una versione di prova di Briar. Il tuo account scadrà fra %d giorno e non può essere rinnovato.</item>
|
<item quantity="one">Questa è una versione di prova di Briar. Il tuo account scadrà fra %d giorno e non può essere rinnovato.</item>
|
||||||
@@ -97,7 +95,6 @@
|
|||||||
<string name="show_onboarding">Mostra l\'aiuto</string>
|
<string name="show_onboarding">Mostra l\'aiuto</string>
|
||||||
<string name="fix">Correggi</string>
|
<string name="fix">Correggi</string>
|
||||||
<string name="help">Aiuto</string>
|
<string name="help">Aiuto</string>
|
||||||
<string name="sorry">Scusa</string>
|
|
||||||
<!--Contacts and Private Conversations-->
|
<!--Contacts and Private Conversations-->
|
||||||
<string name="no_contacts">Sembra che tu sia nuovo qui e non hai ancora contatti.\n\nPremi l\'icona in alto e segui le istruzioni per aggiungere qualche amico alla tua lista.\n\nPer favore ricorda: puoi solo aggiungere nuovi contatti faccia-a-faccia per evitare che altri ti impersonino o leggano i tuoi messaggi in futuro.</string>
|
<string name="no_contacts">Sembra che tu sia nuovo qui e non hai ancora contatti.\n\nPremi l\'icona in alto e segui le istruzioni per aggiungere qualche amico alla tua lista.\n\nPer favore ricorda: puoi solo aggiungere nuovi contatti faccia-a-faccia per evitare che altri ti impersonino o leggano i tuoi messaggi in futuro.</string>
|
||||||
<string name="date_no_private_messages">Nessun messaggio.</string>
|
<string name="date_no_private_messages">Nessun messaggio.</string>
|
||||||
@@ -119,7 +116,6 @@
|
|||||||
<string name="contact_already_exists">Il contatto %s esiste già</string>
|
<string name="contact_already_exists">Il contatto %s esiste già</string>
|
||||||
<string name="contact_exchange_failed">Scambio di contatto fallito</string>
|
<string name="contact_exchange_failed">Scambio di contatto fallito</string>
|
||||||
<string name="qr_code_invalid">Il codice QR non è valido</string>
|
<string name="qr_code_invalid">Il codice QR non è valido</string>
|
||||||
<string name="qr_code_unsupported">Il codice QR che state tentando di scansionare appartiene ad una vecchia versione di %s che non è più supportata.\n\nAssicuratevi entrambi di utilizzare la versione più recente e poi riprovare.</string>
|
|
||||||
<string name="camera_error">Errore fotocamera</string>
|
<string name="camera_error">Errore fotocamera</string>
|
||||||
<string name="connecting_to_device">Connessione al dispositivo\u2026</string>
|
<string name="connecting_to_device">Connessione al dispositivo\u2026</string>
|
||||||
<string name="authenticating_with_device">Autenticazione con il dispositivo\u2026</string>
|
<string name="authenticating_with_device">Autenticazione con il dispositivo\u2026</string>
|
||||||
@@ -373,8 +369,7 @@
|
|||||||
<string name="progress_title_logout">Uscire da Briar ...</string>
|
<string name="progress_title_logout">Uscire da Briar ...</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">È stata rilevata un\'overlay sullo schermo</string>
|
<string name="screen_filter_title">È stata rilevata un\'overlay sullo schermo</string>
|
||||||
<string name="screen_filter_body">Un\'altra app si sta sovrapponendo a Briar. Per proteggere la tua sicurezza, Briar non risponderà ai tocchi quando un\'app si sovrappone.\n\nLe seguenti app potrebbero sovrapporsi:\n\n%1$s</string>
|
<string name="screen_filter_body">Un\'altra app sta disegnando sopra a Briar. Per proteggere la tua sicurezza, Briar non risponderà ai tocchi quando un\'altra app vi starà disegnando sopra.\n\nProva a spegnere le seguenti app mentre usi Briar:\n\n%1$s</string>
|
||||||
<string name="screen_filter_allow">Permetti a queste app di sovrapporsi</string>
|
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<string name="permission_camera_title">Autorizzazione fotocamera</string>
|
<string name="permission_camera_title">Autorizzazione fotocamera</string>
|
||||||
<string name="permission_camera_request_body">Per scansionare il codice QR, Briar deve accedere alla fotocamera.</string>
|
<string name="permission_camera_request_body">Per scansionare il codice QR, Briar deve accedere alla fotocamera.</string>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
<string name="dialog_title_lost_password">パスワードを紛失</string>
|
<string name="dialog_title_lost_password">パスワードを紛失</string>
|
||||||
<string name="dialog_message_lost_password">あなたのBriarアカウントはクラウド上ではなく、暗号化さた上であなたのデバイスに保存さています。したがってBriarはパスワードをリセットできません。アカウントを削除しはじめからやりなおしますか?注意!あなたのID、連絡先、メッセージは永久に削除されます。</string>
|
<string name="dialog_message_lost_password">あなたのBriarアカウントはクラウド上ではなく、暗号化さた上であなたのデバイスに保存さています。したがってBriarはパスワードをリセットできません。アカウントを削除しはじめからやりなおしますか?注意!あなたのID、連絡先、メッセージは永久に削除されます。</string>
|
||||||
<string name="startup_failed_notification_title">Briarを起動できません。</string>
|
<string name="startup_failed_notification_title">Briarを起動できません。</string>
|
||||||
|
<string name="startup_failed_notification_text">Briarを再インストールする必要があります。</string>
|
||||||
<string name="startup_failed_activity_title">起動に失敗</string>
|
<string name="startup_failed_activity_title">起動に失敗</string>
|
||||||
<string name="startup_failed_service_error">プラグインの起動に失敗しました。Briarを再インストールすることで通常は直ります。Briarは中央サーバにデータを保存していないため、アカウントとそれに関連する情報は全て失われることに注意してください。</string>
|
<string name="startup_failed_service_error">プラグインの起動に失敗しました。Briarを再インストールすることで通常は直ります。Briarは中央サーバにデータを保存していないため、アカウントとそれに関連する情報は全て失われることに注意してください。</string>
|
||||||
<string name="expiry_date_reached">このソフトの有効期限が切れました。テストに参加してくださりありがとうございます!</string>
|
<string name="expiry_date_reached">このソフトの有効期限が切れました。テストに参加してくださりありがとうございます!</string>
|
||||||
|
|||||||
@@ -31,7 +31,9 @@
|
|||||||
<string name="dialog_title_lost_password">Tapt passord</string>
|
<string name="dialog_title_lost_password">Tapt passord</string>
|
||||||
<string name="dialog_message_lost_password">Din Briar-konto er lagret kryptert på din enhet, ikke i skyen, så du kan ikke tilbakestille passordet ditt. Ønsker du å slette kontoen og starte igjen?\n\nMerk: Identitetene dine, kontaktene og meldingene vil gå tapt for alltid.</string>
|
<string name="dialog_message_lost_password">Din Briar-konto er lagret kryptert på din enhet, ikke i skyen, så du kan ikke tilbakestille passordet ditt. Ønsker du å slette kontoen og starte igjen?\n\nMerk: Identitetene dine, kontaktene og meldingene vil gå tapt for alltid.</string>
|
||||||
<string name="startup_failed_notification_title">Briar kunne ikke starte</string>
|
<string name="startup_failed_notification_title">Briar kunne ikke starte</string>
|
||||||
|
<string name="startup_failed_notification_text">Det kan hende du må reinstallere Briar.</string>
|
||||||
<string name="startup_failed_activity_title">Oppstartsfeil med Briar</string>
|
<string name="startup_failed_activity_title">Oppstartsfeil med Briar</string>
|
||||||
|
<string name="startup_failed_db_error">Hvis din Briar-database av noen grunn skulle bli skadet uten mulighet for reparasjon, vil din konto, din data, og alle dine kontakter gå tapt. Uheldigvis, må du da reinstallere Briar og sett opp en ny konto.</string>
|
||||||
<string name="startup_failed_service_error">Briar kunne ikke starte det nødvendige programtillegget. Reinstallasjon av Briar fikser vanligvis dette problemet. Merk deg dog at kontoen og all data tilknyttet den vil gå tapt for godt siden Briar ikke bruker sentrale tjenere å lagre dataen din på.</string>
|
<string name="startup_failed_service_error">Briar kunne ikke starte det nødvendige programtillegget. Reinstallasjon av Briar fikser vanligvis dette problemet. Merk deg dog at kontoen og all data tilknyttet den vil gå tapt for godt siden Briar ikke bruker sentrale tjenere å lagre dataen din på.</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Dette er en test-versjon av Briar. Din konto vil utløpe om %d dag, og kan ikke fornyes.</item>
|
<item quantity="one">Dette er en test-versjon av Briar. Din konto vil utløpe om %d dag, og kan ikke fornyes.</item>
|
||||||
@@ -367,6 +369,7 @@
|
|||||||
<string name="progress_title_logout">Logger ut av Briar…</string>
|
<string name="progress_title_logout">Logger ut av Briar…</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">Skjermoverlag oppdaget</string>
|
<string name="screen_filter_title">Skjermoverlag oppdaget</string>
|
||||||
|
<string name="screen_filter_body">Et annet program tegner på toppen av Briar. For å beskytte din sikkerhet, vil Briar ikke reagere på trykk når et annet program tegner over det.\n\nPrøv å skru av følgende programmer når du bruker Briar.\n\n%1$s</string>
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<string name="permission_camera_title">Kameratilgang</string>
|
<string name="permission_camera_title">Kameratilgang</string>
|
||||||
<string name="permission_camera_request_body">For å skanne QR-koden, trenger Briar tilgang til kameraet.</string>
|
<string name="permission_camera_request_body">For å skanne QR-koden, trenger Briar tilgang til kameraet.</string>
|
||||||
|
|||||||
@@ -31,7 +31,9 @@
|
|||||||
<string name="dialog_title_lost_password">Wachtwoord vergeten</string>
|
<string name="dialog_title_lost_password">Wachtwoord vergeten</string>
|
||||||
<string name="dialog_message_lost_password">Je Briar-account is versleuteld opgeslagen op je apparaat, niet in de cloud, dus kunnen we je wachtwoord niet resetten. Wil je je account verwijderen en opnieuw beginnen?\n\nLet op: Je identiteiten, contacten en berichten zullen permanent verloren gaan.</string>
|
<string name="dialog_message_lost_password">Je Briar-account is versleuteld opgeslagen op je apparaat, niet in de cloud, dus kunnen we je wachtwoord niet resetten. Wil je je account verwijderen en opnieuw beginnen?\n\nLet op: Je identiteiten, contacten en berichten zullen permanent verloren gaan.</string>
|
||||||
<string name="startup_failed_notification_title">Briar kon niet opstarten</string>
|
<string name="startup_failed_notification_title">Briar kon niet opstarten</string>
|
||||||
|
<string name="startup_failed_notification_text">Misschien moet je Briar opnieuw installeren</string>
|
||||||
<string name="startup_failed_activity_title">Opstarten Briar mislukt</string>
|
<string name="startup_failed_activity_title">Opstarten Briar mislukt</string>
|
||||||
|
<string name="startup_failed_db_error">Om de een of andere andere reden is je Briar-database corrupt geworden en niet meer te herstellen. Je account, je gegevens en al je contacten zijn verloren. Helaas dien je Briar opnieuw te installeren en een nieuw account aan te maken.</string>
|
||||||
<string name="startup_failed_service_error">Briar kon de vereiste plug-in niet starten. Herinstalleren van Briar lost dit probleem meestal op. Let op dat je al je je account en alle gegevens die daaraan vast zitten zal verliezen omdat Briar geen centrale servers gebruikt om gegevens op te slaan.</string>
|
<string name="startup_failed_service_error">Briar kon de vereiste plug-in niet starten. Herinstalleren van Briar lost dit probleem meestal op. Let op dat je al je je account en alle gegevens die daaraan vast zitten zal verliezen omdat Briar geen centrale servers gebruikt om gegevens op te slaan.</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Dit is een testversie van Briar. Je account verloopt binnen %d dag en kan niet worden vernieuwd.</item>
|
<item quantity="one">Dit is een testversie van Briar. Je account verloopt binnen %d dag en kan niet worden vernieuwd.</item>
|
||||||
@@ -367,6 +369,7 @@
|
|||||||
<string name="progress_title_logout">Uitloggen van Briar…</string>
|
<string name="progress_title_logout">Uitloggen van Briar…</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">Schermoverlay detecteerd</string>
|
<string name="screen_filter_title">Schermoverlay detecteerd</string>
|
||||||
|
<string name="screen_filter_body">Een andere app ligt boven Briar. Om je veiligheid te beschermen zal Briar niet reageren op aanrakingen als er een andere app boven ligt.\n\nProbeer de volgende apps uit te schakelen als je Briar gebruikt:\n\n%1$s</string>
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<string name="permission_camera_title">Cameratoestemming</string>
|
<string name="permission_camera_title">Cameratoestemming</string>
|
||||||
<string name="permission_camera_request_body">Om de QR-code te scannen moet Briar toegang hebben tot de camera.</string>
|
<string name="permission_camera_request_body">Om de QR-code te scannen moet Briar toegang hebben tot de camera.</string>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
Volètz suprimir vòstre compte e ne crear un nòu ?\n
|
Volètz suprimir vòstre compte e ne crear un nòu ?\n
|
||||||
\nMèfi : vòstra identitat, vòstres contactes e messatges seràn perduts per totjorn.</string>
|
\nMèfi : vòstra identitat, vòstres contactes e messatges seràn perduts per totjorn.</string>
|
||||||
<string name="startup_failed_notification_title">Briar a pas pogut aviar</string>
|
<string name="startup_failed_notification_title">Briar a pas pogut aviar</string>
|
||||||
|
<string name="startup_failed_notification_text">Benlèu que vos cal tornar installar Briar.</string>
|
||||||
<string name="startup_failed_activity_title">Fracàs de l’aviada de Briar.</string>
|
<string name="startup_failed_activity_title">Fracàs de l’aviada de Briar.</string>
|
||||||
<string name="startup_failed_service_error">Briar a pas pogut aviar un modul necessari. Tornar installar Briar pòt resolver aquò. Que aquò siá dich : perdretz vòstre compte e totas las donadas ligadas a aqueste. Briar utiliza pas de servidor centralizat per salvar sas donadas.</string>
|
<string name="startup_failed_service_error">Briar a pas pogut aviar un modul necessari. Tornar installar Briar pòt resolver aquò. Que aquò siá dich : perdretz vòstre compte e totas las donadas ligadas a aqueste. Briar utiliza pas de servidor centralizat per salvar sas donadas.</string>
|
||||||
<string name="expiry_date_reached">Vòstre logicial s’acabèt.\nMercés d’aver ensajat !</string>
|
<string name="expiry_date_reached">Vòstre logicial s’acabèt.\nMercés d’aver ensajat !</string>
|
||||||
@@ -345,5 +346,6 @@ Volètz suprimir vòstre compte e ne crear un nòu ?\n
|
|||||||
<string name="progress_title_logout">Desconnecion de Briar...</string>
|
<string name="progress_title_logout">Desconnecion de Briar...</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">Superposicion detectada</string>
|
<string name="screen_filter_title">Superposicion detectada</string>
|
||||||
|
<string name="screen_filter_body">Una autra aplicacion s’aficha per dessús Briar. Per protegir vòstre seguretat Briar respond pas quand una autra aplicacion s’aficha par dessús.\n\nEnsajatz de tampar las aplicacions seguentas quand utilizatz Briar : \n\n%1$s</string>
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -31,11 +31,9 @@
|
|||||||
<string name="dialog_title_lost_password">Perdeu a senha</string>
|
<string name="dialog_title_lost_password">Perdeu a senha</string>
|
||||||
<string name="dialog_message_lost_password">Sua conta Briar é armazenada em seu dispositivo e criptografada, não na Nuvem, assim não podemos recuperar a senha. Você quer deletar sua conta e começar de novo?\n\nAtenção: Isso irá apagar permanentemente suas identidades, contatos e mensagens</string>
|
<string name="dialog_message_lost_password">Sua conta Briar é armazenada em seu dispositivo e criptografada, não na Nuvem, assim não podemos recuperar a senha. Você quer deletar sua conta e começar de novo?\n\nAtenção: Isso irá apagar permanentemente suas identidades, contatos e mensagens</string>
|
||||||
<string name="startup_failed_notification_title">Briar não pode iniciar</string>
|
<string name="startup_failed_notification_title">Briar não pode iniciar</string>
|
||||||
<string name="startup_failed_notification_text">Pressione para mais informações.</string>
|
<string name="startup_failed_notification_text">Você pode precisar reinstalar o Briar.</string>
|
||||||
<string name="startup_failed_activity_title">Inicialização do Briar falhou</string>
|
<string name="startup_failed_activity_title">Inicialização do Briar falhou</string>
|
||||||
<string name="startup_failed_db_error">Por algum motivo, o banco de dados do seu Briar está corrompido e não é possível repará-lo. Sua conta, seus dados e seus contatos foram perdidos. Infelizmente, você precisará reinstalar o Briar e criar uma nova conta escolhendo a opção \'Esqueci minha senha\'.</string>
|
<string name="startup_failed_db_error">Por algum motivo, seu banco de dados do Briar foi corrompido enão pode ser reparado. Sua conta, seus dados e todos seus contatos estão perdidos. Infelizmente, você precisa reinstalar o Briar e criar uma nova conta.</string>
|
||||||
<string name="startup_failed_data_too_old_error">Sua conta foi criada numa versão mais antiga do aplicativo e não pode ser aberta nesta versão. Você pode reinstalar a versão antiga ou deleter sua conta antiga escolhendo a opção \"Esqueci minha senha\".</string>
|
|
||||||
<string name="startup_failed_data_too_new_error">A versão deste aplicativo é muito antiga. Por favor, atualize para a versão mais nova e tente novamente.</string>
|
|
||||||
<string name="startup_failed_service_error">O Briar não pode iniciar devido a um plugin. Reinstalar o Briar geralmente resolve esse problema. Porém, note que ao fazer isso você perderá sua conta e todos os dados associados a ela, já que o Briar não usa um servidor central para armazenar seus dados.</string>
|
<string name="startup_failed_service_error">O Briar não pode iniciar devido a um plugin. Reinstalar o Briar geralmente resolve esse problema. Porém, note que ao fazer isso você perderá sua conta e todos os dados associados a ela, já que o Briar não usa um servidor central para armazenar seus dados.</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Esta é uma versão de teste do Briar. Sua conta irá expirar em %d dia e não poderá ser renovada.</item>
|
<item quantity="one">Esta é uma versão de teste do Briar. Sua conta irá expirar em %d dia e não poderá ser renovada.</item>
|
||||||
@@ -97,7 +95,6 @@
|
|||||||
<string name="show_onboarding">Mostrar dialogo de ajuda</string>
|
<string name="show_onboarding">Mostrar dialogo de ajuda</string>
|
||||||
<string name="fix">Consertar</string>
|
<string name="fix">Consertar</string>
|
||||||
<string name="help">Ajuda</string>
|
<string name="help">Ajuda</string>
|
||||||
<string name="sorry">Sentimos muito</string>
|
|
||||||
<!--Contacts and Private Conversations-->
|
<!--Contacts and Private Conversations-->
|
||||||
<string name="no_contacts">Parece que você é novo aqui e ainda não tem contatos.\nClique no ícone + no topo e siga as instruções para adicionar alguns amigos para sua lista.\nPor favor lembre: você só pode adicionar contatos pessoalmente para prevenir alguém se passar por você ou ler suas mensagens no futuro. </string>
|
<string name="no_contacts">Parece que você é novo aqui e ainda não tem contatos.\nClique no ícone + no topo e siga as instruções para adicionar alguns amigos para sua lista.\nPor favor lembre: você só pode adicionar contatos pessoalmente para prevenir alguém se passar por você ou ler suas mensagens no futuro. </string>
|
||||||
<string name="date_no_private_messages">Sem Mensagens</string>
|
<string name="date_no_private_messages">Sem Mensagens</string>
|
||||||
@@ -119,7 +116,6 @@
|
|||||||
<string name="contact_already_exists">Contato %s já existe</string>
|
<string name="contact_already_exists">Contato %s já existe</string>
|
||||||
<string name="contact_exchange_failed">Troca de contatos falhou</string>
|
<string name="contact_exchange_failed">Troca de contatos falhou</string>
|
||||||
<string name="qr_code_invalid">O QR code é inválido</string>
|
<string name="qr_code_invalid">O QR code é inválido</string>
|
||||||
<string name="qr_code_unsupported">O código QR que você está tentando escanear é de uma versão antiga do %s, que não é mais suportada.\n\nPor favor, verifique que você e a outra pessoa está usando a versão mais recente e tentem de novo.</string>
|
|
||||||
<string name="camera_error">Erro da câmera</string>
|
<string name="camera_error">Erro da câmera</string>
|
||||||
<string name="connecting_to_device">Conectando a device\u2026</string>
|
<string name="connecting_to_device">Conectando a device\u2026</string>
|
||||||
<string name="authenticating_with_device">Autenticando com o dispositivo\u2026</string>
|
<string name="authenticating_with_device">Autenticando com o dispositivo\u2026</string>
|
||||||
@@ -373,8 +369,7 @@
|
|||||||
<string name="progress_title_logout">Saindo do Briar…</string>
|
<string name="progress_title_logout">Saindo do Briar…</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">Sobreposição de tela detectada</string>
|
<string name="screen_filter_title">Sobreposição de tela detectada</string>
|
||||||
<string name="screen_filter_body">Outro aplicativo está se sobrepondo sobre o Briar. Para proteger sua segurança, Briar não responderá a seus toques enquanto estiver sobreposto.\n\nOs seguintes aplicativos podem estar se sobrepondo:\n\n%1$s</string>
|
<string name="screen_filter_body">Outro aplicativo está rodando por cima do Briar. Para proteger sua segurança, o Briar não irá responder por toques quando outro aplicativo estiver por cima.\n\nTente desligar os seguintes aplicativos quando for usar o Briar:\n\n %1$s</string>
|
||||||
<string name="screen_filter_allow">Permitir que estes aplicativos se sobreponham</string>
|
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<string name="permission_camera_title">Permissão da câmera</string>
|
<string name="permission_camera_title">Permissão da câmera</string>
|
||||||
<string name="permission_camera_request_body">O Briar precisa acessar a câmera para pode escanear o QR code.</string>
|
<string name="permission_camera_request_body">O Briar precisa acessar a câmera para pode escanear o QR code.</string>
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<!--Setup-->
|
<!--Setup-->
|
||||||
<string name="setup_title">Добро пожаловать в Briar</string>
|
<string name="setup_title">Добро пожаловать в Briar</string>
|
||||||
<string name="setup_name_explanation">Ваш ник будет показан рядом с любым контентом, который вы публикуете. Его нельзя изменить после создания аккаунта.</string>
|
<string name="setup_name_explanation">Ваш ник будет показан рядом с любым контентом, который вы публикуете. Вы не сможете изменить его после создания аккаунта.</string>
|
||||||
<string name="setup_next">Вперед</string>
|
<string name="setup_next">Вперед</string>
|
||||||
<string name="setup_password_intro">Выберите пароль</string>
|
<string name="setup_password_intro">Выберите пароль</string>
|
||||||
<string name="setup_password_explanation">Ваша учетная запись Briar хранится в зашифрованном виде только на устройстве. Если вы забудете свой пароль или удалите Briar, то не сможете восстановить свою учетную запись.\n\nВыберите длинный пароль, который трудно угадать, например четыре случайных слова или десять случайных букв, цифр и символов.</string>
|
<string name="setup_password_explanation">Ваша учетная запись Briar хранится в зашифрованном виде только на устройстве. Если вы забудете свой пароль или удалите Briar, вы не сможете восстановить свою учетную запись.\n\nВыберите длинный пароль, который трудно угадать, например четыре случайных слова или десять случайных букв, цифр и символов.</string>
|
||||||
<string name="setup_doze_title">Фоновые подключения</string>
|
<string name="setup_doze_title">Фоновые подключения</string>
|
||||||
<string name="setup_doze_intro">Для получения сообщений Briar должен работать в фоновом режиме.</string>
|
<string name="setup_doze_intro">Для получения сообщений, Briar должен работать в фоновом режиме.</string>
|
||||||
<string name="setup_doze_explanation">Для получения сообщений Briar должен работать в фоновом режиме. Отключите оптимизацию электропитания для Briar.</string>
|
<string name="setup_doze_explanation">Для получения сообщений, Briar должен работать в фоновом режиме. Отключите оптимизацию электропитания для Briar.</string>
|
||||||
<string name="setup_doze_button">Разрешить подключения</string>
|
<string name="setup_doze_button">Разрешить подключения</string>
|
||||||
<string name="choose_nickname">Выберите псевдоним</string>
|
<string name="choose_nickname">Выберите псевдоним</string>
|
||||||
<string name="choose_password">Выберите пароль</string>
|
<string name="choose_password">Выберите пароль</string>
|
||||||
@@ -28,14 +28,12 @@
|
|||||||
<string name="try_again">Неверный пароль, повторите попытку</string>
|
<string name="try_again">Неверный пароль, повторите попытку</string>
|
||||||
<string name="sign_in_button">Войти</string>
|
<string name="sign_in_button">Войти</string>
|
||||||
<string name="forgotten_password">Я забыл свой пароль</string>
|
<string name="forgotten_password">Я забыл свой пароль</string>
|
||||||
<string name="dialog_title_lost_password">Пароль утерян</string>
|
<string name="dialog_title_lost_password">Потерянный пароль</string>
|
||||||
<string name="dialog_message_lost_password">Ваша учетная запись Briar хранится в зашифрованном виде только на устройстве, поэтому мы не можем сбросить пароль. Удалить учетную запись и начать заново?\n\nВнимание: ваши идентификаторы, контакты и сообщения будут потеряны навсегда.</string>
|
<string name="dialog_message_lost_password">Ваша учетная запись Briar хранится в зашифрованном виде только на устройстве, поэтому мы не можем сбросить пароль. Удалить учетную запись и начать заново?\n\nВнимание: ваши идентификаторы, контакты и сообщения будут потеряны навсегда.</string>
|
||||||
<string name="startup_failed_notification_title">Не удалось запустить Briar</string>
|
<string name="startup_failed_notification_title">Не удалось запустить Briar</string>
|
||||||
<string name="startup_failed_notification_text">Коснитесь для получения дополнительных сведений.</string>
|
<string name="startup_failed_notification_text">Возможно, потребуется переустановить Briar.</string>
|
||||||
<string name="startup_failed_activity_title">Сбой при запуске Briar</string>
|
<string name="startup_failed_activity_title">Сбой при запуске Briar</string>
|
||||||
<string name="startup_failed_db_error">По какой-то причине, база данных Briar повреждена без возможности восстановления. Вместе с учетной записью будут потеряны ваши данные и ваши контакты. К сожалению, вам нужно переустановить Briar и создать новый аккаунт, выбрав \'я забыл свой пароль\'.</string>
|
<string name="startup_failed_db_error">По какой-то причине, ваша база данных Briar повреждена без возможности восстановления. Ваша учетная запись, ваши данные и все ваши контакты потеряны. К сожалению, вам придется переустановить Briar и создать новую учетную запись.</string>
|
||||||
<string name="startup_failed_data_too_old_error">Ваша учетная запись была создана в старой версии Briar и не может быть открыта в этой версии. Вы должны либо установить старую версию, либо удалить старую учетную запись, выбрав \'я забыл свой пароль\'.</string>
|
|
||||||
<string name="startup_failed_data_too_new_error">Версия приложения слишком старая. Обновите до последней версии и повторите попытку.</string>
|
|
||||||
<string name="startup_failed_service_error">Briar не смог запустить требуемый подключаемый модуль. Переустановка Briar обычно решает эту проблему. Однако обратите внимание, что после этого вы потеряете свою учетную запись и все связанные с ней данные, поскольку Briar не использует центральных серверов для хранения данных.</string>
|
<string name="startup_failed_service_error">Briar не смог запустить требуемый подключаемый модуль. Переустановка Briar обычно решает эту проблему. Однако обратите внимание, что после этого вы потеряете свою учетную запись и все связанные с ней данные, поскольку Briar не использует центральных серверов для хранения данных.</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Это бета-версия Briar. Срок действия вашей учетной записи истечет через %d день и не может быть продлен.</item>
|
<item quantity="one">Это бета-версия Briar. Срок действия вашей учетной записи истечет через %d день и не может быть продлен.</item>
|
||||||
@@ -107,7 +105,6 @@
|
|||||||
<string name="show_onboarding">Показать справку</string>
|
<string name="show_onboarding">Показать справку</string>
|
||||||
<string name="fix">Исправить</string>
|
<string name="fix">Исправить</string>
|
||||||
<string name="help">Помощь</string>
|
<string name="help">Помощь</string>
|
||||||
<string name="sorry">Сожалеем</string>
|
|
||||||
<!--Contacts and Private Conversations-->
|
<!--Contacts and Private Conversations-->
|
||||||
<string name="no_contacts">Кажется, вы здесь новенький и у вас нет контактов.\n\nКоснитесь значка + вверху и следуйте инструкциям, чтобы добавить друзей в список.\n\nПомните: вы можете добавлять новые контакты только лично, чтобы никто не выдал себя за вас и не мог читать ваши сообщения.</string>
|
<string name="no_contacts">Кажется, вы здесь новенький и у вас нет контактов.\n\nКоснитесь значка + вверху и следуйте инструкциям, чтобы добавить друзей в список.\n\nПомните: вы можете добавлять новые контакты только лично, чтобы никто не выдал себя за вас и не мог читать ваши сообщения.</string>
|
||||||
<string name="date_no_private_messages">Нет сообщений.</string>
|
<string name="date_no_private_messages">Нет сообщений.</string>
|
||||||
@@ -129,7 +126,6 @@
|
|||||||
<string name="contact_already_exists">Контакт %s уже существует</string>
|
<string name="contact_already_exists">Контакт %s уже существует</string>
|
||||||
<string name="contact_exchange_failed">Обмен контактами не удался</string>
|
<string name="contact_exchange_failed">Обмен контактами не удался</string>
|
||||||
<string name="qr_code_invalid">Неверный QR-код</string>
|
<string name="qr_code_invalid">Неверный QR-код</string>
|
||||||
<string name="qr_code_unsupported">QR-код, который вы пытаетесь отсканировать, создан в старой версии %s, которая больше не поддерживается.\n\nУбедитесь, что вы работаете с последней версией, а затем повторите попытку.</string>
|
|
||||||
<string name="camera_error">Ошибка камеры</string>
|
<string name="camera_error">Ошибка камеры</string>
|
||||||
<string name="connecting_to_device">Подключение к устройству\u2026</string>
|
<string name="connecting_to_device">Подключение к устройству\u2026</string>
|
||||||
<string name="authenticating_with_device">Аутентификация с устройством\u2026</string>
|
<string name="authenticating_with_device">Аутентификация с устройством\u2026</string>
|
||||||
@@ -244,7 +240,7 @@
|
|||||||
<string name="forum_share_button">Поделиться форумом</string>
|
<string name="forum_share_button">Поделиться форумом</string>
|
||||||
<string name="contacts_selected">Выбранные контакты</string>
|
<string name="contacts_selected">Выбранные контакты</string>
|
||||||
<string name="activity_share_toolbar_header">Выбор контактов</string>
|
<string name="activity_share_toolbar_header">Выбор контактов</string>
|
||||||
<string name="no_contacts_selector">Кажется, вы здесь новенький и у вас нет контактов.\n\nЗагляните сюда после добавления своего первого контакта.</string>
|
<string name="no_contacts_selector">Кажется, вы здесь новенький и у вас нет контактов.\n\nПожалуйста, вернитесь сюда после того, как добавите свой первый контакт.</string>
|
||||||
<string name="forum_shared_snackbar">Поделиться форумом совместно с выбранными контактами</string>
|
<string name="forum_shared_snackbar">Поделиться форумом совместно с выбранными контактами</string>
|
||||||
<string name="forum_share_message">Добавить сообщение (необязательно)</string>
|
<string name="forum_share_message">Добавить сообщение (необязательно)</string>
|
||||||
<string name="forum_share_error">Произошла ошибка при при попытке поделиться этим форумом.</string>
|
<string name="forum_share_error">Произошла ошибка при при попытке поделиться этим форумом.</string>
|
||||||
@@ -278,8 +274,8 @@
|
|||||||
<string name="blogs_publish_blog_post">Опубликовать</string>
|
<string name="blogs_publish_blog_post">Опубликовать</string>
|
||||||
<string name="blogs_blog_post_created">Запись блога создана</string>
|
<string name="blogs_blog_post_created">Запись блога создана</string>
|
||||||
<string name="blogs_blog_post_received">Появилась новая запись блога</string>
|
<string name="blogs_blog_post_received">Появилась новая запись блога</string>
|
||||||
<string name="blogs_blog_post_scroll_to">Перейти</string>
|
<string name="blogs_blog_post_scroll_to">Перейти к</string>
|
||||||
<string name="blogs_feed_empty_state">Это глобальный блог.\n\nПохоже, что никто ничего не писал.\n\nБудьте первым - коснитесь значка пера для создания новой записи.</string>
|
<string name="blogs_feed_empty_state">Это глобальный блог.\n\nПохоже, что никто ничего не писал.\n\nБудьте первым - коснитесь значка пера, чтобы написать новую запись блога.</string>
|
||||||
<string name="blogs_remove_blog">Удалить блог</string>
|
<string name="blogs_remove_blog">Удалить блог</string>
|
||||||
<string name="blogs_remove_blog_dialog_message">Вы действительно хотите удалить этот блог со всеми записями?\nОбратите внимание, что это не приведет к удалению блога на устройствах других пользователей.</string>
|
<string name="blogs_remove_blog_dialog_message">Вы действительно хотите удалить этот блог со всеми записями?\nОбратите внимание, что это не приведет к удалению блога на устройствах других пользователей.</string>
|
||||||
<string name="blogs_remove_blog_ok">Удалить блог</string>
|
<string name="blogs_remove_blog_ok">Удалить блог</string>
|
||||||
@@ -371,13 +367,13 @@
|
|||||||
<!--Link Warning-->
|
<!--Link Warning-->
|
||||||
<string name="link_warning_title">Внимание</string>
|
<string name="link_warning_title">Внимание</string>
|
||||||
<string name="link_warning_intro">Вы собираетесь открыть следующую ссылку в стороннем приложении.</string>
|
<string name="link_warning_intro">Вы собираетесь открыть следующую ссылку в стороннем приложении.</string>
|
||||||
<string name="link_warning_text">Возможно вас хотят идентифицировать. Подумайте, доверяете ли вы человеку, который прислал вам эту ссылку и рассмотрите возможность открытия ее в Orfox.</string>
|
<string name="link_warning_text">Возможно вас хотят идентифицировать. Подумайте, доверяете ли вы человеку, который прислал вам эту ссылку и рассмотрите возможность ее открытия в Orfox.</string>
|
||||||
<string name="link_warning_open_link">Открыть ссылку</string>
|
<string name="link_warning_open_link">Открыть ссылку</string>
|
||||||
<!--Crash Reporter-->
|
<!--Crash Reporter-->
|
||||||
<string name="crash_report_title">Отчет о сбое Briar</string>
|
<string name="crash_report_title">Отчет о сбое Briar</string>
|
||||||
<string name="briar_crashed">К сожалению, Briar неожиданно завершил работу.</string>
|
<string name="briar_crashed">К сожалению, Briar неожиданно завершил работу.</string>
|
||||||
<string name="not_your_fault">Это не ваша вина.</string>
|
<string name="not_your_fault">Это не ваша вина.</string>
|
||||||
<string name="please_send_report">Пожалуйста, помогите сделать Briar лучше, отправив нам отчет о сбое.</string>
|
<string name="please_send_report">Пожалуйста, помогите сделать Briar еще лучше, отправив нам отчет о сбоях.</string>
|
||||||
<string name="report_is_encrypted">Мы обещаем, что отчет зашифрован и будет отправлен безопасно.</string>
|
<string name="report_is_encrypted">Мы обещаем, что отчет зашифрован и будет отправлен безопасно.</string>
|
||||||
<string name="feedback_title">Обратная связь</string>
|
<string name="feedback_title">Обратная связь</string>
|
||||||
<string name="describe_crash">Опишите, что произошло (необязательно)</string>
|
<string name="describe_crash">Опишите, что произошло (необязательно)</string>
|
||||||
@@ -393,8 +389,7 @@
|
|||||||
<string name="progress_title_logout">Выход из Briar…</string>
|
<string name="progress_title_logout">Выход из Briar…</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">Обнаружено наложение экрана</string>
|
<string name="screen_filter_title">Обнаружено наложение экрана</string>
|
||||||
<string name="screen_filter_body">Другое приложение накладывается на Briar. Чтобы защитить вашу безопасность, Briar не будет реагировать на прикосновения, пока есть наложение.\n\nМогут накладываться следующие приложения:\n\n%1$s</string>
|
<string name="screen_filter_body">Другое приложение рисуется поверх Briar. Чтобы защитить вашу безопасность, Briar не будет реагировать на прикосновения, когда другое приложение рисует сверху.\n\nПопробуйте отключить следующие приложения при использовании Briar:\n\n%1$s</string>
|
||||||
<string name="screen_filter_allow">Разрешить этим приложениям наложение?</string>
|
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<string name="permission_camera_title">Разрешение камеры</string>
|
<string name="permission_camera_title">Разрешение камеры</string>
|
||||||
<string name="permission_camera_request_body">Для сканирования QR-кода Briar необходим доступ к камере.</string>
|
<string name="permission_camera_request_body">Для сканирования QR-кода Briar необходим доступ к камере.</string>
|
||||||
|
|||||||
@@ -31,11 +31,9 @@
|
|||||||
<string name="dialog_title_lost_password">U humb Fjalëkalimi</string>
|
<string name="dialog_title_lost_password">U humb Fjalëkalimi</string>
|
||||||
<string name="dialog_message_lost_password">Llogaria juaj Briar depozitohet e fshehtëzuar në pajisjen tuaj, jo në re, ndaj s\’mund ta ricaktojmë fjalëkalimin tuaj. Do të donit ta fshini llogarinë tuaj dhe t\’ia filloni nga e para?\n\nKujdes: Identitetet, kontaktet dhe mesazhet tuaja do të humbin përgjithnjë.</string>
|
<string name="dialog_message_lost_password">Llogaria juaj Briar depozitohet e fshehtëzuar në pajisjen tuaj, jo në re, ndaj s\’mund ta ricaktojmë fjalëkalimin tuaj. Do të donit ta fshini llogarinë tuaj dhe t\’ia filloni nga e para?\n\nKujdes: Identitetet, kontaktet dhe mesazhet tuaja do të humbin përgjithnjë.</string>
|
||||||
<string name="startup_failed_notification_title">Briar-i s\’u nis dot</string>
|
<string name="startup_failed_notification_title">Briar-i s\’u nis dot</string>
|
||||||
<string name="startup_failed_notification_text">Prekeni për më tepër të dhëna.</string>
|
<string name="startup_failed_notification_text">Mund të keni nevojë të ri-instaloni Briar-in.</string>
|
||||||
<string name="startup_failed_activity_title">Dështim Nisjeje i Briar-it</string>
|
<string name="startup_failed_activity_title">Dështim Nisjeje i Briar-it</string>
|
||||||
<string name="startup_failed_db_error">Për ndonjë arsye, baza e të dhënave të Briar-it është e dëmtuar sa nuk ndreqet dot. Llogaria juaj, të dhënat tuaja dhe krejt kontaktet tuaja humbën. Mjerisht, ju duhet të ri-instaloni Briar-in dhe të rregulloni një llogari të re duke zgjedhur \'Kam harruar fjalëkalimin tim\' te hapi për fjalëkalimin.</string>
|
<string name="startup_failed_db_error">Për ndonjë arsye, baza e të dhënave e Briar-it tuaj është aq e dëmtuar, sa s\’mund të ndreqet. Llogaria juaj, të dhënat tuaja dhe krejt lidhjet tuaja me kontaktet kanë humbur. Mjerisht lypset të ri-instaloni Briar-in dhe të rregulloni një llogari të re.</string>
|
||||||
<string name="startup_failed_data_too_old_error">Llogaria juaj qe krijuar me një version të vjetër të këtij aplikacioni dhe s’mund të hapet me këtë version. Ose duhet të ri-instaloni versionin e vjetër, ose të fshini llogarinë tuaj të vjetër duke zgjedhur \'Kam harruar fjalëkalimin tim\' te hapi për fjalëkalimin.</string>
|
|
||||||
<string name="startup_failed_data_too_new_error">Ky version i aplikacionit është shumë i vjetër. Ju lutemi, përmirësojeni me versionin më të ri dhe riprovoni.</string>
|
|
||||||
<string name="startup_failed_service_error">Briar-i s\’arriti të nisë një shtojcë të domosdoshme. Ri-instalimi i Briar-it zakonisht e zgjidh këtë problem. Por, ju lutemi, kini parasysh se me të do të humbni llogarinë tuaj dhe krejt të dhënat e lidhura me të, ngaqë Briar nuk përdor shërbyes qendrorë për të depozituar në ta të dhënat tuaja.</string>
|
<string name="startup_failed_service_error">Briar-i s\’arriti të nisë një shtojcë të domosdoshme. Ri-instalimi i Briar-it zakonisht e zgjidh këtë problem. Por, ju lutemi, kini parasysh se me të do të humbni llogarinë tuaj dhe krejt të dhënat e lidhura me të, ngaqë Briar nuk përdor shërbyes qendrorë për të depozituar në ta të dhënat tuaja.</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">Ky është një version beta i Briar-it. Llogaria juaj do të skadojë për %d ditë dhe s\’mund të rinovohet.</item>
|
<item quantity="one">Ky është një version beta i Briar-it. Llogaria juaj do të skadojë për %d ditë dhe s\’mund të rinovohet.</item>
|
||||||
@@ -97,7 +95,6 @@
|
|||||||
<string name="show_onboarding">Shfaq Dialog Ndihme</string>
|
<string name="show_onboarding">Shfaq Dialog Ndihme</string>
|
||||||
<string name="fix">Ndreqeni</string>
|
<string name="fix">Ndreqeni</string>
|
||||||
<string name="help">Ndihmë</string>
|
<string name="help">Ndihmë</string>
|
||||||
<string name="sorry">Na ndjeni</string>
|
|
||||||
<!--Contacts and Private Conversations-->
|
<!--Contacts and Private Conversations-->
|
||||||
<string name="no_contacts">Duket se jeni i ri këtu dhe ende s\’keni kontakte.\n\nPrekni ikonën + në krye dhe ndiqni udhëzimet që të shtoni ca shokë e miq te lista juaj.\n\nJu lutemi, mbani mend: Mundeni të shtoni kontakte të rinj vetëm duke qenë ballë për ballë me ta. që kështu të pengoni cilindo të hiqet si ju ose të lexojë në të ardhmen mesazhet tuaj.</string>
|
<string name="no_contacts">Duket se jeni i ri këtu dhe ende s\’keni kontakte.\n\nPrekni ikonën + në krye dhe ndiqni udhëzimet që të shtoni ca shokë e miq te lista juaj.\n\nJu lutemi, mbani mend: Mundeni të shtoni kontakte të rinj vetëm duke qenë ballë për ballë me ta. që kështu të pengoni cilindo të hiqet si ju ose të lexojë në të ardhmen mesazhet tuaj.</string>
|
||||||
<string name="date_no_private_messages">S\’ka mesazhe.</string>
|
<string name="date_no_private_messages">S\’ka mesazhe.</string>
|
||||||
@@ -119,7 +116,6 @@
|
|||||||
<string name="contact_already_exists">Kontakti %s ekziston tashmë</string>
|
<string name="contact_already_exists">Kontakti %s ekziston tashmë</string>
|
||||||
<string name="contact_exchange_failed">Shkëmbimi i kontaktit dështoi</string>
|
<string name="contact_exchange_failed">Shkëmbimi i kontaktit dështoi</string>
|
||||||
<string name="qr_code_invalid">Kodi QR është i pavlefshëm</string>
|
<string name="qr_code_invalid">Kodi QR është i pavlefshëm</string>
|
||||||
<string name="qr_code_unsupported">Kodi QR që po provoni të skanoni më poshtë i përket një versioni të vjetër të %s-it, i cili nuk mbulohet më.\n\nJu lutemi, sigurohuni që që të dy ju xhironi versionin më të ri dhe mandej riprovoni.</string>
|
|
||||||
<string name="camera_error">Gabim kamere</string>
|
<string name="camera_error">Gabim kamere</string>
|
||||||
<string name="connecting_to_device">Po lidhet me pajisjen\u2026</string>
|
<string name="connecting_to_device">Po lidhet me pajisjen\u2026</string>
|
||||||
<string name="authenticating_with_device">Po bëhet mirëfilltësimi me pajisjen\u2026</string>
|
<string name="authenticating_with_device">Po bëhet mirëfilltësimi me pajisjen\u2026</string>
|
||||||
@@ -373,8 +369,7 @@
|
|||||||
<string name="progress_title_logout">Po dilet nga Briar-i…</string>
|
<string name="progress_title_logout">Po dilet nga Briar-i…</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">U kap dalje jashtë ekrani</string>
|
<string name="screen_filter_title">U kap dalje jashtë ekrani</string>
|
||||||
<string name="screen_filter_body">Sipër Briar-it po vizaton një tjetër aplikacion. Për të mbrojtur sigurinë tuaj, Briar-i nuk do t’u përgjigjet prekjeve kur një tjetër aplikacion vizaton përsipër.\n\nPërsipër mund të jenë duke vizatuar aplikacionet vijues:\n\n%1$s</string>
|
<string name="screen_filter_body">Përsipër Briar-it po vizatohet nga një aplikacion tjetër. Që të mbrohet siguria juaj, Briar-i nuk do t\’u përgjigjet prekjeve kur përsipër vizatohet nga një aplikacion tjetër.\n\nProvoni të mbyllni aplikacionet vijuese, kur përdorni Briar-in:\n\n%1$s</string>
|
||||||
<string name="screen_filter_allow">Lejoji këto aplikacione të vizatojnë përsipër</string>
|
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<string name="permission_camera_title">Leje mbi kamerën</string>
|
<string name="permission_camera_title">Leje mbi kamerën</string>
|
||||||
<string name="permission_camera_request_body">Që të skanojë kodin QR, Briar-i lypset të hyjë te kamera.</string>
|
<string name="permission_camera_request_body">Që të skanojë kodin QR, Briar-i lypset të hyjë te kamera.</string>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
<string name="dialog_title_lost_password">Izgubljena šifra</string>
|
<string name="dialog_title_lost_password">Izgubljena šifra</string>
|
||||||
<string name="dialog_message_lost_password">Vaš Briar račun je kriptovan i sačuvan na vašem uređaju, ne u server-oblaku, pa nemožemo resetovati vašu šifru. Želite li da izbrišete račun i počnete iz početka?\n\nPozor: Vaši identiteti, kontakti i poruke će biti premanentno izgubljeni.</string>
|
<string name="dialog_message_lost_password">Vaš Briar račun je kriptovan i sačuvan na vašem uređaju, ne u server-oblaku, pa nemožemo resetovati vašu šifru. Želite li da izbrišete račun i počnete iz početka?\n\nPozor: Vaši identiteti, kontakti i poruke će biti premanentno izgubljeni.</string>
|
||||||
<string name="startup_failed_notification_title">Brirar nije mogao da startuje</string>
|
<string name="startup_failed_notification_title">Brirar nije mogao da startuje</string>
|
||||||
|
<string name="startup_failed_notification_text">Možda ćete morati da reinstalirate Briar</string>
|
||||||
<string name="startup_failed_activity_title">Briar neuspješno startovanje</string>
|
<string name="startup_failed_activity_title">Briar neuspješno startovanje</string>
|
||||||
<string name="startup_failed_service_error">Briar nije mogao da startuje potreban plugin. Reinstaliranje Briara obično riješi problem. Međutim, imajte na umu da ćete izgubiti vaš račun i sve podatke vezane za njega pošto Briar ne koristi centralne servere da sačuva vaše podatke.</string>
|
<string name="startup_failed_service_error">Briar nije mogao da startuje potreban plugin. Reinstaliranje Briara obično riješi problem. Međutim, imajte na umu da ćete izgubiti vaš račun i sve podatke vezane za njega pošto Briar ne koristi centralne servere da sačuva vaše podatke.</string>
|
||||||
<string name="expiry_date_reached">Ovaj softver je istekao.\nHvala na testiranju!</string>
|
<string name="expiry_date_reached">Ovaj softver je istekao.\nHvala na testiranju!</string>
|
||||||
@@ -308,5 +309,6 @@
|
|||||||
<string name="progress_title_logout">Isključujete se iz Briara...</string>
|
<string name="progress_title_logout">Isključujete se iz Briara...</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">Detektovano je prekrivanje ekrana</string>
|
<string name="screen_filter_title">Detektovano je prekrivanje ekrana</string>
|
||||||
|
<string name="screen_filter_body">Neka druga aplikacija crta interfejs preko Briara. Kako bi vas zaštitili, Briar neće reagovati na dodir kada druga aplikacija ispisuje preko njega.\n\nProbajte da ugasite slijedeće aplikacije kad koristite Briar:\n\n%1$s</string>
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -31,6 +31,8 @@
|
|||||||
<string name="dialog_title_lost_password">Glömt lösenord?</string>
|
<string name="dialog_title_lost_password">Glömt lösenord?</string>
|
||||||
<string name="dialog_message_lost_password">Eftersom ditt Briar-konto lagras krypterat på din mobil eller läsplatta och inte hos en molntjänst kan vi inte återställa ditt lösenord. Vill du radera ditt konto och skapa ett nytt?\n\nCaution: Du kommer att förlora din profil, dina kontakter och dina meddelanden.</string>
|
<string name="dialog_message_lost_password">Eftersom ditt Briar-konto lagras krypterat på din mobil eller läsplatta och inte hos en molntjänst kan vi inte återställa ditt lösenord. Vill du radera ditt konto och skapa ett nytt?\n\nCaution: Du kommer att förlora din profil, dina kontakter och dina meddelanden.</string>
|
||||||
<string name="startup_failed_notification_title">Briar kunde inte startas </string>
|
<string name="startup_failed_notification_title">Briar kunde inte startas </string>
|
||||||
|
<string name="startup_failed_notification_text">Du kan behöva återinstallera Briar.</string>
|
||||||
|
<string name="startup_failed_db_error">Av någon anledning är din Briar-databas korrumperad och kan inte repareras. Ditt konto, dina data och alla dina kontakter har förlorats. Du behöver tyvärr återinstallera Briar och skapa ett nytt konto.</string>
|
||||||
<string name="startup_failed_service_error">Briar kunde inte starta ett nödvändigt insticksprogram. Att återinstallera Briar brukar lösa problemet, men eftersom dina data inte lagras på en central server innebär detta att du kommer att förlora ditt konto och alla dess tillhörande data.</string>
|
<string name="startup_failed_service_error">Briar kunde inte starta ett nödvändigt insticksprogram. Att återinstallera Briar brukar lösa problemet, men eftersom dina data inte lagras på en central server innebär detta att du kommer att förlora ditt konto och alla dess tillhörande data.</string>
|
||||||
<string name="expiry_date_reached">Mjukvaran har gått ut.\nTack för att du bidragit till att testa!</string>
|
<string name="expiry_date_reached">Mjukvaran har gått ut.\nTack för att du bidragit till att testa!</string>
|
||||||
<!--Navigation Drawer-->
|
<!--Navigation Drawer-->
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
<string name="dialog_title_lost_password">Kayıp Parola</string>
|
<string name="dialog_title_lost_password">Kayıp Parola</string>
|
||||||
<string name="dialog_message_lost_password">Briar hesabınız, bulutta değil şifreli olarak cihazınızda saklanır, bu nedenle şifrenizi sıfırlayamıyoruz. Hesabınızı silmek ve tekrar başlamak ister misiniz? \n\nUyarı: Kimlikleriniz, kişileriniz ve iletileriniz kaybolur.</string>
|
<string name="dialog_message_lost_password">Briar hesabınız, bulutta değil şifreli olarak cihazınızda saklanır, bu nedenle şifrenizi sıfırlayamıyoruz. Hesabınızı silmek ve tekrar başlamak ister misiniz? \n\nUyarı: Kimlikleriniz, kişileriniz ve iletileriniz kaybolur.</string>
|
||||||
<string name="startup_failed_notification_title">Briar başlayamadı</string>
|
<string name="startup_failed_notification_title">Briar başlayamadı</string>
|
||||||
|
<string name="startup_failed_notification_text">Briar\'ı tekrar kurmanız gerekli.</string>
|
||||||
<string name="startup_failed_activity_title">Briar Başlangıç Hatası</string>
|
<string name="startup_failed_activity_title">Briar Başlangıç Hatası</string>
|
||||||
<string name="startup_failed_service_error">Briar gerekli bir eklentiyi başlatamadı. Briar\'ı yeniden yüklemek genellikle bu sorunu çözer. Bununla birlikte, lütfen Briar\'ın verilerinizi depolamak için merkezi sunucuları kullanmadığından hesabınızı ve onunla ilişkili tüm verileri kaybedeceğinizi unutmayın.</string>
|
<string name="startup_failed_service_error">Briar gerekli bir eklentiyi başlatamadı. Briar\'ı yeniden yüklemek genellikle bu sorunu çözer. Bununla birlikte, lütfen Briar\'ın verilerinizi depolamak için merkezi sunucuları kullanmadığından hesabınızı ve onunla ilişkili tüm verileri kaybedeceğinizi unutmayın.</string>
|
||||||
<!--Navigation Drawer-->
|
<!--Navigation Drawer-->
|
||||||
|
|||||||
@@ -31,11 +31,9 @@
|
|||||||
<string name="dialog_title_lost_password">忘记密码</string>
|
<string name="dialog_title_lost_password">忘记密码</string>
|
||||||
<string name="dialog_message_lost_password">您的 Briar 账号被加密储存在您的设备上,而非云端,因此我们无法重置您的密码。您是否希望删除帐号,重新开始?\n\n注意:您的身份、联系人和消息将会永久遗失。</string>
|
<string name="dialog_message_lost_password">您的 Briar 账号被加密储存在您的设备上,而非云端,因此我们无法重置您的密码。您是否希望删除帐号,重新开始?\n\n注意:您的身份、联系人和消息将会永久遗失。</string>
|
||||||
<string name="startup_failed_notification_title">Briar 无法启动</string>
|
<string name="startup_failed_notification_title">Briar 无法启动</string>
|
||||||
<string name="startup_failed_notification_text">点击查看更多信息。</string>
|
<string name="startup_failed_notification_text">你可能需要重新安装 Briar</string>
|
||||||
<string name="startup_failed_activity_title">Briar 启动失败</string>
|
<string name="startup_failed_activity_title">Briar 启动失败</string>
|
||||||
<string name="startup_failed_db_error">由于某种原因,您的 Briar 数据库损坏且无法修复。您的帐户、数据和所有联系人已经丢失。不幸的是,您需要在提示输入密码时选择“我忘记了我的密码”以重新安装 Briar 并建立新帐户。</string>
|
<string name="startup_failed_db_error">由于某种原因,您的 Briar 数据库损坏且无法修复。您的帐户、数据和所有联系人已经丢失。不幸的是,您需要重新安装 Briar 并建立新帐户。</string>
|
||||||
<string name="startup_failed_data_too_old_error">您的帐户由旧版本应用创建,无法在此版本上打开。您需要重新安装旧版本应用或在提示输入密码时选择“我忘记了我的密码”以删除旧帐户。</string>
|
|
||||||
<string name="startup_failed_data_too_new_error">该应用版本过旧。请升级至最新版本并重试。</string>
|
|
||||||
<string name="startup_failed_service_error">Briar 无法开启一个必要插件。通常情况下,重新安装 Briar 可以解决这个问题。但是由于 Briar 并不采用中央服务器来储存您的数据,您将丢失您的账号和与您的账号相关的一切数据。</string>
|
<string name="startup_failed_service_error">Briar 无法开启一个必要插件。通常情况下,重新安装 Briar 可以解决这个问题。但是由于 Briar 并不采用中央服务器来储存您的数据,您将丢失您的账号和与您的账号相关的一切数据。</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="other">这是 Briar 的一个测试版本。您的帐户将在 %d 天后过期,且无法继续使用。</item>
|
<item quantity="other">这是 Briar 的一个测试版本。您的帐户将在 %d 天后过期,且无法继续使用。</item>
|
||||||
@@ -92,7 +90,6 @@
|
|||||||
<string name="show_onboarding">显示帮助对话</string>
|
<string name="show_onboarding">显示帮助对话</string>
|
||||||
<string name="fix">修复</string>
|
<string name="fix">修复</string>
|
||||||
<string name="help">帮助</string>
|
<string name="help">帮助</string>
|
||||||
<string name="sorry">抱歉</string>
|
|
||||||
<!--Contacts and Private Conversations-->
|
<!--Contacts and Private Conversations-->
|
||||||
<string name="no_contacts">你似乎是新来的,目前还没有联系人。\n\n轻触上方的 + 按钮并根据提示添加联系人。\n\n请牢记:您只能通过面对面的方式添加新联系人,以防止未来他人冒充您的身份并查看您的信息。</string>
|
<string name="no_contacts">你似乎是新来的,目前还没有联系人。\n\n轻触上方的 + 按钮并根据提示添加联系人。\n\n请牢记:您只能通过面对面的方式添加新联系人,以防止未来他人冒充您的身份并查看您的信息。</string>
|
||||||
<string name="date_no_private_messages">没有消息。</string>
|
<string name="date_no_private_messages">没有消息。</string>
|
||||||
@@ -114,7 +111,6 @@
|
|||||||
<string name="contact_already_exists">联系人 %s 已存在</string>
|
<string name="contact_already_exists">联系人 %s 已存在</string>
|
||||||
<string name="contact_exchange_failed">联系人交换失败</string>
|
<string name="contact_exchange_failed">联系人交换失败</string>
|
||||||
<string name="qr_code_invalid">二维码无效</string>
|
<string name="qr_code_invalid">二维码无效</string>
|
||||||
<string name="qr_code_unsupported">您正在扫描的是来自 %s 版旧版本的二维码,目前不再支持。\n\n请确保你们两人都在运行最新版本并重试。</string>
|
|
||||||
<string name="camera_error">摄像头出错</string>
|
<string name="camera_error">摄像头出错</string>
|
||||||
<string name="connecting_to_device">正在连接至设备\u2026</string>
|
<string name="connecting_to_device">正在连接至设备\u2026</string>
|
||||||
<string name="authenticating_with_device">正在验证设备\u2026</string>
|
<string name="authenticating_with_device">正在验证设备\u2026</string>
|
||||||
@@ -363,8 +359,7 @@
|
|||||||
<string name="progress_title_logout">登出 Briar…</string>
|
<string name="progress_title_logout">登出 Briar…</string>
|
||||||
<!--Screen Filters & Tapjacking-->
|
<!--Screen Filters & Tapjacking-->
|
||||||
<string name="screen_filter_title">检测到屏幕覆盖</string>
|
<string name="screen_filter_title">检测到屏幕覆盖</string>
|
||||||
<string name="screen_filter_body">另一个应用覆盖在 Briar 上。为了保护您的安全,在有其他应用覆盖的情况下, Briar 将不会对触控做出反应。\n\n这些应用可能覆盖在上:\n\n%1$s</string>
|
<string name="screen_filter_body">另一个应用覆盖在 Briar 上。为了保护您的安全,在有其他应用覆盖的情况下, Briar 将不会对触控做出反应。\n\n使用 Briar 时请尝试关闭以下程序:\n\n%1$s</string>
|
||||||
<string name="screen_filter_allow">允许这些应用覆盖在上</string>
|
|
||||||
<!--Permission Requests-->
|
<!--Permission Requests-->
|
||||||
<string name="permission_camera_title">相机权限</string>
|
<string name="permission_camera_title">相机权限</string>
|
||||||
<string name="permission_camera_request_body">Briar 需要获得相机权限以扫描二维码。</string>
|
<string name="permission_camera_request_body">Briar 需要获得相机权限以扫描二维码。</string>
|
||||||
|
|||||||
@@ -34,11 +34,9 @@
|
|||||||
<string name="dialog_title_lost_password">Lost Password</string>
|
<string name="dialog_title_lost_password">Lost Password</string>
|
||||||
<string name="dialog_message_lost_password">Your Briar account is stored encrypted on your device, not in the cloud, so we can\'t reset your password. Would you like to delete your account and start again?\n\nCaution: Your identities, contacts and messages will be permanently lost.</string>
|
<string name="dialog_message_lost_password">Your Briar account is stored encrypted on your device, not in the cloud, so we can\'t reset your password. Would you like to delete your account and start again?\n\nCaution: Your identities, contacts and messages will be permanently lost.</string>
|
||||||
<string name="startup_failed_notification_title">Briar could not start</string>
|
<string name="startup_failed_notification_title">Briar could not start</string>
|
||||||
<string name="startup_failed_notification_text">Tap for more information.</string>
|
<string name="startup_failed_notification_text">You may need to reinstall Briar.</string>
|
||||||
<string name="startup_failed_activity_title">Briar Startup Failure</string>
|
<string name="startup_failed_activity_title">Briar Startup Failure</string>
|
||||||
<string name="startup_failed_db_error">For some reason, your Briar database is corrupted beyond repair. Your account, your data and all your contacts are lost. Unfortunately, you need to reinstall Briar and set up a new account by choosing \'I have forgotten my password\' at the password prompt.</string>
|
<string name="startup_failed_db_error">For some reason, your Briar database is corrupted beyond repair. Your account, your data and all your contacts are lost. Unfortunately, you need to reinstall Briar and set up a new account.</string>
|
||||||
<string name="startup_failed_data_too_old_error">Your account was created with an old version of this app and cannot be opened with this version. You must either reinstall the old version or delete your old account by choosing \'I have forgotten my password\' at the password prompt.</string>
|
|
||||||
<string name="startup_failed_data_too_new_error">This version of the app is too old. Please upgrade to the latest version and try again.</string>
|
|
||||||
<string name="startup_failed_service_error">Briar was unable to start a required plugin. Reinstalling Briar usually solves this problem. However, please note that you will then lose your account and all data associated with it since Briar is not using central servers to store your data on.</string>
|
<string name="startup_failed_service_error">Briar was unable to start a required plugin. Reinstalling Briar usually solves this problem. However, please note that you will then lose your account and all data associated with it since Briar is not using central servers to store your data on.</string>
|
||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="one">This is a test version of Briar. Your account will expire in %d day and cannot be renewed.</item>
|
<item quantity="one">This is a test version of Briar. Your account will expire in %d day and cannot be renewed.</item>
|
||||||
@@ -46,8 +44,6 @@
|
|||||||
</plurals>
|
</plurals>
|
||||||
<string name="expiry_update">The testing expiry date has been extended. Your account will now expire in %d days.</string>
|
<string name="expiry_update">The testing expiry date has been extended. Your account will now expire in %d days.</string>
|
||||||
<string name="expiry_date_reached">This software has expired.\nThank you for testing!</string>
|
<string name="expiry_date_reached">This software has expired.\nThank you for testing!</string>
|
||||||
<string name="startup_open_database">Decrypting Database…</string>
|
|
||||||
<string name="startup_migrate_database">Upgrading Database…</string>
|
|
||||||
|
|
||||||
<!-- Navigation Drawer -->
|
<!-- Navigation Drawer -->
|
||||||
<string name="nav_drawer_open_description">Open the navigation drawer</string>
|
<string name="nav_drawer_open_description">Open the navigation drawer</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user