mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 02:39:05 +01:00
Compare commits
50 Commits
poll-own-h
...
alpha-1.4.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
592daf9c20 | ||
|
|
3922270db1 | ||
|
|
4ba4e41e69 | ||
|
|
1f699238a9 | ||
|
|
b8e91a12e8 | ||
|
|
06eb01ab0a | ||
|
|
d82509f3ce | ||
|
|
b01c306500 | ||
|
|
61e7635b9f | ||
|
|
f2f356cbd4 | ||
|
|
28f3ab1310 | ||
|
|
8bb3a83ccb | ||
|
|
a742b007ef | ||
|
|
6bfd7bcc4f | ||
|
|
17f5fc7518 | ||
|
|
8dcf988399 | ||
|
|
05bf3833cf | ||
|
|
c39c2ce124 | ||
|
|
0b93af5d71 | ||
|
|
f8e3579a92 | ||
|
|
54e434d812 | ||
|
|
13c3974f73 | ||
|
|
aeb2a370e1 | ||
|
|
0aff23a067 | ||
|
|
a2a2da0260 | ||
|
|
4d7a3bca62 | ||
|
|
91d5698fe9 | ||
|
|
7266c6ee6b | ||
|
|
06b539b911 | ||
|
|
486ba4a3fc | ||
|
|
7f987667fe | ||
|
|
8d22a0ffaf | ||
|
|
43d28608f5 | ||
|
|
c84d3f7707 | ||
|
|
2843e15905 | ||
|
|
a2fb388aa6 | ||
|
|
b7b253cf24 | ||
|
|
f05e9dd746 | ||
|
|
e2a63ee361 | ||
|
|
ff9f706670 | ||
|
|
10ab60569b | ||
|
|
d77d1d67aa | ||
|
|
924425522a | ||
|
|
356e0ee07b | ||
|
|
61658655ff | ||
|
|
40086ffde2 | ||
|
|
1551142e98 | ||
|
|
1c6fb6491a | ||
|
|
cfd4e85e77 | ||
|
|
4d6abfabf7 |
@@ -15,8 +15,8 @@ android {
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 30
|
||||
versionCode 10408
|
||||
versionName "1.4.8"
|
||||
versionCode 10409
|
||||
versionName "1.4.9"
|
||||
consumerProguardFiles 'proguard-rules.txt'
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
@@ -7,6 +7,7 @@ import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
||||
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.bramble.api.sync.OutgoingSessionRecord;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface ConnectionManager {
|
||||
@@ -45,6 +46,14 @@ public interface ConnectionManager {
|
||||
void manageOutgoingConnection(ContactId c, TransportId t,
|
||||
TransportConnectionWriter w);
|
||||
|
||||
/**
|
||||
* Manages an outgoing connection to a contact via a mailbox. The IDs of
|
||||
* any messages sent or acked are added to the given
|
||||
* {@link OutgoingSessionRecord}.
|
||||
*/
|
||||
void manageOutgoingConnection(ContactId c, TransportId t,
|
||||
TransportConnectionWriter w, OutgoingSessionRecord sessionRecord);
|
||||
|
||||
/**
|
||||
* Manages an outgoing connection to a contact over a duplex transport.
|
||||
*/
|
||||
|
||||
@@ -126,16 +126,11 @@ public interface DatabaseComponent extends TransactionManager {
|
||||
TransportKeys k) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if there are any acks or messages to send to the given
|
||||
* contact over a transport with the given maximum latency.
|
||||
* Returns true if there are any acks to send to the given contact.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*
|
||||
* @param eager True if messages that are not yet due for retransmission
|
||||
* should be included
|
||||
*/
|
||||
boolean containsAnythingToSend(Transaction txn, ContactId c,
|
||||
long maxLatency, boolean eager) throws DbException;
|
||||
boolean containsAcksToSend(Transaction txn, ContactId c) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given contact for the given
|
||||
@@ -161,6 +156,18 @@ public interface DatabaseComponent extends TransactionManager {
|
||||
*/
|
||||
boolean containsIdentity(Transaction txn, AuthorId a) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if there are any messages to send to the given contact
|
||||
* over a transport with the given maximum latency.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*
|
||||
* @param eager True if messages that are not yet due for retransmission
|
||||
* should be included
|
||||
*/
|
||||
boolean containsMessagesToSend(Transaction txn, ContactId c,
|
||||
long maxLatency, boolean eager) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given pending contact.
|
||||
* <p/>
|
||||
@@ -534,15 +541,18 @@ public interface DatabaseComponent extends TransactionManager {
|
||||
*/
|
||||
long getNextCleanupDeadline(Transaction txn) throws DbException;
|
||||
|
||||
/*
|
||||
/**
|
||||
* Returns the next time (in milliseconds since the Unix epoch) when a
|
||||
* message is due to be sent to the given contact. The returned value may
|
||||
* be zero if a message is due to be sent immediately, or Long.MAX_VALUE if
|
||||
* no messages are scheduled to be sent.
|
||||
* message is due to be sent to the given contact over a transport with
|
||||
* the given latency.
|
||||
* <p>
|
||||
* The returned value may be zero if a message is due to be sent
|
||||
* immediately, or Long.MAX_VALUE if no messages are scheduled to be sent.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
long getNextSendTime(Transaction txn, ContactId c) throws DbException;
|
||||
long getNextSendTime(Transaction txn, ContactId c, long maxLatency)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the pending contact with the given ID.
|
||||
|
||||
@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.plugin.TransportId;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.concurrent.TimeUnit.DAYS;
|
||||
import static java.util.concurrent.TimeUnit.HOURS;
|
||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
||||
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
|
||||
@@ -65,4 +66,8 @@ public interface MailboxConstants {
|
||||
*/
|
||||
long PROBLEM_MS_SINCE_LAST_SUCCESS = HOURS.toMillis(1);
|
||||
|
||||
/**
|
||||
* The maximum latency of the mailbox transport in milliseconds.
|
||||
*/
|
||||
long MAX_LATENCY = DAYS.toMillis(14);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,9 @@ public interface MailboxSettingsManager {
|
||||
void recordSuccessfulConnection(Transaction txn, long now)
|
||||
throws DbException;
|
||||
|
||||
void recordSuccessfulConnection(Transaction txn, long now,
|
||||
List<MailboxVersion> versions) throws DbException;
|
||||
|
||||
void recordFailedConnectionAttempt(Transaction txn, long now)
|
||||
throws DbException;
|
||||
|
||||
|
||||
@@ -63,9 +63,26 @@ public interface MailboxUpdateManager {
|
||||
*/
|
||||
String GROUP_KEY_SENT_CLIENT_SUPPORTS = "sentClientSupports";
|
||||
|
||||
/**
|
||||
* Returns the latest {@link MailboxUpdate} sent to the given contact.
|
||||
* <p>
|
||||
* If we have our own mailbox then the update will be a
|
||||
* {@link MailboxUpdateWithMailbox} containing the
|
||||
* {@link MailboxProperties} the contact should use for communicating with
|
||||
* our mailbox.
|
||||
*/
|
||||
MailboxUpdate getLocalUpdate(Transaction txn, ContactId c)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the latest {@link MailboxUpdate} received from the given
|
||||
* contact, or null if no update has been received.
|
||||
* <p>
|
||||
* If the contact has a mailbox then the update will be a
|
||||
* {@link MailboxUpdateWithMailbox} containing the
|
||||
* {@link MailboxProperties} we should use for communicating with the
|
||||
* contact's mailbox.
|
||||
*/
|
||||
@Nullable
|
||||
MailboxUpdate getRemoteUpdate(Transaction txn, ContactId c)
|
||||
throws DbException;
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package org.briarproject.bramble.api.sync;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* An interface for holding the IDs of messages sent and acked during an
|
||||
* outgoing {@link SyncSession} so they can be recorded in the DB as sent
|
||||
* or acked at some later time.
|
||||
*/
|
||||
public interface DeferredSendHandler {
|
||||
|
||||
void onAckSent(Collection<MessageId> acked);
|
||||
|
||||
void onMessageSent(MessageId sent);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.briarproject.bramble.api.sync;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
/**
|
||||
* A container for holding the IDs of messages sent and acked during an
|
||||
* outgoing {@link SyncSession}, so they can be recorded in the DB as sent
|
||||
* or acked at some later time.
|
||||
*/
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
public class OutgoingSessionRecord {
|
||||
|
||||
private final Collection<MessageId> ackedIds = new CopyOnWriteArrayList<>();
|
||||
private final Collection<MessageId> sentIds = new CopyOnWriteArrayList<>();
|
||||
|
||||
public void onAckSent(Collection<MessageId> acked) {
|
||||
ackedIds.addAll(acked);
|
||||
}
|
||||
|
||||
public void onMessageSent(MessageId sent) {
|
||||
sentIds.add(sent);
|
||||
}
|
||||
|
||||
public Collection<MessageId> getAckedIds() {
|
||||
return ackedIds;
|
||||
}
|
||||
|
||||
public Collection<MessageId> getSentIds() {
|
||||
return sentIds;
|
||||
}
|
||||
}
|
||||
@@ -12,12 +12,30 @@ import javax.annotation.Nullable;
|
||||
@NotNullByDefault
|
||||
public interface SyncSessionFactory {
|
||||
|
||||
/**
|
||||
* Creates a session for receiving data from a contact.
|
||||
*/
|
||||
SyncSession createIncomingSession(ContactId c, InputStream in,
|
||||
PriorityHandler handler);
|
||||
|
||||
/**
|
||||
* Creates a session for sending data to a contact over a simplex transport.
|
||||
*
|
||||
* @param eager True if messages should be sent eagerly, ie regardless of
|
||||
* whether they're due for retransmission.
|
||||
*/
|
||||
SyncSession createSimplexOutgoingSession(ContactId c, TransportId t,
|
||||
long maxLatency, boolean eager, StreamWriter streamWriter);
|
||||
|
||||
/**
|
||||
* Creates a session for sending data to a contact via a mailbox. The IDs
|
||||
* of any messages sent or acked will be added to the given
|
||||
* {@link OutgoingSessionRecord}.
|
||||
*/
|
||||
SyncSession createSimplexOutgoingSession(ContactId c, TransportId t,
|
||||
long maxLatency, StreamWriter streamWriter,
|
||||
OutgoingSessionRecord sessionRecord);
|
||||
|
||||
SyncSession createDuplexOutgoingSession(ContactId c, TransportId t,
|
||||
long maxLatency, int maxIdleTime, StreamWriter streamWriter,
|
||||
@Nullable Priority priority);
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.briarproject.bramble.api.sync.event;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.Group.Visibility;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -15,12 +16,19 @@ import javax.annotation.concurrent.Immutable;
|
||||
@NotNullByDefault
|
||||
public class GroupVisibilityUpdatedEvent extends Event {
|
||||
|
||||
private final Visibility visibility;
|
||||
private final Collection<ContactId> affected;
|
||||
|
||||
public GroupVisibilityUpdatedEvent(Collection<ContactId> affected) {
|
||||
public GroupVisibilityUpdatedEvent(Visibility visibility,
|
||||
Collection<ContactId> affected) {
|
||||
this.visibility = visibility;
|
||||
this.affected = affected;
|
||||
}
|
||||
|
||||
public Visibility getVisibility() {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contacts affected by the update.
|
||||
*/
|
||||
|
||||
@@ -40,7 +40,7 @@ public class IoUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static void delete(File f) {
|
||||
public static void delete(File f) {
|
||||
if (!f.delete() && LOG.isLoggable(WARNING))
|
||||
LOG.warning("Could not delete " + f.getAbsolutePath());
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
||||
import org.briarproject.bramble.api.sync.OutgoingSessionRecord;
|
||||
import org.briarproject.bramble.api.sync.SyncSessionFactory;
|
||||
import org.briarproject.bramble.api.transport.KeyManager;
|
||||
import org.briarproject.bramble.api.transport.StreamReaderFactory;
|
||||
@@ -100,7 +101,16 @@ class ConnectionManagerImpl implements ConnectionManager {
|
||||
TransportConnectionWriter w) {
|
||||
ioExecutor.execute(new OutgoingSimplexSyncConnection(keyManager,
|
||||
connectionRegistry, streamReaderFactory, streamWriterFactory,
|
||||
syncSessionFactory, transportPropertyManager, c, t, w));
|
||||
syncSessionFactory, transportPropertyManager, c, t, w, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void manageOutgoingConnection(ContactId c, TransportId t,
|
||||
TransportConnectionWriter w, OutgoingSessionRecord sessionRecord) {
|
||||
ioExecutor.execute(new OutgoingSimplexSyncConnection(keyManager,
|
||||
connectionRegistry, streamReaderFactory, streamWriterFactory,
|
||||
syncSessionFactory, transportPropertyManager, c, t, w,
|
||||
sessionRecord));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
||||
import org.briarproject.bramble.api.sync.OutgoingSessionRecord;
|
||||
import org.briarproject.bramble.api.sync.SyncSession;
|
||||
import org.briarproject.bramble.api.sync.SyncSessionFactory;
|
||||
import org.briarproject.bramble.api.transport.KeyManager;
|
||||
@@ -16,6 +17,8 @@ import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
@@ -26,6 +29,8 @@ class OutgoingSimplexSyncConnection extends SyncConnection implements Runnable {
|
||||
private final ContactId contactId;
|
||||
private final TransportId transportId;
|
||||
private final TransportConnectionWriter writer;
|
||||
@Nullable
|
||||
private final OutgoingSessionRecord sessionRecord;
|
||||
|
||||
OutgoingSimplexSyncConnection(KeyManager keyManager,
|
||||
ConnectionRegistry connectionRegistry,
|
||||
@@ -34,13 +39,15 @@ class OutgoingSimplexSyncConnection extends SyncConnection implements Runnable {
|
||||
SyncSessionFactory syncSessionFactory,
|
||||
TransportPropertyManager transportPropertyManager,
|
||||
ContactId contactId, TransportId transportId,
|
||||
TransportConnectionWriter writer) {
|
||||
TransportConnectionWriter writer,
|
||||
@Nullable OutgoingSessionRecord sessionRecord) {
|
||||
super(keyManager, connectionRegistry, streamReaderFactory,
|
||||
streamWriterFactory, syncSessionFactory,
|
||||
transportPropertyManager);
|
||||
this.contactId = contactId;
|
||||
this.transportId = transportId;
|
||||
this.writer = writer;
|
||||
this.sessionRecord = sessionRecord;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -71,10 +78,16 @@ class OutgoingSimplexSyncConnection extends SyncConnection implements Runnable {
|
||||
StreamWriter streamWriter = streamWriterFactory.createStreamWriter(
|
||||
w.getOutputStream(), ctx);
|
||||
ContactId c = requireNonNull(ctx.getContactId());
|
||||
// Use eager retransmission if the transport is lossy and cheap
|
||||
return syncSessionFactory.createSimplexOutgoingSession(c,
|
||||
ctx.getTransportId(), w.getMaxLatency(), w.isLossyAndCheap(),
|
||||
streamWriter);
|
||||
if (sessionRecord == null) {
|
||||
// Use eager retransmission if the transport is lossy and cheap
|
||||
return syncSessionFactory.createSimplexOutgoingSession(c,
|
||||
ctx.getTransportId(), w.getMaxLatency(),
|
||||
w.isLossyAndCheap(), streamWriter);
|
||||
} else {
|
||||
return syncSessionFactory.createSimplexOutgoingSession(c,
|
||||
ctx.getTransportId(), w.getMaxLatency(), streamWriter,
|
||||
sessionRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -163,16 +163,11 @@ interface Database<T> {
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if there are any acks or messages to send to the given
|
||||
* contact over a transport with the given maximum latency.
|
||||
* Returns true if there are any acks to send to the given contact.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*
|
||||
* @param eager True if messages that are not yet due for retransmission
|
||||
* should be included
|
||||
*/
|
||||
boolean containsAnythingToSend(T txn, ContactId c, long maxLatency,
|
||||
boolean eager) throws DbException;
|
||||
boolean containsAcksToSend(T txn, ContactId c) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given contact for the given
|
||||
@@ -212,6 +207,18 @@ interface Database<T> {
|
||||
*/
|
||||
boolean containsMessage(T txn, MessageId m) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if there are any messages to send to the given
|
||||
* contact over a transport with the given maximum latency.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*
|
||||
* @param eager True if messages that are not yet due for retransmission
|
||||
* should be included
|
||||
*/
|
||||
boolean containsMessagesToSend(T txn, ContactId c, long maxLatency,
|
||||
boolean eager) throws DbException;
|
||||
|
||||
/**
|
||||
* Returns true if the database contains the given pending contact.
|
||||
* <p/>
|
||||
@@ -580,13 +587,16 @@ interface Database<T> {
|
||||
|
||||
/**
|
||||
* Returns the next time (in milliseconds since the Unix epoch) when a
|
||||
* message is due to be sent to the given contact. The returned value may
|
||||
* be zero if a message is due to be sent immediately, or Long.MAX_VALUE
|
||||
* if no messages are scheduled to be sent.
|
||||
* message is due to be sent to the given contact over a transport with
|
||||
* the given latency.
|
||||
* <p>
|
||||
* The returned value may be zero if a message is due to be sent
|
||||
* immediately, or Long.MAX_VALUE if no messages are scheduled to be sent.
|
||||
* <p/>
|
||||
* Read-only.
|
||||
*/
|
||||
long getNextSendTime(T txn, ContactId c) throws DbException;
|
||||
long getNextSendTime(T txn, ContactId c, long maxLatency)
|
||||
throws DbException;
|
||||
|
||||
/**
|
||||
* Returns the pending contact with the given ID.
|
||||
|
||||
@@ -342,12 +342,12 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAnythingToSend(Transaction transaction, ContactId c,
|
||||
long maxLatency, boolean eager) throws DbException {
|
||||
public boolean containsAcksToSend(Transaction transaction, ContactId c)
|
||||
throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsContact(txn, c))
|
||||
throw new NoSuchContactException();
|
||||
return db.containsAnythingToSend(txn, c, maxLatency, eager);
|
||||
return db.containsAcksToSend(txn, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -373,6 +373,15 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
return db.containsIdentity(txn, a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsMessagesToSend(Transaction transaction, ContactId c,
|
||||
long maxLatency, boolean eager) throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
if (!db.containsContact(txn, c))
|
||||
throw new NoSuchContactException();
|
||||
return db.containsMessagesToSend(txn, c, maxLatency, eager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsPendingContact(Transaction transaction,
|
||||
PendingContactId p) throws DbException {
|
||||
@@ -805,10 +814,10 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNextSendTime(Transaction transaction, ContactId c)
|
||||
throws DbException {
|
||||
public long getNextSendTime(Transaction transaction, ContactId c,
|
||||
long maxLatency) throws DbException {
|
||||
T txn = unbox(transaction);
|
||||
return db.getNextSendTime(txn, c);
|
||||
return db.getNextSendTime(txn, c, maxLatency);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1016,7 +1025,8 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
db.getGroupVisibility(txn, id).keySet();
|
||||
db.removeGroup(txn, id);
|
||||
transaction.attach(new GroupRemovedEvent(g));
|
||||
transaction.attach(new GroupVisibilityUpdatedEvent(affected));
|
||||
transaction.attach(new GroupVisibilityUpdatedEvent(INVISIBLE,
|
||||
affected));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1141,7 +1151,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
||||
else if (v == INVISIBLE) db.removeGroupVisibility(txn, c, g);
|
||||
else db.setGroupVisibility(txn, c, g, v == SHARED);
|
||||
List<ContactId> affected = singletonList(c);
|
||||
transaction.attach(new GroupVisibilityUpdatedEvent(affected));
|
||||
transaction.attach(new GroupVisibilityUpdatedEvent(v, affected));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1147,8 +1147,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAnythingToSend(Connection txn, ContactId c,
|
||||
long maxLatency, boolean eager) throws DbException {
|
||||
public boolean containsAcksToSend(Connection txn, ContactId c)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
@@ -1160,34 +1160,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
boolean acksToSend = rs.next();
|
||||
rs.close();
|
||||
ps.close();
|
||||
if (acksToSend) return true;
|
||||
if (eager) {
|
||||
sql = "SELECT NULL from statuses"
|
||||
+ " WHERE contactId = ? AND state = ?"
|
||||
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
||||
+ " AND deleted = FALSE AND seen = FALSE";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
ps.setInt(2, DELIVERED.getValue());
|
||||
} else {
|
||||
long now = clock.currentTimeMillis();
|
||||
sql = "SELECT NULL FROM statuses"
|
||||
+ " WHERE contactId = ? AND state = ?"
|
||||
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
||||
+ " AND deleted = FALSE AND seen = FALSE"
|
||||
+ " AND (expiry <= ? OR maxLatency IS NULL"
|
||||
+ " OR ? < maxLatency)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
ps.setInt(2, DELIVERED.getValue());
|
||||
ps.setLong(3, now);
|
||||
ps.setLong(4, maxLatency);
|
||||
}
|
||||
rs = ps.executeQuery();
|
||||
boolean messagesToSend = rs.next();
|
||||
rs.close();
|
||||
ps.close();
|
||||
return messagesToSend;
|
||||
return acksToSend;
|
||||
} catch (SQLException e) {
|
||||
tryToClose(rs, LOG, WARNING);
|
||||
tryToClose(ps, LOG, WARNING);
|
||||
@@ -1307,6 +1280,46 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsMessagesToSend(Connection txn, ContactId c,
|
||||
long maxLatency, boolean eager) throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
if (eager) {
|
||||
String sql = "SELECT NULL from statuses"
|
||||
+ " WHERE contactId = ? AND state = ?"
|
||||
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
||||
+ " AND deleted = FALSE AND seen = FALSE";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
ps.setInt(2, DELIVERED.getValue());
|
||||
} else {
|
||||
long now = clock.currentTimeMillis();
|
||||
String sql = "SELECT NULL FROM statuses"
|
||||
+ " WHERE contactId = ? AND state = ?"
|
||||
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
||||
+ " AND deleted = FALSE AND seen = FALSE"
|
||||
+ " AND (expiry <= ? OR maxLatency IS NULL"
|
||||
+ " OR ? < maxLatency)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
ps.setInt(2, DELIVERED.getValue());
|
||||
ps.setLong(3, now);
|
||||
ps.setLong(4, maxLatency);
|
||||
}
|
||||
rs = ps.executeQuery();
|
||||
boolean messagesToSend = rs.next();
|
||||
rs.close();
|
||||
ps.close();
|
||||
return messagesToSend;
|
||||
} catch (SQLException e) {
|
||||
tryToClose(rs, LOG, WARNING);
|
||||
tryToClose(ps, LOG, WARNING);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsPendingContact(Connection txn, PendingContactId p)
|
||||
throws DbException {
|
||||
@@ -2477,12 +2490,28 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNextSendTime(Connection txn, ContactId c)
|
||||
public long getNextSendTime(Connection txn, ContactId c, long maxLatency)
|
||||
throws DbException {
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
String sql = "SELECT expiry FROM statuses"
|
||||
// Are any messages sendable immediately?
|
||||
String sql = "SELECT NULL FROM statuses"
|
||||
+ " WHERE contactId = ? AND state = ?"
|
||||
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
||||
+ " AND deleted = FALSE AND seen = FALSE"
|
||||
+ " AND (maxLatency IS NULL OR ? < maxLatency)";
|
||||
ps = txn.prepareStatement(sql);
|
||||
ps.setInt(1, c.getInt());
|
||||
ps.setInt(2, DELIVERED.getValue());
|
||||
ps.setLong(3, maxLatency);
|
||||
rs = ps.executeQuery();
|
||||
boolean found = rs.next();
|
||||
rs.close();
|
||||
ps.close();
|
||||
if (found) return 0;
|
||||
// When is the earliest expiry time (could be in the past)?
|
||||
sql = "SELECT expiry FROM statuses"
|
||||
+ " WHERE contactId = ? AND state = ?"
|
||||
+ " AND groupShared = TRUE AND messageShared = TRUE"
|
||||
+ " AND deleted = FALSE AND seen = FALSE"
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.GuardedBy;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Logger.getLogger;
|
||||
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
class ContactMailboxClient implements MailboxClient {
|
||||
|
||||
private static final Logger LOG =
|
||||
getLogger(ContactMailboxClient.class.getName());
|
||||
|
||||
private final MailboxWorkerFactory workerFactory;
|
||||
private final ConnectivityChecker connectivityChecker;
|
||||
private final TorReachabilityMonitor reachabilityMonitor;
|
||||
private final Object lock = new Object();
|
||||
|
||||
@GuardedBy("lock")
|
||||
@Nullable
|
||||
private MailboxWorker uploadWorker = null, downloadWorker = null;
|
||||
|
||||
@Inject
|
||||
ContactMailboxClient(MailboxWorkerFactory workerFactory,
|
||||
ConnectivityChecker connectivityChecker,
|
||||
TorReachabilityMonitor reachabilityMonitor) {
|
||||
this.workerFactory = workerFactory;
|
||||
this.connectivityChecker = connectivityChecker;
|
||||
this.reachabilityMonitor = reachabilityMonitor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
LOG.info("Started");
|
||||
// Nothing to do until contact is assigned
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
LOG.info("Destroyed");
|
||||
MailboxWorker uploadWorker, downloadWorker;
|
||||
synchronized (lock) {
|
||||
uploadWorker = this.uploadWorker;
|
||||
this.uploadWorker = null;
|
||||
downloadWorker = this.downloadWorker;
|
||||
this.downloadWorker = null;
|
||||
}
|
||||
if (uploadWorker != null) uploadWorker.destroy();
|
||||
if (downloadWorker != null) downloadWorker.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assignContactForUpload(ContactId contactId,
|
||||
MailboxProperties properties, MailboxFolderId folderId) {
|
||||
LOG.info("Contact assigned for upload");
|
||||
if (properties.isOwner()) throw new IllegalArgumentException();
|
||||
// For a contact's mailbox we should always be uploading to the outbox
|
||||
// assigned to us by the contact
|
||||
if (!folderId.equals(properties.getOutboxId())) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
MailboxWorker uploadWorker = workerFactory.createUploadWorker(
|
||||
connectivityChecker, properties, folderId, contactId);
|
||||
synchronized (lock) {
|
||||
if (this.uploadWorker != null) throw new IllegalStateException();
|
||||
this.uploadWorker = uploadWorker;
|
||||
}
|
||||
uploadWorker.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deassignContactForUpload(ContactId contactId) {
|
||||
LOG.info("Contact deassigned for upload");
|
||||
MailboxWorker uploadWorker;
|
||||
synchronized (lock) {
|
||||
uploadWorker = this.uploadWorker;
|
||||
this.uploadWorker = null;
|
||||
}
|
||||
if (uploadWorker != null) uploadWorker.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assignContactForDownload(ContactId contactId,
|
||||
MailboxProperties properties, MailboxFolderId folderId) {
|
||||
LOG.info("Contact assigned for download");
|
||||
if (properties.isOwner()) throw new IllegalArgumentException();
|
||||
// For a contact's mailbox we should always be downloading from the
|
||||
// inbox assigned to us by the contact
|
||||
if (!folderId.equals(properties.getInboxId())) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
MailboxWorker downloadWorker =
|
||||
workerFactory.createDownloadWorkerForContactMailbox(
|
||||
connectivityChecker, reachabilityMonitor, properties);
|
||||
synchronized (lock) {
|
||||
if (this.downloadWorker != null) throw new IllegalStateException();
|
||||
this.downloadWorker = downloadWorker;
|
||||
}
|
||||
downloadWorker.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deassignContactForDownload(ContactId contactId) {
|
||||
LOG.info("Contact deassigned for download");
|
||||
MailboxWorker downloadWorker;
|
||||
synchronized (lock) {
|
||||
downloadWorker = this.downloadWorker;
|
||||
this.downloadWorker = null;
|
||||
}
|
||||
if (downloadWorker != null) downloadWorker.destroy();
|
||||
}
|
||||
}
|
||||
@@ -90,7 +90,7 @@ class ContactMailboxDownloadWorker implements MailboxWorker,
|
||||
LOG.info("Started");
|
||||
synchronized (lock) {
|
||||
// Don't allow the worker to be reused
|
||||
if (state != State.CREATED) throw new IllegalStateException();
|
||||
if (state != State.CREATED) return;
|
||||
state = State.CONNECTIVITY_CHECK;
|
||||
}
|
||||
// Avoid leaking observer in case destroy() is called concurrently
|
||||
@@ -146,10 +146,12 @@ class ContactMailboxDownloadWorker implements MailboxWorker,
|
||||
if (state == State.DOWNLOAD_CYCLE_1) {
|
||||
LOG.info("First download cycle finished");
|
||||
state = State.WAITING_FOR_TOR;
|
||||
apiCall = null;
|
||||
addObserver = true;
|
||||
} else if (state == State.DOWNLOAD_CYCLE_2) {
|
||||
LOG.info("Second download cycle finished");
|
||||
state = State.FINISHED;
|
||||
apiCall = null;
|
||||
}
|
||||
}
|
||||
if (addObserver) {
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
interface MailboxClient {
|
||||
|
||||
/**
|
||||
* Asynchronously starts the client.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Destroys the client and its workers, cancelling any pending tasks or
|
||||
* retries.
|
||||
*/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Assigns a contact to the client for upload.
|
||||
*/
|
||||
void assignContactForUpload(ContactId c, MailboxProperties properties,
|
||||
MailboxFolderId folderId);
|
||||
|
||||
/**
|
||||
* Deassigns a contact from the client for upload.
|
||||
*/
|
||||
void deassignContactForUpload(ContactId c);
|
||||
|
||||
/**
|
||||
* Assigns a contact to the client for download.
|
||||
*/
|
||||
void assignContactForDownload(ContactId c, MailboxProperties properties,
|
||||
MailboxFolderId folderId);
|
||||
|
||||
/**
|
||||
* Deassigns a contact from the client for download.
|
||||
*/
|
||||
void deassignContactForDownload(ContactId c);
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.OutgoingSessionRecord;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -16,6 +18,14 @@ interface MailboxFileManager {
|
||||
*/
|
||||
File createTempFileForDownload() throws IOException;
|
||||
|
||||
/**
|
||||
* Creates a file to be uploaded to the given contact and writes any
|
||||
* waiting data to the file. The IDs of any messages sent or acked will
|
||||
* be added to the given {@link OutgoingSessionRecord}.
|
||||
*/
|
||||
File createAndWriteTempFileForUpload(ContactId contactId,
|
||||
OutgoingSessionRecord sessionRecord) throws IOException;
|
||||
|
||||
/**
|
||||
* Handles a file that has been downloaded. The file should be created
|
||||
* with {@link #createTempFileForDownload()}.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.connection.ConnectionManager;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.event.EventListener;
|
||||
@@ -10,13 +11,18 @@ import org.briarproject.bramble.api.mailbox.MailboxDirectory;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.PluginManager;
|
||||
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
||||
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
||||
import org.briarproject.bramble.api.plugin.event.TransportActiveEvent;
|
||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||
import org.briarproject.bramble.api.sync.OutgoingSessionRecord;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
@@ -30,6 +36,7 @@ import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleS
|
||||
import static org.briarproject.bramble.api.mailbox.MailboxConstants.ID;
|
||||
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
|
||||
import static org.briarproject.bramble.api.plugin.file.FileConstants.PROP_PATH;
|
||||
import static org.briarproject.bramble.util.IoUtils.delete;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
|
||||
@ThreadSafe
|
||||
@@ -41,6 +48,7 @@ class MailboxFileManagerImpl implements MailboxFileManager, EventListener {
|
||||
|
||||
// Package access for testing
|
||||
static final String DOWNLOAD_DIR_NAME = "downloads";
|
||||
static final String UPLOAD_DIR_NAME = "uploads";
|
||||
|
||||
private final Executor ioExecutor;
|
||||
private final PluginManager pluginManager;
|
||||
@@ -67,14 +75,44 @@ class MailboxFileManagerImpl implements MailboxFileManager, EventListener {
|
||||
|
||||
@Override
|
||||
public File createTempFileForDownload() throws IOException {
|
||||
return createTempFile(DOWNLOAD_DIR_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File createAndWriteTempFileForUpload(ContactId contactId,
|
||||
OutgoingSessionRecord sessionRecord) throws IOException {
|
||||
File f = createTempFile(UPLOAD_DIR_NAME);
|
||||
// We shouldn't reach this point until the plugin has been started
|
||||
SimplexPlugin plugin =
|
||||
(SimplexPlugin) requireNonNull(pluginManager.getPlugin(ID));
|
||||
TransportProperties p = new TransportProperties();
|
||||
p.put(PROP_PATH, f.getAbsolutePath());
|
||||
TransportConnectionWriter writer = plugin.createWriter(p);
|
||||
if (writer == null) {
|
||||
delete(f);
|
||||
throw new IOException();
|
||||
}
|
||||
MailboxFileWriter decorated = new MailboxFileWriter(writer);
|
||||
LOG.info("Writing file for upload");
|
||||
connectionManager.manageOutgoingConnection(contactId, ID, decorated,
|
||||
sessionRecord);
|
||||
if (decorated.awaitDisposal()) {
|
||||
// An exception was thrown during the session - delete the file
|
||||
delete(f);
|
||||
throw new IOException();
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
private File createTempFile(String dirName) throws IOException {
|
||||
// Wait for orphaned files to be handled before creating new files
|
||||
try {
|
||||
orphanLatch.await();
|
||||
} catch (InterruptedException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
File downloadDir = createDirectoryIfNeeded(DOWNLOAD_DIR_NAME);
|
||||
return File.createTempFile("mailbox", ".tmp", downloadDir);
|
||||
File dir = createDirectoryIfNeeded(dirName);
|
||||
return File.createTempFile("mailbox", ".tmp", dir);
|
||||
}
|
||||
|
||||
private File createDirectoryIfNeeded(String name) throws IOException {
|
||||
@@ -116,6 +154,8 @@ class MailboxFileManagerImpl implements MailboxFileManager, EventListener {
|
||||
|
||||
@Override
|
||||
public void eventOccurred(Event e) {
|
||||
// Wait for the transport to become active before handling orphaned
|
||||
// files so that we can get the plugin from the plugin manager
|
||||
if (e instanceof TransportActiveEvent) {
|
||||
TransportActiveEvent t = (TransportActiveEvent) e;
|
||||
if (t.getTransportId().equals(ID)) {
|
||||
@@ -127,17 +167,25 @@ class MailboxFileManagerImpl implements MailboxFileManager, EventListener {
|
||||
|
||||
/**
|
||||
* This method is called at startup, as soon as the plugin is started, to
|
||||
* handle any files that were left in the download directory at the last
|
||||
* shutdown.
|
||||
* delete any files that were left in the upload directory at the last
|
||||
* shutdown and handle any files that were left in the download directory.
|
||||
*/
|
||||
@IoExecutor
|
||||
private void handleOrphanedFiles() {
|
||||
try {
|
||||
File uploadDir = createDirectoryIfNeeded(UPLOAD_DIR_NAME);
|
||||
File[] orphanedUploads = uploadDir.listFiles();
|
||||
if (orphanedUploads != null) {
|
||||
for (File f : orphanedUploads) delete(f);
|
||||
}
|
||||
File downloadDir = createDirectoryIfNeeded(DOWNLOAD_DIR_NAME);
|
||||
File[] orphans = downloadDir.listFiles();
|
||||
// Now that we've got the list of orphans, new files can be created
|
||||
File[] orphanedDownloads = downloadDir.listFiles();
|
||||
// Now that we've got the list of orphaned downloads, new files
|
||||
// can be created in the download directory
|
||||
orphanLatch.countDown();
|
||||
if (orphans != null) for (File f : orphans) handleDownloadedFile(f);
|
||||
if (orphanedDownloads != null) {
|
||||
for (File f : orphanedDownloads) handleDownloadedFile(f);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
@@ -165,9 +213,58 @@ class MailboxFileManagerImpl implements MailboxFileManager, EventListener {
|
||||
delegate.dispose(exception, recognised);
|
||||
if (isHandlingComplete(exception, recognised)) {
|
||||
LOG.info("Deleting downloaded file");
|
||||
if (!file.delete()) {
|
||||
LOG.warning("Failed to delete downloaded file");
|
||||
}
|
||||
delete(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MailboxFileWriter
|
||||
implements TransportConnectionWriter {
|
||||
|
||||
private final TransportConnectionWriter delegate;
|
||||
private final BlockingQueue<Boolean> disposalResult =
|
||||
new ArrayBlockingQueue<>(1);
|
||||
|
||||
private MailboxFileWriter(TransportConnectionWriter delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxLatency() {
|
||||
return delegate.getMaxLatency();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxIdleTime() {
|
||||
return delegate.getMaxIdleTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLossyAndCheap() {
|
||||
return delegate.isLossyAndCheap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
return delegate.getOutputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(boolean exception) throws IOException {
|
||||
delegate.dispose(exception);
|
||||
disposalResult.add(exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the delegate to be disposed and returns true if an
|
||||
* exception occurred.
|
||||
*/
|
||||
private boolean awaitDisposal() {
|
||||
try {
|
||||
return disposalResult.take();
|
||||
} catch (InterruptedException e) {
|
||||
LOG.info("Interrupted while waiting for disposal");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,12 @@ import org.briarproject.bramble.api.mailbox.MailboxPairingTask;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxStatus;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -98,34 +100,35 @@ class MailboxManagerImpl implements MailboxManager {
|
||||
|
||||
@Override
|
||||
public boolean checkConnection() {
|
||||
boolean success;
|
||||
List<MailboxVersion> versions = null;
|
||||
try {
|
||||
MailboxProperties props = db.transactionWithNullableResult(true,
|
||||
mailboxSettingsManager::getOwnMailboxProperties);
|
||||
if (props == null) throw new DbException();
|
||||
success = api.checkStatus(props);
|
||||
versions = api.getServerSupports(props);
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
// we don't treat this is a failure to record
|
||||
return false;
|
||||
} catch (IOException | MailboxApi.ApiException e) {
|
||||
// we record this as a failure
|
||||
success = false;
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
try {
|
||||
recordCheckResult(success);
|
||||
recordCheckResult(versions);
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
return success;
|
||||
return versions != null;
|
||||
}
|
||||
|
||||
private void recordCheckResult(boolean success) throws DbException {
|
||||
private void recordCheckResult(@Nullable List<MailboxVersion> versions)
|
||||
throws DbException {
|
||||
long now = clock.currentTimeMillis();
|
||||
db.transaction(false, txn -> {
|
||||
if (success) {
|
||||
mailboxSettingsManager.recordSuccessfulConnection(txn, now);
|
||||
if (versions != null) {
|
||||
mailboxSettingsManager
|
||||
.recordSuccessfulConnection(txn, now, versions);
|
||||
} else {
|
||||
mailboxSettingsManager.recordFailedConnectionAttempt(txn, now);
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ public class MailboxModule {
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
MailboxSettingsManager provideMailboxSettingsManager(
|
||||
MailboxSettingsManagerImpl mailboxSettingsManager) {
|
||||
return mailboxSettingsManager;
|
||||
@@ -114,4 +115,10 @@ public class MailboxModule {
|
||||
}
|
||||
return mailboxFileManager;
|
||||
}
|
||||
|
||||
@Provides
|
||||
MailboxWorkerFactory provideMailboxWorkerFactory(
|
||||
MailboxWorkerFactoryImpl mailboxWorkerFactory) {
|
||||
return mailboxWorkerFactory;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,13 +20,13 @@ import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
||||
|
||||
@Immutable
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
class MailboxSettingsManagerImpl implements MailboxSettingsManager {
|
||||
|
||||
@@ -77,13 +77,7 @@ class MailboxSettingsManagerImpl implements MailboxSettingsManager {
|
||||
s.put(SETTINGS_KEY_ONION, p.getBaseUrl());
|
||||
s.put(SETTINGS_KEY_TOKEN, p.getAuthToken().toString());
|
||||
List<MailboxVersion> serverSupports = p.getServerSupports();
|
||||
int[] ints = new int[serverSupports.size() * 2];
|
||||
int i = 0;
|
||||
for (MailboxVersion v : serverSupports) {
|
||||
ints[i++] = v.getMajor();
|
||||
ints[i++] = v.getMinor();
|
||||
}
|
||||
s.putIntArray(SETTINGS_KEY_SERVER_SUPPORTS, ints);
|
||||
encodeServerSupports(serverSupports, s);
|
||||
settingsManager.mergeSettings(txn, s, SETTINGS_NAMESPACE);
|
||||
for (MailboxHook hook : hooks) {
|
||||
hook.mailboxPaired(txn, p.getOnion(), p.getServerSupports());
|
||||
@@ -121,14 +115,30 @@ class MailboxSettingsManagerImpl implements MailboxSettingsManager {
|
||||
@Override
|
||||
public void recordSuccessfulConnection(Transaction txn, long now)
|
||||
throws DbException {
|
||||
Settings oldSettings =
|
||||
settingsManager.getSettings(txn, SETTINGS_NAMESPACE);
|
||||
recordSuccessfulConnection(txn, now, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordSuccessfulConnection(Transaction txn, long now,
|
||||
@Nullable List<MailboxVersion> versions) throws DbException {
|
||||
Settings s = new Settings();
|
||||
// fetch version that the server supports first
|
||||
List<MailboxVersion> serverSupports;
|
||||
if (versions == null) {
|
||||
Settings oldSettings =
|
||||
settingsManager.getSettings(txn, SETTINGS_NAMESPACE);
|
||||
serverSupports = parseServerSupports(oldSettings);
|
||||
} else {
|
||||
serverSupports = versions;
|
||||
// store new versions
|
||||
encodeServerSupports(serverSupports, s);
|
||||
}
|
||||
// now record the successful connection
|
||||
s.putLong(SETTINGS_KEY_LAST_ATTEMPT, now);
|
||||
s.putLong(SETTINGS_KEY_LAST_SUCCESS, now);
|
||||
s.putInt(SETTINGS_KEY_ATTEMPTS, 0);
|
||||
settingsManager.mergeSettings(txn, s, SETTINGS_NAMESPACE);
|
||||
List<MailboxVersion> serverSupports = parseServerSupports(oldSettings);
|
||||
// broadcast status event
|
||||
MailboxStatus status = new MailboxStatus(now, now, 0, serverSupports);
|
||||
txn.attach(new OwnMailboxConnectionStatusEvent(status));
|
||||
}
|
||||
@@ -171,6 +181,17 @@ class MailboxSettingsManagerImpl implements MailboxSettingsManager {
|
||||
return filename;
|
||||
}
|
||||
|
||||
private void encodeServerSupports(List<MailboxVersion> serverSupports,
|
||||
Settings s) {
|
||||
int[] ints = new int[serverSupports.size() * 2];
|
||||
int i = 0;
|
||||
for (MailboxVersion v : serverSupports) {
|
||||
ints[i++] = v.getMajor();
|
||||
ints[i++] = v.getMinor();
|
||||
}
|
||||
s.putIntArray(SETTINGS_KEY_SERVER_SUPPORTS, ints);
|
||||
}
|
||||
|
||||
private List<MailboxVersion> parseServerSupports(Settings s)
|
||||
throws DbException {
|
||||
if (!s.containsKey(SETTINGS_KEY_SERVER_SUPPORTS)) return emptyList();
|
||||
|
||||
@@ -0,0 +1,394 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.Cancellable;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.event.EventExecutor;
|
||||
import org.briarproject.bramble.api.event.EventListener;
|
||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.sync.OutgoingSessionRecord;
|
||||
import org.briarproject.bramble.api.sync.event.GroupVisibilityUpdatedEvent;
|
||||
import org.briarproject.bramble.api.sync.event.MessageSharedEvent;
|
||||
import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.api.system.TaskScheduler;
|
||||
import org.briarproject.bramble.mailbox.ConnectivityChecker.ConnectivityObserver;
|
||||
import org.briarproject.bramble.mailbox.MailboxApi.ApiException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.GuardedBy;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static java.util.logging.Logger.getLogger;
|
||||
import static org.briarproject.bramble.api.mailbox.MailboxConstants.MAX_LATENCY;
|
||||
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
||||
import static org.briarproject.bramble.util.IoUtils.delete;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
class MailboxUploadWorker implements MailboxWorker, ConnectivityObserver,
|
||||
EventListener {
|
||||
|
||||
/**
|
||||
* When the worker is started it checks for data to send. If data is ready
|
||||
* to send, the worker waits for a connectivity check, then writes and
|
||||
* uploads a file and checks again for data to send.
|
||||
* <p>
|
||||
* If data is due to be sent at some time in the future, the worker
|
||||
* schedules a wakeup for that time and also listens for events indicating
|
||||
* that new data may be ready to send.
|
||||
* <p>
|
||||
* If there's no data to send, the worker listens for events indicating
|
||||
* that new data may be ready to send.
|
||||
*/
|
||||
private enum State {
|
||||
CREATED,
|
||||
CHECKING_FOR_DATA,
|
||||
WAITING_FOR_DATA,
|
||||
CONNECTIVITY_CHECK,
|
||||
WRITING_UPLOADING,
|
||||
DESTROYED
|
||||
}
|
||||
|
||||
private static final Logger LOG =
|
||||
getLogger(MailboxUploadWorker.class.getName());
|
||||
|
||||
/**
|
||||
* When we're waiting for data to send and an event indicates that new data
|
||||
* may have become available, wait this long before checking the DB. This
|
||||
* should help to avoid creating lots of small files when several acks or
|
||||
* messages become available to send in a short period (eg when reading a
|
||||
* file downloaded from a mailbox).
|
||||
* <p>
|
||||
* Package access for testing.
|
||||
*/
|
||||
static final long CHECK_DELAY_MS = 5_000;
|
||||
|
||||
/**
|
||||
* How long to wait before retrying when an exception occurs while writing
|
||||
* a file.
|
||||
* <p>
|
||||
* Package access for testing.
|
||||
*/
|
||||
static final long RETRY_DELAY_MS = MINUTES.toMillis(1);
|
||||
|
||||
private final Executor ioExecutor;
|
||||
private final DatabaseComponent db;
|
||||
private final Clock clock;
|
||||
private final TaskScheduler taskScheduler;
|
||||
private final EventBus eventBus;
|
||||
private final ConnectivityChecker connectivityChecker;
|
||||
private final MailboxApiCaller mailboxApiCaller;
|
||||
private final MailboxApi mailboxApi;
|
||||
private final MailboxFileManager mailboxFileManager;
|
||||
private final MailboxProperties mailboxProperties;
|
||||
private final MailboxFolderId folderId;
|
||||
private final ContactId contactId;
|
||||
|
||||
private final Object lock = new Object();
|
||||
|
||||
@GuardedBy("lock")
|
||||
private State state = State.CREATED;
|
||||
|
||||
@GuardedBy("lock")
|
||||
@Nullable
|
||||
private Cancellable wakeupTask = null, checkTask = null, apiCall = null;
|
||||
|
||||
@GuardedBy("lock")
|
||||
@Nullable
|
||||
private File file = null;
|
||||
|
||||
MailboxUploadWorker(@IoExecutor Executor ioExecutor,
|
||||
DatabaseComponent db,
|
||||
Clock clock,
|
||||
TaskScheduler taskScheduler,
|
||||
EventBus eventBus,
|
||||
ConnectivityChecker connectivityChecker,
|
||||
MailboxApiCaller mailboxApiCaller,
|
||||
MailboxApi mailboxApi,
|
||||
MailboxFileManager mailboxFileManager,
|
||||
MailboxProperties mailboxProperties,
|
||||
MailboxFolderId folderId,
|
||||
ContactId contactId) {
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.db = db;
|
||||
this.clock = clock;
|
||||
this.taskScheduler = taskScheduler;
|
||||
this.eventBus = eventBus;
|
||||
this.connectivityChecker = connectivityChecker;
|
||||
this.mailboxApiCaller = mailboxApiCaller;
|
||||
this.mailboxApi = mailboxApi;
|
||||
this.mailboxFileManager = mailboxFileManager;
|
||||
this.mailboxProperties = mailboxProperties;
|
||||
this.folderId = folderId;
|
||||
this.contactId = contactId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
LOG.info("Started");
|
||||
synchronized (lock) {
|
||||
// Don't allow the worker to be reused
|
||||
if (state != State.CREATED) return;
|
||||
state = State.CHECKING_FOR_DATA;
|
||||
}
|
||||
ioExecutor.execute(this::checkForDataToSend);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
LOG.info("Destroyed");
|
||||
Cancellable wakeupTask, checkTask, apiCall;
|
||||
File file;
|
||||
synchronized (lock) {
|
||||
state = State.DESTROYED;
|
||||
wakeupTask = this.wakeupTask;
|
||||
this.wakeupTask = null;
|
||||
checkTask = this.checkTask;
|
||||
this.checkTask = null;
|
||||
apiCall = this.apiCall;
|
||||
this.apiCall = null;
|
||||
file = this.file;
|
||||
this.file = null;
|
||||
}
|
||||
if (wakeupTask != null) wakeupTask.cancel();
|
||||
if (checkTask != null) checkTask.cancel();
|
||||
if (apiCall != null) apiCall.cancel();
|
||||
if (file != null) delete(file);
|
||||
connectivityChecker.removeObserver(this);
|
||||
eventBus.removeListener(this);
|
||||
}
|
||||
|
||||
@IoExecutor
|
||||
private void checkForDataToSend() {
|
||||
synchronized (lock) {
|
||||
checkTask = null;
|
||||
if (state != State.CHECKING_FOR_DATA) return;
|
||||
}
|
||||
LOG.info("Checking for data to send");
|
||||
try {
|
||||
db.transaction(true, txn -> {
|
||||
long nextSendTime;
|
||||
if (db.containsAcksToSend(txn, contactId)) {
|
||||
nextSendTime = 0L;
|
||||
} else {
|
||||
nextSendTime = db.getNextSendTime(txn, contactId,
|
||||
MAX_LATENCY);
|
||||
}
|
||||
// Handle the result on the event executor to avoid races with
|
||||
// incoming events
|
||||
txn.attach(() -> handleNextSendTime(nextSendTime));
|
||||
});
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
}
|
||||
|
||||
@EventExecutor
|
||||
private void handleNextSendTime(long nextSendTime) {
|
||||
if (nextSendTime == Long.MAX_VALUE) {
|
||||
// Nothing is sendable now or due to be sent in the future. Wait
|
||||
// for an event indicating that new data may be ready to send
|
||||
waitForDataToSend();
|
||||
} else {
|
||||
// Work out the delay until data's ready to send (may be negative)
|
||||
long delay = nextSendTime - clock.currentTimeMillis();
|
||||
if (delay > 0) {
|
||||
// Schedule a wakeup when data will be ready to send. If an
|
||||
// event is received in the meantime indicating that new data
|
||||
// may be ready to send, we'll cancel the wakeup
|
||||
scheduleWakeup(delay);
|
||||
} else {
|
||||
// Data is ready to send now
|
||||
checkConnectivity();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventExecutor
|
||||
private void waitForDataToSend() {
|
||||
synchronized (lock) {
|
||||
if (state != State.CHECKING_FOR_DATA) return;
|
||||
state = State.WAITING_FOR_DATA;
|
||||
LOG.info("Waiting for data to send");
|
||||
}
|
||||
}
|
||||
|
||||
@EventExecutor
|
||||
private void scheduleWakeup(long delay) {
|
||||
synchronized (lock) {
|
||||
if (state != State.CHECKING_FOR_DATA) return;
|
||||
state = State.WAITING_FOR_DATA;
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
LOG.info("Scheduling wakeup in " + delay + " ms");
|
||||
}
|
||||
wakeupTask = taskScheduler.schedule(this::wakeUp, ioExecutor,
|
||||
delay, MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
@IoExecutor
|
||||
private void wakeUp() {
|
||||
LOG.info("Woke up");
|
||||
synchronized (lock) {
|
||||
wakeupTask = null;
|
||||
if (state != State.WAITING_FOR_DATA) return;
|
||||
state = State.CHECKING_FOR_DATA;
|
||||
}
|
||||
checkForDataToSend();
|
||||
}
|
||||
|
||||
@EventExecutor
|
||||
private void checkConnectivity() {
|
||||
synchronized (lock) {
|
||||
if (state != State.CHECKING_FOR_DATA) return;
|
||||
state = State.CONNECTIVITY_CHECK;
|
||||
}
|
||||
LOG.info("Checking connectivity");
|
||||
// Avoid leaking observer in case destroy() is called concurrently
|
||||
// before observer is added
|
||||
connectivityChecker.checkConnectivity(mailboxProperties, this);
|
||||
boolean destroyed;
|
||||
synchronized (lock) {
|
||||
destroyed = state == State.DESTROYED;
|
||||
}
|
||||
if (destroyed) connectivityChecker.removeObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectivityCheckSucceeded() {
|
||||
LOG.info("Connectivity check succeeded");
|
||||
synchronized (lock) {
|
||||
if (state != State.CONNECTIVITY_CHECK) return;
|
||||
state = State.WRITING_UPLOADING;
|
||||
}
|
||||
ioExecutor.execute(this::writeAndUploadFile);
|
||||
}
|
||||
|
||||
@IoExecutor
|
||||
private void writeAndUploadFile() {
|
||||
synchronized (lock) {
|
||||
if (state != State.WRITING_UPLOADING) return;
|
||||
}
|
||||
OutgoingSessionRecord sessionRecord = new OutgoingSessionRecord();
|
||||
File file;
|
||||
try {
|
||||
file = mailboxFileManager.createAndWriteTempFileForUpload(
|
||||
contactId, sessionRecord);
|
||||
} catch (IOException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
// Try again after a delay
|
||||
synchronized (lock) {
|
||||
if (state != State.WRITING_UPLOADING) return;
|
||||
state = State.CHECKING_FOR_DATA;
|
||||
checkTask = taskScheduler.schedule(this::checkForDataToSend,
|
||||
ioExecutor, RETRY_DELAY_MS, MILLISECONDS);
|
||||
}
|
||||
return;
|
||||
}
|
||||
boolean deleteFile = false;
|
||||
synchronized (lock) {
|
||||
if (state == State.WRITING_UPLOADING) {
|
||||
this.file = file;
|
||||
apiCall = mailboxApiCaller.retryWithBackoff(
|
||||
new SimpleApiCall(() -> apiCallUploadFile(file,
|
||||
sessionRecord)));
|
||||
} else {
|
||||
deleteFile = true;
|
||||
}
|
||||
}
|
||||
if (deleteFile) delete(file);
|
||||
}
|
||||
|
||||
@IoExecutor
|
||||
private void apiCallUploadFile(File file,
|
||||
OutgoingSessionRecord sessionRecord)
|
||||
throws IOException, ApiException {
|
||||
synchronized (lock) {
|
||||
if (state != State.WRITING_UPLOADING) return;
|
||||
}
|
||||
LOG.info("Uploading file");
|
||||
mailboxApi.addFile(mailboxProperties, folderId, file);
|
||||
markMessagesSentOrAcked(sessionRecord);
|
||||
synchronized (lock) {
|
||||
if (state != State.WRITING_UPLOADING) return;
|
||||
state = State.CHECKING_FOR_DATA;
|
||||
apiCall = null;
|
||||
this.file = null;
|
||||
}
|
||||
delete(file);
|
||||
checkForDataToSend();
|
||||
}
|
||||
|
||||
private void markMessagesSentOrAcked(OutgoingSessionRecord sessionRecord) {
|
||||
Collection<MessageId> acked = sessionRecord.getAckedIds();
|
||||
Collection<MessageId> sent = sessionRecord.getSentIds();
|
||||
try {
|
||||
db.transaction(false, txn -> {
|
||||
if (!acked.isEmpty()) {
|
||||
db.setAckSent(txn, contactId, acked);
|
||||
}
|
||||
if (!sent.isEmpty()) {
|
||||
db.setMessagesSent(txn, contactId, sent, MAX_LATENCY);
|
||||
}
|
||||
});
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof MessageToAckEvent) {
|
||||
MessageToAckEvent m = (MessageToAckEvent) e;
|
||||
if (m.getContactId().equals(contactId)) {
|
||||
LOG.info("Message to ack");
|
||||
onDataToSend();
|
||||
}
|
||||
} else if (e instanceof MessageSharedEvent) {
|
||||
LOG.info("Message shared");
|
||||
onDataToSend();
|
||||
} else if (e instanceof GroupVisibilityUpdatedEvent) {
|
||||
GroupVisibilityUpdatedEvent g = (GroupVisibilityUpdatedEvent) e;
|
||||
if (g.getVisibility() == SHARED &&
|
||||
g.getAffectedContacts().contains(contactId)) {
|
||||
LOG.info("Group shared");
|
||||
onDataToSend();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventExecutor
|
||||
private void onDataToSend() {
|
||||
Cancellable wakeupTask;
|
||||
synchronized (lock) {
|
||||
if (state != State.WAITING_FOR_DATA) return;
|
||||
state = State.CHECKING_FOR_DATA;
|
||||
wakeupTask = this.wakeupTask;
|
||||
this.wakeupTask = null;
|
||||
// Delay the check to avoid creating lots of small files
|
||||
checkTask = taskScheduler.schedule(this::checkForDataToSend,
|
||||
ioExecutor, CHECK_DELAY_MS, MILLISECONDS);
|
||||
}
|
||||
// If we had scheduled a wakeup when data was due to be sent, cancel it
|
||||
if (wakeupTask != null) wakeupTask.cancel();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
interface MailboxWorkerFactory {
|
||||
|
||||
MailboxWorker createUploadWorker(ConnectivityChecker connectivityChecker,
|
||||
MailboxProperties properties, MailboxFolderId folderId,
|
||||
ContactId contactId);
|
||||
|
||||
MailboxWorker createDownloadWorkerForContactMailbox(
|
||||
ConnectivityChecker connectivityChecker,
|
||||
TorReachabilityMonitor reachabilityMonitor,
|
||||
MailboxProperties properties);
|
||||
|
||||
MailboxWorker createDownloadWorkerForOwnMailbox(
|
||||
ConnectivityChecker connectivityChecker,
|
||||
TorReachabilityMonitor reachabilityMonitor,
|
||||
MailboxProperties properties);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.api.system.TaskScheduler;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
class MailboxWorkerFactoryImpl implements MailboxWorkerFactory {
|
||||
|
||||
private final Executor ioExecutor;
|
||||
private final DatabaseComponent db;
|
||||
private final Clock clock;
|
||||
private final TaskScheduler taskScheduler;
|
||||
private final EventBus eventBus;
|
||||
private final MailboxApiCaller mailboxApiCaller;
|
||||
private final MailboxApi mailboxApi;
|
||||
private final MailboxFileManager mailboxFileManager;
|
||||
|
||||
@Inject
|
||||
MailboxWorkerFactoryImpl(@IoExecutor Executor ioExecutor,
|
||||
DatabaseComponent db,
|
||||
Clock clock,
|
||||
TaskScheduler taskScheduler,
|
||||
EventBus eventBus,
|
||||
MailboxApiCaller mailboxApiCaller,
|
||||
MailboxApi mailboxApi,
|
||||
MailboxFileManager mailboxFileManager) {
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.db = db;
|
||||
this.clock = clock;
|
||||
this.taskScheduler = taskScheduler;
|
||||
this.eventBus = eventBus;
|
||||
this.mailboxApiCaller = mailboxApiCaller;
|
||||
this.mailboxApi = mailboxApi;
|
||||
this.mailboxFileManager = mailboxFileManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailboxWorker createUploadWorker(
|
||||
ConnectivityChecker connectivityChecker,
|
||||
MailboxProperties properties, MailboxFolderId folderId,
|
||||
ContactId contactId) {
|
||||
MailboxUploadWorker worker = new MailboxUploadWorker(ioExecutor, db,
|
||||
clock, taskScheduler, eventBus, connectivityChecker,
|
||||
mailboxApiCaller, mailboxApi, mailboxFileManager,
|
||||
properties, folderId, contactId);
|
||||
eventBus.addListener(worker);
|
||||
return worker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailboxWorker createDownloadWorkerForContactMailbox(
|
||||
ConnectivityChecker connectivityChecker,
|
||||
TorReachabilityMonitor reachabilityMonitor,
|
||||
MailboxProperties properties) {
|
||||
return new ContactMailboxDownloadWorker(connectivityChecker,
|
||||
reachabilityMonitor, mailboxApiCaller, mailboxApi,
|
||||
mailboxFileManager, properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailboxWorker createDownloadWorkerForOwnMailbox(
|
||||
ConnectivityChecker connectivityChecker,
|
||||
TorReachabilityMonitor reachabilityMonitor,
|
||||
MailboxProperties properties) {
|
||||
// TODO
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,13 @@ import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.TransactionManager;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.mailbox.MailboxApi.ApiException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
@@ -55,11 +57,12 @@ class OwnMailboxConnectivityChecker extends ConnectivityCheckerImpl {
|
||||
private boolean checkConnectivityAndStoreResult(
|
||||
MailboxProperties properties) throws DbException {
|
||||
try {
|
||||
if (!mailboxApi.checkStatus(properties)) throw new ApiException();
|
||||
List<MailboxVersion> serverSupports =
|
||||
mailboxApi.getServerSupports(properties);
|
||||
LOG.info("Own mailbox is reachable");
|
||||
long now = clock.currentTimeMillis();
|
||||
db.transaction(false, txn -> mailboxSettingsManager
|
||||
.recordSuccessfulConnection(txn, now));
|
||||
.recordSuccessfulConnection(txn, now, serverSupports));
|
||||
// Call the observers and cache the result
|
||||
onConnectivityCheckSucceeded(now);
|
||||
return false; // Don't retry
|
||||
|
||||
@@ -0,0 +1,369 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.Cancellable;
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.contact.event.ContactAddedEvent;
|
||||
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.NoSuchContactException;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.event.EventExecutor;
|
||||
import org.briarproject.bramble.api.event.EventListener;
|
||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdateWithMailbox;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.mailbox.ConnectivityChecker.ConnectivityObserver;
|
||||
import org.briarproject.bramble.mailbox.MailboxApi.ApiException;
|
||||
import org.briarproject.bramble.mailbox.MailboxApi.MailboxContact;
|
||||
import org.briarproject.bramble.mailbox.MailboxApi.TolerableFailureException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.GuardedBy;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static java.util.logging.Logger.getLogger;
|
||||
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
class OwnMailboxContactListWorker
|
||||
implements MailboxWorker, ConnectivityObserver, EventListener {
|
||||
|
||||
/**
|
||||
* When the worker is started it waits for a connectivity check, then
|
||||
* fetches the remote contact list and compares it to the local contact
|
||||
* list.
|
||||
* <p>
|
||||
* Any contacts that are missing from the remote list are added to the
|
||||
* mailbox's contact list, while any contacts that are missing from the
|
||||
* local list are removed from the mailbox's contact list.
|
||||
* <p>
|
||||
* Once the remote contact list has been brought up to date, the worker
|
||||
* waits for events indicating that contacts have been added or removed.
|
||||
* Each time an event is received, the worker updates the mailbox's
|
||||
* contact list and then goes back to waiting.
|
||||
*/
|
||||
private enum State {
|
||||
CREATED,
|
||||
CONNECTIVITY_CHECK,
|
||||
FETCHING_CONTACT_LIST,
|
||||
UPDATING_CONTACT_LIST,
|
||||
WAITING_FOR_CHANGES,
|
||||
DESTROYED
|
||||
}
|
||||
|
||||
private static final Logger LOG =
|
||||
getLogger(OwnMailboxContactListWorker.class.getName());
|
||||
|
||||
private final Executor ioExecutor;
|
||||
private final DatabaseComponent db;
|
||||
private final EventBus eventBus;
|
||||
private final ConnectivityChecker connectivityChecker;
|
||||
private final MailboxApiCaller mailboxApiCaller;
|
||||
private final MailboxApi mailboxApi;
|
||||
private final MailboxUpdateManager mailboxUpdateManager;
|
||||
private final MailboxProperties mailboxProperties;
|
||||
private final Object lock = new Object();
|
||||
|
||||
@GuardedBy("lock")
|
||||
private State state = State.CREATED;
|
||||
|
||||
@GuardedBy("lock")
|
||||
@Nullable
|
||||
private Cancellable apiCall = null;
|
||||
|
||||
/**
|
||||
* A queue of updates waiting to be applied to the remote contact list.
|
||||
*/
|
||||
@GuardedBy("lock")
|
||||
private final Queue<Update> updates = new LinkedList<>();
|
||||
|
||||
OwnMailboxContactListWorker(@IoExecutor Executor ioExecutor,
|
||||
DatabaseComponent db,
|
||||
EventBus eventBus,
|
||||
ConnectivityChecker connectivityChecker,
|
||||
MailboxApiCaller mailboxApiCaller,
|
||||
MailboxApi mailboxApi,
|
||||
MailboxUpdateManager mailboxUpdateManager,
|
||||
MailboxProperties mailboxProperties) {
|
||||
if (!mailboxProperties.isOwner()) throw new IllegalArgumentException();
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.db = db;
|
||||
this.connectivityChecker = connectivityChecker;
|
||||
this.mailboxApiCaller = mailboxApiCaller;
|
||||
this.mailboxApi = mailboxApi;
|
||||
this.mailboxUpdateManager = mailboxUpdateManager;
|
||||
this.mailboxProperties = mailboxProperties;
|
||||
this.eventBus = eventBus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
LOG.info("Started");
|
||||
synchronized (lock) {
|
||||
if (state != State.CREATED) return;
|
||||
state = State.CONNECTIVITY_CHECK;
|
||||
}
|
||||
// Avoid leaking observer in case destroy() is called concurrently
|
||||
// before observer is added
|
||||
connectivityChecker.checkConnectivity(mailboxProperties, this);
|
||||
boolean destroyed;
|
||||
synchronized (lock) {
|
||||
destroyed = state == State.DESTROYED;
|
||||
}
|
||||
if (destroyed) connectivityChecker.removeObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
LOG.info("Destroyed");
|
||||
Cancellable apiCall;
|
||||
synchronized (lock) {
|
||||
state = State.DESTROYED;
|
||||
apiCall = this.apiCall;
|
||||
this.apiCall = null;
|
||||
}
|
||||
if (apiCall != null) apiCall.cancel();
|
||||
connectivityChecker.removeObserver(this);
|
||||
eventBus.removeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectivityCheckSucceeded() {
|
||||
LOG.info("Connectivity check succeeded");
|
||||
synchronized (lock) {
|
||||
if (state != State.CONNECTIVITY_CHECK) return;
|
||||
state = State.FETCHING_CONTACT_LIST;
|
||||
apiCall = mailboxApiCaller.retryWithBackoff(
|
||||
new SimpleApiCall(this::apiCallFetchContactList));
|
||||
}
|
||||
}
|
||||
|
||||
@IoExecutor
|
||||
private void apiCallFetchContactList() throws IOException, ApiException {
|
||||
synchronized (lock) {
|
||||
if (state != State.FETCHING_CONTACT_LIST) return;
|
||||
}
|
||||
LOG.info("Fetching remote contact list");
|
||||
Collection<ContactId> remote =
|
||||
mailboxApi.getContacts(mailboxProperties);
|
||||
ioExecutor.execute(() -> loadLocalContactList(remote));
|
||||
}
|
||||
|
||||
@IoExecutor
|
||||
private void loadLocalContactList(Collection<ContactId> remote) {
|
||||
synchronized (lock) {
|
||||
if (state != State.FETCHING_CONTACT_LIST) return;
|
||||
apiCall = null;
|
||||
}
|
||||
LOG.info("Loading local contact list");
|
||||
try {
|
||||
db.transaction(true, txn -> {
|
||||
Collection<Contact> local = db.getContacts(txn);
|
||||
// Handle the result on the event executor to avoid races with
|
||||
// incoming events
|
||||
txn.attach(() -> reconcileContactLists(local, remote));
|
||||
});
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
}
|
||||
|
||||
@EventExecutor
|
||||
private void reconcileContactLists(Collection<Contact> local,
|
||||
Collection<ContactId> remote) {
|
||||
Set<ContactId> localIds = new HashSet<>();
|
||||
for (Contact c : local) localIds.add(c.getId());
|
||||
remote = new HashSet<>(remote);
|
||||
synchronized (lock) {
|
||||
if (state != State.FETCHING_CONTACT_LIST) return;
|
||||
for (ContactId c : localIds) {
|
||||
if (!remote.contains(c)) updates.add(new Update(true, c));
|
||||
}
|
||||
for (ContactId c : remote) {
|
||||
if (!localIds.contains(c)) updates.add(new Update(false, c));
|
||||
}
|
||||
if (updates.isEmpty()) {
|
||||
LOG.info("Contact list is up to date");
|
||||
state = State.WAITING_FOR_CHANGES;
|
||||
} else {
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
LOG.info(updates.size() + " updates to apply");
|
||||
}
|
||||
state = State.UPDATING_CONTACT_LIST;
|
||||
ioExecutor.execute(this::updateContactList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@IoExecutor
|
||||
private void updateContactList() {
|
||||
Update update;
|
||||
synchronized (lock) {
|
||||
if (state != State.UPDATING_CONTACT_LIST) return;
|
||||
update = updates.poll();
|
||||
if (update == null) {
|
||||
LOG.info("No more updates to process");
|
||||
state = State.WAITING_FOR_CHANGES;
|
||||
apiCall = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (update.add) loadMailboxProperties(update.contactId);
|
||||
else removeContact(update.contactId);
|
||||
}
|
||||
|
||||
@IoExecutor
|
||||
private void loadMailboxProperties(ContactId c) {
|
||||
synchronized (lock) {
|
||||
if (state != State.UPDATING_CONTACT_LIST) return;
|
||||
}
|
||||
LOG.info("Loading mailbox properties for contact");
|
||||
try {
|
||||
MailboxUpdate mailboxUpdate = db.transactionWithResult(true, txn ->
|
||||
mailboxUpdateManager.getLocalUpdate(txn, c));
|
||||
if (mailboxUpdate instanceof MailboxUpdateWithMailbox) {
|
||||
addContact(c, (MailboxUpdateWithMailbox) mailboxUpdate);
|
||||
} else {
|
||||
// Our own mailbox was concurrently unpaired. This worker will
|
||||
// be destroyed soon, so we can stop here
|
||||
LOG.info("Own mailbox was unpaired");
|
||||
}
|
||||
} catch (NoSuchContactException e) {
|
||||
// Contact was removed concurrently. Move on to the next update.
|
||||
// Later we may process a removal update for this contact, which
|
||||
// was never added to the mailbox's contact list. The removal API
|
||||
// call should fail safely with a TolerableFailureException
|
||||
LOG.info("No such contact");
|
||||
updateContactList();
|
||||
} catch (DbException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
}
|
||||
|
||||
@IoExecutor
|
||||
private void addContact(ContactId c, MailboxUpdateWithMailbox withMailbox) {
|
||||
MailboxProperties props = withMailbox.getMailboxProperties();
|
||||
MailboxContact contact = new MailboxContact(c, props.getAuthToken(),
|
||||
requireNonNull(props.getInboxId()),
|
||||
requireNonNull(props.getOutboxId()));
|
||||
synchronized (lock) {
|
||||
if (state != State.UPDATING_CONTACT_LIST) return;
|
||||
apiCall = mailboxApiCaller.retryWithBackoff(new SimpleApiCall(() ->
|
||||
apiCallAddContact(contact)));
|
||||
}
|
||||
}
|
||||
|
||||
@IoExecutor
|
||||
private void apiCallAddContact(MailboxContact contact)
|
||||
throws IOException, ApiException, TolerableFailureException {
|
||||
synchronized (lock) {
|
||||
if (state != State.UPDATING_CONTACT_LIST) return;
|
||||
}
|
||||
LOG.info("Adding contact to remote contact list");
|
||||
mailboxApi.addContact(mailboxProperties, contact);
|
||||
updateContactList();
|
||||
}
|
||||
|
||||
@IoExecutor
|
||||
private void removeContact(ContactId c) {
|
||||
synchronized (lock) {
|
||||
if (state != State.UPDATING_CONTACT_LIST) return;
|
||||
apiCall = mailboxApiCaller.retryWithBackoff(new SimpleApiCall(() ->
|
||||
apiCallRemoveContact(c)));
|
||||
}
|
||||
}
|
||||
|
||||
@IoExecutor
|
||||
private void apiCallRemoveContact(ContactId c)
|
||||
throws IOException, ApiException {
|
||||
synchronized (lock) {
|
||||
if (state != State.UPDATING_CONTACT_LIST) return;
|
||||
}
|
||||
LOG.info("Removing contact from remote contact list");
|
||||
try {
|
||||
mailboxApi.deleteContact(mailboxProperties, c);
|
||||
} catch (TolerableFailureException e) {
|
||||
// Catch this so we can continue to the next update
|
||||
logException(LOG, INFO, e);
|
||||
}
|
||||
updateContactList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof ContactAddedEvent) {
|
||||
LOG.info("Contact added");
|
||||
onContactAdded(((ContactAddedEvent) e).getContactId());
|
||||
} else if (e instanceof ContactRemovedEvent) {
|
||||
LOG.info("Contact removed");
|
||||
onContactRemoved(((ContactRemovedEvent) e).getContactId());
|
||||
}
|
||||
}
|
||||
|
||||
@EventExecutor
|
||||
private void onContactAdded(ContactId c) {
|
||||
synchronized (lock) {
|
||||
if (state != State.UPDATING_CONTACT_LIST &&
|
||||
state != State.WAITING_FOR_CHANGES) {
|
||||
return;
|
||||
}
|
||||
updates.add(new Update(true, c));
|
||||
if (state == State.WAITING_FOR_CHANGES) {
|
||||
state = State.UPDATING_CONTACT_LIST;
|
||||
ioExecutor.execute(this::updateContactList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventExecutor
|
||||
private void onContactRemoved(ContactId c) {
|
||||
synchronized (lock) {
|
||||
if (state != State.UPDATING_CONTACT_LIST &&
|
||||
state != State.WAITING_FOR_CHANGES) {
|
||||
return;
|
||||
}
|
||||
updates.add(new Update(false, c));
|
||||
if (state == State.WAITING_FOR_CHANGES) {
|
||||
state = State.UPDATING_CONTACT_LIST;
|
||||
ioExecutor.execute(this::updateContactList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An update that should be applied to the remote contact list.
|
||||
*/
|
||||
private static class Update {
|
||||
|
||||
/**
|
||||
* True if the contact should be added, false if the contact should be
|
||||
* removed.
|
||||
*/
|
||||
private final boolean add;
|
||||
private final ContactId contactId;
|
||||
|
||||
private Update(boolean add, ContactId contactId) {
|
||||
this.add = add;
|
||||
this.contactId = contactId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,14 +9,12 @@ import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.DAYS;
|
||||
import static org.briarproject.bramble.api.mailbox.MailboxConstants.ID;
|
||||
import static org.briarproject.bramble.api.mailbox.MailboxConstants.MAX_LATENCY;
|
||||
|
||||
@NotNullByDefault
|
||||
public class MailboxPluginFactory implements SimplexPluginFactory {
|
||||
|
||||
private static final long MAX_LATENCY = DAYS.toMillis(14);
|
||||
|
||||
@Inject
|
||||
MailboxPluginFactory() {
|
||||
}
|
||||
|
||||
@@ -106,7 +106,8 @@ class RemovableDriveManagerImpl
|
||||
@Override
|
||||
public boolean isWriterTaskNeeded(ContactId c) throws DbException {
|
||||
return db.transactionWithResult(true, txn ->
|
||||
db.containsAnythingToSend(txn, c, MAX_LATENCY, true));
|
||||
db.containsAcksToSend(txn, c) ||
|
||||
db.containsMessagesToSend(txn, c, MAX_LATENCY, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -50,6 +50,7 @@ import static java.util.logging.Level.WARNING;
|
||||
import static java.util.logging.Logger.getLogger;
|
||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
|
||||
import static org.briarproject.bramble.api.record.Record.RECORD_HEADER_BYTES;
|
||||
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
|
||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
|
||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
|
||||
import static org.briarproject.bramble.api.sync.SyncConstants.SUPPORTED_VERSIONS;
|
||||
@@ -235,8 +236,10 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
||||
generateOffer();
|
||||
} else if (e instanceof GroupVisibilityUpdatedEvent) {
|
||||
GroupVisibilityUpdatedEvent g = (GroupVisibilityUpdatedEvent) e;
|
||||
if (g.getAffectedContacts().contains(contactId))
|
||||
if (g.getVisibility() == SHARED &&
|
||||
g.getAffectedContacts().contains(contactId)) {
|
||||
generateOffer();
|
||||
}
|
||||
} else if (e instanceof MessageRequestedEvent) {
|
||||
if (((MessageRequestedEvent) e).getContactId().equals(contactId))
|
||||
generateBatch();
|
||||
@@ -310,7 +313,8 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
||||
Collection<Message> batch =
|
||||
db.generateRequestedBatch(txn, contactId,
|
||||
BATCH_CAPACITY, maxLatency);
|
||||
setNextSendTime(db.getNextSendTime(txn, contactId));
|
||||
setNextSendTime(db.getNextSendTime(txn, contactId,
|
||||
maxLatency));
|
||||
return batch;
|
||||
});
|
||||
if (LOG.isLoggable(INFO))
|
||||
@@ -353,7 +357,8 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
||||
Offer o = db.transactionWithNullableResult(false, txn -> {
|
||||
Offer offer = db.generateOffer(txn, contactId,
|
||||
MAX_MESSAGE_IDS, maxLatency);
|
||||
setNextSendTime(db.getNextSendTime(txn, contactId));
|
||||
setNextSendTime(db.getNextSendTime(txn, contactId,
|
||||
maxLatency));
|
||||
return offer;
|
||||
});
|
||||
if (LOG.isLoggable(INFO))
|
||||
|
||||
@@ -7,9 +7,9 @@ import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
import org.briarproject.bramble.api.sync.Ack;
|
||||
import org.briarproject.bramble.api.sync.DeferredSendHandler;
|
||||
import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.sync.OutgoingSessionRecord;
|
||||
import org.briarproject.bramble.api.sync.SyncRecordWriter;
|
||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||
|
||||
@@ -29,7 +29,7 @@ import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LEN
|
||||
|
||||
/**
|
||||
* A {@link SimplexOutgoingSession} for sending and acking messages via a
|
||||
* mailbox. The session uses a {@link DeferredSendHandler} to record the IDs
|
||||
* mailbox. The session uses a {@link OutgoingSessionRecord} to record the IDs
|
||||
* of the messages sent and acked during the session so that they can be
|
||||
* recorded in the DB as sent or acked after the file has been successfully
|
||||
* uploaded to the mailbox.
|
||||
@@ -41,7 +41,7 @@ class MailboxOutgoingSession extends SimplexOutgoingSession {
|
||||
private static final Logger LOG =
|
||||
getLogger(MailboxOutgoingSession.class.getName());
|
||||
|
||||
private final DeferredSendHandler deferredSendHandler;
|
||||
private final OutgoingSessionRecord sessionRecord;
|
||||
private final long initialCapacity;
|
||||
|
||||
MailboxOutgoingSession(DatabaseComponent db,
|
||||
@@ -51,11 +51,11 @@ class MailboxOutgoingSession extends SimplexOutgoingSession {
|
||||
long maxLatency,
|
||||
StreamWriter streamWriter,
|
||||
SyncRecordWriter recordWriter,
|
||||
DeferredSendHandler deferredSendHandler,
|
||||
OutgoingSessionRecord sessionRecord,
|
||||
long capacity) {
|
||||
super(db, eventBus, contactId, transportId, maxLatency, streamWriter,
|
||||
recordWriter);
|
||||
this.deferredSendHandler = deferredSendHandler;
|
||||
this.sessionRecord = sessionRecord;
|
||||
this.initialCapacity = capacity;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ class MailboxOutgoingSession extends SimplexOutgoingSession {
|
||||
Collection<MessageId> idsToAck = loadMessageIdsToAck();
|
||||
if (idsToAck.isEmpty()) break;
|
||||
recordWriter.writeAck(new Ack(idsToAck));
|
||||
deferredSendHandler.onAckSent(idsToAck);
|
||||
sessionRecord.onAckSent(idsToAck);
|
||||
LOG.info("Sent ack");
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ class MailboxOutgoingSession extends SimplexOutgoingSession {
|
||||
db.getMessageToSend(txn, contactId, m, maxLatency, false));
|
||||
if (message == null) continue; // No longer shared
|
||||
recordWriter.writeMessage(message);
|
||||
deferredSendHandler.onMessageSent(m);
|
||||
sessionRecord.onMessageSent(m);
|
||||
LOG.info("Sent message");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
import org.briarproject.bramble.api.sync.OutgoingSessionRecord;
|
||||
import org.briarproject.bramble.api.sync.Priority;
|
||||
import org.briarproject.bramble.api.sync.PriorityHandler;
|
||||
import org.briarproject.bramble.api.sync.SyncRecordReader;
|
||||
@@ -25,6 +26,8 @@ import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static org.briarproject.bramble.api.mailbox.MailboxConstants.MAX_FILE_PAYLOAD_BYTES;
|
||||
|
||||
@Immutable
|
||||
@NotNullByDefault
|
||||
class SyncSessionFactoryImpl implements SyncSessionFactory {
|
||||
@@ -73,6 +76,18 @@ class SyncSessionFactoryImpl implements SyncSessionFactory {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SyncSession createSimplexOutgoingSession(ContactId c, TransportId t,
|
||||
long maxLatency, StreamWriter streamWriter,
|
||||
OutgoingSessionRecord sessionRecord) {
|
||||
OutputStream out = streamWriter.getOutputStream();
|
||||
SyncRecordWriter recordWriter =
|
||||
recordWriterFactory.createRecordWriter(out);
|
||||
return new MailboxOutgoingSession(db, eventBus, c, t, maxLatency,
|
||||
streamWriter, recordWriter, sessionRecord,
|
||||
MAX_FILE_PAYLOAD_BYTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SyncSession createDuplexOutgoingSession(ContactId c, TransportId t,
|
||||
long maxLatency, int maxIdleTime, StreamWriter streamWriter,
|
||||
|
||||
@@ -17,17 +17,17 @@ n Bridge obfs4 85.242.211.221:8042 A36A938DD7FDB8BACC846BA326EE0BA0D89A9252 cert
|
||||
n Bridge obfs4 74.104.165.202:9002 EF432018A6AA5D970B2F84E39CD30A147030141C cert=PhppfUusY85dHGvWtGTybZ1fED4DtbHmALkNMIOIYrAz1B4xN7/2a5gyiZe1epju1BOHVg iat-mode=0
|
||||
n Bridge obfs4 93.95.226.151:41185 460B0CFFC0CF1D965F3DE064E08BA1915E7C916A cert=inluPzp5Jp5OzZar1eQb4dcQ/YlAj/v0kHAUCoCr3rmLt03+pVuVTjoH4mRy4+acXpn+Gw iat-mode=0
|
||||
n Bridge obfs4 120.29.217.52:5223 40FE3DB9800272F9CDC76422F8ED7883280EE96D cert=/71PS4l8c/XJ4DIItlH9xMqNvPFg2RUTrHvPlQWh48u5et8h/yyyjCcYphUadDsfBWpaGQ iat-mode=0
|
||||
n Bridge obfs4 83.97.179.29:1199 D83068BFAA28E71DB024B786E1E803BE14257127 cert=IduGtt05tM59Xmvo0oVNWgIRgY4OGPJjFP+y2oa6RMDHQBL/GRyFOOgX70iiazNAIJNkPw iat-mode=0
|
||||
n Bridge obfs4 207.181.244.13:40132 37FE8D782F5DD2BAEEDAAB8257B701344676B6DD cert=f5Hbfn3ToMzH170cV8DfLly3vRynveidfOfDcbradIDtbLDX15V2yQ8eEH2CPKQJmQR2Hg iat-mode=0
|
||||
n Bridge obfs4 76.255.201.112:8888 96CF36C2ECCFB7376AB6BE905BECD2C2AE8AEFCD cert=+q0pjaiM0JMqHL/BKqCRD+pjflaw/S406eUDF7CnFgamvQW3l2HVLJhQ6uX9P8zff0PLGg iat-mode=0
|
||||
n Bridge obfs4 65.108.159.114:14174 E1AD374BA9F34BD98862D128AC54D40C7DC138AE cert=YMkxMSBN2OOd99AkJpFaEUyKkdqZgJt9oVJEgO1QnT37n/Vc2yR4nhx4k4VkPLfEP1f4eg iat-mode=0
|
||||
n Bridge obfs4 185.177.207.138:8443 53716FE26F23C8C6A71A2BC5D9D8DC64747278C7 cert=6jcYVilMEzxdsWghSrQFpYYJlkkir/GPIXw/EnddUK3S8ToVpMG8u1SwMOEdEs735RrMHw iat-mode=0
|
||||
n Bridge obfs4 176.123.2.253:1933 B855D141CE6C4DE0F7EA4AAED83EBA8373FA8191 cert=1rOoSaRagc6PPR//paIl+ukv1N+xWKCdBXMFxK0k/moEwH0lk5bURBrUDzIX35fVzaiicQ iat-mode=0
|
||||
n Bridge obfs4 5.252.176.61:9418 3E61130100AD827AB9CB33DAC052D9BC49A39509 cert=/aMyBPnKbQFISithD3i1KHUdpWeMpWG3SvUpq1YWCf2EQohFxQfw+646gW1knm4BI/DLRA iat-mode=0
|
||||
n Bridge obfs4 70.34.213.156:12345 BC1C79ABBAE085D305346E7A2B0E838953B4B4D3 cert=3Sk4uA3/NiAsn4ObOUzjIzARclGmkiEUrku8o8bkq4ZL+dek9uLj/d5LZ5nAXT6L9S0CZA iat-mode=0
|
||||
n Bridge obfs4 202.61.224.111:6902 A4F91299763DB925AE3BD29A0FC1A9821E5D9BAE cert=NBKm2MJ83wMvYShkqpD5RrbDtW5YpIZrFNnMw7Dj1XOM3plU60Bh4eziaQXe8fGtb8ZqKg iat-mode=0
|
||||
n Bridge obfs4 87.121.72.109:9002 C8081D4731C953FA4AE166946E72B29153351E34 cert=bikAqxKV6Ch5gFCBTdPI28VeShYa1ZgkLmvc7YZNLWFsFZoaCULL/3AQKjpIfvSiJs5jGQ iat-mode=0
|
||||
n Bridge obfs4 172.104.17.96:17900 B6B37AC96E163D0A5ECE55826D17B50B70F0A7F8 cert=gUz7svhPxoALgeN4lMYrXK7NBnaDqwu6SKRJOhaO9IIMBpnB8UhMCMKzzMho3b0RxWzBVg iat-mode=0
|
||||
n Bridge obfs4 70.34.249.113:443 F441B16ABB1055794C2CE01821FC05047B2C8CFC cert=MauLNoyq8EwjY4Qe0oASYzs2hXdSjNgy+BtP9oo1naHhRsyKTtAZzeNv08RnzWjMJrTwcg iat-mode=0
|
||||
v Bridge 135.181.113.164:54444 74AF4CCA614C454B7D3E81FF8BACD78CEBC7D7DE
|
||||
v Bridge 92.243.15.235:9001 477EAD3C04036B48235F1F27FC91420A286A4B7F
|
||||
v Bridge 77.96.91.103:443 ED000A75B79A58F1D83A4D1675C2A9395B71BE8E
|
||||
v Bridge 213.108.108.145:17674 A39C0FE47963B6E8CFE9815549864DE544935A31
|
||||
m Bridge meek_lite 192.0.2.2:2 97700DFE9F483596DDA6264C4D7DF7641E1E39CE url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com
|
||||
m Bridge meek_lite 192.0.2.2:2 97700DFE9F483596DDA6264C4D7DF7641E1E39CE url=https://meek.azureedge.net/ front=ajax.aspnetcdn.com
|
||||
|
||||
@@ -17,7 +17,6 @@ import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
import org.briarproject.bramble.api.transport.KeyManager;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.DbExpectations;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -63,13 +62,9 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
private final long timestamp = System.currentTimeMillis();
|
||||
private final boolean alice = new Random().nextBoolean();
|
||||
|
||||
private ContactManagerImpl contactManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
contactManager = new ContactManagerImpl(db, keyManager,
|
||||
identityManager, pendingContactFactory);
|
||||
}
|
||||
private final ContactManagerImpl contactManager =
|
||||
new ContactManagerImpl(db, keyManager, identityManager,
|
||||
pendingContactFactory);
|
||||
|
||||
@Test
|
||||
public void testAddContact() throws Exception {
|
||||
|
||||
@@ -2,7 +2,6 @@ package org.briarproject.bramble.data;
|
||||
|
||||
import org.briarproject.bramble.test.BrambleTestCase;
|
||||
import org.briarproject.bramble.util.StringUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -17,14 +16,8 @@ import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
public class BdfWriterImplTest extends BrambleTestCase {
|
||||
|
||||
private ByteArrayOutputStream out = null;
|
||||
private BdfWriterImpl w = null;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
out = new ByteArrayOutputStream();
|
||||
w = new BdfWriterImpl(out);
|
||||
}
|
||||
private final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
private final BdfWriterImpl w = new BdfWriterImpl(out);
|
||||
|
||||
@Test
|
||||
public void testWriteNull() throws IOException {
|
||||
|
||||
@@ -303,11 +303,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
throws Exception {
|
||||
context.checking(new Expectations() {{
|
||||
// Check whether the contact is in the DB (which it's not)
|
||||
exactly(25).of(database).startTransaction();
|
||||
exactly(27).of(database).startTransaction();
|
||||
will(returnValue(txn));
|
||||
exactly(25).of(database).containsContact(txn, contactId);
|
||||
exactly(27).of(database).containsContact(txn, contactId);
|
||||
will(returnValue(false));
|
||||
exactly(25).of(database).abortTransaction(txn);
|
||||
exactly(27).of(database).abortTransaction(txn);
|
||||
}});
|
||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||
eventExecutor, shutdownManager);
|
||||
@@ -321,6 +321,23 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
||||
// Expected
|
||||
}
|
||||
|
||||
try {
|
||||
db.transaction(true, transaction ->
|
||||
db.containsAcksToSend(transaction, contactId));
|
||||
fail();
|
||||
} catch (NoSuchContactException expected) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
try {
|
||||
db.transaction(true, transaction ->
|
||||
db.containsMessagesToSend(transaction, contactId,
|
||||
123, true));
|
||||
fail();
|
||||
} catch (NoSuchContactException expected) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
try {
|
||||
db.transaction(false, transaction ->
|
||||
db.generateAck(transaction, contactId, 123));
|
||||
|
||||
@@ -378,9 +378,9 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
||||
|
||||
// Initially there should be nothing to send
|
||||
assertFalse(
|
||||
db.containsAnythingToSend(txn, contactId, MAX_LATENCY, false));
|
||||
db.containsMessagesToSend(txn, contactId, MAX_LATENCY, false));
|
||||
assertFalse(
|
||||
db.containsAnythingToSend(txn, contactId, MAX_LATENCY, true));
|
||||
db.containsMessagesToSend(txn, contactId, MAX_LATENCY, true));
|
||||
|
||||
// Add some messages to ack
|
||||
Message message1 = getMessage(groupId);
|
||||
@@ -389,10 +389,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
||||
db.addMessage(txn, message1, DELIVERED, true, false, contactId);
|
||||
|
||||
// Both message IDs should be returned
|
||||
assertTrue(
|
||||
db.containsAnythingToSend(txn, contactId, MAX_LATENCY, false));
|
||||
assertTrue(
|
||||
db.containsAnythingToSend(txn, contactId, MAX_LATENCY, true));
|
||||
assertTrue(db.containsAcksToSend(txn, contactId));
|
||||
Collection<MessageId> ids = db.getMessagesToAck(txn, contactId, 1234);
|
||||
assertEquals(asList(messageId, messageId1), ids);
|
||||
|
||||
@@ -400,10 +397,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
||||
db.lowerAckFlag(txn, contactId, asList(messageId, messageId1));
|
||||
|
||||
// No message IDs should be returned
|
||||
assertFalse(
|
||||
db.containsAnythingToSend(txn, contactId, MAX_LATENCY, false));
|
||||
assertFalse(
|
||||
db.containsAnythingToSend(txn, contactId, MAX_LATENCY, true));
|
||||
assertFalse(db.containsAcksToSend(txn, contactId));
|
||||
assertEquals(emptyList(), db.getMessagesToAck(txn, contactId, 1234));
|
||||
|
||||
// Raise the ack flag again
|
||||
@@ -411,10 +405,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
||||
db.raiseAckFlag(txn, contactId, messageId1);
|
||||
|
||||
// Both message IDs should be returned
|
||||
assertTrue(
|
||||
db.containsAnythingToSend(txn, contactId, MAX_LATENCY, false));
|
||||
assertTrue(
|
||||
db.containsAnythingToSend(txn, contactId, MAX_LATENCY, true));
|
||||
assertTrue(db.containsAcksToSend(txn, contactId));
|
||||
ids = db.getMessagesToAck(txn, contactId, 1234);
|
||||
assertEquals(asList(messageId, messageId1), ids);
|
||||
|
||||
@@ -2029,37 +2020,51 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
||||
db.addMessage(txn, message, UNKNOWN, false, false, null);
|
||||
|
||||
// There should be no messages to send
|
||||
assertEquals(Long.MAX_VALUE, db.getNextSendTime(txn, contactId));
|
||||
assertEquals(Long.MAX_VALUE,
|
||||
db.getNextSendTime(txn, contactId, MAX_LATENCY));
|
||||
|
||||
// Share the group with the contact - still no messages to send
|
||||
db.addGroupVisibility(txn, contactId, groupId, true);
|
||||
assertEquals(Long.MAX_VALUE, db.getNextSendTime(txn, contactId));
|
||||
assertEquals(Long.MAX_VALUE,
|
||||
db.getNextSendTime(txn, contactId, MAX_LATENCY));
|
||||
|
||||
// Set the message's state to DELIVERED - still no messages to send
|
||||
db.setMessageState(txn, messageId, DELIVERED);
|
||||
assertEquals(Long.MAX_VALUE, db.getNextSendTime(txn, contactId));
|
||||
assertEquals(Long.MAX_VALUE,
|
||||
db.getNextSendTime(txn, contactId, MAX_LATENCY));
|
||||
|
||||
// Share the message - now it should be sendable immediately
|
||||
db.setMessageShared(txn, messageId, true);
|
||||
assertEquals(0, db.getNextSendTime(txn, contactId));
|
||||
assertEquals(0, db.getNextSendTime(txn, contactId, MAX_LATENCY));
|
||||
|
||||
// Mark the message as requested - it should still be sendable
|
||||
db.raiseRequestedFlag(txn, contactId, messageId);
|
||||
assertEquals(0, db.getNextSendTime(txn, contactId));
|
||||
assertEquals(0, db.getNextSendTime(txn, contactId, MAX_LATENCY));
|
||||
|
||||
// Update the message's expiry time as though we sent it - now the
|
||||
// message should be sendable after one round-trip
|
||||
db.updateRetransmissionData(txn, contactId, messageId, 1000);
|
||||
assertEquals(now + 2000, db.getNextSendTime(txn, contactId));
|
||||
db.updateRetransmissionData(txn, contactId, messageId, MAX_LATENCY);
|
||||
assertEquals(now + MAX_LATENCY * 2,
|
||||
db.getNextSendTime(txn, contactId, MAX_LATENCY));
|
||||
|
||||
// The message should be sendable immediately over a transport with
|
||||
// lower latency
|
||||
assertEquals(0L, db.getNextSendTime(txn, contactId, MAX_LATENCY - 1));
|
||||
|
||||
// Update the message's expiry time again - now it should be sendable
|
||||
// after two round-trips
|
||||
db.updateRetransmissionData(txn, contactId, messageId, 1000);
|
||||
assertEquals(now + 4000, db.getNextSendTime(txn, contactId));
|
||||
db.updateRetransmissionData(txn, contactId, messageId, MAX_LATENCY);
|
||||
assertEquals(now + MAX_LATENCY * 4,
|
||||
db.getNextSendTime(txn, contactId, MAX_LATENCY));
|
||||
|
||||
// The message should be sendable immediately over a transport with
|
||||
// lower latency
|
||||
assertEquals(0L, db.getNextSendTime(txn, contactId, MAX_LATENCY - 1));
|
||||
|
||||
// Delete the message - there should be no messages to send
|
||||
db.deleteMessage(txn, messageId);
|
||||
assertEquals(Long.MAX_VALUE, db.getNextSendTime(txn, contactId));
|
||||
assertEquals(Long.MAX_VALUE,
|
||||
db.getNextSendTime(txn, contactId, MAX_LATENCY));
|
||||
|
||||
db.commitTransaction(txn);
|
||||
db.close();
|
||||
@@ -2124,7 +2129,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
||||
db.updateRetransmissionData(txn, contactId, messageId, MAX_LATENCY);
|
||||
|
||||
// The message should expire after 2 * MAX_LATENCY
|
||||
assertEquals(now + MAX_LATENCY * 2, db.getNextSendTime(txn, contactId));
|
||||
assertEquals(now + MAX_LATENCY * 2,
|
||||
db.getNextSendTime(txn, contactId, MAX_LATENCY));
|
||||
|
||||
// Time: now + MAX_LATENCY * 2 - 1
|
||||
// The message should not yet be sendable
|
||||
@@ -2167,7 +2173,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
||||
db.updateRetransmissionData(txn, contactId, messageId, MAX_LATENCY);
|
||||
|
||||
// The message should expire after 2 * MAX_LATENCY
|
||||
assertEquals(now + MAX_LATENCY * 2, db.getNextSendTime(txn, contactId));
|
||||
assertEquals(now + MAX_LATENCY * 2,
|
||||
db.getNextSendTime(txn, contactId, MAX_LATENCY));
|
||||
|
||||
// The message should not be sendable via the same transport
|
||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||
@@ -2214,7 +2221,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
||||
db.updateRetransmissionData(txn, contactId, messageId, MAX_LATENCY);
|
||||
|
||||
// The message should expire after 2 * MAX_LATENCY
|
||||
assertEquals(now + MAX_LATENCY * 2, db.getNextSendTime(txn, contactId));
|
||||
assertEquals(now + MAX_LATENCY * 2,
|
||||
db.getNextSendTime(txn, contactId, MAX_LATENCY));
|
||||
|
||||
// Time: now + MAX_LATENCY * 2 - 1
|
||||
// The message should not yet be sendable
|
||||
@@ -2225,8 +2233,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
||||
// Reset the retransmission times
|
||||
db.resetUnackedMessagesToSend(txn, contactId);
|
||||
|
||||
// The message should have infinitely short expiry
|
||||
assertEquals(0, db.getNextSendTime(txn, contactId));
|
||||
// The message should be sendable immediately
|
||||
assertEquals(0, db.getNextSendTime(txn, contactId, MAX_LATENCY));
|
||||
|
||||
// The message should be sendable
|
||||
ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||
@@ -2579,7 +2587,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
||||
private void assertNothingToSendLazily(Database<Connection> db,
|
||||
Connection txn) throws Exception {
|
||||
assertFalse(
|
||||
db.containsAnythingToSend(txn, contactId, MAX_LATENCY, false));
|
||||
db.containsMessagesToSend(txn, contactId, MAX_LATENCY, false));
|
||||
Collection<MessageId> ids =
|
||||
db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||
assertTrue(ids.isEmpty());
|
||||
@@ -2590,7 +2598,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
||||
private void assertOneMessageToSendLazily(Database<Connection> db,
|
||||
Connection txn) throws Exception {
|
||||
assertTrue(
|
||||
db.containsAnythingToSend(txn, contactId, MAX_LATENCY, false));
|
||||
db.containsMessagesToSend(txn, contactId, MAX_LATENCY, false));
|
||||
Collection<MessageId> ids =
|
||||
db.getMessagesToSend(txn, contactId, ONE_MEGABYTE, MAX_LATENCY);
|
||||
assertEquals(singletonList(messageId), ids);
|
||||
@@ -2601,7 +2609,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
||||
private void assertNothingToSendEagerly(Database<Connection> db,
|
||||
Connection txn) throws Exception {
|
||||
assertFalse(
|
||||
db.containsAnythingToSend(txn, contactId, MAX_LATENCY, true));
|
||||
db.containsMessagesToSend(txn, contactId, MAX_LATENCY, true));
|
||||
Collection<MessageId> unacked =
|
||||
db.getUnackedMessagesToSend(txn, contactId);
|
||||
assertTrue(unacked.isEmpty());
|
||||
@@ -2611,7 +2619,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
||||
private void assertOneMessageToSendEagerly(Database<Connection> db,
|
||||
Connection txn) throws Exception {
|
||||
assertTrue(
|
||||
db.containsAnythingToSend(txn, contactId, MAX_LATENCY, true));
|
||||
db.containsMessagesToSend(txn, contactId, MAX_LATENCY, true));
|
||||
Collection<MessageId> unacked =
|
||||
db.getUnackedMessagesToSend(txn, contactId);
|
||||
assertEquals(singletonList(messageId), unacked);
|
||||
|
||||
@@ -14,7 +14,6 @@ import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.DbExpectations;
|
||||
import org.jmock.Expectations;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
@@ -41,13 +40,8 @@ public class IdentityManagerImplTest extends BrambleMockTestCase {
|
||||
private final KeyPair handshakeKeyPair =
|
||||
new KeyPair(handshakePublicKey, handshakePrivateKey);
|
||||
|
||||
private IdentityManagerImpl identityManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
identityManager =
|
||||
new IdentityManagerImpl(db, crypto, authorFactory, clock);
|
||||
}
|
||||
private final IdentityManagerImpl identityManager =
|
||||
new IdentityManagerImpl(db, crypto, authorFactory, clock);
|
||||
|
||||
@Test
|
||||
public void testOpenDatabaseIdentityRegistered() throws Exception {
|
||||
|
||||
@@ -10,7 +10,6 @@ import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.DbExpectations;
|
||||
import org.jmock.Expectations;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -34,12 +33,8 @@ public class LifecycleManagerImplTest extends BrambleMockTestCase {
|
||||
|
||||
private final SecretKey dbKey = getSecretKey();
|
||||
|
||||
private LifecycleManagerImpl lifecycleManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
lifecycleManager = new LifecycleManagerImpl(db, eventBus, clock);
|
||||
}
|
||||
private final LifecycleManagerImpl lifecycleManager =
|
||||
new LifecycleManagerImpl(db, eventBus, clock);
|
||||
|
||||
@Test
|
||||
public void testOpenDatabaseHooksAreCalledAtStartup() throws Exception {
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.jmock.Expectations;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS;
|
||||
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
|
||||
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
||||
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
|
||||
|
||||
public class ContactMailboxClientTest extends BrambleMockTestCase {
|
||||
|
||||
private final MailboxWorkerFactory workerFactory =
|
||||
context.mock(MailboxWorkerFactory.class);
|
||||
private final ConnectivityChecker connectivityChecker =
|
||||
context.mock(ConnectivityChecker.class);
|
||||
private final TorReachabilityMonitor reachabilityMonitor =
|
||||
context.mock(TorReachabilityMonitor.class);
|
||||
private final MailboxWorker uploadWorker =
|
||||
context.mock(MailboxWorker.class, "uploadWorker");
|
||||
private final MailboxWorker downloadWorker =
|
||||
context.mock(MailboxWorker.class, "downloadWorker");
|
||||
|
||||
private final MailboxProperties properties =
|
||||
getMailboxProperties(false, CLIENT_SUPPORTS);
|
||||
private final MailboxFolderId inboxId =
|
||||
requireNonNull(properties.getInboxId());
|
||||
private final MailboxFolderId outboxId =
|
||||
requireNonNull(properties.getOutboxId());
|
||||
private final ContactId contactId = getContactId();
|
||||
|
||||
private final ContactMailboxClient client =
|
||||
new ContactMailboxClient(workerFactory, connectivityChecker,
|
||||
reachabilityMonitor);
|
||||
|
||||
@Test
|
||||
public void testStartAndDestroyWithNoContactsAssigned() {
|
||||
client.start();
|
||||
client.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssignContactForUploadAndDestroyClient() {
|
||||
client.start();
|
||||
|
||||
// When the contact is assigned, the worker should be created and
|
||||
// started
|
||||
expectCreateAndStartUploadWorker();
|
||||
client.assignContactForUpload(contactId, properties, outboxId);
|
||||
|
||||
// When the client is destroyed, the worker should be destroyed
|
||||
expectDestroyWorker(uploadWorker);
|
||||
client.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssignAndDeassignContactForUpload() {
|
||||
client.start();
|
||||
|
||||
// When the contact is assigned, the worker should be created and
|
||||
// started
|
||||
expectCreateAndStartUploadWorker();
|
||||
client.assignContactForUpload(contactId, properties, outboxId);
|
||||
|
||||
// When the contact is deassigned, the worker should be destroyed
|
||||
expectDestroyWorker(uploadWorker);
|
||||
client.deassignContactForUpload(contactId);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
client.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assignContactForDownloadAndDestroyClient() {
|
||||
client.start();
|
||||
|
||||
// When the contact is assigned, the worker should be created and
|
||||
// started
|
||||
expectCreateAndStartDownloadWorker();
|
||||
client.assignContactForDownload(contactId, properties, inboxId);
|
||||
|
||||
// When the client is destroyed, the worker should be destroyed
|
||||
expectDestroyWorker(downloadWorker);
|
||||
client.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assignAndDeassignContactForDownload() {
|
||||
client.start();
|
||||
|
||||
// When the contact is assigned, the worker should be created and
|
||||
// started
|
||||
expectCreateAndStartDownloadWorker();
|
||||
client.assignContactForDownload(contactId, properties, inboxId);
|
||||
|
||||
// When the contact is deassigned, the worker should be destroyed
|
||||
expectDestroyWorker(downloadWorker);
|
||||
client.deassignContactForDownload(contactId);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
client.destroy();
|
||||
}
|
||||
|
||||
private void expectCreateAndStartUploadWorker() {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(workerFactory).createUploadWorker(connectivityChecker,
|
||||
properties, outboxId, contactId);
|
||||
will(returnValue(uploadWorker));
|
||||
oneOf(uploadWorker).start();
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectCreateAndStartDownloadWorker() {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(workerFactory).createDownloadWorkerForContactMailbox(
|
||||
connectivityChecker, reachabilityMonitor, properties);
|
||||
will(returnValue(downloadWorker));
|
||||
oneOf(downloadWorker).start();
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectDestroyWorker(MailboxWorker worker) {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(worker).destroy();
|
||||
}});
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.Cancellable;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxFileId;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.mailbox.MailboxApi.MailboxFile;
|
||||
@@ -7,6 +8,7 @@ import org.briarproject.bramble.mailbox.MailboxApi.TolerableFailureException;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.CaptureArgumentAction;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.lib.action.DoAllAction;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -36,6 +38,7 @@ public class ContactMailboxDownloadWorkerTest extends BrambleMockTestCase {
|
||||
private final MailboxApi mailboxApi = context.mock(MailboxApi.class);
|
||||
private final MailboxFileManager mailboxFileManager =
|
||||
context.mock(MailboxFileManager.class);
|
||||
private final Cancellable apiCall = context.mock(Cancellable.class);
|
||||
|
||||
private final MailboxProperties mailboxProperties =
|
||||
getMailboxProperties(false, CLIENT_SUPPORTS);
|
||||
@@ -96,30 +99,36 @@ public class ContactMailboxDownloadWorkerTest extends BrambleMockTestCase {
|
||||
|
||||
// When the connectivity check succeeds, a list-inbox task should be
|
||||
// started for the first download cycle
|
||||
AtomicReference<ApiCall> listTask = new AtomicReference<>(null);
|
||||
AtomicReference<ApiCall> listTask = new AtomicReference<>();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(with(any(ApiCall.class)));
|
||||
will(new CaptureArgumentAction<>(listTask, ApiCall.class, 0));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(listTask, ApiCall.class, 0),
|
||||
returnValue(apiCall)
|
||||
));
|
||||
}});
|
||||
|
||||
worker.onConnectivityCheckSucceeded();
|
||||
|
||||
// When the list-inbox tasks runs and finds some files to download,
|
||||
// it should start a download task for the first file
|
||||
AtomicReference<ApiCall> downloadTask = new AtomicReference<>(null);
|
||||
AtomicReference<ApiCall> downloadTask = new AtomicReference<>();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(mailboxApi).getFiles(mailboxProperties,
|
||||
requireNonNull(mailboxProperties.getInboxId()));
|
||||
will(returnValue(files));
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(with(any(ApiCall.class)));
|
||||
will(new CaptureArgumentAction<>(downloadTask, ApiCall.class, 0));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(downloadTask, ApiCall.class, 0),
|
||||
returnValue(apiCall)
|
||||
));
|
||||
}});
|
||||
|
||||
assertFalse(listTask.get().callApi());
|
||||
|
||||
// When the first download task runs it should download the file to the
|
||||
// location provided by the file manager and start a delete task
|
||||
AtomicReference<ApiCall> deleteTask = new AtomicReference<>(null);
|
||||
AtomicReference<ApiCall> deleteTask = new AtomicReference<>();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(mailboxFileManager).createTempFileForDownload();
|
||||
will(returnValue(tempFile));
|
||||
@@ -128,7 +137,10 @@ public class ContactMailboxDownloadWorkerTest extends BrambleMockTestCase {
|
||||
file1.name, tempFile);
|
||||
oneOf(mailboxFileManager).handleDownloadedFile(tempFile);
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(with(any(ApiCall.class)));
|
||||
will(new CaptureArgumentAction<>(deleteTask, ApiCall.class, 0));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(deleteTask, ApiCall.class, 0),
|
||||
returnValue(apiCall)
|
||||
));
|
||||
}});
|
||||
|
||||
assertFalse(downloadTask.get().callApi());
|
||||
@@ -140,7 +152,10 @@ public class ContactMailboxDownloadWorkerTest extends BrambleMockTestCase {
|
||||
requireNonNull(mailboxProperties.getInboxId()), file1.name);
|
||||
will(throwException(new TolerableFailureException()));
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(with(any(ApiCall.class)));
|
||||
will(new CaptureArgumentAction<>(downloadTask, ApiCall.class, 0));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(downloadTask, ApiCall.class, 0),
|
||||
returnValue(apiCall)
|
||||
));
|
||||
}});
|
||||
|
||||
assertFalse(deleteTask.get().callApi());
|
||||
@@ -155,7 +170,10 @@ public class ContactMailboxDownloadWorkerTest extends BrambleMockTestCase {
|
||||
file2.name, tempFile);
|
||||
oneOf(mailboxFileManager).handleDownloadedFile(tempFile);
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(with(any(ApiCall.class)));
|
||||
will(new CaptureArgumentAction<>(deleteTask, ApiCall.class, 0));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(deleteTask, ApiCall.class, 0),
|
||||
returnValue(apiCall)
|
||||
));
|
||||
}});
|
||||
|
||||
assertFalse(downloadTask.get().callApi());
|
||||
@@ -168,7 +186,10 @@ public class ContactMailboxDownloadWorkerTest extends BrambleMockTestCase {
|
||||
requireNonNull(mailboxProperties.getInboxId()), file2.name);
|
||||
will(throwException(new TolerableFailureException()));
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(with(any(ApiCall.class)));
|
||||
will(new CaptureArgumentAction<>(listTask, ApiCall.class, 0));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(listTask, ApiCall.class, 0),
|
||||
returnValue(apiCall)
|
||||
));
|
||||
}});
|
||||
|
||||
assertFalse(deleteTask.get().callApi());
|
||||
@@ -188,7 +209,10 @@ public class ContactMailboxDownloadWorkerTest extends BrambleMockTestCase {
|
||||
// be started for the second download cycle
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(with(any(ApiCall.class)));
|
||||
will(new CaptureArgumentAction<>(listTask, ApiCall.class, 0));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(listTask, ApiCall.class, 0),
|
||||
returnValue(apiCall)
|
||||
));
|
||||
}});
|
||||
|
||||
worker.onTorReachable();
|
||||
|
||||
@@ -2,16 +2,20 @@ package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.connection.ConnectionManager;
|
||||
import org.briarproject.bramble.api.connection.ConnectionManager.TagController;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState;
|
||||
import org.briarproject.bramble.api.plugin.PluginManager;
|
||||
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
||||
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
||||
import org.briarproject.bramble.api.plugin.event.TransportActiveEvent;
|
||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
|
||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||
import org.briarproject.bramble.api.sync.OutgoingSessionRecord;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.CaptureArgumentAction;
|
||||
import org.briarproject.bramble.test.ConsumeArgumentAction;
|
||||
import org.briarproject.bramble.test.RunAction;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.lib.action.DoAllAction;
|
||||
@@ -20,6 +24,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@@ -28,11 +33,14 @@ import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleS
|
||||
import static org.briarproject.bramble.api.mailbox.MailboxConstants.ID;
|
||||
import static org.briarproject.bramble.api.plugin.file.FileConstants.PROP_PATH;
|
||||
import static org.briarproject.bramble.mailbox.MailboxFileManagerImpl.DOWNLOAD_DIR_NAME;
|
||||
import static org.briarproject.bramble.mailbox.MailboxFileManagerImpl.UPLOAD_DIR_NAME;
|
||||
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
||||
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
||||
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class MailboxFileManagerImplTest extends BrambleMockTestCase {
|
||||
|
||||
@@ -47,6 +55,10 @@ public class MailboxFileManagerImplTest extends BrambleMockTestCase {
|
||||
private final SimplexPlugin plugin = context.mock(SimplexPlugin.class);
|
||||
private final TransportConnectionReader transportConnectionReader =
|
||||
context.mock(TransportConnectionReader.class);
|
||||
private final TransportConnectionWriter transportConnectionWriter =
|
||||
context.mock(TransportConnectionWriter.class);
|
||||
|
||||
private final ContactId contactId = getContactId();
|
||||
|
||||
private File mailboxDir;
|
||||
private MailboxFileManagerImpl manager;
|
||||
@@ -65,17 +77,25 @@ public class MailboxFileManagerImplTest extends BrambleMockTestCase {
|
||||
|
||||
@Test
|
||||
public void testHandlesOrphanedFilesAtStartup() throws Exception {
|
||||
// Create an orphaned file, left behind at the previous shutdown
|
||||
// Create an orphaned upload, left behind at the previous shutdown
|
||||
File uploadDir = new File(mailboxDir, UPLOAD_DIR_NAME);
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
uploadDir.mkdirs();
|
||||
File orphanedUpload = new File(uploadDir, "orphan");
|
||||
assertTrue(orphanedUpload.createNewFile());
|
||||
|
||||
// Create an orphaned download, left behind at the previous shutdown
|
||||
File downloadDir = new File(mailboxDir, DOWNLOAD_DIR_NAME);
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
downloadDir.mkdirs();
|
||||
File orphan = new File(downloadDir, "orphan");
|
||||
assertTrue(orphan.createNewFile());
|
||||
File orphanedDownload = new File(downloadDir, "orphan");
|
||||
assertTrue(orphanedDownload.createNewFile());
|
||||
|
||||
TransportProperties props = new TransportProperties();
|
||||
props.put(PROP_PATH, orphan.getAbsolutePath());
|
||||
props.put(PROP_PATH, orphanedDownload.getAbsolutePath());
|
||||
|
||||
// When the plugin becomes active the orphaned file should be handled
|
||||
// When the plugin becomes active the orphaned upload should be deleted
|
||||
// and the orphaned download should be handled
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(ioExecutor).execute(with(any(Runnable.class)));
|
||||
will(new RunAction());
|
||||
@@ -90,10 +110,12 @@ public class MailboxFileManagerImplTest extends BrambleMockTestCase {
|
||||
}});
|
||||
|
||||
manager.eventOccurred(new TransportActiveEvent(ID));
|
||||
|
||||
assertFalse(orphanedUpload.exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeletesFileWhenReadSucceeds() throws Exception {
|
||||
public void testDeletesDownloadedFileWhenReadSucceeds() throws Exception {
|
||||
expectCheckForOrphans();
|
||||
manager.eventOccurred(new TransportActiveEvent(ID));
|
||||
|
||||
@@ -102,7 +124,7 @@ public class MailboxFileManagerImplTest extends BrambleMockTestCase {
|
||||
new AtomicReference<>(null);
|
||||
AtomicReference<TagController> controller = new AtomicReference<>(null);
|
||||
|
||||
expectPassFileToConnectionManager(f, reader, controller);
|
||||
expectPassDownloadedFileToConnectionManager(f, reader, controller);
|
||||
manager.handleDownloadedFile(f);
|
||||
|
||||
// The read is successful, so the tag controller should allow the tag
|
||||
@@ -117,29 +139,117 @@ public class MailboxFileManagerImplTest extends BrambleMockTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeletesFileWhenTagIsNotRecognised() throws Exception {
|
||||
testDeletesFile(false, RUNNING, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeletesFileWhenReadFails() throws Exception {
|
||||
testDeletesFile(true, RUNNING, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoesNotDeleteFileWhenTagIsNotRecognisedAtShutdown()
|
||||
public void testDeletesDownloadedFileWhenTagIsNotRecognised()
|
||||
throws Exception {
|
||||
testDeletesFile(false, STOPPING, true);
|
||||
testDeletesDownloadedFile(false, RUNNING, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoesNotDeleteFileWhenReadFailsAtShutdown()
|
||||
throws Exception {
|
||||
testDeletesFile(true, STOPPING, true);
|
||||
public void testDeletesDownloadedFileWhenReadFails() throws Exception {
|
||||
testDeletesDownloadedFile(true, RUNNING, false);
|
||||
}
|
||||
|
||||
private void testDeletesFile(boolean recognised, LifecycleState state,
|
||||
boolean fileExists) throws Exception {
|
||||
@Test
|
||||
public void testDoesNotDeleteDownloadedFileWhenTagIsNotRecognisedAtShutdown()
|
||||
throws Exception {
|
||||
testDeletesDownloadedFile(false, STOPPING, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoesNotDeleteDownloadedFileWhenReadFailsAtShutdown()
|
||||
throws Exception {
|
||||
testDeletesDownloadedFile(true, STOPPING, true);
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void testThrowsExceptionIfPluginFailsToCreateWriter()
|
||||
throws Exception {
|
||||
OutgoingSessionRecord sessionRecord = new OutgoingSessionRecord();
|
||||
|
||||
expectCheckForOrphans();
|
||||
manager.eventOccurred(new TransportActiveEvent(ID));
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(pluginManager).getPlugin(ID);
|
||||
will(returnValue(plugin));
|
||||
oneOf(plugin).createWriter(with(any(TransportProperties.class)));
|
||||
will(returnValue(null));
|
||||
}});
|
||||
|
||||
manager.createAndWriteTempFileForUpload(contactId, sessionRecord);
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void testThrowsExceptionIfSessionFailsWithException()
|
||||
throws Exception {
|
||||
OutgoingSessionRecord sessionRecord = new OutgoingSessionRecord();
|
||||
|
||||
expectCheckForOrphans();
|
||||
manager.eventOccurred(new TransportActiveEvent(ID));
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(pluginManager).getPlugin(ID);
|
||||
will(returnValue(plugin));
|
||||
oneOf(plugin).createWriter(with(any(TransportProperties.class)));
|
||||
will(returnValue(transportConnectionWriter));
|
||||
oneOf(transportConnectionWriter).dispose(true);
|
||||
oneOf(connectionManager).manageOutgoingConnection(with(contactId),
|
||||
with(ID), with(any(TransportConnectionWriter.class)),
|
||||
with(sessionRecord));
|
||||
// The session fails with an exception. We need to use an action
|
||||
// for this, as createAndWriteTempFileForUpload() waits for it to
|
||||
// happen before returning
|
||||
will(new ConsumeArgumentAction<>(TransportConnectionWriter.class, 2,
|
||||
writer -> {
|
||||
try {
|
||||
writer.dispose(true);
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
));
|
||||
}});
|
||||
|
||||
manager.createAndWriteTempFileForUpload(contactId, sessionRecord);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReturnsFileIfSessionSucceeds() throws Exception {
|
||||
OutgoingSessionRecord sessionRecord = new OutgoingSessionRecord();
|
||||
|
||||
expectCheckForOrphans();
|
||||
manager.eventOccurred(new TransportActiveEvent(ID));
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(pluginManager).getPlugin(ID);
|
||||
will(returnValue(plugin));
|
||||
oneOf(plugin).createWriter(with(any(TransportProperties.class)));
|
||||
will(returnValue(transportConnectionWriter));
|
||||
oneOf(transportConnectionWriter).dispose(false);
|
||||
oneOf(connectionManager).manageOutgoingConnection(with(contactId),
|
||||
with(ID), with(any(TransportConnectionWriter.class)),
|
||||
with(sessionRecord));
|
||||
// The session succeeds. We need to use an action for this, as
|
||||
// createAndWriteTempFileForUpload() waits for it to happen before
|
||||
// returning
|
||||
will(new ConsumeArgumentAction<>(TransportConnectionWriter.class, 2,
|
||||
writer -> {
|
||||
try {
|
||||
writer.dispose(false);
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
));
|
||||
}});
|
||||
|
||||
File f = manager.createAndWriteTempFileForUpload(contactId,
|
||||
sessionRecord);
|
||||
assertTrue(f.exists());
|
||||
}
|
||||
|
||||
private void testDeletesDownloadedFile(boolean recognised,
|
||||
LifecycleState state, boolean fileExists) throws Exception {
|
||||
expectCheckForOrphans();
|
||||
manager.eventOccurred(new TransportActiveEvent(ID));
|
||||
|
||||
@@ -148,7 +258,7 @@ public class MailboxFileManagerImplTest extends BrambleMockTestCase {
|
||||
new AtomicReference<>(null);
|
||||
AtomicReference<TagController> controller = new AtomicReference<>(null);
|
||||
|
||||
expectPassFileToConnectionManager(f, reader, controller);
|
||||
expectPassDownloadedFileToConnectionManager(f, reader, controller);
|
||||
manager.handleDownloadedFile(f);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
@@ -169,7 +279,7 @@ public class MailboxFileManagerImplTest extends BrambleMockTestCase {
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectPassFileToConnectionManager(File f,
|
||||
private void expectPassDownloadedFileToConnectionManager(File f,
|
||||
AtomicReference<TransportConnectionReader> reader,
|
||||
AtomicReference<TagController> controller) {
|
||||
TransportProperties props = new TransportProperties();
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.db.TransactionManager;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||
import org.briarproject.bramble.api.mailbox.event.OwnMailboxConnectionStatusEvent;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.DbExpectations;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS;
|
||||
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
|
||||
import static org.briarproject.bramble.test.TestUtils.hasEvent;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class MailboxManagerImplTest extends BrambleMockTestCase {
|
||||
|
||||
private final Executor ioExecutor = context.mock(Executor.class);
|
||||
private final MailboxApi api = context.mock(MailboxApi.class);
|
||||
private final TransactionManager db =
|
||||
context.mock(TransactionManager.class);
|
||||
private final MailboxSettingsManager mailboxSettingsManager =
|
||||
context.mock(MailboxSettingsManager.class);
|
||||
private final MailboxPairingTaskFactory pairingTaskFactory =
|
||||
context.mock(MailboxPairingTaskFactory.class);
|
||||
private final Clock clock =
|
||||
context.mock(Clock.class);
|
||||
|
||||
private final MailboxManagerImpl manager = new MailboxManagerImpl(
|
||||
ioExecutor, api, db, mailboxSettingsManager, pairingTaskFactory,
|
||||
clock);
|
||||
|
||||
@Test
|
||||
public void testDbExceptionDoesNotRecordFailure() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithNullableResult(with(true),
|
||||
withNullableDbCallable(txn));
|
||||
oneOf(mailboxSettingsManager).getOwnMailboxProperties(txn);
|
||||
will(throwException(new DbException()));
|
||||
}});
|
||||
|
||||
assertFalse(manager.checkConnection());
|
||||
assertFalse(hasEvent(txn, OwnMailboxConnectionStatusEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIOExceptionDoesRecordFailure() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
Transaction txn2 = new Transaction(null, false);
|
||||
MailboxProperties props = getMailboxProperties(true, CLIENT_SUPPORTS);
|
||||
long now = new Random().nextLong();
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithNullableResult(with(true),
|
||||
withNullableDbCallable(txn));
|
||||
oneOf(mailboxSettingsManager).getOwnMailboxProperties(txn);
|
||||
will(returnValue(props));
|
||||
oneOf(api).getServerSupports(props);
|
||||
will(throwException(new IOException()));
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(db).transaction(with(false), withDbRunnable(txn2));
|
||||
oneOf(mailboxSettingsManager)
|
||||
.recordFailedConnectionAttempt(txn2, now);
|
||||
}});
|
||||
|
||||
assertFalse(manager.checkConnection());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApiExceptionDoesRecordFailure() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
Transaction txn2 = new Transaction(null, false);
|
||||
MailboxProperties props = getMailboxProperties(true, CLIENT_SUPPORTS);
|
||||
long now = new Random().nextLong();
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithNullableResult(with(true),
|
||||
withNullableDbCallable(txn));
|
||||
oneOf(mailboxSettingsManager).getOwnMailboxProperties(txn);
|
||||
will(returnValue(props));
|
||||
oneOf(api).getServerSupports(props);
|
||||
will(throwException(new MailboxApi.ApiException()));
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(db).transaction(with(false), withDbRunnable(txn2));
|
||||
oneOf(mailboxSettingsManager)
|
||||
.recordFailedConnectionAttempt(txn2, now);
|
||||
}});
|
||||
|
||||
assertFalse(manager.checkConnection());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectionSuccess() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
Transaction txn2 = new Transaction(null, false);
|
||||
MailboxProperties props = getMailboxProperties(true, CLIENT_SUPPORTS);
|
||||
long now = new Random().nextLong();
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithNullableResult(with(true),
|
||||
withNullableDbCallable(txn));
|
||||
oneOf(mailboxSettingsManager).getOwnMailboxProperties(txn);
|
||||
will(returnValue(props));
|
||||
oneOf(api).getServerSupports(props);
|
||||
will(returnValue(CLIENT_SUPPORTS));
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(db).transaction(with(false), withDbRunnable(txn2));
|
||||
oneOf(mailboxSettingsManager)
|
||||
.recordSuccessfulConnection(txn2, now, CLIENT_SUPPORTS);
|
||||
}});
|
||||
|
||||
assertTrue(manager.checkConnection());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,6 @@ import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
||||
import org.briarproject.bramble.api.mailbox.event.OwnMailboxConnectionStatusEvent;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.DbExpectations;
|
||||
@@ -33,7 +32,6 @@ import static java.util.Collections.singletonList;
|
||||
import static org.briarproject.bramble.test.TestUtils.getContact;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||
import static org.briarproject.bramble.test.TestUtils.hasEvent;
|
||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -138,7 +136,6 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase {
|
||||
i.getAndIncrement();
|
||||
});
|
||||
task.run();
|
||||
hasEvent(txn, OwnMailboxConnectionStatusEvent.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -18,6 +18,7 @@ import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTINGS_KEY_ATTEMPTS;
|
||||
import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTINGS_KEY_LAST_ATTEMPT;
|
||||
import static org.briarproject.bramble.mailbox.MailboxSettingsManagerImpl.SETTINGS_KEY_LAST_SUCCESS;
|
||||
@@ -162,6 +163,28 @@ public class MailboxSettingsManagerImplTest extends BrambleMockTestCase {
|
||||
}});
|
||||
|
||||
manager.recordSuccessfulConnection(txn, now);
|
||||
assertTrue(hasEvent(txn, OwnMailboxConnectionStatusEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecordsSuccessWithVersions() throws Exception {
|
||||
Transaction txn = new Transaction(null, false);
|
||||
List<MailboxVersion> versions = singletonList(new MailboxVersion(2, 1));
|
||||
Settings expectedSettings = new Settings();
|
||||
expectedSettings.putLong(SETTINGS_KEY_LAST_ATTEMPT, now);
|
||||
expectedSettings.putLong(SETTINGS_KEY_LAST_SUCCESS, now);
|
||||
expectedSettings.putInt(SETTINGS_KEY_ATTEMPTS, 0);
|
||||
expectedSettings.putInt(SETTINGS_KEY_SERVER_SUPPORTS, 0);
|
||||
int[] newVersionsInts = {2, 1};
|
||||
expectedSettings
|
||||
.putIntArray(SETTINGS_KEY_SERVER_SUPPORTS, newVersionsInts);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(settingsManager).mergeSettings(txn, expectedSettings,
|
||||
SETTINGS_NAMESPACE);
|
||||
}});
|
||||
|
||||
manager.recordSuccessfulConnection(txn, now, versions);
|
||||
hasEvent(txn, OwnMailboxConnectionStatusEvent.class);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,465 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.Cancellable;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxFolderId;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.sync.OutgoingSessionRecord;
|
||||
import org.briarproject.bramble.api.sync.event.MessageSharedEvent;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.api.system.TaskScheduler;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.CaptureArgumentAction;
|
||||
import org.briarproject.bramble.test.ConsumeArgumentAction;
|
||||
import org.briarproject.bramble.test.DbExpectations;
|
||||
import org.briarproject.bramble.test.RunAction;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.lib.action.DoAllAction;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS;
|
||||
import static org.briarproject.bramble.api.mailbox.MailboxConstants.MAX_LATENCY;
|
||||
import static org.briarproject.bramble.mailbox.MailboxUploadWorker.CHECK_DELAY_MS;
|
||||
import static org.briarproject.bramble.mailbox.MailboxUploadWorker.RETRY_DELAY_MS;
|
||||
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
||||
import static org.briarproject.bramble.test.TestUtils.getContactId;
|
||||
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class MailboxUploadWorkerTest extends BrambleMockTestCase {
|
||||
|
||||
private final Executor ioExecutor = context.mock(Executor.class);
|
||||
private final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||
private final Clock clock = context.mock(Clock.class);
|
||||
private final TaskScheduler taskScheduler =
|
||||
context.mock(TaskScheduler.class);
|
||||
private final EventBus eventBus = context.mock(EventBus.class);
|
||||
private final ConnectivityChecker connectivityChecker =
|
||||
context.mock(ConnectivityChecker.class);
|
||||
private final MailboxApiCaller mailboxApiCaller =
|
||||
context.mock(MailboxApiCaller.class);
|
||||
private final MailboxApi mailboxApi = context.mock(MailboxApi.class);
|
||||
private final MailboxFileManager mailboxFileManager =
|
||||
context.mock(MailboxFileManager.class);
|
||||
private final Cancellable apiCall =
|
||||
context.mock(Cancellable.class, "apiCall");
|
||||
private final Cancellable wakeupTask =
|
||||
context.mock(Cancellable.class, "wakeupTask");
|
||||
private final Cancellable checkTask =
|
||||
context.mock(Cancellable.class, "checkTask");
|
||||
|
||||
private final MailboxProperties mailboxProperties =
|
||||
getMailboxProperties(false, CLIENT_SUPPORTS);
|
||||
private final long now = System.currentTimeMillis();
|
||||
private final MailboxFolderId folderId = new MailboxFolderId(getRandomId());
|
||||
private final ContactId contactId = getContactId();
|
||||
private final MessageId ackedId = new MessageId(getRandomId());
|
||||
private final MessageId sentId = new MessageId(getRandomId());
|
||||
private final MessageId newMessageId = new MessageId(getRandomId());
|
||||
|
||||
private File testDir, tempFile;
|
||||
private MailboxUploadWorker worker;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
testDir = getTestDirectory();
|
||||
tempFile = new File(testDir, "temp");
|
||||
worker = new MailboxUploadWorker(ioExecutor, db, clock, taskScheduler,
|
||||
eventBus, connectivityChecker, mailboxApiCaller, mailboxApi,
|
||||
mailboxFileManager, mailboxProperties, folderId, contactId);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
deleteTestDirectory(testDir);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChecksForDataWhenStartedAndRemovesObserverWhenDestroyed()
|
||||
throws Exception {
|
||||
// When the worker is started it should check for data to send
|
||||
expectRunTaskOnIoExecutor();
|
||||
expectCheckForDataToSendNoDataWaiting();
|
||||
|
||||
worker.start();
|
||||
|
||||
// When the worker is destroyed it should remove the connectivity
|
||||
// observer and event listener
|
||||
expectRemoveObserverAndListener();
|
||||
|
||||
worker.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChecksConnectivityWhenStartedIfDataIsReady()
|
||||
throws Exception {
|
||||
Transaction recordTxn = new Transaction(null, false);
|
||||
|
||||
// When the worker is started it should check for data to send. As
|
||||
// there's data ready to send immediately, the worker should start a
|
||||
// connectivity check
|
||||
expectRunTaskOnIoExecutor();
|
||||
expectCheckForDataToSendAndStartConnectivityCheck();
|
||||
|
||||
worker.start();
|
||||
|
||||
// Create the temporary file so we can test that it gets deleted
|
||||
assertTrue(testDir.mkdirs());
|
||||
assertTrue(tempFile.createNewFile());
|
||||
|
||||
// When the connectivity check succeeds, the worker should write a file
|
||||
// and start an upload task
|
||||
expectRunTaskOnIoExecutor();
|
||||
AtomicReference<ApiCall> upload = new AtomicReference<>();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(mailboxFileManager).createAndWriteTempFileForUpload(
|
||||
with(contactId), with(any(OutgoingSessionRecord.class)));
|
||||
will(new DoAllAction(
|
||||
// Record some IDs as acked and sent
|
||||
new ConsumeArgumentAction<>(OutgoingSessionRecord.class, 1,
|
||||
record -> {
|
||||
record.onAckSent(singletonList(ackedId));
|
||||
record.onMessageSent(sentId);
|
||||
}),
|
||||
returnValue(tempFile)
|
||||
));
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(with(any(ApiCall.class)));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(upload, ApiCall.class, 0),
|
||||
returnValue(apiCall)
|
||||
));
|
||||
}});
|
||||
|
||||
worker.onConnectivityCheckSucceeded();
|
||||
|
||||
// When the upload task runs, it should upload the file, record
|
||||
// the acked/sent messages in the DB, and check for more data to send
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(mailboxApi).addFile(mailboxProperties, folderId, tempFile);
|
||||
oneOf(db).transaction(with(false), withDbRunnable(recordTxn));
|
||||
oneOf(db).setAckSent(recordTxn, contactId, singletonList(ackedId));
|
||||
oneOf(db).setMessagesSent(recordTxn, contactId,
|
||||
singletonList(sentId), MAX_LATENCY);
|
||||
}});
|
||||
expectCheckForDataToSendNoDataWaiting();
|
||||
|
||||
assertFalse(upload.get().callApi());
|
||||
|
||||
// When the worker is destroyed it should remove the connectivity
|
||||
// observer and event listener
|
||||
expectRemoveObserverAndListener();
|
||||
|
||||
worker.destroy();
|
||||
|
||||
// The file should have been deleted
|
||||
assertFalse(tempFile.exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelsApiCallWhenDestroyed() throws Exception {
|
||||
// When the worker is started it should check for data to send. As
|
||||
// there's data ready to send immediately, the worker should start a
|
||||
// connectivity check
|
||||
expectRunTaskOnIoExecutor();
|
||||
expectCheckForDataToSendAndStartConnectivityCheck();
|
||||
|
||||
worker.start();
|
||||
|
||||
// Create the temporary file so we can test that it gets deleted
|
||||
assertTrue(testDir.mkdirs());
|
||||
assertTrue(tempFile.createNewFile());
|
||||
|
||||
// When the connectivity check succeeds, the worker should write a file
|
||||
// and start an upload task
|
||||
expectRunTaskOnIoExecutor();
|
||||
AtomicReference<ApiCall> upload = new AtomicReference<>();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(mailboxFileManager).createAndWriteTempFileForUpload(
|
||||
with(contactId), with(any(OutgoingSessionRecord.class)));
|
||||
will(new DoAllAction(
|
||||
// Record some IDs as acked and sent
|
||||
new ConsumeArgumentAction<>(OutgoingSessionRecord.class, 1,
|
||||
record -> {
|
||||
record.onAckSent(singletonList(ackedId));
|
||||
record.onMessageSent(sentId);
|
||||
}),
|
||||
returnValue(tempFile)
|
||||
));
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(with(any(ApiCall.class)));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(upload, ApiCall.class, 0),
|
||||
returnValue(apiCall)
|
||||
));
|
||||
}});
|
||||
|
||||
worker.onConnectivityCheckSucceeded();
|
||||
|
||||
// When the worker is destroyed it should remove the connectivity
|
||||
// observer and event listener and cancel the upload task
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(apiCall).cancel();
|
||||
}});
|
||||
expectRemoveObserverAndListener();
|
||||
|
||||
worker.destroy();
|
||||
|
||||
// The file should have been deleted
|
||||
assertFalse(tempFile.exists());
|
||||
|
||||
// If the upload task runs anyway (cancellation came too late), it
|
||||
// should return early when it finds the state has changed
|
||||
assertFalse(upload.get().callApi());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchedulesWakeupWhenStartedIfDataIsNotReady()
|
||||
throws Exception {
|
||||
// When the worker is started it should check for data to send. As
|
||||
// the data isn't ready to send immediately, the worker should
|
||||
// schedule a wakeup
|
||||
expectRunTaskOnIoExecutor();
|
||||
AtomicReference<Runnable> wakeup = new AtomicReference<>();
|
||||
expectCheckForDataToSendAndScheduleWakeup(wakeup);
|
||||
|
||||
worker.start();
|
||||
|
||||
// When the wakeup task runs it should check for data to send
|
||||
expectCheckForDataToSendNoDataWaiting();
|
||||
|
||||
wakeup.get().run();
|
||||
|
||||
// When the worker is destroyed it should remove the connectivity
|
||||
// observer and event listener
|
||||
expectRemoveObserverAndListener();
|
||||
|
||||
worker.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelsWakeupIfDestroyedBeforeWakingUp() throws Exception {
|
||||
// When the worker is started it should check for data to send. As
|
||||
// the data isn't ready to send immediately, the worker should
|
||||
// schedule a wakeup
|
||||
expectRunTaskOnIoExecutor();
|
||||
AtomicReference<Runnable> wakeup = new AtomicReference<>();
|
||||
expectCheckForDataToSendAndScheduleWakeup(wakeup);
|
||||
|
||||
worker.start();
|
||||
|
||||
// When the worker is destroyed it should cancel the wakeup and
|
||||
// remove the connectivity observer and event listener
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(wakeupTask).cancel();
|
||||
}});
|
||||
expectRemoveObserverAndListener();
|
||||
|
||||
worker.destroy();
|
||||
|
||||
// If the wakeup task runs anyway (cancellation came too late), it
|
||||
// should return early without doing anything
|
||||
wakeup.get().run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelsWakeupIfEventIsReceivedBeforeWakingUp()
|
||||
throws Exception {
|
||||
// When the worker is started it should check for data to send. As
|
||||
// the data isn't ready to send immediately, the worker should
|
||||
// schedule a wakeup
|
||||
expectRunTaskOnIoExecutor();
|
||||
AtomicReference<Runnable> wakeup = new AtomicReference<>();
|
||||
expectCheckForDataToSendAndScheduleWakeup(wakeup);
|
||||
|
||||
worker.start();
|
||||
|
||||
// Before the wakeup task runs, the worker receives an event that
|
||||
// indicates new data may be available. The worker should cancel the
|
||||
// wakeup task and schedule a check for new data after a short delay
|
||||
AtomicReference<Runnable> check = new AtomicReference<>();
|
||||
expectScheduleCheck(check, CHECK_DELAY_MS);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(wakeupTask).cancel();
|
||||
}});
|
||||
|
||||
worker.eventOccurred(new MessageSharedEvent(newMessageId));
|
||||
|
||||
// If the wakeup task runs anyway (cancellation came too late), it
|
||||
// should return early when it finds the state has changed
|
||||
wakeup.get().run();
|
||||
|
||||
// Before the check task runs, the worker receives another event that
|
||||
// indicates new data may be available. The event should be ignored,
|
||||
// as a check for new data has already been scheduled
|
||||
worker.eventOccurred(new MessageSharedEvent(newMessageId));
|
||||
|
||||
// When the check task runs, it should check for new data
|
||||
expectCheckForDataToSendNoDataWaiting();
|
||||
|
||||
check.get().run();
|
||||
|
||||
// When the worker is destroyed it should remove the connectivity
|
||||
// observer and event listener
|
||||
expectRemoveObserverAndListener();
|
||||
|
||||
worker.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelsCheckWhenDestroyed() throws Exception {
|
||||
// When the worker is started it should check for data to send
|
||||
expectRunTaskOnIoExecutor();
|
||||
expectCheckForDataToSendNoDataWaiting();
|
||||
|
||||
worker.start();
|
||||
|
||||
// The worker receives an event that indicates new data may be
|
||||
// available. The worker should schedule a check for new data after
|
||||
// a short delay
|
||||
AtomicReference<Runnable> check = new AtomicReference<>();
|
||||
expectScheduleCheck(check, CHECK_DELAY_MS);
|
||||
|
||||
worker.eventOccurred(new MessageSharedEvent(newMessageId));
|
||||
|
||||
// When the worker is destroyed it should cancel the check and
|
||||
// remove the connectivity observer and event listener
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(checkTask).cancel();
|
||||
}});
|
||||
expectRemoveObserverAndListener();
|
||||
|
||||
worker.destroy();
|
||||
|
||||
// If the check runs anyway (cancellation came too late), it should
|
||||
// return early when it finds the state has changed
|
||||
check.get().run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetriesAfterDelayIfExceptionOccursWhileWritingFile()
|
||||
throws Exception {
|
||||
// When the worker is started it should check for data to send. As
|
||||
// there's data ready to send immediately, the worker should start a
|
||||
// connectivity check
|
||||
expectRunTaskOnIoExecutor();
|
||||
expectCheckForDataToSendAndStartConnectivityCheck();
|
||||
|
||||
worker.start();
|
||||
|
||||
// When the connectivity check succeeds, the worker should try to
|
||||
// write a file. This fails with an exception, so the worker should
|
||||
// retry by scheduling a check for new data after a short delay
|
||||
expectRunTaskOnIoExecutor();
|
||||
AtomicReference<Runnable> check = new AtomicReference<>();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(mailboxFileManager).createAndWriteTempFileForUpload(
|
||||
with(contactId), with(any(OutgoingSessionRecord.class)));
|
||||
will(throwException(new IOException())); // Oh noes!
|
||||
}});
|
||||
expectScheduleCheck(check, RETRY_DELAY_MS);
|
||||
|
||||
worker.onConnectivityCheckSucceeded();
|
||||
|
||||
// When the check task runs it should check for new data
|
||||
expectCheckForDataToSendNoDataWaiting();
|
||||
|
||||
check.get().run();
|
||||
|
||||
// When the worker is destroyed it should remove the connectivity
|
||||
// observer and event listener
|
||||
expectRemoveObserverAndListener();
|
||||
|
||||
worker.destroy();
|
||||
}
|
||||
|
||||
private void expectRunTaskOnIoExecutor() {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(ioExecutor).execute(with(any(Runnable.class)));
|
||||
will(new RunAction());
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectCheckForDataToSendNoDataWaiting() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transaction(with(true), withDbRunnable(txn));
|
||||
oneOf(db).containsAcksToSend(txn, contactId);
|
||||
will(returnValue(false));
|
||||
oneOf(db).getNextSendTime(txn, contactId, MAX_LATENCY);
|
||||
will(returnValue(Long.MAX_VALUE)); // No data waiting
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectCheckForDataToSendAndScheduleWakeup(
|
||||
AtomicReference<Runnable> wakeup) throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transaction(with(true), withDbRunnable(txn));
|
||||
oneOf(db).containsAcksToSend(txn, contactId);
|
||||
will(returnValue(false));
|
||||
oneOf(db).getNextSendTime(txn, contactId, MAX_LATENCY);
|
||||
will(returnValue(now + 1234L)); // Data waiting but not ready
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(taskScheduler).schedule(with(any(Runnable.class)),
|
||||
with(ioExecutor), with(1234L), with(MILLISECONDS));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(wakeup, Runnable.class, 0),
|
||||
returnValue(wakeupTask)
|
||||
));
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectCheckForDataToSendAndStartConnectivityCheck()
|
||||
throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transaction(with(true), withDbRunnable(txn));
|
||||
oneOf(db).containsAcksToSend(txn, contactId);
|
||||
will(returnValue(false));
|
||||
oneOf(db).getNextSendTime(txn, contactId, MAX_LATENCY);
|
||||
will(returnValue(0L)); // Data ready to send
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(connectivityChecker).checkConnectivity(mailboxProperties,
|
||||
worker);
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectScheduleCheck(AtomicReference<Runnable> check,
|
||||
long delay) {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(taskScheduler).schedule(with(any(Runnable.class)),
|
||||
with(ioExecutor), with(delay), with(MILLISECONDS));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(check, Runnable.class, 0),
|
||||
returnValue(checkTask)
|
||||
));
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectRemoveObserverAndListener() {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(connectivityChecker).removeObserver(worker);
|
||||
oneOf(eventBus).removeListener(worker);
|
||||
}});
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.db.TransactionManager;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxVersion;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.bramble.mailbox.ConnectivityChecker.ConnectivityObserver;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
@@ -15,8 +16,10 @@ import org.jmock.lib.action.DoAllAction;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS;
|
||||
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@@ -39,6 +42,8 @@ public class OwnMailboxConnectivityCheckerTest extends BrambleMockTestCase {
|
||||
private final MailboxProperties properties =
|
||||
getMailboxProperties(true, CLIENT_SUPPORTS);
|
||||
private final long now = System.currentTimeMillis();
|
||||
private final List<MailboxVersion> serverSupports =
|
||||
singletonList(new MailboxVersion(123, 456));
|
||||
|
||||
@Test
|
||||
public void testObserverIsCalledWhenCheckSucceeds() throws Exception {
|
||||
@@ -62,12 +67,13 @@ public class OwnMailboxConnectivityCheckerTest extends BrambleMockTestCase {
|
||||
// When the check succeeds, the success should be recorded in the DB
|
||||
// and the observer should be called
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(mailboxApi).checkStatus(properties);
|
||||
will(returnValue(true));
|
||||
oneOf(mailboxApi).getServerSupports(properties);
|
||||
will(returnValue(serverSupports));
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||
oneOf(mailboxSettingsManager).recordSuccessfulConnection(txn, now);
|
||||
oneOf(mailboxSettingsManager).recordSuccessfulConnection(txn, now,
|
||||
serverSupports);
|
||||
oneOf(observer).onConnectivityCheckSucceeded();
|
||||
}});
|
||||
|
||||
@@ -97,7 +103,7 @@ public class OwnMailboxConnectivityCheckerTest extends BrambleMockTestCase {
|
||||
// When the check fails, the failure should be recorded in the DB and
|
||||
// the observer should not be called
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(mailboxApi).checkStatus(properties);
|
||||
oneOf(mailboxApi).getServerSupports(properties);
|
||||
will(throwException(new IOException()));
|
||||
oneOf(clock).currentTimeMillis();
|
||||
will(returnValue(now));
|
||||
|
||||
@@ -0,0 +1,406 @@
|
||||
package org.briarproject.bramble.mailbox;
|
||||
|
||||
import org.briarproject.bramble.api.Cancellable;
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.contact.event.ContactAddedEvent;
|
||||
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.NoSuchContactException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxProperties;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
|
||||
import org.briarproject.bramble.api.mailbox.MailboxUpdateWithMailbox;
|
||||
import org.briarproject.bramble.mailbox.MailboxApi.MailboxContact;
|
||||
import org.briarproject.bramble.mailbox.MailboxApi.TolerableFailureException;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.CaptureArgumentAction;
|
||||
import org.briarproject.bramble.test.DbExpectations;
|
||||
import org.briarproject.bramble.test.RunAction;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.lib.action.DoAllAction;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS;
|
||||
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
|
||||
import static org.briarproject.bramble.test.TestUtils.getContact;
|
||||
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
public class OwnMailboxContactListWorkerTest extends BrambleMockTestCase {
|
||||
|
||||
private final Executor ioExecutor = context.mock(Executor.class);
|
||||
private final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||
private final EventBus eventBus = context.mock(EventBus.class);
|
||||
private final ConnectivityChecker connectivityChecker =
|
||||
context.mock(ConnectivityChecker.class);
|
||||
private final MailboxApiCaller mailboxApiCaller =
|
||||
context.mock(MailboxApiCaller.class);
|
||||
private final MailboxApi mailboxApi = context.mock(MailboxApi.class);
|
||||
private final MailboxUpdateManager mailboxUpdateManager =
|
||||
context.mock(MailboxUpdateManager.class);
|
||||
private final Cancellable apiCall = context.mock(Cancellable.class);
|
||||
|
||||
private final MailboxProperties mailboxProperties =
|
||||
getMailboxProperties(true, CLIENT_SUPPORTS);
|
||||
private final Contact contact1 = getContact(), contact2 = getContact();
|
||||
private final MailboxProperties contactProperties1 =
|
||||
getMailboxProperties(false, CLIENT_SUPPORTS);
|
||||
private final MailboxProperties contactProperties2 =
|
||||
getMailboxProperties(false, CLIENT_SUPPORTS);
|
||||
private final MailboxUpdateWithMailbox update1 =
|
||||
new MailboxUpdateWithMailbox(CLIENT_SUPPORTS, contactProperties1);
|
||||
private final MailboxUpdateWithMailbox update2 =
|
||||
new MailboxUpdateWithMailbox(CLIENT_SUPPORTS, contactProperties2);
|
||||
|
||||
private final OwnMailboxContactListWorker worker =
|
||||
new OwnMailboxContactListWorker(ioExecutor, db, eventBus,
|
||||
connectivityChecker, mailboxApiCaller, mailboxApi,
|
||||
mailboxUpdateManager, mailboxProperties);
|
||||
|
||||
@Test
|
||||
public void testChecksConnectivityWhenStartedAndRemovesObserverWhenDestroyed() {
|
||||
// When the worker is started it should start a connectivity check
|
||||
expectStartConnectivityCheck();
|
||||
|
||||
worker.start();
|
||||
|
||||
// When the worker is destroyed it should remove the connectivity
|
||||
// observer and event listener
|
||||
expectRemoveConnectivityObserverAndEventListener();
|
||||
|
||||
worker.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdatesContactListWhenConnectivityCheckSucceeds()
|
||||
throws Exception {
|
||||
// When the worker is started it should start a connectivity check
|
||||
expectStartConnectivityCheck();
|
||||
|
||||
worker.start();
|
||||
|
||||
// When the connectivity check succeeds, the worker should start a
|
||||
// task to fetch the remote contact list
|
||||
AtomicReference<ApiCall> fetchList = new AtomicReference<>();
|
||||
expectStartTaskToFetchRemoteContactList(fetchList);
|
||||
|
||||
worker.onConnectivityCheckSucceeded();
|
||||
|
||||
// When the fetch task runs it should fetch the remote contact list,
|
||||
// load the local contact list, and find the differences. Contact 2
|
||||
// needs to be added and contact 1 needs to be removed. The worker
|
||||
// should load the mailbox update for contact 2 and start a task to
|
||||
// add contact 2 to the mailbox
|
||||
expectFetchRemoteContactList(singletonList(contact1.getId()));
|
||||
expectRunTaskOnIoExecutor();
|
||||
expectLoadLocalContactList(singletonList(contact2));
|
||||
expectRunTaskOnIoExecutor();
|
||||
expectLoadMailboxUpdate(contact2, update2);
|
||||
AtomicReference<ApiCall> addContact = new AtomicReference<>();
|
||||
expectStartTaskToAddContact(addContact);
|
||||
|
||||
assertFalse(fetchList.get().callApi());
|
||||
|
||||
// When the add-contact task runs it should add contact 2 to the
|
||||
// mailbox, then continue with the next update
|
||||
AtomicReference<MailboxContact> added = new AtomicReference<>();
|
||||
expectAddContactToMailbox(added);
|
||||
AtomicReference<ApiCall> removeContact = new AtomicReference<>();
|
||||
expectStartTaskToRemoveContact(removeContact);
|
||||
|
||||
assertFalse(addContact.get().callApi());
|
||||
|
||||
// Check that the added contact has the expected properties
|
||||
MailboxContact expected = new MailboxContact(contact2.getId(),
|
||||
contactProperties2.getAuthToken(),
|
||||
requireNonNull(contactProperties2.getInboxId()),
|
||||
requireNonNull(contactProperties2.getOutboxId()));
|
||||
assertMailboxContactEquals(expected, added.get());
|
||||
|
||||
// When the remove-contact task runs it should remove contact 1 from
|
||||
// the mailbox
|
||||
expectRemoveContactFromMailbox(contact1);
|
||||
|
||||
assertFalse(removeContact.get().callApi());
|
||||
|
||||
// When the worker is destroyed it should remove the connectivity
|
||||
// observer and event listener
|
||||
expectRemoveConnectivityObserverAndEventListener();
|
||||
|
||||
worker.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandlesEventsAfterMakingInitialUpdates() throws Exception {
|
||||
// When the worker is started it should start a connectivity check
|
||||
expectStartConnectivityCheck();
|
||||
|
||||
worker.start();
|
||||
|
||||
// When the connectivity check succeeds, the worker should start a
|
||||
// task to fetch the remote contact list
|
||||
AtomicReference<ApiCall> fetchList = new AtomicReference<>();
|
||||
expectStartTaskToFetchRemoteContactList(fetchList);
|
||||
|
||||
worker.onConnectivityCheckSucceeded();
|
||||
|
||||
// When the fetch task runs it should fetch the remote contact list,
|
||||
// load the local contact list, and find the differences. The lists
|
||||
// are the same, so the worker should wait for changes
|
||||
expectFetchRemoteContactList(emptyList());
|
||||
expectRunTaskOnIoExecutor();
|
||||
expectLoadLocalContactList(emptyList());
|
||||
|
||||
assertFalse(fetchList.get().callApi());
|
||||
|
||||
// When a contact is added, the worker should load the contact's
|
||||
// mailbox update and start a task to add the contact to the mailbox
|
||||
expectRunTaskOnIoExecutor();
|
||||
expectLoadMailboxUpdate(contact1, update1);
|
||||
AtomicReference<ApiCall> addContact = new AtomicReference<>();
|
||||
expectStartTaskToAddContact(addContact);
|
||||
|
||||
worker.eventOccurred(new ContactAddedEvent(contact1.getId(), true));
|
||||
|
||||
// When the add-contact task runs it should add contact 1 to the
|
||||
// mailbox
|
||||
AtomicReference<MailboxContact> added = new AtomicReference<>();
|
||||
expectAddContactToMailbox(added);
|
||||
|
||||
assertFalse(addContact.get().callApi());
|
||||
|
||||
// Check that the added contact has the expected properties
|
||||
MailboxContact expected = new MailboxContact(contact1.getId(),
|
||||
contactProperties1.getAuthToken(),
|
||||
requireNonNull(contactProperties1.getInboxId()),
|
||||
requireNonNull(contactProperties1.getOutboxId()));
|
||||
assertMailboxContactEquals(expected, added.get());
|
||||
|
||||
// When the contact is removed again, the worker should start a task
|
||||
// to remove the contact from the mailbox
|
||||
expectRunTaskOnIoExecutor();
|
||||
AtomicReference<ApiCall> removeContact = new AtomicReference<>();
|
||||
expectStartTaskToRemoveContact(removeContact);
|
||||
|
||||
worker.eventOccurred(new ContactRemovedEvent(contact1.getId()));
|
||||
|
||||
// When the remove-contact task runs it should remove the contact from
|
||||
// the mailbox
|
||||
expectRemoveContactFromMailbox(contact1);
|
||||
|
||||
assertFalse(removeContact.get().callApi());
|
||||
|
||||
// When the worker is destroyed it should remove the connectivity
|
||||
// observer and event listener
|
||||
expectRemoveConnectivityObserverAndEventListener();
|
||||
|
||||
worker.destroy();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testHandlesNoSuchContactException() throws Exception {
|
||||
// When the worker is started it should start a connectivity check
|
||||
expectStartConnectivityCheck();
|
||||
|
||||
worker.start();
|
||||
|
||||
// When the connectivity check succeeds, the worker should start a
|
||||
// task to fetch the remote contact list
|
||||
AtomicReference<ApiCall> fetchList = new AtomicReference<>();
|
||||
expectStartTaskToFetchRemoteContactList(fetchList);
|
||||
|
||||
worker.onConnectivityCheckSucceeded();
|
||||
|
||||
// When the fetch task runs it should fetch the remote contact list,
|
||||
// load the local contact list, and find the differences. Contact 1
|
||||
// needs to be added, so the worker should submit a task to the
|
||||
// IO executor to load the contact's mailbox update
|
||||
expectFetchRemoteContactList(emptyList());
|
||||
expectRunTaskOnIoExecutor();
|
||||
expectLoadLocalContactList(singletonList(contact1));
|
||||
AtomicReference<Runnable> loadUpdate = new AtomicReference<>();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(ioExecutor).execute(with(any(Runnable.class)));
|
||||
will(new CaptureArgumentAction<>(loadUpdate, Runnable.class, 0));
|
||||
}});
|
||||
|
||||
assertFalse(fetchList.get().callApi());
|
||||
|
||||
// Before the contact's mailbox update can be loaded, the contact
|
||||
// is removed
|
||||
worker.eventOccurred(new ContactRemovedEvent(contact1.getId()));
|
||||
|
||||
// When the load-update task runs, a NoSuchContactException is thrown.
|
||||
// The worker should abandon adding the contact and move on to the
|
||||
// next update, which is the removal of the same contact. The worker
|
||||
// should start a task to remove the contact from the mailbox
|
||||
Transaction txn = new Transaction(null, false);
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(mailboxUpdateManager).getLocalUpdate(txn, contact1.getId());
|
||||
will(throwException(new NoSuchContactException()));
|
||||
}});
|
||||
AtomicReference<ApiCall> removeContact = new AtomicReference<>();
|
||||
expectStartTaskToRemoveContact(removeContact);
|
||||
|
||||
loadUpdate.get().run();
|
||||
|
||||
// When the remove-contact task runs it should remove the contact from
|
||||
// the mailbox. The contact was never added, so the call throws a
|
||||
// TolerableFailureException
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(mailboxApi).deleteContact(mailboxProperties,
|
||||
contact1.getId());
|
||||
will(throwException(new TolerableFailureException()));
|
||||
}});
|
||||
|
||||
assertFalse(removeContact.get().callApi());
|
||||
|
||||
// When the worker is destroyed it should remove the connectivity
|
||||
// observer and event listener
|
||||
expectRemoveConnectivityObserverAndEventListener();
|
||||
|
||||
worker.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelsApiCallWhenDestroyed() {
|
||||
// When the worker is started it should start a connectivity check
|
||||
expectStartConnectivityCheck();
|
||||
|
||||
worker.start();
|
||||
|
||||
// When the connectivity check succeeds, the worker should start a
|
||||
// task to fetch the remote contact list
|
||||
AtomicReference<ApiCall> fetchList = new AtomicReference<>();
|
||||
expectStartTaskToFetchRemoteContactList(fetchList);
|
||||
|
||||
worker.onConnectivityCheckSucceeded();
|
||||
|
||||
// The worker is destroyed before the task runs. The worker should
|
||||
// cancel the task remove the connectivity observer and event listener
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(apiCall).cancel();
|
||||
}});
|
||||
expectRemoveConnectivityObserverAndEventListener();
|
||||
|
||||
worker.destroy();
|
||||
}
|
||||
|
||||
private void expectStartConnectivityCheck() {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(connectivityChecker).checkConnectivity(
|
||||
with(mailboxProperties), with(worker));
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectRemoveConnectivityObserverAndEventListener() {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(connectivityChecker).removeObserver(worker);
|
||||
oneOf(eventBus).removeListener(worker);
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectStartTaskToFetchRemoteContactList(
|
||||
AtomicReference<ApiCall> task) {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(with(any(ApiCall.class)));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(task, ApiCall.class, 0),
|
||||
returnValue(apiCall)
|
||||
));
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectFetchRemoteContactList(List<ContactId> remote)
|
||||
throws Exception {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(mailboxApi).getContacts(mailboxProperties);
|
||||
will(returnValue(remote));
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectLoadLocalContactList(List<Contact> local)
|
||||
throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transaction(with(true), withDbRunnable(txn));
|
||||
oneOf(db).getContacts(txn);
|
||||
will(returnValue(local));
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectLoadMailboxUpdate(Contact c, MailboxUpdate update)
|
||||
throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true),
|
||||
withDbCallable(txn));
|
||||
oneOf(mailboxUpdateManager).getLocalUpdate(txn, c.getId());
|
||||
will(returnValue(update));
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectStartTaskToAddContact(AtomicReference<ApiCall> task) {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(with(any(ApiCall.class)));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(task, ApiCall.class, 0),
|
||||
returnValue(apiCall)
|
||||
));
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectAddContactToMailbox(
|
||||
AtomicReference<MailboxContact> added) throws Exception {
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(mailboxApi).addContact(with(mailboxProperties),
|
||||
with(any(MailboxContact.class)));
|
||||
will(new CaptureArgumentAction<>(added, MailboxContact.class, 1));
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectStartTaskToRemoveContact(AtomicReference<ApiCall> task) {
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(mailboxApiCaller).retryWithBackoff(with(any(ApiCall.class)));
|
||||
will(new DoAllAction(
|
||||
new CaptureArgumentAction<>(task, ApiCall.class, 0),
|
||||
returnValue(apiCall)
|
||||
));
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectRemoveContactFromMailbox(Contact c) throws Exception {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(mailboxApi).deleteContact(mailboxProperties, c.getId());
|
||||
}});
|
||||
}
|
||||
|
||||
private void expectRunTaskOnIoExecutor() {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(ioExecutor).execute(with(any(Runnable.class)));
|
||||
will(new RunAction());
|
||||
}});
|
||||
}
|
||||
|
||||
private void assertMailboxContactEquals(MailboxContact expected,
|
||||
MailboxContact actual) {
|
||||
assertEquals(expected.contactId, actual.contactId);
|
||||
assertEquals(expected.token, actual.token);
|
||||
assertEquals(expected.inboxId, actual.inboxId);
|
||||
assertEquals(expected.outboxId, actual.outboxId);
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.CaptureArgumentAction;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.lib.action.DoAllAction;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -38,13 +37,9 @@ public class TorReachabilityMonitorImplTest extends BrambleMockTestCase {
|
||||
private final TorReachabilityObserver observer =
|
||||
context.mock(TorReachabilityObserver.class);
|
||||
|
||||
private TorReachabilityMonitorImpl monitor;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
monitor = new TorReachabilityMonitorImpl(ioExecutor, taskScheduler,
|
||||
pluginManager, eventBus);
|
||||
}
|
||||
private final TorReachabilityMonitorImpl monitor =
|
||||
new TorReachabilityMonitorImpl(ioExecutor, taskScheduler,
|
||||
pluginManager, eventBus);
|
||||
|
||||
@Test
|
||||
public void testSchedulesTaskWhenStartedIfTorIsActive() {
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.briarproject.bramble.test.ImmediateExecutor;
|
||||
import org.briarproject.bramble.test.RunAction;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.imposters.ByteBuddyClassImposteriser;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
@@ -59,22 +58,18 @@ public class PollerImplTest extends BrambleMockTestCase {
|
||||
private final SecureRandom random;
|
||||
|
||||
private final Executor ioExecutor = new ImmediateExecutor();
|
||||
private final Executor wakefulIoExecutor = new ImmediateExecutor();
|
||||
private final TransportId transportId = getTransportId();
|
||||
private final ContactId contactId = getContactId();
|
||||
private final TransportProperties properties = new TransportProperties();
|
||||
private final int pollingInterval = 60 * 1000;
|
||||
private final long now = System.currentTimeMillis();
|
||||
|
||||
private PollerImpl poller;
|
||||
private final PollerImpl poller;
|
||||
|
||||
public PollerImplTest() {
|
||||
context.setImposteriser(ByteBuddyClassImposteriser.INSTANCE);
|
||||
random = context.mock(SecureRandom.class);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
Executor wakefulIoExecutor = new ImmediateExecutor();
|
||||
poller = new PollerImpl(ioExecutor, wakefulIoExecutor, scheduler,
|
||||
connectionManager, connectionRegistry, pluginManager,
|
||||
transportPropertyManager, random, clock);
|
||||
|
||||
@@ -12,7 +12,6 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||
import org.briarproject.bramble.api.settings.Settings;
|
||||
import org.briarproject.bramble.test.BrambleTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -46,13 +45,11 @@ public class LanTcpPluginTest extends BrambleTestCase {
|
||||
|
||||
private final Backoff backoff = new TestBackoff();
|
||||
private final ExecutorService ioExecutor = newCachedThreadPool();
|
||||
private final Callback callback = new Callback();
|
||||
|
||||
private Callback callback = null;
|
||||
private LanTcpPlugin plugin = null;
|
||||
private final LanTcpPlugin plugin;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
callback = new Callback();
|
||||
public LanTcpPluginTest() {
|
||||
plugin = new LanTcpPlugin(ioExecutor, ioExecutor, backoff, callback,
|
||||
0, 0, 1000) {
|
||||
@Override
|
||||
|
||||
@@ -34,7 +34,6 @@ import org.briarproject.bramble.test.DbExpectations;
|
||||
import org.briarproject.bramble.test.ImmediateExecutor;
|
||||
import org.briarproject.bramble.test.PredicateMatcher;
|
||||
import org.jmock.Expectations;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Random;
|
||||
@@ -93,14 +92,10 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
|
||||
getTransportProperties(3);
|
||||
private final boolean alice = new Random().nextBoolean();
|
||||
|
||||
private RendezvousPollerImpl rendezvousPoller;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
rendezvousPoller = new RendezvousPollerImpl(ioExecutor, scheduler, db,
|
||||
identityManager, transportCrypto, rendezvousCrypto,
|
||||
pluginManager, connectionManager, eventBus, clock);
|
||||
}
|
||||
private final RendezvousPollerImpl rendezvousPoller =
|
||||
new RendezvousPollerImpl(ioExecutor, scheduler, db,
|
||||
identityManager, transportCrypto, rendezvousCrypto,
|
||||
pluginManager, connectionManager, eventBus, clock);
|
||||
|
||||
@Test
|
||||
public void testAddsPendingContactsAndSchedulesPollingAtStartup()
|
||||
|
||||
@@ -6,10 +6,10 @@ import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
import org.briarproject.bramble.api.sync.Ack;
|
||||
import org.briarproject.bramble.api.sync.DeferredSendHandler;
|
||||
import org.briarproject.bramble.api.sync.GroupId;
|
||||
import org.briarproject.bramble.api.sync.Message;
|
||||
import org.briarproject.bramble.api.sync.MessageId;
|
||||
import org.briarproject.bramble.api.sync.OutgoingSessionRecord;
|
||||
import org.briarproject.bramble.api.sync.SyncRecordWriter;
|
||||
import org.briarproject.bramble.api.sync.Versions;
|
||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||
@@ -30,6 +30,7 @@ import static org.briarproject.bramble.test.TestUtils.getContactId;
|
||||
import static org.briarproject.bramble.test.TestUtils.getMessage;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class MailboxOutgoingSessionTest extends BrambleMockTestCase {
|
||||
|
||||
@@ -40,8 +41,6 @@ public class MailboxOutgoingSessionTest extends BrambleMockTestCase {
|
||||
private final StreamWriter streamWriter = context.mock(StreamWriter.class);
|
||||
private final SyncRecordWriter recordWriter =
|
||||
context.mock(SyncRecordWriter.class);
|
||||
private final DeferredSendHandler deferredSendHandler =
|
||||
context.mock(DeferredSendHandler.class);
|
||||
|
||||
private final ContactId contactId = getContactId();
|
||||
private final TransportId transportId = getTransportId();
|
||||
@@ -53,9 +52,10 @@ public class MailboxOutgoingSessionTest extends BrambleMockTestCase {
|
||||
|
||||
@Test
|
||||
public void testNothingToSend() throws Exception {
|
||||
OutgoingSessionRecord sessionRecord = new OutgoingSessionRecord();
|
||||
MailboxOutgoingSession session = new MailboxOutgoingSession(db,
|
||||
eventBus, contactId, transportId, MAX_LATENCY,
|
||||
streamWriter, recordWriter, deferredSendHandler,
|
||||
streamWriter, recordWriter, sessionRecord,
|
||||
MAX_FILE_PAYLOAD_BYTES);
|
||||
|
||||
Transaction noAckIdTxn = new Transaction(null, true);
|
||||
@@ -92,13 +92,17 @@ public class MailboxOutgoingSessionTest extends BrambleMockTestCase {
|
||||
}});
|
||||
|
||||
session.run();
|
||||
|
||||
assertEquals(emptyList(), sessionRecord.getAckedIds());
|
||||
assertEquals(emptyList(), sessionRecord.getSentIds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSomethingToSend() throws Exception {
|
||||
OutgoingSessionRecord sessionRecord = new OutgoingSessionRecord();
|
||||
MailboxOutgoingSession session = new MailboxOutgoingSession(db,
|
||||
eventBus, contactId, transportId, MAX_LATENCY,
|
||||
streamWriter, recordWriter, deferredSendHandler,
|
||||
streamWriter, recordWriter, sessionRecord,
|
||||
MAX_FILE_PAYLOAD_BYTES);
|
||||
|
||||
Transaction ackIdTxn = new Transaction(null, true);
|
||||
@@ -127,8 +131,6 @@ public class MailboxOutgoingSessionTest extends BrambleMockTestCase {
|
||||
oneOf(recordWriter).getBytesWritten();
|
||||
will(returnValue((long) versionRecordBytes));
|
||||
oneOf(recordWriter).writeAck(with(any(Ack.class)));
|
||||
oneOf(deferredSendHandler)
|
||||
.onAckSent(singletonList(message.getId()));
|
||||
// No more messages to ack
|
||||
oneOf(db).transactionWithResult(with(true),
|
||||
withDbCallable(noAckIdTxn));
|
||||
@@ -150,7 +152,6 @@ public class MailboxOutgoingSessionTest extends BrambleMockTestCase {
|
||||
MAX_LATENCY, false);
|
||||
will(returnValue(message1));
|
||||
oneOf(recordWriter).writeMessage(message1);
|
||||
oneOf(deferredSendHandler).onMessageSent(message1.getId());
|
||||
// Send the end of stream marker
|
||||
oneOf(streamWriter).sendEndOfStream();
|
||||
// Remove listener
|
||||
@@ -158,6 +159,11 @@ public class MailboxOutgoingSessionTest extends BrambleMockTestCase {
|
||||
}});
|
||||
|
||||
session.run();
|
||||
|
||||
assertEquals(singletonList(message.getId()),
|
||||
sessionRecord.getAckedIds());
|
||||
assertEquals(singletonList(message1.getId()),
|
||||
sessionRecord.getSentIds());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -167,9 +173,10 @@ public class MailboxOutgoingSessionTest extends BrambleMockTestCase {
|
||||
long capacity = RECORD_HEADER_BYTES + MessageId.LENGTH * MAX_MESSAGE_IDS
|
||||
+ RECORD_HEADER_BYTES + MessageId.LENGTH + MessageId.LENGTH - 1;
|
||||
|
||||
OutgoingSessionRecord sessionRecord = new OutgoingSessionRecord();
|
||||
MailboxOutgoingSession session = new MailboxOutgoingSession(db,
|
||||
eventBus, contactId, transportId, MAX_LATENCY,
|
||||
streamWriter, recordWriter, deferredSendHandler, capacity);
|
||||
streamWriter, recordWriter, sessionRecord, capacity);
|
||||
|
||||
Transaction ackIdTxn1 = new Transaction(null, true);
|
||||
Transaction ackIdTxn2 = new Transaction(null, true);
|
||||
@@ -184,6 +191,9 @@ public class MailboxOutgoingSessionTest extends BrambleMockTestCase {
|
||||
}
|
||||
List<MessageId> idsInSecondAck =
|
||||
singletonList(new MessageId(getRandomId()));
|
||||
List<MessageId> allIds = new ArrayList<>(MAX_MESSAGE_IDS + 1);
|
||||
allIds.addAll(idsInFirstAck);
|
||||
allIds.addAll(idsInSecondAck);
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
// Add listener
|
||||
@@ -200,7 +210,6 @@ public class MailboxOutgoingSessionTest extends BrambleMockTestCase {
|
||||
will(returnValue(idsInFirstAck));
|
||||
// Send the first ack record
|
||||
oneOf(recordWriter).writeAck(with(any(Ack.class)));
|
||||
oneOf(deferredSendHandler).onAckSent(idsInFirstAck);
|
||||
// Calculate remaining capacity for acks
|
||||
oneOf(recordWriter).getBytesWritten();
|
||||
will(returnValue((long) versionRecordBytes + firstAckRecordBytes));
|
||||
@@ -211,7 +220,6 @@ public class MailboxOutgoingSessionTest extends BrambleMockTestCase {
|
||||
will(returnValue(idsInSecondAck));
|
||||
// Send the second ack record
|
||||
oneOf(recordWriter).writeAck(with(any(Ack.class)));
|
||||
oneOf(deferredSendHandler).onAckSent(idsInSecondAck);
|
||||
// Not enough capacity left for another ack
|
||||
oneOf(recordWriter).getBytesWritten();
|
||||
will(returnValue((long) versionRecordBytes + firstAckRecordBytes
|
||||
@@ -227,5 +235,8 @@ public class MailboxOutgoingSessionTest extends BrambleMockTestCase {
|
||||
}});
|
||||
|
||||
session.run();
|
||||
|
||||
assertEquals(allIds, sessionRecord.getAckedIds());
|
||||
assertEquals(emptyList(), sessionRecord.getSentIds());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import org.briarproject.bramble.api.sync.SyncRecordReader;
|
||||
import org.briarproject.bramble.api.sync.Versions;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.jmock.Expectations;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -44,12 +43,8 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
|
||||
context.mock(MessageFactory.class);
|
||||
private final RecordReader recordReader = context.mock(RecordReader.class);
|
||||
|
||||
private SyncRecordReader reader;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
reader = new SyncRecordReaderImpl(messageFactory, recordReader);
|
||||
}
|
||||
private final SyncRecordReader reader =
|
||||
new SyncRecordReaderImpl(messageFactory, recordReader);
|
||||
|
||||
@Test
|
||||
public void testNoFormatExceptionIfAckIsMaximumSize() throws Exception {
|
||||
|
||||
@@ -20,7 +20,6 @@ import org.briarproject.bramble.api.sync.validation.MessageValidator;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.DbExpectations;
|
||||
import org.briarproject.bramble.test.ImmediateExecutor;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -70,11 +69,10 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
|
||||
private final MessageContext validResultWithDependencies =
|
||||
new MessageContext(metadata, singletonList(messageId1));
|
||||
|
||||
private ValidationManagerImpl vm;
|
||||
private final ValidationManagerImpl vm =
|
||||
new ValidationManagerImpl(db, dbExecutor, validationExecutor);
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
vm = new ValidationManagerImpl(db, dbExecutor, validationExecutor);
|
||||
public ValidationManagerImplTest() {
|
||||
vm.registerMessageValidator(clientId, majorVersion, validator);
|
||||
vm.registerIncomingMessageHook(clientId, majorVersion, hook);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.briarproject.bramble.test;
|
||||
|
||||
import org.briarproject.bramble.api.Consumer;
|
||||
import org.hamcrest.Description;
|
||||
import org.jmock.api.Action;
|
||||
import org.jmock.api.Invocation;
|
||||
|
||||
public class ConsumeArgumentAction<T> implements Action {
|
||||
|
||||
private final Class<T> capturedClass;
|
||||
private final int index;
|
||||
private final Consumer<T> consumer;
|
||||
|
||||
public ConsumeArgumentAction(Class<T> capturedClass, int index,
|
||||
Consumer<T> consumer) {
|
||||
this.capturedClass = capturedClass;
|
||||
this.index = index;
|
||||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Invocation invocation) {
|
||||
consumer.accept(capturedClass.cast(invocation.getParameter(index)));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("passes an argument to a consumer");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import org.hamcrest.Description;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.api.Action;
|
||||
import org.jmock.api.Invocation;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -72,13 +71,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
|
||||
private final SecretKey rootKey = getSecretKey();
|
||||
private final Random random = new Random();
|
||||
|
||||
private TransportKeyManager transportKeyManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
transportKeyManager = new TransportKeyManagerImpl(db, transportCrypto,
|
||||
dbExecutor, scheduler, clock, transportId, maxLatency);
|
||||
}
|
||||
private final TransportKeyManager transportKeyManager =
|
||||
new TransportKeyManagerImpl(db, transportCrypto, dbExecutor,
|
||||
scheduler, clock, transportId, maxLatency);
|
||||
|
||||
@Test
|
||||
public void testKeysAreUpdatedAtStartup() throws Exception {
|
||||
|
||||
@@ -4,7 +4,6 @@ import org.briarproject.bramble.api.plugin.PluginCallback;
|
||||
import org.briarproject.bramble.api.properties.TransportProperties;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.jmock.Expectations;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -25,12 +24,8 @@ public class ModemPluginTest extends BrambleMockTestCase {
|
||||
private final PluginCallback callback = context.mock(PluginCallback.class);
|
||||
private final Modem modem = context.mock(Modem.class);
|
||||
|
||||
private ModemPlugin plugin;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
plugin = new ModemPlugin(modemFactory, serialPortList, callback, 0);
|
||||
}
|
||||
private final ModemPlugin plugin =
|
||||
new ModemPlugin(modemFactory, serialPortList, callback, 0);
|
||||
|
||||
@Test
|
||||
public void testModemCreation() throws Exception {
|
||||
|
||||
@@ -26,8 +26,8 @@ android {
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 30
|
||||
versionCode 10408
|
||||
versionName "1.4.8"
|
||||
versionCode 10409
|
||||
versionName "1.4.9"
|
||||
applicationId "org.briarproject.briar.android"
|
||||
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
@@ -100,7 +100,7 @@ dependencies {
|
||||
implementation project(path: ':briar-core', configuration: 'default')
|
||||
implementation project(path: ':bramble-core', configuration: 'default')
|
||||
implementation project(':bramble-android')
|
||||
implementation 'org.briarproject:dont-kill-me-lib:0.2.2'
|
||||
implementation 'org.briarproject:dont-kill-me-lib:0.2.5'
|
||||
|
||||
implementation 'androidx.fragment:fragment:1.3.4'
|
||||
implementation 'androidx.preference:preference:1.1.1'
|
||||
|
||||
@@ -493,9 +493,6 @@
|
||||
|
||||
<queries>
|
||||
<package android:name="info.guardianproject.ripple" />
|
||||
<package android:name="com.huawei.systemmanager" />
|
||||
<package android:name="com.huawei.powergenie" />
|
||||
<package android:name="com.evenwell.PowerMonitor" />
|
||||
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
@@ -32,7 +32,8 @@ public class DozeFragment extends SetupFragment
|
||||
private DozeView dozeView;
|
||||
private HuaweiProtectedAppsView huaweiProtectedAppsView;
|
||||
private HuaweiAppLaunchView huaweiAppLaunchView;
|
||||
private XiaomiView xiaomiView;
|
||||
private XiaomiRecentAppsView xiaomiRecentAppsView;
|
||||
private XiaomiLockAppsView xiaomiLockAppsView;
|
||||
private Button next;
|
||||
private boolean secondAttempt = false;
|
||||
|
||||
@@ -54,8 +55,10 @@ public class DozeFragment extends SetupFragment
|
||||
huaweiProtectedAppsView.setOnCheckedChangedListener(this);
|
||||
huaweiAppLaunchView = v.findViewById(R.id.huaweiAppLaunchView);
|
||||
huaweiAppLaunchView.setOnCheckedChangedListener(this);
|
||||
xiaomiView = v.findViewById(R.id.xiaomiView);
|
||||
xiaomiView.setOnCheckedChangedListener(this);
|
||||
xiaomiRecentAppsView = v.findViewById(R.id.xiaomiRecentAppsView);
|
||||
xiaomiRecentAppsView.setOnCheckedChangedListener(this);
|
||||
xiaomiLockAppsView = v.findViewById(R.id.xiaomiLockAppsView);
|
||||
xiaomiLockAppsView.setOnCheckedChangedListener(this);
|
||||
next = v.findViewById(R.id.next);
|
||||
ProgressBar progressBar = v.findViewById(R.id.progress);
|
||||
|
||||
@@ -102,7 +105,8 @@ public class DozeFragment extends SetupFragment
|
||||
next.setEnabled(dozeView.isChecked() &&
|
||||
huaweiProtectedAppsView.isChecked() &&
|
||||
huaweiAppLaunchView.isChecked() &&
|
||||
xiaomiView.isChecked());
|
||||
xiaomiRecentAppsView.isChecked() &&
|
||||
xiaomiLockAppsView.isChecked());
|
||||
}
|
||||
|
||||
@SuppressLint("BatteryLife")
|
||||
|
||||
@@ -50,7 +50,7 @@ class DozeView extends PowerView {
|
||||
onButtonClickListener.run();
|
||||
}
|
||||
|
||||
public void setOnButtonClickListener(Runnable runnable) {
|
||||
void setOnButtonClickListener(Runnable runnable) {
|
||||
onButtonClickListener = runnable;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package org.briarproject.briar.android.account;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import static android.widget.Toast.LENGTH_LONG;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static java.util.logging.Logger.getLogger;
|
||||
import static org.briarproject.android.dontkillmelib.XiaomiUtils.getXiaomiLockAppsIntent;
|
||||
import static org.briarproject.android.dontkillmelib.XiaomiUtils.xiaomiLockAppsNeedsToBeShown;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
|
||||
@UiThread
|
||||
@NotNullByDefault
|
||||
class XiaomiLockAppsView extends PowerView {
|
||||
|
||||
private static final Logger LOG =
|
||||
getLogger(XiaomiLockAppsView.class.getName());
|
||||
|
||||
public XiaomiLockAppsView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public XiaomiLockAppsView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public XiaomiLockAppsView(Context context, @Nullable AttributeSet attrs,
|
||||
int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setText(R.string.dnkm_xiaomi_lock_apps_text);
|
||||
setButtonText(R.string.dnkm_xiaomi_lock_apps_button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsToBeShown() {
|
||||
return xiaomiLockAppsNeedsToBeShown(getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
@StringRes
|
||||
protected int getHelpText() {
|
||||
return R.string.dnkm_xiaomi_lock_apps_help;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onButtonClick() {
|
||||
try {
|
||||
getContext().startActivity(getXiaomiLockAppsIntent());
|
||||
setChecked(true);
|
||||
return;
|
||||
} catch (SecurityException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
Toast.makeText(getContext(),
|
||||
R.string.dnkm_xiaomi_lock_apps_error_toast,
|
||||
LENGTH_LONG).show();
|
||||
// Let the user continue with setup
|
||||
setChecked(true);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.briarproject.briar.android.account;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
@@ -12,23 +11,23 @@ import javax.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import static org.briarproject.android.dontkillmelib.XiaomiUtils.isMiuiTenOrLater;
|
||||
import static org.briarproject.android.dontkillmelib.XiaomiUtils.isXiaomiOrRedmiDevice;
|
||||
import static org.briarproject.android.dontkillmelib.XiaomiUtils.isMiuiVersionAtLeast;
|
||||
import static org.briarproject.android.dontkillmelib.XiaomiUtils.xiaomiRecentAppsNeedsToBeShown;
|
||||
import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog;
|
||||
|
||||
@UiThread
|
||||
@NotNullByDefault
|
||||
class XiaomiView extends PowerView {
|
||||
class XiaomiRecentAppsView extends PowerView {
|
||||
|
||||
public XiaomiView(Context context) {
|
||||
public XiaomiRecentAppsView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public XiaomiView(Context context, @Nullable AttributeSet attrs) {
|
||||
public XiaomiRecentAppsView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public XiaomiView(Context context, @Nullable AttributeSet attrs,
|
||||
public XiaomiRecentAppsView(Context context, @Nullable AttributeSet attrs,
|
||||
int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setText(R.string.dnkm_xiaomi_text);
|
||||
@@ -37,7 +36,7 @@ class XiaomiView extends PowerView {
|
||||
|
||||
@Override
|
||||
public boolean needsToBeShown() {
|
||||
return isXiaomiOrRedmiDevice();
|
||||
return xiaomiRecentAppsNeedsToBeShown();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,7 +47,7 @@ class XiaomiView extends PowerView {
|
||||
|
||||
@Override
|
||||
protected void onButtonClick() {
|
||||
int bodyRes = isMiuiTenOrLater()
|
||||
int bodyRes = isMiuiVersionAtLeast(10, 0)
|
||||
? R.string.dnkm_xiaomi_dialog_body_new
|
||||
: R.string.dnkm_xiaomi_dialog_body_old;
|
||||
showOnboardingDialog(getContext(), getContext().getString(bodyRes));
|
||||
@@ -25,6 +25,7 @@ import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
@@ -104,7 +105,7 @@ public abstract class BriarActivity extends BaseActivity {
|
||||
LOG.info("Not signed in, launching StartupActivity");
|
||||
Intent i = new Intent(this, StartupActivity.class);
|
||||
startActivityForResult(i, REQUEST_PASSWORD);
|
||||
} else if (lockManager.isLocked() && !isFinishing()) {
|
||||
} else if (SDK_INT >= 21 && lockManager.isLocked() && !isFinishing()) {
|
||||
// Also check that the activity isn't finishing already.
|
||||
// This is possible if we finished in onActivityResult().
|
||||
// Launching another UnlockActivity would cause a loop.
|
||||
@@ -115,10 +116,7 @@ public abstract class BriarActivity extends BaseActivity {
|
||||
briarController.hasDozed(new UiResultHandler<Boolean>(this) {
|
||||
@Override
|
||||
public void onResultUi(Boolean result) {
|
||||
if (result) {
|
||||
showDozeDialog(getString(R.string.dnkm_warning_dozed,
|
||||
getString(R.string.app_name)));
|
||||
}
|
||||
if (result) showDozeDialog(R.string.dnkm_warning_dozed_1);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -175,7 +173,7 @@ public abstract class BriarActivity extends BaseActivity {
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
protected void showDozeDialog(String message) {
|
||||
protected void showDozeDialog(@StringRes int message) {
|
||||
AlertDialog.Builder b =
|
||||
new AlertDialog.Builder(this, R.style.BriarDialogTheme);
|
||||
b.setMessage(message);
|
||||
|
||||
@@ -175,13 +175,8 @@ public class AddNearbyContactActivity extends BriarActivity
|
||||
showErrorFragment();
|
||||
} else {
|
||||
String msg;
|
||||
if (qrCodeTooOld) {
|
||||
msg = getString(R.string.qr_code_too_old,
|
||||
getString(R.string.app_name));
|
||||
} else {
|
||||
msg = getString(R.string.qr_code_too_new,
|
||||
getString(R.string.app_name));
|
||||
}
|
||||
if (qrCodeTooOld) msg = getString(R.string.qr_code_too_old_1);
|
||||
else msg = getString(R.string.qr_code_too_new_1);
|
||||
showNextFragment(AddNearbyContactErrorFragment.newInstance(msg));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,16 +78,15 @@ class WebServer extends NanoHTTPD {
|
||||
try (InputStream is = ctx.getAssets().open(FILE_HTML)) {
|
||||
doc = Jsoup.parse(is, UTF_8.name(), "");
|
||||
}
|
||||
String app = ctx.getString(R.string.app_name);
|
||||
String appV = app + " " + VERSION_NAME;
|
||||
String filename = getApkFileName();
|
||||
doc.select("#download_title").first()
|
||||
.text(ctx.getString(R.string.website_download_title, appV));
|
||||
.text(ctx.getString(R.string.website_download_title_1,
|
||||
VERSION_NAME));
|
||||
doc.select("#download_intro").first()
|
||||
.text(ctx.getString(R.string.website_download_intro, app));
|
||||
.text(ctx.getString(R.string.website_download_intro_1));
|
||||
doc.select(".button").first().attr("href", filename);
|
||||
doc.select("#download_button").first()
|
||||
.text(ctx.getString(R.string.website_download_title, app));
|
||||
.text(ctx.getString(R.string.website_download_button));
|
||||
doc.select("#download_outro").first()
|
||||
.text(ctx.getString(R.string.website_download_outro));
|
||||
doc.select("#troubleshooting_title").first()
|
||||
|
||||
@@ -63,6 +63,8 @@ public class MailboxStatusFragment extends Fragment {
|
||||
private Button wizardButton;
|
||||
private Button unlinkButton;
|
||||
private ProgressBar unlinkProgress;
|
||||
@Nullable
|
||||
private AlertDialog dialog = null;
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
@@ -129,6 +131,15 @@ public class MailboxStatusFragment extends Fragment {
|
||||
refresher = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
if (dialog != null) {
|
||||
dialog.dismiss();
|
||||
dialog = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void onMailboxStateChanged(MailboxStatus status) {
|
||||
@ColorRes int tintRes;
|
||||
@DrawableRes int iconRes;
|
||||
@@ -216,12 +227,15 @@ public class MailboxStatusFragment extends Fragment {
|
||||
(dialog, which) -> dialog.cancel());
|
||||
builder.setNegativeButton(R.string.mailbox_status_unlink_button,
|
||||
(dialog, which) -> {
|
||||
beginDelayedTransition((ViewGroup) requireView());
|
||||
ViewGroup v = (ViewGroup) getView();
|
||||
if (v != null) beginDelayedTransition(v);
|
||||
unlinkButton.setVisibility(INVISIBLE);
|
||||
unlinkProgress.setVisibility(VISIBLE);
|
||||
viewModel.unlink();
|
||||
});
|
||||
builder.show();
|
||||
builder.setOnDismissListener(dialog ->
|
||||
MailboxStatusFragment.this.dialog = null);
|
||||
dialog = builder.show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -135,12 +135,23 @@ class MailboxViewModel extends DbViewModel
|
||||
} else if (e instanceof TransportInactiveEvent) {
|
||||
TransportId id = ((TransportInactiveEvent) e).getTransportId();
|
||||
if (!TorConstants.ID.equals(id)) return;
|
||||
MailboxState lastState = pairingState.getLastValue();
|
||||
if (lastState instanceof MailboxState.IsPaired) {
|
||||
pairingState.setEvent(new MailboxState.IsPaired(false));
|
||||
} else if (lastState != null) {
|
||||
onTorInactive();
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void onTorInactive() {
|
||||
MailboxState lastState = pairingState.getLastValue();
|
||||
if (lastState instanceof MailboxState.IsPaired) {
|
||||
// we are already paired, so use IsPaired state
|
||||
pairingState.setEvent(new MailboxState.IsPaired(false));
|
||||
} else if (lastState instanceof MailboxState.Pairing) {
|
||||
MailboxState.Pairing p = (MailboxState.Pairing) lastState;
|
||||
// check that we not just finished pairing (showing success screen)
|
||||
if (!(p.pairingState instanceof MailboxPairingState.Paired)) {
|
||||
pairingState.setEvent(new MailboxState.OfflineWhenPairing());
|
||||
}
|
||||
// else ignore offline event as user will be leaving UI flow anyway
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ public class NavDrawerActivity extends BriarActivity implements
|
||||
}
|
||||
}
|
||||
navDrawerViewModel.shouldAskForDozeWhitelisting().observe(this, ask -> {
|
||||
if (ask) showDozeDialog(getString(R.string.dnkm_doze_intro));
|
||||
if (ask) showDozeDialog(R.string.dnkm_doze_intro);
|
||||
});
|
||||
|
||||
Toolbar toolbar = setUpCustomToolbar(false);
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/huaweiProtectedAppsView" />
|
||||
|
||||
<org.briarproject.briar.android.account.XiaomiView
|
||||
android:id="@+id/xiaomiView"
|
||||
<org.briarproject.briar.android.account.XiaomiRecentAppsView
|
||||
android:id="@+id/xiaomiRecentAppsView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="@dimen/margin_large"
|
||||
@@ -47,6 +47,15 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/huaweiAppLaunchView" />
|
||||
|
||||
<org.briarproject.briar.android.account.XiaomiLockAppsView
|
||||
android:id="@+id/xiaomiLockAppsView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="@dimen/margin_large"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/xiaomiRecentAppsView" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/next"
|
||||
style="@style/BriarButton"
|
||||
@@ -57,7 +66,7 @@
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/xiaomiView"
|
||||
app:layout_constraintTop_toBottomOf="@+id/xiaomiLockAppsView"
|
||||
app:layout_constraintVertical_bias="1.0"
|
||||
tools:enabled="true" />
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<string name="more_info">Повече информация</string>
|
||||
<string name="don_t_ask_again">Спиране на този въпрос</string>
|
||||
<string name="dnkm_huawei_protected_text">Докоснете бутона по-долу и се уверете, че Briar е защитен в екрана за „Защитени приложения“.</string>
|
||||
<string name="dnkm_huawei_protected_button">Защитаване на Briar</string>
|
||||
<string name="dnkm_huawei_protected_button">Предпазване на Briar</string>
|
||||
<string name="dnkm_huawei_protected_help">Ако не добавите Briar в списъка на защитени приложения, няма да може да работи на заден план.</string>
|
||||
<string name="dnkm_huawei_app_launch_text">Докоснете бутона по-долу, отворете „Стартиране на приложения“ и се уверете, че за Briar е избрано „Ръчно управление“.</string>
|
||||
<string name="dnkm_huawei_app_launch_help">Ако за Briar не е избрано „Ръчно управление“ в екрана „Стартиране на приложения“, тогава няма да може да работи на заден план.</string>
|
||||
@@ -26,7 +26,7 @@
|
||||
<string name="dnkm_xiaomi_button">Предпазване на Briar</string>
|
||||
<string name="dnkm_xiaomi_help">Ако Briar не е заключен в списъка с последно използваните приложения, няма да работи на заден план.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Отворете списъка с отворени приложения (списък за превключване на приложения)\n\n2. Плъзнете надолу върху изображението на Briar докато се покаже икона на катинар\n\n3. Ако катинарът е отключен го докоснете, за да го заключите</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Отворете списъка с отворени приложения (списък за превключване на приложения)\n\n2. Докоснете и задръжте върху изображението на Briar докато се покаже икона на катинар\n\n3. Ако катинарът е отключен го докоснете, за да го заключите</string>
|
||||
<string name="dnkm_warning_dozed_1">Briar не може да работи във фонов режим</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">Парола</string>
|
||||
<string name="try_again">Грешна парола, опитайте отново</string>
|
||||
@@ -48,7 +48,7 @@
|
||||
</plurals>
|
||||
<plurals name="old_android_expiry_warning">
|
||||
<item quantity="one">Android 4 не се поддържа. Briar ще спре да работи на %s (след %d ден). Инсталирайте Briar на друго устройство и създайте нов профил.</item>
|
||||
<item quantity="other">Android 4 не се поддържа. Briar ще спре да работи на %s (след %d дни). Инсталирайте Briar на друго устройство и създайте нов профил.</item>
|
||||
<item quantity="other">Android 4 не се поддържа. Briar ще спре да работи на %s (след %d дена). Инсталирайте Briar на друго устройство и създайте нов профил.</item>
|
||||
</plurals>
|
||||
<string name="expiry_date_reached">Софтуерът е с изтекъл срок.\nБлагодарим за изпитването!</string>
|
||||
<string name="download_briar">За да продължите да използвате Briar изтеглете последното издание.</string>
|
||||
@@ -87,8 +87,8 @@
|
||||
<!--Transports: Wi-Fi-->
|
||||
<string name="transport_lan">Wi-Fi</string>
|
||||
<string name="transport_lan_long">Същата безжична мрежа</string>
|
||||
<string name="lan_device_status_on">Устройството е свързан с безжична мрежа</string>
|
||||
<string name="lan_device_status_off">Устройството не е свързан с безжична мрежа</string>
|
||||
<string name="lan_device_status_on">Устройството е свързано с безжична мрежа</string>
|
||||
<string name="lan_device_status_off">Устройството не е свързано с безжична мрежа</string>
|
||||
<string name="lan_plugin_status_enabling">Briar се свързва с безжична мрежа</string>
|
||||
<string name="lan_plugin_status_active">Briar е свързан с безжична мрежа</string>
|
||||
<string name="lan_plugin_status_inactive">Briar не е свързан с безжична мрежа</string>
|
||||
@@ -230,8 +230,8 @@
|
||||
<string name="contact_added_toast">Добавен контакт: %s</string>
|
||||
<string name="contact_already_exists">Контактът %s вече съществува</string>
|
||||
<string name="qr_code_invalid">Кодът за QR е недействителен</string>
|
||||
<string name="qr_code_too_old">Сканираният код за QR е от по-ранно издание на %s.\n\nНека вашия контакт инсталира последното издание и да пробва отново.</string>
|
||||
<string name="qr_code_too_new">Сканираният код за QR е от по-ново издание на %s.\n\nИнсталирайте последното издание и пробвайте отново.</string>
|
||||
<string name="qr_code_too_old_1">Сканираният код за QR е от по-ранно издание на Briar.\n\nНека вашия контакт инсталира последното издание и да пробва отново.</string>
|
||||
<string name="qr_code_too_new_1">Сканираният код за QR е от по-ново издание на Briar.\n\nИнсталирайте последното издание и пробвайте отново.</string>
|
||||
<string name="camera_error">Грешка в камерата</string>
|
||||
<string name="connecting_to_device">Свързване с устройство\u2026</string>
|
||||
<string name="authenticating_with_device">Удостоверяване с устройство\u2026</string>
|
||||
@@ -584,25 +584,34 @@
|
||||
<string name="mailbox_setup_qr_code_wrong_title">Грешен код на QR</string>
|
||||
<string name="mailbox_setup_qr_code_wrong_description">Сканираният код е недействителен. Отворете приложението Briar Malibox на устройството, на което е инсталирано и сканирайте кода, който то предостави.</string>
|
||||
<string name="mailbox_setup_already_paired_title">Пощенската кутия е вече свързана</string>
|
||||
<string name="mailbox_setup_already_paired_description">Изключете връзката с пощенската кутия на другото устройство и опитайте отново.</string>
|
||||
<string name="mailbox_setup_already_paired_description">Прекъснете връзката с пощенската кутия от другото устройство и опитайте отново.</string>
|
||||
<string name="mailbox_setup_io_error_title">Грешка при свързване</string>
|
||||
<string name="mailbox_setup_io_error_description">Уверете се, че и двете устройства са свързани към интернет, и опитайте отново.</string>
|
||||
<string name="mailbox_setup_assertion_error_title">Грешка в пощенската кутия</string>
|
||||
<string name="mailbox_setup_assertion_error_description">Изпратете обратна връзка (с анонимизирани данни) през приложението Briar ако проблемът продължи да се появява.</string>
|
||||
<string name="mailbox_setup_camera_error_description">Няма достъп до камерата. Опитайте отново и след рестарт на усройството.</string>
|
||||
<string name="mailbox_setup_paired_title">Свързан</string>
|
||||
<string name="mailbox_setup_paired_description">Пощенската кутия е свързана с Briar.\n\nЗа да е винаги на линия, я дръжте включена в захранване и свързана с безжична мрежа.</string>
|
||||
<string name="tor_offline_title">Извън линия</string>
|
||||
<string name="tor_offline_button_check">Проверете настройките на връзката</string>
|
||||
<string name="mailbox_status_title">Състояние на пощенаската кутия</string>
|
||||
<string name="mailbox_status_connected_title">Пощенската кутия работи</string>
|
||||
<string name="mailbox_status_problem_title">Briar не може да се свърже с пощенската кутия</string>
|
||||
<string name="mailbox_status_failure_title">Пощенската кутия не е достъпна</string>
|
||||
<string name="mailbox_status_app_too_old_title">Изданието на Briar е твърде старо</string>
|
||||
<string name="mailbox_status_app_too_old_message">Инсталирайте последното издание на Briar и пробвайте отново.</string>
|
||||
<string name="mailbox_status_mailbox_too_old_title">Изданието на Пощенската кутия е твърде старо</string>
|
||||
<string name="mailbox_status_mailbox_too_old_message">Инсталирайте последното издание на Пощенска кутия и пробвайте отново.</string>
|
||||
<string name="mailbox_status_check_button">Проверка на връзката</string>
|
||||
<!--Example for string substitution: Last connection: 3min ago-->
|
||||
<string name="mailbox_status_connected_info">Последно свързване: %s</string>
|
||||
<!--Indicates that there never was a connection to the mailbox. Last connection: Never-->
|
||||
<string name="mailbox_status_connected_never">Никога</string>
|
||||
<string name="mailbox_status_unlink_button">Изключване на връзка</string>
|
||||
<string name="mailbox_status_unlink_dialog_title">Ще изключите ли връзката с пощенската кутия?</string>
|
||||
<string name="mailbox_status_unlink_dialog_question">Сигурни ли сте, че желаете да изключите връзката с пощенската кутия?</string>
|
||||
<string name="mailbox_status_unlink_button">Прекъсване на връзка</string>
|
||||
<string name="mailbox_status_unlink_dialog_title">Ще прекъснете ли връзката с пощенската кутия?</string>
|
||||
<string name="mailbox_status_unlink_dialog_question">Сигурни ли сте, че желаете да прекъснете връзката с пощенската кутия?</string>
|
||||
<string name="mailbox_status_unlink_dialog_warning">Ако прекъснете връзката с пощенската кутия, няма да получавате съобщения докато Briar е без мрежа.</string>
|
||||
<string name="mailbox_status_unlink_no_wipe_title">Връзката с пощенската кутия е прекъсната</string>
|
||||
<string name="mailbox_error_wizard_info2">Върнете се на този екран, когато получите достъп до устройството.</string>
|
||||
<!--Conversation Settings-->
|
||||
<string name="disappearing_messages_title">Изчезващи съобщения</string>
|
||||
@@ -695,7 +704,7 @@
|
||||
<string name="permission_hotspot_location_request_body">За да създаде безжична точка за достъп, на Briar му е необходимо разрешение за достъп до местоположението.\n\nBriar не го пази и не го споделя с никого.</string>
|
||||
<string name="permission_hotspot_location_denied_body">Отказахте достъп до местоположението, но то е необходимо за създаване на безжична точка за достъп.\n\nОбмислете дали да не дадете разрешение.</string>
|
||||
<string name="wifi_settings_title">Настройки на Wi-Fi</string>
|
||||
<string name="wifi_settings_request_enable_body">За създаване на безжична точка за достъп Briar се нуждае от Wi-Fi. Включете го.</string>
|
||||
<string name="wifi_settings_request_enable_body">За да създаде безжична точка за достъп, Briar се нуждае от безжична мрежа. Включете Wi-Fi.</string>
|
||||
<string name="hotspot_tab_manual">Ръчно</string>
|
||||
<!--The placeholder to be inserted into the string 'hotspot_manual_wifi': People can connect by %s-->
|
||||
<string name="hotspot_scanning_a_qr_code">като сканират код за QR</string>
|
||||
@@ -715,9 +724,10 @@
|
||||
<string name="hotspot_manual_site_address">Адрес (URL)</string>
|
||||
<string name="hotspot_qr_site">Устройството ви създава безжична точка за достъп. Хората, които са свързани към нея могат да изтеглят Briar като сканират този код за QR.</string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">Изтеглете %s</string>
|
||||
<string name="website_download_intro">Някой наблизо споделя с вас %s.</string>
|
||||
<string name="website_download_outro">След като файлът се изтегли, отворете го и го инсталирайте.</string>
|
||||
<string name="website_download_title_1">Изтегляне на Briar %s</string>
|
||||
<string name="website_download_intro_1">Някой наблизо споделя Briar с вас.</string>
|
||||
<string name="website_download_button">Изтегляне на Briar</string>
|
||||
<string name="website_download_outro">След като файлът бъде изтеглен, го отворете и го инсталирайте.</string>
|
||||
<string name="website_troubleshooting_title">Отстраняване на неизправности</string>
|
||||
<string name="website_troubleshooting_1">Ако не можете да изтеглите приложението пробвайте с друг мрежов четец.</string>
|
||||
<string name="hotspot_help_wifi_title">Проблеми при свързване чрез Wi-Fi:</string>
|
||||
@@ -726,7 +736,7 @@
|
||||
<string name="hotspot_help_wifi_3">Рестартирайте устройството, което създава безжичната точка за достъп, отворете Briar и го споделете отново.</string>
|
||||
<string name="hotspot_help_site_title">Проблеми при посещаване на страницата:</string>
|
||||
<string name="hotspot_help_site_1">Уверете се, че въвеждате адреса точно, както е показан. Дори малка грешка може да доведе до неуспех.</string>
|
||||
<string name="hotspot_help_site_2">Уверете се, че устройството е свързано с правилната мрежа на Wi-Fi (вижте по-горе) докато отваряте страницата.</string>
|
||||
<string name="hotspot_help_site_2">Уверете се, че устройството е свързано с правилната безжична мрежа (вижте по-горе) докато отваряте страницата.</string>
|
||||
<string name="hotspot_help_site_3">Ако имате инсталирано приложение за защитна стена се уверете, че не спира достъпа.</string>
|
||||
<string name="hotspot_help_site_4">Ако можете да отворите страницата, но не и да изтеглите приложението на Briar пробвайте с друг мрежов четец.</string>
|
||||
<string name="hotspot_help_fallback_title">Нищо не става?</string>
|
||||
@@ -741,8 +751,11 @@
|
||||
<string name="hotspot_error_start_callback_no_group_info">Безжичната точка не може да стартира: няма информация за група</string>
|
||||
<string name="hotspot_error_web_server_start">Грешка при стартиране на уеб сървър</string>
|
||||
<string name="hotspot_flag_test">Внимание: Това приложение е инсталирано с Android Studio и НЕ може да бъде инсталирано на друго устройство.</string>
|
||||
<string name="hotspot_error_framework_busy">Безжичната точка не може да бъде стартирана.\n\nАко има включена друга безжична точка за достъп или споделяте мобилните си данни по безжичен път, опитайте да ги спрете и пробвайте отново.</string>
|
||||
<!--Transfer Data via Removable Drives-->
|
||||
<string name="removable_drive_menu_title">Свързване чрез преносим диск</string>
|
||||
<string name="removable_drive_intro">Ако не можете да се свържете с контакта си чрез интернет, безжична мрежа или Bluetooth, Briar може да прехвърли съобщенията и на преносим диск, например памет на USB или SD карта.</string>
|
||||
<string name="removable_drive_explanation">Ако не можете да се свържете с контакта си чрез интернет, безжична мрежа или Bluetooth, Briar може да прехвърли съобщенията и на преносим диск, например памет на USB или SD карта.\n\nКогато използвате бутона „Изпращане на сведения“, всичко, коeто чака да бъде изпратено на контакта, ще бъде записано на преносимия диск. Това включва лични съобщения, прикачени файлове, блогове, форуми и частни групи.\n\nПреди да бъде записано на преносимия диск, всичко ще бъде шифровано.\n\nКогато контактът ви получи сменяемото устройство, за да внесе съобщенията в Briar, той може да използва бутона „Получаване на сведения“.</string>
|
||||
<string name="removable_drive_title_send">Изпращане на сведения</string>
|
||||
<string name="removable_drive_title_receive">Получаване на сведения</string>
|
||||
<string name="removable_drive_send_intro">Докоснете бутона по-долу, за да бъде създаден файл, който ще съдържа шифрованите съобщения. Можете да изберете къде да бъде запазен този файл.\n\nАко желаете да го запазите на преносим диск го включете сега.</string>
|
||||
|
||||
@@ -26,7 +26,10 @@
|
||||
<string name="dnkm_xiaomi_button">Briar schützen</string>
|
||||
<string name="dnkm_xiaomi_help">Wenn Briar nicht in der Liste der zuletzt verwendeten Apps gesperrt ist, kann es nicht im Hintergrund ausgeführt werden.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Öffne die Liste der zuletzt verwendeten Apps (auch \'App Switcher\' genannt)\n\n2. Wische auf dem Bild von Briar nach unten, um das Vorhängeschlosssymbol anzuzeigen\n\n3. Wenn das Vorhängeschloss nicht gesperrt ist, tippe darauf, um es zu sperren</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Öffne die Liste der zuletzt verwendeten Apps (auch \'App Switcher\' genannt)\n\n2. Halte das Bild von Briar gedrückt, bis die Schaltfläche für das Vorhängeschloss angezeigt wird\n\n3. Wenn das Vorhängeschloss nicht gesperrt ist, tippe darauf, um es zu sperren</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Öffne die Liste der zuletzt verwendeten Apps (auch \'App Switcher\' genannt)\n\n2. Wenn neben Briar ein kleines Vorhängeschloss angezeigt wird, brauchst du nichts zu tun.\n\n3. Wenn kein Vorhängeschloss vorhanden ist, halte das Bild von Briar gedrückt, bis die Schaltfläche für das Vorhängeschloss erscheint, und tippe dann darauf</string>
|
||||
<string name="dnkm_xiaomi_lock_apps_text">Bitte tippe auf die Schaltfläche unten, um die Sicherheitseinstellungen zu öffnen. Tippe auf \"Geschwindigkeit erhöhen\", dann auf \"Apps sperren\" und stelle sicher, dass Briar auf \"Gesperrt\" gesetzt ist.</string>
|
||||
<string name="dnkm_xiaomi_lock_apps_help">Wenn Briar nicht auf \" Gesperrt\" im Bereich \"Apps sperren\" gesetzt wurde, kann sie nicht im Hintergrund ausgeführt werden.</string>
|
||||
<string name="dnkm_warning_dozed_1">Briar konnte nicht im Hintergrund ausgeführt werden</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">Passwort</string>
|
||||
<string name="try_again">Passwort falsch, bitte erneut versuchen</string>
|
||||
@@ -169,11 +172,11 @@
|
||||
<string name="set_contact_alias_hint">Name des Kontakts</string>
|
||||
<string name="menu_item_disappearing_messages">Selbstlöschende Nachrichten</string>
|
||||
<!--The first placeholder will show a duration like "7 days". The second placeholder at the end will add "Tap to learn more."-->
|
||||
<string name="auto_delete_msg_you_enabled">Deine Nachrichten werden nach %1$sgelöscht. %2$s</string>
|
||||
<string name="auto_delete_msg_you_enabled">Deine Nachrichten werden nach %1$s gelöscht. %2$s</string>
|
||||
<!--The placeholder at the end will add "Tap to learn more."-->
|
||||
<string name="auto_delete_msg_you_disabled">Deine Nachrichten werden nicht gelöscht. %1$s</string>
|
||||
<!--The first placeholder will show a contact's name. The second placeholder will show a duration like "7 days". The third placeholder at the end will add "Tap to learn more."-->
|
||||
<string name="auto_delete_msg_contact_enabled">%1$s\'s Nachrichten werden nach%2$sgelöscht. %3$s</string>
|
||||
<string name="auto_delete_msg_contact_enabled">%1$s\'s Nachrichten werden nach %2$s gelöscht. %3$s</string>
|
||||
<plurals name="duration_minutes">
|
||||
<item quantity="one">%d Minute</item>
|
||||
<item quantity="other">%d Minuten</item>
|
||||
@@ -230,8 +233,8 @@
|
||||
<string name="contact_added_toast">Kontakt hinzugefügt: %s</string>
|
||||
<string name="contact_already_exists">Kontakt %s existiert bereits</string>
|
||||
<string name="qr_code_invalid">Der QR-Code ist ungültig</string>
|
||||
<string name="qr_code_too_old">Der QR-Code, den du eingescannt hast, kommt von einer älteren Version von %s.\n\nBitte deinen Kontakt, zur neuesten Version upzudaten, und probiere es erneut.</string>
|
||||
<string name="qr_code_too_new">Der QR-Code, den du gescannt hast, kommt von einer neueren Version.\n\nBitte aktualisiere %s auf die neueste Version und versuche es erneut.</string>
|
||||
<string name="qr_code_too_old_1">Der QR-Code, den du gescannt hast, kommt von einer älteren Version von Briar.\n\nBitte deinen Kontakt, zur neuesten Version upzudaten, und versuche es erneut.</string>
|
||||
<string name="qr_code_too_new_1">Der QR-Code, den du gescannt hast, kommt von einer neueren Version.\n\nBitte aktualisiere Briar auf die neueste Version und versuche es erneut.</string>
|
||||
<string name="camera_error">Kamerafehler</string>
|
||||
<string name="connecting_to_device">Verbinde mit Gerät\u2026</string>
|
||||
<string name="authenticating_with_device">Authentifiziere Gerät\u2026</string>
|
||||
@@ -307,7 +310,7 @@
|
||||
<string name="introduction_error">Es gab einen Fehler beim Versuch, die Kontaktempfehlung zu verschicken.</string>
|
||||
<string name="introduction_request_sent">Du wolltest %1$s an %2$s als Kontakt empfehlen</string>
|
||||
<string name="introduction_request_received">%1$s schlägt vor, dich als Kontakt an %2$s zu empfehlen. Möchtest du %2$s zu deiner Kontaktliste hinzufügen?</string>
|
||||
<string name="introduction_request_exists_received">%1$s schlägt vor, dich als Kontakt an %2$s zu empfehlen. %2$s ist allerdings bereits in deiner Kontaktliste. Da %1$s das vielleicht nicht weiss, kannst du trotzdem antworten:</string>
|
||||
<string name="introduction_request_exists_received">%1$s schlägt vor, dich als Kontakt an %2$s zu empfehlen. %2$s ist allerdings bereits in deiner Kontaktliste. Da %1$s das vielleicht nicht weiß, kannst du trotzdem antworten:</string>
|
||||
<string name="introduction_request_answered_received">%1$s schlägt vor, dich als Kontakt an %2$s zu empfehlen. </string>
|
||||
<string name="introduction_response_accepted_sent">Du hast die Kontaktempfehlung von %1$s angenommen.</string>
|
||||
<string name="introduction_response_accepted_sent_info">Bevor %1$s zu deinen Kontakten hinzugefügt wird, muss die Kontaktempfehlung ebenfalls akzeptieren werden. Dies kann eine Weile dauern.</string>
|
||||
@@ -412,7 +415,7 @@
|
||||
<string name="forum_share_error">Es gab einen Fehler beim Versuch, dieses Forum zu teilen.</string>
|
||||
<string name="forum_invitation_received">%1$s hat das Forum \"%2$s\" mit dir geteilt.</string>
|
||||
<string name="forum_invitation_sent">Du hast das Forum \"%1$s\" mit %2$s geteilt.</string>
|
||||
<string name="forum_invitations_title">Forumeinladungen</string>
|
||||
<string name="forum_invitations_title">Foreneinladungen</string>
|
||||
<string name="forum_invitation_exists">Du hast bereits eine Einladung zu diesem Forum angenommen.\n\nMehrere Einladungen anzunehmen wird deine Verbindung zu diesem Forum schneller und zuverlässiger machen.</string>
|
||||
<string name="forum_joined_toast">Dem Forum beigetreten</string>
|
||||
<string name="forum_declined_toast">Einladung abgelehnt</string>
|
||||
@@ -476,7 +479,7 @@
|
||||
<string name="blogs_rss_feeds_manage_updated">Letzte Aktualisierung:</string>
|
||||
<string name="blogs_rss_remove_feed">Feed entfernen</string>
|
||||
<string name="blogs_rss_remove_feed_dialog_message">Bist du sicher, dass du diesen Feed löschen willst?\n\nBeiträge werden von deinem Gerät entfernt, aber nicht von den Geräten anderer Personen.\n\nAlle Kontakte, für die du diesen Feed freigegeben hast, können keine Updates mehr erhalten.</string>
|
||||
<string name="blogs_rss_remove_feed_ok">Aufheben</string>
|
||||
<string name="blogs_rss_remove_feed_ok">Entfernen</string>
|
||||
<string name="blogs_rss_feeds_manage_empty_state">Keine RSS-Feeds vorhanden\n\nTippe auf das + Symbol, um einen Feed zu importieren</string>
|
||||
<string name="blogs_rss_feeds_manage_error">Es gab ein Problem beim Laden deiner Feeds. Bitte versuche es später erneut.</string>
|
||||
<!--Settings Profile Picture-->
|
||||
@@ -602,6 +605,10 @@
|
||||
<string name="mailbox_status_connected_title">Mailbox läuft</string>
|
||||
<string name="mailbox_status_problem_title">Briar hat Probleme mit der Verbindung zur Mailbox</string>
|
||||
<string name="mailbox_status_failure_title">Mailbox ist nicht verfügbar</string>
|
||||
<string name="mailbox_status_app_too_old_title">Briar ist zu alt</string>
|
||||
<string name="mailbox_status_app_too_old_message">Aktualisiere Briar auf die neueste Version der App und versuche es erneut.</string>
|
||||
<string name="mailbox_status_mailbox_too_old_title">Mailbox ist zu alt</string>
|
||||
<string name="mailbox_status_mailbox_too_old_message">Aktualisiere deine Mailbox auf die neueste Version der App und versuche es erneut.</string>
|
||||
<string name="mailbox_status_check_button">Verbindung überprüfen</string>
|
||||
<!--Example for string substitution: Last connection: 3min ago-->
|
||||
<string name="mailbox_status_connected_info">Letzte Verbindung: %s</string>
|
||||
@@ -613,8 +620,30 @@
|
||||
<string name="mailbox_status_unlink_dialog_warning">Wenn du die Verknüpfung mit deiner Mailbox aufhebst, kannst du keine Nachrichten empfangen, während Briar offline ist.</string>
|
||||
<string name="mailbox_status_unlink_no_wipe_title">Deine Mailbox wurde getrennt</string>
|
||||
<string name="mailbox_status_unlink_no_wipe_message">Wenn du das nächste Mal Zugriff auf dein Mailbox-Gerät hast, öffne bitte die Mailbox-App und tippe auf die Schaltfläche \"Trennen\", um den Vorgang abzuschließen.\n\nWenn du keinen Zugriff mehr auf dein Mailbox-Gerät hast, mach dir keine Sorgen. Deine Daten sind verschlüsselt, sodass sie sicher bleiben, auch wenn du den Vorgang nicht abschließt.</string>
|
||||
<string name="mailbox_error_notification_channel_title">Briar Mailbox Problem</string>
|
||||
<string name="mailbox_error_notification_title">Briar Mailbox ist nicht verfügbar</string>
|
||||
<string name="mailbox_error_notification_text">Antippen, um das Problem zu beheben.</string>
|
||||
<string name="mailbox_error_wizard_button">Problem beheben</string>
|
||||
<string name="mailbox_error_wizard_title">Assistent zur Fehlerbehebung für die Mailbox</string>
|
||||
<string name="mailbox_error_wizard_question1">Hast du Zugriff auf dein Mailbox-Gerät?</string>
|
||||
<string name="mailbox_error_wizard_answer1">Ja, ich habe jetzt Zugriff darauf.</string>
|
||||
<string name="mailbox_error_wizard_answer2">Im Moment nicht, aber ich kann später Zugriff darauf bekommen.</string>
|
||||
<string name="mailbox_error_wizard_answer3">Nein, ich habe keinen Zugriff mehr darauf.</string>
|
||||
<string name="mailbox_error_wizard_info1_1">Überprüfe, ob das Mailbox-Gerät eingeschaltet und mit dem Internet verbunden ist.</string>
|
||||
<string name="mailbox_error_wizard_question1_1">Öffne die Mailbox-App. Was siehst du?</string>
|
||||
<string name="mailbox_error_wizard_answer1_1">Ich sehe eine Anleitung zum Einrichten der Mailbox</string>
|
||||
<string name="mailbox_error_wizard_answer1_2">Ich sehe einen QR-Code</string>
|
||||
<string name="mailbox_error_wizard_answer1_3">Ich sehe \"Mailbox wird ausgeführt\"</string>
|
||||
<string name="mailbox_error_wizard_answer1_4">Ich sehe \"Gerät ist offline\"</string>
|
||||
<string name="mailbox_error_wizard_info1_1_1">Bitte trenne die Verknüpfung deiner Mailbox über die Schaltfläche unten und folge dann den Anweisungen auf dem Mailbox-Gerät, um sie erneut zu verbinden.</string>
|
||||
<string name="mailbox_error_wizard_info_1_1_2">Bitte trenne die Verknüpfung deiner Mailbox über die Schaltfläche unten und scanne dann den QR-Code, um sie erneut zu verbinden.</string>
|
||||
<string name="mailbox_error_wizard_info1_1_3">Bitte benutze die Schaltfläche unten, um die Verbindung zwischen Briar und der Mailbox zu überprüfen.\n\n
|
||||
Wenn die Verbindung erneut fehlschlägt:\n
|
||||
\u2022 Überprüfe, ob die Mailbox- und Briar-Apps auf die neueste Version aktualisiert sind.\n
|
||||
\u2022 Starte deine Mailbox- und Briar-Geräte neu und versuche es erneut.</string>
|
||||
<string name="mailbox_error_wizard_info1_1_4">Überprüfe, ob das Mailbox-Gerät ordnungsgemäß mit dem Internet verbunden ist.\n\nÜberprüfe, ob die Uhr auf dem Mailbox-Gerät die richtige Uhrzeit, das richtige Datum und die richtige Zeitzone anzeigt.\n\nÜberprüfe, ob die Mailbox- und Briar-Apps auf die neueste Version aktualisiert sind.\n\nStarte deine Mailbox- und Briar-Geräte neu und versuche es erneut.</string>
|
||||
<string name="mailbox_error_wizard_info2">Bitte rufe diesen Bildschirm wieder auf, wenn du Zugriff auf das Gerät hast.</string>
|
||||
<string name="mailbox_error_wizard_info3">Bitte trenne die Verknüpfung deiner Mailbox über die Schaltfläche unten.\n\nNach der Trennung deiner alten Mailbox kannst du jederzeit eine neue Mailbox einrichten.</string>
|
||||
<!--Conversation Settings-->
|
||||
<string name="disappearing_messages_title">Selbstlöschende Nachrichten</string>
|
||||
<string name="disappearing_messages_explanation_long">Wenn diese Einstellung aktiviert ist, werden neue
|
||||
@@ -663,7 +692,7 @@
|
||||
<string name="send_report">Bericht senden</string>
|
||||
<string name="close">Schließen</string>
|
||||
<string name="dev_report_sending">Rückmeldung wird gesendet…</string>
|
||||
<string name="dev_report_sent">Feedback senden</string>
|
||||
<string name="dev_report_sent">Feedback gesendet</string>
|
||||
<string name="dev_report_saved">Der Bericht wurde gespeichert. Er wird verschickt, wenn du dich das nächste Mal bei Briar anmeldest.</string>
|
||||
<string name="dev_report_error">Fehler: Senden des Reports fehlgeschlagen</string>
|
||||
<!--Sign Out-->
|
||||
@@ -682,7 +711,7 @@
|
||||
<string name="permission_camera_location_title">Kamera und Standort</string>
|
||||
<string name="permission_camera_location_request_body">Um den QR-Code zu scannen, braucht Briar Zugriff auf die Kamera.\n\nUm Bluetooth-Geräte zu finden, braucht Briar Zugriff auf deinen Standort.\n\nBriar speichert weder deinen Standort noch gibt es ihn an andere weiter.</string>
|
||||
<string name="permission_camera_denied_body">Du hast den Zugriff auf die Kamera verweigert, aber das Hinzufügen von Kontakten erfordert die Verwendung der Kamera.\n\nBitte gewähre den Zugriff.</string>
|
||||
<string name="permission_location_denied_body">Du hast den Zugriff auf deinen Standort verweigert, aber Briar benötigt diese Berechtigung, um Bluetooth-Geräte zu erkennen.\n\nBitte gewähre den Zugriff.</string>
|
||||
<string name="permission_location_denied_body">Du hast den Zugriff auf deinen Standort verweigert, aber Briar benötigt diese Berechtigung, um Bluetooth-Geräte zu erkennen.\n\nBitte überlege, ob du Zugriff gewährst.</string>
|
||||
<string name="permission_location_setting_title">Standorteinstellung</string>
|
||||
<string name="permission_location_setting_body">Die Standorteinstellung deines Geräts muss aktiviert sein, um andere Geräte über Bluetooth zu finden. Bitte aktiviere den Standort, um fortzufahren. Du kannst sie anschließend wieder deaktivieren.</string>
|
||||
<string name="permission_location_setting_button">Standort aktivieren</string>
|
||||
@@ -708,7 +737,7 @@
|
||||
<string name="hotspot_notification_title">Briar offline teilen</string>
|
||||
<string name="hotspot_button_connected">Weiter</string>
|
||||
<string name="permission_hotspot_location_request_body">Um einen WLAN-Hotspot zu erstellen, benötigt Briar die Erlaubnis, auf deinen Standort zuzugreifen.\n\nBriar speichert weder deinen Standort noch gibt es ihn an andere weiter.</string>
|
||||
<string name="permission_hotspot_location_denied_body">Du hast den Zugriff auf deinen Standort verweigert, aber Briar benötigt diese Berechtigung, um einen WLAN-Hotspot zu erstellen.\n\nBitte gewähre den Zugriff.</string>
|
||||
<string name="permission_hotspot_location_denied_body">Du hast den Zugriff auf deinen Standort verweigert, aber Briar benötigt diese Berechtigung, um einen WLAN-Hotspot zu erstellen.\n\nBitte überlege, ob du Zugriff gewährst.</string>
|
||||
<string name="wifi_settings_title">WLAN-Einstellungen</string>
|
||||
<string name="wifi_settings_request_enable_body">Um einen WLAN-Hotspot zu erstellen, benötigt Briar das WLAN. Bitte aktiviere es.</string>
|
||||
<string name="hotspot_tab_manual">Manuell</string>
|
||||
@@ -730,8 +759,9 @@
|
||||
<string name="hotspot_manual_site_address">Adresse (URL)</string>
|
||||
<string name="hotspot_qr_site">Dein Telefon stellt einen WLAN-Hotspot bereit. Personen, die mit dem Hotspot verbunden sind, können Briar durch Scannen dieses QR-Codes herunterladen.</string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">Download %s</string>
|
||||
<string name="website_download_intro">Jemand in der Nähe hat %s mit dir geteilt.</string>
|
||||
<string name="website_download_title_1">Briar %s herunterladen</string>
|
||||
<string name="website_download_intro_1">Jemand in der Nähe hat Briar mit dir geteilt.</string>
|
||||
<string name="website_download_button">Briar herunterladen</string>
|
||||
<string name="website_download_outro">Nach Abschluss des Downloads öffne die heruntergeladene Datei und installiere sie.</string>
|
||||
<string name="website_troubleshooting_title">Fehlerbehebung</string>
|
||||
<string name="website_troubleshooting_1">Wenn du die App nicht herunterladen kannst, versuche es mit einer anderen Webbrowser-App.</string>
|
||||
|
||||
@@ -1,36 +1,31 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources>
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Bienvenido a Briar</string>
|
||||
<string name="setup_name_explanation">Tu nombre de usuario aparecerá junto a cualquier contenido que publiques. No puedes cambiarlo después de crear tu cuenta.</string>
|
||||
<string name="setup_next">Siguiente</string>
|
||||
<string name="setup_password_intro">Elige una contraseña</string>
|
||||
<string name="setup_password_explanation">Tu cuenta Briar se almacena cifrada en tu dispositivo, no en la nube. Si olvidas tu contraseña o desinstalas Briar, no hay manera de recuperarla.\n\nElige una contraseña larga que sea difícil de adivinar, como cuatro palabras aleatorias o diez letras, números y símbolos al azar.</string>
|
||||
<string name="dnkm_doze_title">Conexiones de segundo plano</string>
|
||||
<string name="dnkm_doze_intro">Para recibir mensajes, Briar necesita mantenerse conectado en segundo plano.</string>
|
||||
<string name="dnkm_doze_explanation">Para recibir mensajes, Briar necesita mantenerse conectado en segundo plano. Desactiva las optimizaciones de la batería para que Briar pueda permanecer conectado.</string>
|
||||
<string name="dnkm_doze_button">Permitir conexiones</string>
|
||||
<string name="choose_nickname">Elige tu nombre de usuario</string>
|
||||
<string name="choose_password">Elige tu contraseña</string>
|
||||
<string name="confirm_password">Confirma tu contraseña</string>
|
||||
<string name="name_too_long">El nombre es demasiado largo</string>
|
||||
<string name="password_too_weak">La contraseña es demasiado débil</string>
|
||||
<string name="passwords_do_not_match">Las contraseñas no coinciden</string>
|
||||
<string name="create_account_button">Crea una cuenta</string>
|
||||
<string name="more_info">Más información</string>
|
||||
<string name="don_t_ask_again">No preguntes de nuevo</string>
|
||||
<string name="dnkm_huawei_protected_text">Por favor pulsa el botón de abajo y asegúrate de que Briar está protegido en la pantalla \"Aplicaciones protegidas\".</string>
|
||||
<string name="dnkm_huawei_protected_button">Proteger Briar</string>
|
||||
<string name="dnkm_huawei_protected_help">Si Briar no se agrega a la lista de aplicaciones protegidas, no podrá ejecutarse en segundo plano.</string>
|
||||
<string name="dnkm_huawei_app_launch_text">Por favor, pulsa el botón de abajo, abre la pantalla \"lanzamiento de aplicación\" y asegúrate de que Briar esté configurado como \"Gestionar manualmente\".</string>
|
||||
<string name="dnkm_huawei_app_launch_button">Abrir Ajustes de Batería</string>
|
||||
<string name="dnkm_huawei_app_launch_help">Si Briar no está configurado como \"Gestionar manualmente\" en la pantalla \"lanzamiento de aplicación\", no será capaz de ejecutarse en segundo plano.</string>
|
||||
<string name="dnkm_xiaomi_text">Para ejecutarse en segundo plano, Briar necesita estar bloqueado en la lista de aplicaciones recientes.</string>
|
||||
<string name="dnkm_xiaomi_button">Proteger Briar</string>
|
||||
<string name="dnkm_xiaomi_help">Si Briar no está bloqueado en la lista de aplicaciones recientes, no podrá ejecutarse en segundo plano.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Abre la lista de aplicaciones recientes (también llamada selectora de aplicaciones)\n\n2. Desliza hacia abajo sobre la imagen de Briar para mostrar el ícono de un candado\n\n3. Si el candado no está bloqueado, púlsalo para hacerlo</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Abre la lista de aplicaciones recientes (también llamada selectora de aplicaciones)\n\n2. Presiona y mantén la imagen de Briar hasta que aparezca el botón de un candado\n\n3. Si el candado no está bloqueado, púlsalo para hacerlo</string>
|
||||
<string name="dnkm_warning_dozed">%s no pudo ejecutarse en segundo plano</string>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Bienvenido a Briar</string>
|
||||
<string name="setup_name_explanation">Tu nombre de usuario aparecerá junto a cualquier contenido que publiques. No puedes cambiarlo después de crear tu cuenta.</string>
|
||||
<string name="setup_next">Siguiente</string>
|
||||
<string name="setup_password_intro">Elige una contraseña</string>
|
||||
<string name="setup_password_explanation">Tu cuenta Briar se almacena cifrada en tu dispositivo, no en la nube. Si olvidas tu contraseña o desinstalas Briar, no hay manera de recuperarla.\n\nElige una contraseña larga que sea difícil de adivinar, como cuatro palabras aleatorias o diez letras, números y símbolos al azar.</string>
|
||||
<string name="dnkm_doze_intro">Para recibir mensajes, Briar necesita mantenerse conectado en segundo plano.</string>
|
||||
<string name="dnkm_doze_explanation">Para recibir mensajes, Briar necesita mantenerse conectado en segundo plano. Desactiva las optimizaciones de la batería para que Briar pueda permanecer conectado.</string>
|
||||
<string name="choose_nickname">Elige tu nombre de usuario</string>
|
||||
<string name="choose_password">Elige tu contraseña</string>
|
||||
<string name="confirm_password">Confirma tu contraseña</string>
|
||||
<string name="name_too_long">El nombre es demasiado largo</string>
|
||||
<string name="password_too_weak">La contraseña es demasiado débil</string>
|
||||
<string name="passwords_do_not_match">Las contraseñas no coinciden</string>
|
||||
<string name="create_account_button">Crea una cuenta</string>
|
||||
<string name="more_info">Más información</string>
|
||||
<string name="don_t_ask_again">No preguntes de nuevo</string>
|
||||
<string name="dnkm_huawei_protected_text">Por favor pulsa el botón de abajo y asegúrate de que Briar está protegido en la pantalla \"Aplicaciones protegidas\".</string>
|
||||
<string name="dnkm_huawei_protected_button">Proteger Briar</string>
|
||||
<string name="dnkm_huawei_protected_help">Si Briar no se agrega a la lista de aplicaciones protegidas, no podrá ejecutarse en segundo plano.</string>
|
||||
<string name="dnkm_huawei_app_launch_text">Por favor, pulsa el botón de abajo, abre la pantalla \"lanzamiento de aplicación\" y asegúrate de que Briar esté configurado como \"Gestionar manualmente\".</string>
|
||||
<string name="dnkm_huawei_app_launch_help">Si Briar no está configurado como \"Gestionar manualmente\" en la pantalla \"lanzamiento de aplicación\", no será capaz de ejecutarse en segundo plano.</string>
|
||||
<string name="dnkm_xiaomi_text">Para ejecutarse en segundo plano, Briar necesita estar bloqueado en la lista de aplicaciones recientes.</string>
|
||||
<string name="dnkm_xiaomi_button">Proteger Briar</string>
|
||||
<string name="dnkm_xiaomi_help">Si Briar no está bloqueado en la lista de aplicaciones recientes, no podrá ejecutarse en segundo plano.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Abre la lista de aplicaciones recientes (también llamada selectora de aplicaciones)\n\n2. Desliza hacia abajo sobre la imagen de Briar para mostrar el ícono de un candado\n\n3. Si el candado no está bloqueado, púlsalo para hacerlo</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">Contraseña</string>
|
||||
<string name="try_again">Contraseña incorrecta, inténtalo de nuevo</string>
|
||||
@@ -48,10 +43,12 @@
|
||||
<string name="startup_failed_service_error">Briar no fue capaz de iniciar un componente requerido.\n\nPor favor, actualiza a la última versión de la aplicación e inténtalo de nuevo.</string>
|
||||
<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="many">Esta es una versión de prueba de Briar. Tu cuenta expirará en %d días y no podrá ser renovada.</item>
|
||||
<item quantity="other">Esta es una versión de prueba de Briar. Tu cuenta expirará en %d días y no podrá ser renovada.</item>
|
||||
</plurals>
|
||||
<plurals name="old_android_expiry_warning">
|
||||
<item quantity="one">Android 4 ya no es soportado. Briar dejará de funcionar sobre %s (en %d días). Por favor, instala Briar en un dispositivo más nuevo y crea una cuenta nueva.</item>
|
||||
<item quantity="many">Android 4 ya no es soportado. Briar dejará de funcionar sobre %s (en %d días). Por favor, instala Briar en un dispositivo más nuevo y crea una cuenta nueva.</item>
|
||||
<item quantity="other">Android 4 ya no es soportado. Briar dejará de funcionar sobre %s (en %d días). Por favor, instala Briar en un dispositivo más nuevo y crea una cuenta nueva.</item>
|
||||
</plurals>
|
||||
<string name="expiry_date_reached">Este programa ha caducado.\n¡Gracias por probarlo!</string>
|
||||
@@ -114,18 +111,22 @@
|
||||
<string name="ongoing_notification_text">Toca para abrir Briar.</string>
|
||||
<plurals name="private_message_notification_text">
|
||||
<item quantity="one">Tienes un nuevo mensaje privado.</item>
|
||||
<item quantity="many">Tienes %d nuevos mensajes privados.</item>
|
||||
<item quantity="other">Tienes %d nuevos mensajes privados.</item>
|
||||
</plurals>
|
||||
<plurals name="group_message_notification_text">
|
||||
<item quantity="one">Tienes un nuevo mensaje de grupo.</item>
|
||||
<item quantity="many">Tienes %d nuevos mensajes de grupo.</item>
|
||||
<item quantity="other">Tienes %d nuevos mensajes de grupo.</item>
|
||||
</plurals>
|
||||
<plurals name="forum_post_notification_text">
|
||||
<item quantity="one">Hay una nueva publicación en el foro.</item>
|
||||
<item quantity="many">Hay %d nuevas publicaciones en el foro.</item>
|
||||
<item quantity="other">Hay %d nuevas publicaciones en el foro.</item>
|
||||
</plurals>
|
||||
<plurals name="blog_post_notification_text">
|
||||
<item quantity="one">Hay una nueva entrada de blog.</item>
|
||||
<item quantity="many">Hay %d nuevos artículos de blog.</item>
|
||||
<item quantity="other">Hay %d nuevos artículos de blog.</item>
|
||||
</plurals>
|
||||
<!--Misc-->
|
||||
@@ -180,14 +181,17 @@
|
||||
<string name="auto_delete_msg_contact_enabled">Los mensajes de %1$s desaparecerán después de %2$s. %3$s</string>
|
||||
<plurals name="duration_minutes">
|
||||
<item quantity="one">%d minuto</item>
|
||||
<item quantity="many">%d minutos</item>
|
||||
<item quantity="other">%d minutos</item>
|
||||
</plurals>
|
||||
<plurals name="duration_hours">
|
||||
<item quantity="one">%d hora</item>
|
||||
<item quantity="many">%d horas</item>
|
||||
<item quantity="other">%d horas</item>
|
||||
</plurals>
|
||||
<plurals name="duration_days">
|
||||
<item quantity="one">%d día</item>
|
||||
<item quantity="many">%d días</item>
|
||||
<item quantity="other">%d días</item>
|
||||
</plurals>
|
||||
<!--The first placeholder will show a contact's name. The second placeholder at the end will add "Tap to learn more."-->
|
||||
@@ -234,8 +238,6 @@
|
||||
<string name="contact_added_toast">Contacto añadido: %s</string>
|
||||
<string name="contact_already_exists">El contacto %s ya existe</string>
|
||||
<string name="qr_code_invalid">El código QR no es válido</string>
|
||||
<string name="qr_code_too_old">El código QR que has escaneado proviene de una versión anterior de %s.\n\nPor favor solicita a tu contacto que actualice a la última versión y luego intenta nuevamente.</string>
|
||||
<string name="qr_code_too_new">El código QR que has escaneado proviene de una versión posterior de %s.\n\nPor favor actualiza a la última versión y luego intenta nuevamente.</string>
|
||||
<string name="camera_error">Error de cámara</string>
|
||||
<string name="connecting_to_device">Conectando al dispositivo\u2026</string>
|
||||
<string name="authenticating_with_device">Autentificándose con el dispositivo\u2026</string>
|
||||
@@ -280,6 +282,7 @@
|
||||
<string name="step_2">2</string>
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Nuevo contacto añadido.</item>
|
||||
<item quantity="many">%d nuevos contactos añadidos.</item>
|
||||
<item quantity="other">%d nuevos contactos añadidos.</item>
|
||||
</plurals>
|
||||
<string name="offline_state">No hay conexión a Internet</string>
|
||||
@@ -300,7 +303,6 @@
|
||||
<string name="pending_contact_updated_toast">Contacto pendiente actualizado</string>
|
||||
<!--Introductions-->
|
||||
<string name="introduction_onboarding_title">Presenta a tus contactos</string>
|
||||
<string name="introduction_onboarding_text">Presenta a tus contactos entre sí para ahorrarles encontrarse en persona para poder conectar mediante Briar.</string>
|
||||
<string name="introduction_menu_item">Hacer presentación</string>
|
||||
<string name="introduction_activity_title">Seleccionar contacto</string>
|
||||
<string name="introduction_not_possible">Ya tienes una presentación en curso con estos contactos. Por favor, deja que esto termine primero. Si tu o tus contactos raramente están en línea, esto puede tomar algún tiempo.</string>
|
||||
@@ -336,6 +338,7 @@
|
||||
<string name="groups_created_by">Creado por %s</string>
|
||||
<plurals name="messages">
|
||||
<item quantity="one">%d mensaje</item>
|
||||
<item quantity="many">%d mensajes</item>
|
||||
<item quantity="other">%d mensajes</item>
|
||||
</plurals>
|
||||
<string name="groups_group_is_empty">Este grupo está vacío</string>
|
||||
@@ -369,6 +372,7 @@
|
||||
<string name="groups_invitations_declined">Invitación de grupo declinada</string>
|
||||
<plurals name="groups_invitations_open">
|
||||
<item quantity="one">%d invitación de grupo sin responder</item>
|
||||
<item quantity="many">%d invitaciones de grupo sin responder</item>
|
||||
<item quantity="other">%d invitaciones de grupo sin responder</item>
|
||||
</plurals>
|
||||
<string name="groups_invitations_response_accepted_sent">Aceptaste la invitación de grupo de %s.</string>
|
||||
@@ -395,6 +399,7 @@
|
||||
<string name="no_posts">Sin publicaciones</string>
|
||||
<plurals name="posts">
|
||||
<item quantity="one">%d publicación</item>
|
||||
<item quantity="many">%d publicaciones</item>
|
||||
<item quantity="other">%d publicaciones</item>
|
||||
</plurals>
|
||||
<string name="forum_new_message_hint">Nueva publicación</string>
|
||||
@@ -432,6 +437,7 @@
|
||||
<string name="shared_with">Compartido con %1$d (%2$d en línea)</string>
|
||||
<plurals name="forums_shared">
|
||||
<item quantity="one">%d foro compartido por contactos</item>
|
||||
<item quantity="many">%d foros compartidos por contactos</item>
|
||||
<item quantity="other">%d foros compartidos por contactos</item>
|
||||
</plurals>
|
||||
<string name="nobody">Nadie</string>
|
||||
@@ -588,9 +594,29 @@
|
||||
<string name="mailbox_setup_connecting">Conectando...</string>
|
||||
<string name="mailbox_setup_qr_code_wrong_title">Código QR erróneo</string>
|
||||
<string name="mailbox_setup_qr_code_wrong_description">El código escaneado no es válido. Por favor abre la aplicación Buzón de Briar en tu dispositivo de buzón y escanea el código QR que presenta.</string>
|
||||
<string name="mailbox_setup_already_paired_title">Buzón ya vinculado</string>
|
||||
<string name="mailbox_setup_already_paired_description">Desvincula el Buzón en tu otro dispositivo e inténtalo de nuevo.</string>
|
||||
<string name="mailbox_setup_io_error_title">No se pudo conectar</string>
|
||||
<string name="mailbox_setup_io_error_description">Asegúrate de que ambos dispositivos estén conectados a Internet e inténtalo de nuevo.</string>
|
||||
<string name="mailbox_setup_assertion_error_title">Error del buzón</string>
|
||||
<string name="mailbox_setup_assertion_error_description">Por favor, envía tus comentarios (con datos anónimos) a través de la aplicación Briar si la dificultad persiste.</string>
|
||||
<string name="mailbox_setup_camera_error_description">No se pudo acceder a la cámara. Inténtalo de nuevo, tal vez después de reiniciar el dispositivo.</string>
|
||||
<string name="mailbox_setup_paired_title">Conectado</string>
|
||||
<string name="mailbox_setup_paired_description">Tu Buzón ha sido vinculado exitosamente con Briar.\n
|
||||
\nMantén tu Buzón conectado al suministro eléctrico y al Wi-Fi, de modo que siempre esté en línea.</string>
|
||||
<string name="tor_offline_title">Desconectado</string>
|
||||
<string name="tor_offline_description">Asegúrate de que este dispositivo esté en línea y las conexiones a Internet estén permitidas.\n\nLuego, espera a que el ícono de un globo en las configuraciones de conexión se torne verde.</string>
|
||||
<string name="tor_offline_description">Asegúrate de que este dispositivo esté en línea y las conexiones a Internet estén permitidas.\n
|
||||
\nLuego, espera a que el ícono de un globo en las configuraciones de conexión se torne verde.</string>
|
||||
<string name="tor_offline_button_check">Comprobar configuración de conexión</string>
|
||||
<string name="mailbox_status_title">Estado del buzón</string>
|
||||
<string name="mailbox_status_connected_title">El buzón está en ejecución</string>
|
||||
<string name="mailbox_status_failure_title">El buzón no está disponible</string>
|
||||
<string name="mailbox_status_check_button">Comprobar conexión</string>
|
||||
<!--Example for string substitution: Last connection: 3min ago-->
|
||||
<string name="mailbox_status_connected_info">Última conexión: %s</string>
|
||||
<!--Indicates that there never was a connection to the mailbox. Last connection: Never-->
|
||||
<string name="mailbox_status_connected_never">Nunca</string>
|
||||
<string name="mailbox_status_unlink_button">Desvincular</string>
|
||||
<!--Conversation Settings-->
|
||||
<string name="disappearing_messages_title">Mensajes con caducidad</string>
|
||||
<string name="disappearing_messages_explanation_long">Activar este ajuste hará que los nuevos
|
||||
@@ -698,6 +724,7 @@
|
||||
<string name="hotspot_no_peers_connected">No hay dispositivos conectados</string>
|
||||
<plurals name="hotspot_peers_connected">
|
||||
<item quantity="one">%s dispositivo conectado</item>
|
||||
<item quantity="many">%s dispositivos conectados</item>
|
||||
<item quantity="other">%s dispositivos conectados</item>
|
||||
</plurals>
|
||||
<!--Download link-->
|
||||
@@ -706,8 +733,6 @@
|
||||
<string name="hotspot_manual_site_address">Dirección (URL)</string>
|
||||
<string name="hotspot_qr_site">Tu teléfono está proporcionando un punto de acceso Wi-Fi. Las personas que están conectadas al mismo pueden descargar Briar escaneando este código QR.</string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">Descargar %s</string>
|
||||
<string name="website_download_intro">Alguien en las cercanías compartió %s contigo.</string>
|
||||
<string name="website_download_outro">Luego de que la descarga se complete, abre el archivo descargado e instálalo.</string>
|
||||
<string name="website_troubleshooting_title">Resolución de problemas</string>
|
||||
<string name="website_troubleshooting_1">Si no puedes descargar la aplicación, inténtalo con una aplicación de navegación web diferente.</string>
|
||||
|
||||
@@ -28,7 +28,10 @@
|
||||
<string name="dnkm_xiaomi_button">حفاظت از Briar (برایر)</string>
|
||||
<string name="dnkm_xiaomi_help">اگر برایر (Briar) در لیست اپهای اخیر قفل نشود، قادر با اجرا در پسزمینه نخواهد بود.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. لیست اپهای اخیر (یا app switcher) را باز کنید\n\n2. عکس اپ برایر (Briar) را پایین کشیده تا آیکون قفل نمایش یابد\n\n3. اگر قفل بسته نیست، روی آن بزنید تا قفل شود</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. لیست اپهای اخیر (یا app switcher) را باز کنید\n\n2. اروی عکس اپ برایر (Briar) نگه داشته تا آیکون قفل نمایش یابد\n\n3. اگر قفل بسته نیست، روی آن بزنید تا قفل شود</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. فهرست برنامههای اخیر را باز کنید (که به آن app switcher نیز گفته میشود)\n\n2. اگر Briar تصویر کوچکی از یک قفل در کنار نام خود دارد، دیگر لازم نیست کاری انجام دهید\n\n3. اگر قفلی وجود ندارد، تصویر Briar را فشار داده و نگه دارید تا دکمه قفل ظاهر شود، سپس روی آن ضربه بزنید.</string>
|
||||
<string name="dnkm_xiaomi_lock_apps_text">لطفا روی دکمه زیر ضربه بزنید تا تنظیمات امنیتی باز شود. روی \"Boost speed\" ضربه بزنید، سپس روی \"Lock apps\" ضربه بزنید و مطمئن شوید که Briar روی \"Locked\" تنظیم شده است.</string>
|
||||
<string name="dnkm_xiaomi_lock_apps_help">اگر Briar در صفحه \"Lock apps\" روی \"Locked\" تنظیم نشود، نمیتواند در پسزمینه اجرا شود.</string>
|
||||
<string name="dnkm_warning_dozed_1">Briar قادر به اجرا در پسزمینه نبود</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">گذرواژه</string>
|
||||
<string name="try_again">گذرواژه اشتباه است، لطفا دوباره سعی کنید</string>
|
||||
@@ -240,12 +243,8 @@
|
||||
<string name="contact_added_toast">مخاطب اضافه شد: %s</string>
|
||||
<string name="contact_already_exists">مخاطب %s از قبل وجود دارد</string>
|
||||
<string name="qr_code_invalid">کد کیوآر نامعتبر می باشد</string>
|
||||
<string name="qr_code_too_old">کد کیوآر اسکن شده متعلق به یک نسخه قدیمی از %s است.
|
||||
|
||||
لطفا از مخاطب خود بخواهید تا به آخرین نسخه ارتقا داده و سپس دوباره تلاش کنید.</string>
|
||||
<string name="qr_code_too_new">کد کیوآر اسکن شده توسط شما متعلق به یک نسخه جدیدتر از %s است.
|
||||
|
||||
لطفا به آخرین نسخه ارتقا داده و دوباره تلاش کنید.</string>
|
||||
<string name="qr_code_too_old_1">کد QR که اسکن کردهاید مربوط به نسخه قدیمی Briar است.\n\nلطفا از مخاطب خود بخواهید به آخرین نسخه ارتقا دهد و سپس دوباره امتحان کنید.</string>
|
||||
<string name="qr_code_too_new_1">کد QR که اسکن کردهاید مربوط به نسخه جدیدتری از Briar است.\n\nلطفا به آخرین نسخه ارتقا دهید و سپس دوباره امتحان کنید.</string>
|
||||
<string name="camera_error">خطای دوربین</string>
|
||||
<string name="connecting_to_device">اتصال به دستگاهu2026\</string>
|
||||
<string name="authenticating_with_device">تصدیق سازی با دستگاه u2026\</string>
|
||||
@@ -638,6 +637,10 @@
|
||||
<string name="mailbox_status_connected_title">Mailbox در حال اجراست</string>
|
||||
<string name="mailbox_status_problem_title">Briar در اتصال به صندوق پستی به مشکلی برخورده است</string>
|
||||
<string name="mailbox_status_failure_title">صندوق پستی در دسترس نیست</string>
|
||||
<string name="mailbox_status_app_too_old_title">Briar خیلی قدیمی است</string>
|
||||
<string name="mailbox_status_app_too_old_message">Briar را به آخرین نسخه برنامه بهروزرسانی کنید و دوباره امتحان کنید.</string>
|
||||
<string name="mailbox_status_mailbox_too_old_title">Mailbox خیلی قدیمی است</string>
|
||||
<string name="mailbox_status_mailbox_too_old_message">Mailbox خود را به آخرین نسخه برنامه بهروزرسانی کنید و دوباره امتحان کنید.</string>
|
||||
<string name="mailbox_status_check_button">اتصال را بررسی کنید</string>
|
||||
<!--Example for string substitution: Last connection: 3min ago-->
|
||||
<string name="mailbox_status_connected_info">آخرین اتصال: %s</string>
|
||||
@@ -800,8 +803,9 @@ Briar (برایر) موقعیت شما را ذخیره نمیکند و آن
|
||||
<string name="hotspot_manual_site_address">آدرس (URL)</string>
|
||||
<string name="hotspot_qr_site">تلفن شما Wi-Fi hotspot ارائه میکند. کسانی که به hotspot متصل هستند، میتوانند Briar را با اسکن این کد QR دانلود کنند.</string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">دانلود %s</string>
|
||||
<string name="website_download_intro">فردی در نزدیکی %s را با شما به اشتراک گذاشته است.</string>
|
||||
<string name="website_download_title_1">دانلود Briar %s</string>
|
||||
<string name="website_download_intro_1">شخصی در همین نزدیکی Briar را با شما به اشتراک گذاشته است.</string>
|
||||
<string name="website_download_button">دانلود Briar</string>
|
||||
<string name="website_download_outro">پس از تکمیل دانلود، فایل دانلود شده را باز کرده و نصب کنید.</string>
|
||||
<string name="website_troubleshooting_title">◾️ عیب یابی</string>
|
||||
<string name="website_troubleshooting_1">اگر قادر به دانلود کردن برنامه نیستید، با مرورگر دیگری امتحان کنید.</string>
|
||||
|
||||
@@ -1,37 +1,31 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources>
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Bienvenue à 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_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 oubliez votre mot de passe ou désinstallez Briar, votre compte ne peut pas être récupéré.\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="dnkm_doze_title">Connexions d’arrière-plan</string>
|
||||
<string name="dnkm_doze_intro">Pour recevoir des messages, Briar a besoin de rester connectée en arrière-plan.</string>
|
||||
<string name="dnkm_doze_explanation">Pour recevoir des messages, Briar a besoin de rester connectée en arrière-plan. Veuillez désactiver les optimisations de la pile afin que Briar puisse rester connectée.</string>
|
||||
<string name="dnkm_doze_button">Autoriser les connexions</string>
|
||||
<string name="choose_nickname">Choisissez votre pseudonyme</string>
|
||||
<string name="choose_password">Choisissez votre mot de passe</string>
|
||||
<string name="confirm_password">Confirmez votre mot de passe</string>
|
||||
<string name="name_too_long">Le nom est trop long</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="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="dnkm_huawei_protected_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="dnkm_huawei_protected_button">Protéger Briar</string>
|
||||
<string name="dnkm_huawei_protected_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="dnkm_huawei_app_launch_text">Veuillez toucher le bouton ci-dessous, ouvrir l’écran « Lancement des applis » et vous assurer que « Gérer manuellement » est défini pour Briar.</string>
|
||||
<string name="dnkm_huawei_app_launch_button">Ouvrez les paramètres de la pile</string>
|
||||
<string name="dnkm_huawei_app_launch_help">Si « Gérer manuellement » n’est pas défini pour Briar dans l’écran « Lancement des applis », l’appli ne pourra pas fonctionner en arrière-plan.</string>
|
||||
<string name="dnkm_huawei_app_launch_error_toast">Impossible d’ouvrir les paramètres de la pile</string>
|
||||
<string name="dnkm_xiaomi_text">Pour fonctionner en arrière-plan, Briar doit être verrouillée à la liste des applis récentes.</string>
|
||||
<string name="dnkm_xiaomi_button">Protéger Briar</string>
|
||||
<string name="dnkm_xiaomi_help">Si Briar n’est pas verrouillée à la liste des applis récentes, elle ne pourra pas fonctionner en arrière-plan.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Ouvrez la liste des applis récentes (aussi appelé sélecteur d’appli)\n\n2. Balayez l’image de Briar vers le bas pour afficher l’icône de verrou\n\n3. Si le verrou n’est pas verrouillé, touchez pour le verrouiller</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Ouvrez la liste des applis récentes (aussi appelé sélecteur d’appli)\n\n2. Touchez et maintenez l’image de Briar jusqu’à l’apparition du verrou\n\n3. Si le verrou n’est pas verrouillé, touchez pour le verrouiller</string>
|
||||
<string name="dnkm_warning_dozed">%s n’a pas pu fonctionner en arrière-plan</string>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Bienvenue à 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_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 oubliez votre mot de passe ou désinstallez Briar, votre compte ne peut pas être récupéré.\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="dnkm_doze_intro">Pour recevoir des messages, Briar a besoin de rester connectée en arrière-plan.</string>
|
||||
<string name="dnkm_doze_explanation">Pour recevoir des messages, Briar a besoin de rester connectée en arrière-plan. Veuillez désactiver les optimisations de la pile afin que Briar puisse rester connectée.</string>
|
||||
<string name="choose_nickname">Choisissez votre pseudonyme</string>
|
||||
<string name="choose_password">Choisissez votre mot de passe</string>
|
||||
<string name="confirm_password">Confirmez votre mot de passe</string>
|
||||
<string name="name_too_long">Le nom est trop long</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="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="dnkm_huawei_protected_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="dnkm_huawei_protected_button">Protéger Briar</string>
|
||||
<string name="dnkm_huawei_protected_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="dnkm_huawei_app_launch_text">Veuillez toucher le bouton ci-dessous, ouvrir l’écran « Lancement des applis » et vous assurer que « Gérer manuellement » est défini pour Briar.</string>
|
||||
<string name="dnkm_huawei_app_launch_help">Si « Gérer manuellement » n’est pas défini pour Briar dans l’écran « Lancement des applis », l’appli ne pourra pas fonctionner en arrière-plan.</string>
|
||||
<string name="dnkm_xiaomi_text">Pour fonctionner en arrière-plan, Briar doit être verrouillée à la liste des applis récentes.</string>
|
||||
<string name="dnkm_xiaomi_button">Protéger Briar</string>
|
||||
<string name="dnkm_xiaomi_help">Si Briar n’est pas verrouillée à la liste des applis récentes, elle ne pourra pas fonctionner en arrière-plan.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Ouvrez la liste des applis récentes (aussi appelé sélecteur d’appli)\n\n2. Balayez l’image de Briar vers le bas pour afficher l’icône de verrou\n\n3. Si le verrou n’est pas verrouillé, touchez pour le verrouiller</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">Mot de passe</string>
|
||||
<string name="try_again">Le mot de passe est erroné, réessayez</string>
|
||||
@@ -49,10 +43,12 @@
|
||||
<string name="startup_failed_service_error">Briar n’a pas pu lancer un composant essentiel.\n\nVeuillez mettre l’appli à jour vers la version la plus récente et réessayer.</string>
|
||||
<plurals name="expiry_warning">
|
||||
<item quantity="one">Ceci est une version d’essai de Briar. Votre compte arrivera à expiration dans %d jour et ne peut pas être renouvelé.</item>
|
||||
<item quantity="many">Ceci est une version d’essai de Briar. Votre compte arrivera à expiration dans %d jours et ne pourra pas être renouvelé.</item>
|
||||
<item quantity="other">Ceci est une version d’essai de Briar. Votre compte arrivera à expiration dans %d jours et ne pourra pas être renouvelé.</item>
|
||||
</plurals>
|
||||
<plurals name="old_android_expiry_warning">
|
||||
<item quantity="one">Android 4 n’est plus pris en charge. Briar cessera de fonctionner le %s (dans %d jour). Veuillez installer Briar sur un appareil plus récent et créer un nouveau compte.</item>
|
||||
<item quantity="many">Android 4 n’est plus pris en charge. Briar cessera de fonctionner le %s (dans %d jours). Veuillez installer Briar sur un appareil plus récent et créer un nouveau compte.</item>
|
||||
<item quantity="other">Android 4 n’est plus pris en charge. Briar cessera de fonctionner le %s (dans %d jours). Veuillez installer Briar sur un appareil plus récent et créer un nouveau compte.</item>
|
||||
</plurals>
|
||||
<string name="expiry_date_reached">Ce logiciel est arrivé à expiration.\nMerci de l’avoir testé !</string>
|
||||
@@ -115,18 +111,22 @@
|
||||
<string name="ongoing_notification_text">Toucher pour ouvrir Briar.</string>
|
||||
<plurals name="private_message_notification_text">
|
||||
<item quantity="one">Nouveau message privé.</item>
|
||||
<item quantity="many">%d nouveaux messages privés.</item>
|
||||
<item quantity="other">%d nouveaux messages privés.</item>
|
||||
</plurals>
|
||||
<plurals name="group_message_notification_text">
|
||||
<item quantity="one">Nouveau message de groupe.</item>
|
||||
<item quantity="many">%d nouveaux messages de groupe.</item>
|
||||
<item quantity="other">%d nouveaux messages de groupe.</item>
|
||||
</plurals>
|
||||
<plurals name="forum_post_notification_text">
|
||||
<item quantity="one">Un nouvel article de forum.</item>
|
||||
<item quantity="many">%d nouveaux articles de forum.</item>
|
||||
<item quantity="other">%d nouveaux articles de forum.</item>
|
||||
</plurals>
|
||||
<plurals name="blog_post_notification_text">
|
||||
<item quantity="one">Nouveau billet de blogue.</item>
|
||||
<item quantity="many">%d nouveaux billets de blogue.</item>
|
||||
<item quantity="other">%d nouveaux billets de blogue.</item>
|
||||
</plurals>
|
||||
<!--Misc-->
|
||||
@@ -181,14 +181,17 @@
|
||||
<string name="auto_delete_msg_contact_enabled">Les messages de %1$s disparaîtront après %2$s. %3$s</string>
|
||||
<plurals name="duration_minutes">
|
||||
<item quantity="one">%d minute</item>
|
||||
<item quantity="many">%d minutes</item>
|
||||
<item quantity="other">%d minutes</item>
|
||||
</plurals>
|
||||
<plurals name="duration_hours">
|
||||
<item quantity="one">%d heure</item>
|
||||
<item quantity="many">%d heures</item>
|
||||
<item quantity="other">%d heures</item>
|
||||
</plurals>
|
||||
<plurals name="duration_days">
|
||||
<item quantity="one">%d jour</item>
|
||||
<item quantity="many">%d jours</item>
|
||||
<item quantity="other">%d jours</item>
|
||||
</plurals>
|
||||
<!--The first placeholder will show a contact's name. The second placeholder at the end will add "Tap to learn more."-->
|
||||
@@ -235,17 +238,15 @@
|
||||
<string name="contact_added_toast">Contact ajouté : %s</string>
|
||||
<string name="contact_already_exists">Le contact %s existe déjà</string>
|
||||
<string name="qr_code_invalid">Le code QR est invalide</string>
|
||||
<string name="qr_code_too_old">Le code QR que vous avez balayé provient d’une version plus ancienne de %s.\n\nVeuillez demander à votre contact de passer à la version la plus récente et réessayer.</string>
|
||||
<string name="qr_code_too_new">Le code QR que vous avez balayé provient d’une version plus récente de %s.\n\nVeuillez passer à la version la plus récente et réessayer.</string>
|
||||
<string name="camera_error">Erreur de l’appareil photo</string>
|
||||
<string name="connecting_to_device">Connexion à l’appareil\u2026</string>
|
||||
<string name="authenticating_with_device">Autentification avec l’appareil\u2026</string>
|
||||
<string name="connection_error_title">Impossible de se connecter à votre contact</string>
|
||||
<string name="connection_error_feedback">Si le problème persiste, veuillez nous <a href="feedback">envoyer une rétroaction</a> pour nous aider à améliorer l’appli.</string>
|
||||
<!--Adding Contacts Remotely-->
|
||||
<string name="add_contact_remotely_title_case">Ajouter un contact éloigné</string>
|
||||
<string name="add_contact_remotely_title_case">Ajouter un contact à distance</string>
|
||||
<string name="add_contact_nearby_title">Ajouter un contact à proximité</string>
|
||||
<string name="add_contact_remotely_title">Ajouter un contact éloigné</string>
|
||||
<string name="add_contact_remotely_title">Ajouter un contact à distance</string>
|
||||
<string name="contact_link_intro">Saisissez ici le lien de votre contact</string>
|
||||
<string name="contact_link_hint">Lien de votre contact</string>
|
||||
<string name="paste_button">Coller</string>
|
||||
@@ -281,6 +282,7 @@
|
||||
<string name="step_2">2</string>
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Un nouveau contact a été ajouté</item>
|
||||
<item quantity="many">%d nouveaux contacts ont été ajoutés.</item>
|
||||
<item quantity="other">%d nouveaux contacts ont été ajoutés.</item>
|
||||
</plurals>
|
||||
<string name="offline_state">Aucune connexion à Internet</string>
|
||||
@@ -301,7 +303,7 @@
|
||||
<string name="pending_contact_updated_toast">Le contact en attente a été mis à jour</string>
|
||||
<!--Introductions-->
|
||||
<string name="introduction_onboarding_title">Présenter vos contacts</string>
|
||||
<string name="introduction_onboarding_text">Vous pouvez présenter vos contacts mutuellement, afin qu’ils n’aient pas à se rencontrer en personne pour se connecter les uns aux autres avec Briar.</string>
|
||||
<string name="introduction_onboarding_text">Présentez vos contacts l\'un à l\'autre ainsi ils pourront se contacter via Briar.</string>
|
||||
<string name="introduction_menu_item">Faire les présentations</string>
|
||||
<string name="introduction_activity_title">Sélectionner un contact </string>
|
||||
<string name="introduction_not_possible">Une présentation est déjà en cours avec ces contacts. Veuillez d’abord lui permettre de se terminer. Si vous ou vos contacts êtes rarement en ligne, cela peut prendre du temps.</string>
|
||||
@@ -337,6 +339,7 @@
|
||||
<string name="groups_created_by">Créé par %s</string>
|
||||
<plurals name="messages">
|
||||
<item quantity="one">%d message</item>
|
||||
<item quantity="many">%d messages</item>
|
||||
<item quantity="other">%d messages</item>
|
||||
</plurals>
|
||||
<string name="groups_group_is_empty">Ce groupe est vide</string>
|
||||
@@ -370,6 +373,7 @@
|
||||
<string name="groups_invitations_declined">L’invitation au groupe a été refusée</string>
|
||||
<plurals name="groups_invitations_open">
|
||||
<item quantity="one">%d invitation au groupe en attente</item>
|
||||
<item quantity="many">%d invitations au groupe en attente</item>
|
||||
<item quantity="other">%d invitations au groupe en attente</item>
|
||||
</plurals>
|
||||
<string name="groups_invitations_response_accepted_sent">Vous avez accepté l’invitation au groupe de %s.</string>
|
||||
@@ -396,6 +400,7 @@
|
||||
<string name="no_posts">Aucun article</string>
|
||||
<plurals name="posts">
|
||||
<item quantity="one">%d article</item>
|
||||
<item quantity="many">%d articles</item>
|
||||
<item quantity="other">%d articles</item>
|
||||
</plurals>
|
||||
<string name="forum_new_message_hint">Nouvelle article</string>
|
||||
@@ -433,6 +438,7 @@
|
||||
<string name="shared_with">Partagé avec %1$d (%2$d en ligne)</string>
|
||||
<plurals name="forums_shared">
|
||||
<item quantity="one">%d forum partagé par des contacts</item>
|
||||
<item quantity="many">%d forums partagés par des contacts</item>
|
||||
<item quantity="other">%d forums partagés par des contacts</item>
|
||||
</plurals>
|
||||
<string name="nobody">Personne</string>
|
||||
@@ -593,10 +599,13 @@
|
||||
<string name="mailbox_setup_io_error_title">Connexion impossible</string>
|
||||
<string name="mailbox_setup_io_error_description">Assurez-vous que les deux appareils sont connectés à Internet et réessayez.</string>
|
||||
<string name="mailbox_setup_assertion_error_title">Erreur de la Boîte de courriel</string>
|
||||
<string name="mailbox_setup_assertion_error_description">Merci de transmettre vos retours (données anonymes) via l\'application Briar si le problème persiste.</string>
|
||||
<string name="mailbox_setup_camera_error_description">Pas d\'accès à l\'appareil photo. réessayez après avoir redémarré l\'appareil.</string>
|
||||
<string name="mailbox_setup_paired_title">Connecté</string>
|
||||
<string name="mailbox_setup_paired_description">Votre Boîte de courriel a été reliée avec succès à Briar.\n
|
||||
\nGarder votre boîte de courriel connectée à l’alimentation et au Wi-Fi afin qu’elle soit toujours en ligne.</string>
|
||||
<string name="tor_offline_title">Hors ligne</string>
|
||||
<string name="tor_offline_button_check">Vérifiez les paramètres de connexion.</string>
|
||||
<string name="mailbox_status_title">État de la Boîte de courriel</string>
|
||||
<string name="mailbox_status_connected_title">La Boîte de courriel est en cours d’exécution</string>
|
||||
<!--Example for string substitution: Last connection: 3min ago-->
|
||||
@@ -704,6 +713,8 @@ copies des messages que vous envoyez.
|
||||
<string name="hotspot_scanning_a_qr_code">balayant un code QR</string>
|
||||
<!--Wi-Fi setup-->
|
||||
<!--The %s placeholder will be replaced with the translation of 'hotspot_scanning_a_qr_code'-->
|
||||
<string name="hotspot_manual_wifi_ssid">Nom du réseau</string>
|
||||
<string name="hotspot_no_peers_connected">Aucun appareil connecté</string>
|
||||
<!--Download link-->
|
||||
<!--The %s placeholder will be replaced with the translation of 'hotspot_scanning_a_qr_code'-->
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
|
||||
@@ -1,36 +1,31 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources>
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Velkomin í Briar</string>
|
||||
<string name="setup_name_explanation">Stuttnefnið þitt birtist við hlið alls þess efnis sem þú sendir inn. Þú getur ekki breytt því eftir að þú hefur skráð notandaaðganginn þinn.</string>
|
||||
<string name="setup_next">Næsta</string>
|
||||
<string name="setup_password_intro">Veldu lykilorð</string>
|
||||
<string name="setup_password_explanation">Notandaaðgangur þinn í Briar er geymdur dulritaður á tækinu þínu, ekki í tölvuskýi. Ef þú gleymir lykilorðinu þínu eða fjarlægir Briar, þá er engin leið til að endurheimta notandaaðganginn þinn.\n\nVeldu langt lykilorð sem erfitt er að giska á, svo sem eins og fjögur orð af handahófi, eða slembna samsetningu tíu bósktafa, tölustafa og tákna.</string>
|
||||
<string name="dnkm_doze_title">Bakgrunnstengingar</string>
|
||||
<string name="dnkm_doze_intro">Til að taka á móti skilaboðum þarf Briar að haldast tengt í bakgrunni.</string>
|
||||
<string name="dnkm_doze_explanation">Til að taka á móti skilaboðum þarf Briar að haldast tengt í bakgrunni. Gerðu orkusparnaðarferli óvirk svo Briar geti haldið tengingum.</string>
|
||||
<string name="dnkm_doze_button">Leyfa tengingar</string>
|
||||
<string name="choose_nickname">Veldu þér stuttnefni</string>
|
||||
<string name="choose_password">Veldu þér lykilorð</string>
|
||||
<string name="confirm_password">Staðfestu lykilorðið</string>
|
||||
<string name="name_too_long">Nafnið er of langt</string>
|
||||
<string name="password_too_weak">Lykilorðið er of veikt</string>
|
||||
<string name="passwords_do_not_match">Lykilorðin stemma ekki</string>
|
||||
<string name="create_account_button">Búa til notandaaðgang</string>
|
||||
<string name="more_info">Nánari upplýsingar</string>
|
||||
<string name="don_t_ask_again">Ekki spyrja aftur</string>
|
||||
<string name="dnkm_huawei_protected_text">Ýttu á hnappinn hér fyrir neðan og gakktu úr skugga um að Briar sé varið á skjánum \"Varin forrit\".</string>
|
||||
<string name="dnkm_huawei_protected_button">Vernda Briar</string>
|
||||
<string name="dnkm_huawei_protected_help">Ef Briar er ekki bætt á listann yfir varin forrit, getur það ekki keyrt í bakgrunni.</string>
|
||||
<string name="dnkm_huawei_app_launch_text">Ýttu á hnappinn hér fyrir neðan, opnaðu \"Ræsing forrits\" skjáinn og gakktu úr skugga um að Briar sé stillt á \"Stýra handvirkt\".</string>
|
||||
<string name="dnkm_huawei_app_launch_button">Opna rafhlöðustillingar</string>
|
||||
<string name="dnkm_huawei_app_launch_help">Ef Briar er ekki stillt á \"Stýra handvirkt\" í \"Ræsing forrits\" skjánum, mun það ekki geta keyrt í bakgrunni.</string>
|
||||
<string name="dnkm_xiaomi_text">Til að keyra í bakgrunni þarf Briar að vera læst við listann yfir nýleg forrit.</string>
|
||||
<string name="dnkm_xiaomi_button">Vernda Briar</string>
|
||||
<string name="dnkm_xiaomi_help">Ef Briar er ekki læst við listann yfir nýleg forrit, mun það ekki geta keyrt í bakgrunni.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Opnaðu listann yfir nýleg forrit (einnig kallað forritaskiptir)\n\n2. Strjúktu niður myndina af Briar til að birta hengilástáknið\n\n3. Ef hengilásinn er ekki læstur, ýttu á hann til að læsa</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Opnaðu listann yfir nýleg forrit (einnig kallað forritaskiptir)\n\n2. Ýttu og haltu niðri á myndina af Briar til að birta hengiláshnappinn\n\n3. Ef hengilásinn er ekki læstur, ýttu á hann til að læsa</string>
|
||||
<string name="dnkm_warning_dozed">%s gat ekki keyrt í bakgrunni</string>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Velkomin í Briar</string>
|
||||
<string name="setup_name_explanation">Stuttnefnið þitt birtist við hlið alls þess efnis sem þú sendir inn. Þú getur ekki breytt því eftir að þú hefur skráð notandaaðganginn þinn.</string>
|
||||
<string name="setup_next">Næsta</string>
|
||||
<string name="setup_password_intro">Veldu lykilorð</string>
|
||||
<string name="setup_password_explanation">Notandaaðgangur þinn í Briar er geymdur dulritaður á tækinu þínu, ekki í tölvuskýi. Ef þú gleymir lykilorðinu þínu eða fjarlægir Briar, þá er engin leið til að endurheimta notandaaðganginn þinn.\n\nVeldu langt lykilorð sem erfitt er að giska á, svo sem eins og fjögur orð af handahófi, eða slembna samsetningu tíu bósktafa, tölustafa og tákna.</string>
|
||||
<string name="dnkm_doze_intro">Til að taka á móti skilaboðum þarf Briar að haldast tengt í bakgrunni.</string>
|
||||
<string name="dnkm_doze_explanation">Til að taka á móti skilaboðum þarf Briar að haldast tengt í bakgrunni. Gerðu orkusparnaðarferli óvirk svo Briar geti haldið tengingum.</string>
|
||||
<string name="choose_nickname">Veldu þér stuttnefni</string>
|
||||
<string name="choose_password">Veldu þér lykilorð</string>
|
||||
<string name="confirm_password">Staðfestu lykilorðið</string>
|
||||
<string name="name_too_long">Nafnið er of langt</string>
|
||||
<string name="password_too_weak">Lykilorðið er of veikt</string>
|
||||
<string name="passwords_do_not_match">Lykilorðin stemma ekki</string>
|
||||
<string name="create_account_button">Búa til notandaaðgang</string>
|
||||
<string name="more_info">Nánari upplýsingar</string>
|
||||
<string name="don_t_ask_again">Ekki spyrja aftur</string>
|
||||
<string name="dnkm_huawei_protected_text">Ýttu á hnappinn hér fyrir neðan og gakktu úr skugga um að Briar sé varið á skjánum \"Varin forrit\".</string>
|
||||
<string name="dnkm_huawei_protected_button">Vernda Briar</string>
|
||||
<string name="dnkm_huawei_protected_help">Ef Briar er ekki bætt á listann yfir varin forrit, getur það ekki keyrt í bakgrunni.</string>
|
||||
<string name="dnkm_huawei_app_launch_text">Ýttu á hnappinn hér fyrir neðan, opnaðu \"Ræsing forrits\" skjáinn og gakktu úr skugga um að Briar sé stillt á \"Stýra handvirkt\".</string>
|
||||
<string name="dnkm_huawei_app_launch_help">Ef Briar er ekki stillt á \"Stýra handvirkt\" í \"Ræsing forrits\" skjánum, mun það ekki geta keyrt í bakgrunni.</string>
|
||||
<string name="dnkm_xiaomi_text">Til að keyra í bakgrunni þarf Briar að vera læst við listann yfir nýleg forrit.</string>
|
||||
<string name="dnkm_xiaomi_button">Vernda Briar</string>
|
||||
<string name="dnkm_xiaomi_help">Ef Briar er ekki læst við listann yfir nýleg forrit, mun það ekki geta keyrt í bakgrunni.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Opnaðu listann yfir nýleg forrit (einnig kallað forritaskiptir)\n\n2. Strjúktu niður myndina af Briar til að birta hengilástáknið\n\n3. Ef hengilásinn er ekki læstur, ýttu á hann til að læsa</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">Lykilorð</string>
|
||||
<string name="try_again">Rangt lykilorð, reyndu aftur</string>
|
||||
@@ -234,8 +229,6 @@
|
||||
<string name="contact_added_toast">Tengilið bætt við: %s</string>
|
||||
<string name="contact_already_exists">Tengiliðurinn %s er þegar til</string>
|
||||
<string name="qr_code_invalid">QR-kóðinn er ógildur</string>
|
||||
<string name="qr_code_too_old">QR-kóðinn sem þú skannaðir kemur frá eldri útgáfu af %s.\n\nBiddu tengiliðinn þinn um að uppfæra í nýjustu útgáfuna og prófaðu síðan aftur.</string>
|
||||
<string name="qr_code_too_new">QR-kóðinn sem þú skannaðir kemur frá nýrri útgáfu af %s.\n\nUppfærðu í nýjustu útgáfuna og prófaðu síðan aftur.</string>
|
||||
<string name="camera_error">Villa í myndavél</string>
|
||||
<string name="connecting_to_device">Tengist við tæki\u2026</string>
|
||||
<string name="authenticating_with_device">Auðkenni við tæki\u2026</string>
|
||||
@@ -300,7 +293,6 @@
|
||||
<string name="pending_contact_updated_toast">Tengiliður í bið uppfærður</string>
|
||||
<!--Introductions-->
|
||||
<string name="introduction_onboarding_title">Kynntu tengiliðina þína</string>
|
||||
<string name="introduction_onboarding_text">Þú getur kynnt tengiliðina þína fyrir hver öðrum, svo að þeir þurfi ekki að hittast í eigin persónu til að tengjast í gegnum Briar.</string>
|
||||
<string name="introduction_menu_item">Útbúa kynningu</string>
|
||||
<string name="introduction_activity_title">Veldu tengilið</string>
|
||||
<string name="introduction_not_possible">Þú ert þegar með eina kynningu í vinnslu gagnvart þessum tengiliðum. Leyfðu því ferli að ljúka fyrst. Ef þú eða tengiliðirnir þínir eruð sjaldan á netinu, gæti þetta tekið svolítinn tíma.</string>
|
||||
@@ -604,10 +596,13 @@
|
||||
<string name="tor_offline_button_check">Athugaðu tengistillingarnar</string>
|
||||
<string name="mailbox_status_title">Staða pósthólfs</string>
|
||||
<string name="mailbox_status_connected_title">Pósthólf er í gangi</string>
|
||||
<string name="mailbox_status_failure_title">Pósthólf er ekki tiltækt</string>
|
||||
<string name="mailbox_status_check_button">Athugaðu tenginguna</string>
|
||||
<!--Example for string substitution: Last connection: 3min ago-->
|
||||
<string name="mailbox_status_connected_info">Síðasta tenging: %s</string>
|
||||
<!--Indicates that there never was a connection to the mailbox. Last connection: Never-->
|
||||
<string name="mailbox_status_connected_never">Aldrei</string>
|
||||
<string name="mailbox_status_unlink_button">Aftengja</string>
|
||||
<!--Conversation Settings-->
|
||||
<string name="disappearing_messages_title">Sjálfeyðandi skilaboð</string>
|
||||
<string name="disappearing_messages_explanation_long">Ef kveikt er á þessari stillingu munu ný
|
||||
@@ -723,8 +718,6 @@
|
||||
<string name="hotspot_manual_site_address">Vistfang (URL)</string>
|
||||
<string name="hotspot_qr_site">Síminn þinn er að reka Wi-Fi aðgangsstað. Fólk sem er tengt aðgangsstaðnum getur sótt Briar með því að skanna þennan QR-kóða.</string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">Sækja %s</string>
|
||||
<string name="website_download_intro">Einhver í nágrenninu hefur deilt %s með þér.</string>
|
||||
<string name="website_download_outro">Eftir að niðurhalinu er lokið, skaltu opna sóttu skrána og setja hana upp.</string>
|
||||
<string name="website_troubleshooting_title">Lausn á vandamálum</string>
|
||||
<string name="website_troubleshooting_1">Ef þú getur ekki sótt forritið, ættirðu að prófa það með öðrum vafra.</string>
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
<string name="dnkm_xiaomi_button">Proteggi Briar</string>
|
||||
<string name="dnkm_xiaomi_help">Se Briar non è fissato nella lista di app recenti, non potrà funzionare in secondo piano.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Apri la lista di app recenti (chiamata anche app switcher)\n\n2. Scorri fino alla schermata di Briar per mostrare l\'icona del lucchetto\n\n3. Se il lucchetto non è chiuso, toccalo per chiuderlo</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Apri la lista di app recenti (chiamata anche app switcher)\n\n2. Tieni premuta la schermata di Briar finché non compare l\'icona del lucchetto\n\n3. Se il lucchetto non è chiuso, toccalo per chiuderlo</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">Password</string>
|
||||
<string name="try_again">Password sbagliata, riprova</string>
|
||||
@@ -239,8 +238,6 @@
|
||||
<string name="contact_added_toast">Contatto aggiunto: %s</string>
|
||||
<string name="contact_already_exists">Il contatto %s esiste già</string>
|
||||
<string name="qr_code_invalid">Il codice QR non è valido</string>
|
||||
<string name="qr_code_too_old">Il codice QR che hai scansionato proviene da una vecchia versione di %s.\n\nChiedi al tuo contatto di aggiornare all\'ultima versione e poi riprova.</string>
|
||||
<string name="qr_code_too_new">Il codice QR che hai scansionato proviene da una versione più recente di %s.\n\nAggiorna all\'ultima versione e poi riprova.</string>
|
||||
<string name="camera_error">Errore fotocamera</string>
|
||||
<string name="connecting_to_device">Connessione al dispositivo\u2026</string>
|
||||
<string name="authenticating_with_device">Autenticazione con il dispositivo\u2026</string>
|
||||
@@ -627,6 +624,9 @@
|
||||
<string name="mailbox_status_unlink_dialog_warning">Se la scolleghi non potrai più ricevere messaggi mentre Briar è offline.</string>
|
||||
<string name="mailbox_status_unlink_no_wipe_title">La casella postale è stata scollegata</string>
|
||||
<string name="mailbox_status_unlink_no_wipe_message">La prossima volta che avrai accesso al dispositivo della casella postale, apri l\'app Mailbox e tocca il pulsante \"Scollega\" per completare il processo.\n\nSe non hai più accesso al dispositivo, non preoccuparti. I dati sono cifrati e rimarranno sicuri anche se non completi il processo.</string>
|
||||
<string name="mailbox_error_notification_channel_title">Problema casella postale di Briar</string>
|
||||
<string name="mailbox_error_notification_title">Casella postale di Briar non disponibile</string>
|
||||
<string name="mailbox_error_notification_text">Tocca per risolvere il problema.</string>
|
||||
<string name="mailbox_error_wizard_button">Risolvi problema</string>
|
||||
<string name="mailbox_error_wizard_title">Wizard risoluzione problemi casella postale</string>
|
||||
<string name="mailbox_error_wizard_question1">Hai accesso al dispositivo della casella postale?</string>
|
||||
@@ -764,8 +764,6 @@
|
||||
<string name="hotspot_manual_site_address">Indirizzo (URL)</string>
|
||||
<string name="hotspot_qr_site">Il tuo telefono sta fornendo un hotspot Wi-Fi. Le persone connesse all\'hotspot possono scaricare Briar scansionando questo codice QR.</string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">Scarica %s</string>
|
||||
<string name="website_download_intro">Qualcuno nelle vicinanze ha condiviso %s con te.</string>
|
||||
<string name="website_download_outro">Dopo il completamento del download, apri il file scaricato e installalo.</string>
|
||||
<string name="website_troubleshooting_title">Risoluzione dei problemi</string>
|
||||
<string name="website_troubleshooting_1">Se non puoi scaricare l\'app, prova con un browser web diverso.</string>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Briarへようこそ</string>
|
||||
<string name="setup_title">Briar へようこそ</string>
|
||||
<string name="setup_name_explanation">あなたのニックネームは、常に、あなたが投稿するコンテンツとともに表示されます。プロフィール作成後、編集はできません。</string>
|
||||
<string name="setup_next">次へ</string>
|
||||
<string name="setup_password_intro">パスワードを選択</string>
|
||||
<string name="setup_password_explanation">Briarのアカウント情報はクラウドではなく、暗号化された端末に保存されます。アプリのアンインストールやパスワードの紛失をした場合、アカウントへのアクセスとデータを回復する手段はありません。\n\n推測するのが難しい、長いパスワードを設定してください。ランダムな4単語やランダムな10文字と数字と記号を組み合わせたものなどです。</string>
|
||||
<string name="dnkm_doze_intro">メッセージを受信するには、Briarはバックグラウンドで接続を維持する必要があります。</string>
|
||||
<string name="dnkm_doze_explanation">メッセージを受信するには、Briarはバックグラウンドで接続を維持する必要があります。 Briarが接続を維持できるように、バッテリーの最適化を無効にしてください。</string>
|
||||
<string name="setup_password_explanation">Briar のアカウント情報はクラウドではなく、暗号化された端末に保存されます。アプリのアンインストールやパスワードを紛失した場合、アカウントへのアクセスとデータを回復する手段はありません。\n\n推測するのが難しい、長いパスワードを設定してください。ランダムな4単語やランダムな10文字と数字と記号を組み合わせたものなどです。</string>
|
||||
<string name="dnkm_doze_intro">メッセージを受信するために、Briar はバックグラウンドで接続を維持する必要があります。</string>
|
||||
<string name="dnkm_doze_explanation">メッセージを受信するために、Briar はバックグラウンドで接続を維持する必要があります。 Briar が接続を維持できるように、バッテリーの最適化を無効にしてください。</string>
|
||||
<string name="choose_nickname">ニックネームを入力</string>
|
||||
<string name="choose_password">パスワードを入力</string>
|
||||
<string name="confirm_password">確認のため再度パスワードを入力</string>
|
||||
@@ -17,36 +17,42 @@
|
||||
<string name="create_account_button">アカウントを作成</string>
|
||||
<string name="more_info">詳細情報</string>
|
||||
<string name="don_t_ask_again">次からは尋ねない</string>
|
||||
<string name="dnkm_huawei_protected_text">下のボタンをタップして、「保護されたアプリ」画面でBriarが保護されていることを確認してください。</string>
|
||||
<string name="dnkm_huawei_protected_button">Briarを保護</string>
|
||||
<string name="dnkm_huawei_protected_help">Briarが保護されたアプリのリストに追加されていない場合、Briarはバックグラウンドで実行することができません。</string>
|
||||
<string name="dnkm_xiaomi_button">Briarを保護</string>
|
||||
<string name="dnkm_huawei_protected_text">下のボタンをタップして、「保護されたアプリ」画面で Briar が保護されていることを確認してください。</string>
|
||||
<string name="dnkm_huawei_protected_button">Briar を保護する</string>
|
||||
<string name="dnkm_huawei_protected_help">Briar が保護されたアプリのリストに追加されていないと、Briar はバックグラウンドで実行することができません。</string>
|
||||
<string name="dnkm_huawei_app_launch_text">下のボタンをタップして「アプリの起動」画面を開き、Briar が「手動で管理する」に設定されていることを確認してください。</string>
|
||||
<string name="dnkm_huawei_app_launch_help">「アプリ起動」画面で Briar を「手動で管理する」に設定していないと、バックグラウンドで動作させることができません。</string>
|
||||
<string name="dnkm_xiaomi_text">バックグラウンドで実行するには、Briar を最近のアプリのリストにロックする必要があります。</string>
|
||||
<string name="dnkm_xiaomi_button">Briar を保護する</string>
|
||||
<string name="dnkm_xiaomi_help">Briar が最近のアプリのリストにロックされていないと、バックグラウンドで実行することができません。</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. 最近使ったアプリのリスト(アプリスイッチャーともいう)を開いて下さい。\n\n2. Briar の画像を下にスワイプすると、南京錠のアイコンが表示されます。\n\n3. ロックされていない場合は、タップしてロックします。</string>
|
||||
<string name="dnkm_warning_dozed_1">Briarはバックグラウンドで実行することができませんでした</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">パスワード</string>
|
||||
<string name="try_again">パスワードが間違っています。もう一度入力してください。</string>
|
||||
<string name="dialog_title_cannot_check_password">パスワードを確認できません</string>
|
||||
<string name="dialog_message_cannot_check_password">Briarはあなたのパスワードを確認できません。この問題を解決するため、デバイスの再起動を試してください。</string>
|
||||
<string name="dialog_message_cannot_check_password">Briar がパスワードを確認することができませんでした。この問題を解決するには、端末の再起動を試してください。</string>
|
||||
<string name="sign_in_button">サインイン</string>
|
||||
<string name="forgotten_password">パスワードを忘れました</string>
|
||||
<string name="dialog_title_lost_password">パスワードを紛失</string>
|
||||
<string name="dialog_message_lost_password">あなたのBriarアカウントはクラウド上ではなく、暗号化さた上であなたのデバイスに保存さています。したがってBriarはパスワードをリセットできません。アカウントを削除しはじめからやりなおしますか?\n\n注意:あなたのID、連絡先、メッセージは永久に復元できません。</string>
|
||||
<string name="startup_failed_activity_title">起動に失敗しました</string>
|
||||
<string name="startup_failed_clock_error">デバイスの時計が不正なので、Briarは起動できませんでした。\n\nデバイスの時計を正しい時刻に設定して、再試行してください。</string>
|
||||
<string name="startup_failed_db_error">Briarは、あなたのアカウント、連絡先、メッセージを含むデータベースを開くことができませんでした。\n\nアプリを最新版にアップグレードして再度お試しいただくか、パスワード入力画面で\'パスワードを忘れました\'を選択して新しいアカウントを設定してください。</string>
|
||||
<string name="dialog_message_lost_password">Briar アカウントはクラウド上ではなく、暗号化さた上であなたの端末に保存さています。したがって、Briar はパスワードをリセットできません。アカウントを削除して、はじめからやり直しますか?\n\n注意:あなたのID、連絡先、メッセージは永久に失われます。</string>
|
||||
<string name="startup_failed_activity_title">Briar の起動に失敗しました</string>
|
||||
<string name="startup_failed_clock_error">お使いの端末の時計が正しくないため、Briar は起動できませんでした。\n\n端末の時計を正しい時刻に設定してから、もう一度試してください。</string>
|
||||
<string name="startup_failed_db_error">Briar は、あなたのアカウント、連絡先、メッセージを含むデータベースを開くことができませんでした。\n\nアプリを最新版にアップグレードしてもう一度お試しいただくか、パスワード入力画面で「パスワードを忘れました」を選択して新しいアカウントを設定してください。</string>
|
||||
<string name="startup_failed_data_too_old_error">あなたのアカウントは古いバージョンのアプリで作成されたもので、このバージョンでは開くことができません。\n\n古いバージョンを再インストールするか、パスワード入力画面で\'パスワードを忘れました\'を選択して新しいアカウントを設定する必要があります。</string>
|
||||
<string name="startup_failed_data_too_new_error">あなたのアカウントは、このアプリの新しいバージョンで作成されたもので、このバージョンでは開くことができません。\n\n最新版にアップグレードしてから、もう一度試してください。</string>
|
||||
<string name="startup_failed_service_error">Briarは、必要なコンポーネントを起動できませんでした。\n\nアプリの最新版にアップグレードしてから、もう一度試してください。</string>
|
||||
<string name="startup_failed_service_error">Briar は、必要なコンポーネントを起動できませんでした。\n\nアプリの最新版にアップグレードしてから、もう一度試してください。</string>
|
||||
<plurals name="expiry_warning">
|
||||
<item quantity="other">これは、Briarのテストバージョンです。 アカウントは%d日で期限切れになり、更新できません。</item>
|
||||
<item quantity="other">これは、Briar のテストバージョンです。 アカウントはあと%d日で期限切れになり、更新できません。</item>
|
||||
</plurals>
|
||||
<plurals name="old_android_expiry_warning">
|
||||
<item quantity="other">Android 4は最早サポートされていません。Briarは(%d日後に)%s上での動作を停止します。新しい端末にBriarをインストールして、新しいアカウントを作成してください。</item>
|
||||
<item quantity="other">Android 4はサポートされなくなりました。Briar は(%d日後に)%s上での動作を停止します。新しい端末に Briar をインストールして、新しいアカウントを作成してください。</item>
|
||||
</plurals>
|
||||
<string name="expiry_date_reached">このソフトウェアの有効期限が切れました。テストに参加してくださりありがとうございます!</string>
|
||||
<string name="download_briar">Briarの使用を続けるならば、最新リリースをダウンロードしてください。</string>
|
||||
<string name="download_briar">Briarの使用を続けるには、最新リリースをダウンロードしてください。</string>
|
||||
<string name="create_new_account">新しいアカウントを作成する必要があります。同じニックネームも使用できます。</string>
|
||||
<string name="download_briar_button">最新リリースをダウンロード</string>
|
||||
<string name="old_android_expiry_date_reached">Briarは最早Android 4上での実行をサポートしていません。\n新しい端末にBriarをインストールしてください。</string>
|
||||
<string name="old_android_expiry_date_reached">Briar は Android 4 では動作しなくなりました。\n新しい端末にBriarをインストールしてください。</string>
|
||||
<string name="old_android_delete_account">下のボタンをタップして、この端末からあなたのアカウントを削除できます。</string>
|
||||
<string name="delete_account_button">アカウントを削除</string>
|
||||
<string name="startup_open_database">データベースの復号化中…</string>
|
||||
@@ -63,36 +69,36 @@
|
||||
<string name="lock_button">アプリをロック</string>
|
||||
<string name="settings_button">設定</string>
|
||||
<string name="sign_out_button">サインアウト</string>
|
||||
<string name="transports_onboarding_text">ここにタップすると、Briarがあなたの連絡先に接続する方法を制御できます。</string>
|
||||
<string name="transports_onboarding_text">ここにタップすると、Briar があなたの連絡先に接続する方法を制御できます。</string>
|
||||
<!--Transports: Tor-->
|
||||
<string name="transport_tor">インターネット</string>
|
||||
<string name="tor_device_status_online_wifi">電話機はWi-Fiでインターネットにアクセスできます</string>
|
||||
<string name="tor_device_status_online_mobile">電話機はモバイル データでインターネットにアクセスできます</string>
|
||||
<string name="tor_device_status_offline">電話機がインターネットに接続できない</string>
|
||||
<string name="tor_plugin_status_enabling">Briarはインターネットに接続中</string>
|
||||
<string name="tor_plugin_status_active">Briarはインターネットに接続しました</string>
|
||||
<string name="tor_plugin_status_inactive">Briarはインターネットに接続不可能</string>
|
||||
<string name="tor_plugin_status_disabled">Briarはインターネットを使用しないように設定されました</string>
|
||||
<string name="tor_plugin_status_disabled_mobile_data">Briarはモバイルデータを使用しないように設定されました</string>
|
||||
<string name="tor_plugin_status_disabled_battery">Briarはバッテリー駆動時にインターネットを使用しないように設定されました</string>
|
||||
<string name="tor_plugin_status_disabled_country_blocked">Briarはこの国でインターネットを使わないように設定されました</string>
|
||||
<string name="tor_device_status_offline">電話機がインターネットに接続できません</string>
|
||||
<string name="tor_plugin_status_enabling">Briar はインターネットに接続中です…</string>
|
||||
<string name="tor_plugin_status_active">Briar はインターネットに接続されました</string>
|
||||
<string name="tor_plugin_status_inactive">Briar はインターネットに接続できません</string>
|
||||
<string name="tor_plugin_status_disabled">Briar はインターネットを使用しないように設定されています</string>
|
||||
<string name="tor_plugin_status_disabled_mobile_data">Briar はモバイルデータを使用しないように設定されています</string>
|
||||
<string name="tor_plugin_status_disabled_battery">Briar はバッテリー駆動時にインターネットを使用しないように設定されています</string>
|
||||
<string name="tor_plugin_status_disabled_country_blocked">Briar はこの国でインターネットを使わないように設定されています</string>
|
||||
<!--Transports: Wi-Fi-->
|
||||
<string name="transport_lan">Wi-Fi</string>
|
||||
<string name="transport_lan_long">同じWi-Fiネットワーク</string>
|
||||
<string name="lan_device_status_on">電話機はWi-Fiに接続されました</string>
|
||||
<string name="transport_lan_long">同じ Wi-Fi ネットワーク</string>
|
||||
<string name="lan_device_status_on">電話機は Wi-Fi に接続されました</string>
|
||||
<string name="lan_device_status_off">電話機はWi-Fiに接続されていません</string>
|
||||
<string name="lan_plugin_status_enabling">BriarはWi-Fiネットワークに接続中</string>
|
||||
<string name="lan_plugin_status_active">BriarはWi-Fiネットワークに接続されました</string>
|
||||
<string name="lan_plugin_status_inactive">BriarはWi-Fiネットワークに接続不可能</string>
|
||||
<string name="lan_plugin_status_disabled">BriarはWi-Fiネットワークを使用しないように設定されました</string>
|
||||
<string name="lan_plugin_status_enabling">Briar は Wi-Fi ネットワークに接続中です…</string>
|
||||
<string name="lan_plugin_status_active">Briar は Wi-Fi ネットワークに接続されました</string>
|
||||
<string name="lan_plugin_status_inactive">Briar は Wi-Fi ネットワークに接続できません</string>
|
||||
<string name="lan_plugin_status_disabled">Briar は Wi-Fi ネットワークを使用しないように設定されています</string>
|
||||
<!--Transports: Bluetooth-->
|
||||
<string name="transport_bt">Bluetooth</string>
|
||||
<string name="bt_device_status_on">電話機のBluetoothはオンにされました</string>
|
||||
<string name="bt_device_status_off">電話機のBluetoothはオフにされました</string>
|
||||
<string name="bt_plugin_status_enabling">BriarはBluetoothに接続中</string>
|
||||
<string name="bt_plugin_status_active">BriarはBluetoothに接続しました</string>
|
||||
<string name="bt_plugin_status_inactive">BriarはBluetoothに接続不可能</string>
|
||||
<string name="bt_plugin_status_disabled">BriarはBluetoothを使用しないように設定されました</string>
|
||||
<string name="bt_device_status_on">携帯電話の Bluetooth はオンになっています</string>
|
||||
<string name="bt_device_status_off">携帯電話の Bluetooth はオフにされました</string>
|
||||
<string name="bt_plugin_status_enabling">Briar は Bluetooth に接続中です…</string>
|
||||
<string name="bt_plugin_status_active">Briar は Bluetooth に接続しました</string>
|
||||
<string name="bt_plugin_status_inactive">Briar は Bluetooth に接続できません</string>
|
||||
<string name="bt_plugin_status_disabled">Briar は Bluetooth を使用しないように設定されています</string>
|
||||
<!--Notifications-->
|
||||
<string name="reminder_notification_title">Briarからサインアウト</string>
|
||||
<string name="reminder_notification_text">タップして再ログインします。</string>
|
||||
@@ -174,6 +180,9 @@
|
||||
<!--The first placeholder will show a contact's name. The second placeholder at the end will add "Tap to learn more."-->
|
||||
<string name="auto_delete_msg_contact_disabled">%1$sのメッセージは消えません。%2$s</string>
|
||||
<string name="tap_to_learn_more">タップすると詳細が表示されます。</string>
|
||||
<string name="auto_delete_changed_warning_title">消えるメッセージが変更されました</string>
|
||||
<string name="auto_delete_changed_warning_message_enabled">メッセージの作成を開始してから、消えるメッセージが有効になりました。</string>
|
||||
<string name="auto_delete_changed_warning_message_disabled">メッセージの作成を開始してから、消えるメッセージは無効になりました。</string>
|
||||
<string name="auto_delete_changed_warning_send">とりあえず送る</string>
|
||||
<string name="delete_all_messages">全てのメッセージを削除</string>
|
||||
<string name="dialog_title_delete_all_messages">メッセージの削除時に確認</string>
|
||||
@@ -212,11 +221,11 @@
|
||||
<string name="contact_added_toast">追加された連絡先:%s</string>
|
||||
<string name="contact_already_exists">連絡先%sは既に存在しています </string>
|
||||
<string name="qr_code_invalid">QRコードが無効です</string>
|
||||
<string name="qr_code_too_old">スキャンしたQRコードは%sの古いバージョンから取得されました。\n\n最新版へアップグレードしてもらって、もう一度お試しください。</string>
|
||||
<string name="qr_code_too_new">スキャンしたQRコードは、新しいバージョンの%sから取得されました。\n\n最新版にアップグレードしてから、もう一度お試しください。</string>
|
||||
<string name="qr_code_too_old_1">スキャンしたQRコードはBriarの古いバージョンから取得されました。\n\n最新版へアップグレードしてもらって、もう一度お試しください。</string>
|
||||
<string name="qr_code_too_new_1">スキャンしたQRコードは、新しいバージョンのBriarから取得されました。\n\n最新版にアップグレードしてから、もう一度お試しください。</string>
|
||||
<string name="camera_error">カメラエラー</string>
|
||||
<string name="connecting_to_device">デバイスに接続中\u2026</string>
|
||||
<string name="authenticating_with_device">デバイス同士での認証中\u2026</string>
|
||||
<string name="connecting_to_device">端末に接続中\u2026</string>
|
||||
<string name="authenticating_with_device">端末同士での認証中\u2026</string>
|
||||
<string name="connection_error_title">連絡先に接続できませんでした</string>
|
||||
<string name="connection_error_feedback">この問題が解決しない場合、アプリを改善するために<a href="feedback">フィードバック</a>を送信してください。</string>
|
||||
<!--Adding Contacts Remotely-->
|
||||
@@ -277,6 +286,7 @@
|
||||
<string name="pending_contact_updated_toast">保留中の連絡先が更新されました</string>
|
||||
<!--Introductions-->
|
||||
<string name="introduction_onboarding_title">連絡先を紹介</string>
|
||||
<string name="introduction_onboarding_text">連絡先をお互いに紹介することで、Briarで繋がることができます。</string>
|
||||
<string name="introduction_menu_item">はじめに</string>
|
||||
<string name="introduction_activity_title">連絡先を選択</string>
|
||||
<string name="introduction_not_possible">これらの連絡先については、すでに1つの紹介が進行中です。 これが最初に完了するようにしてください。 あなたやあなたの連絡相手がめったにオンラインにならない場合、これには時間がかかることがあります。</string>
|
||||
@@ -305,7 +315,7 @@
|
||||
<string name="connect_via_bluetooth_start">Bluetooth経由で接続中…</string>
|
||||
<string name="connect_via_bluetooth_success">Bluetooth経由で接続に成功</string>
|
||||
<string name="connect_via_bluetooth_error">Bluetooth経由で接続不可能。</string>
|
||||
<string name="connect_via_bluetooth_error_not_supported">Bluetoothはデバイスによってサポートされていません。</string>
|
||||
<string name="connect_via_bluetooth_error_not_supported">Bluetoothは端末によってサポートされていません。</string>
|
||||
<!--Private Groups-->
|
||||
<string name="groups_list_empty">表示するグループがありません</string>
|
||||
<string name="groups_list_empty_action">「+」アイコンをタップしてグループを作成するか、連絡先に登録している誰かにグループを共有してもらう</string>
|
||||
@@ -338,8 +348,8 @@
|
||||
<string name="groups_dissolved_dialog_message">このグループの作成者はこのグループを削除しました。\n\nそのため、書き込まれたすべてのメンバーは会話を続けることができなくなり、最新のメッセージも受信できなくなりました。</string>
|
||||
<!--Private Group Invitations-->
|
||||
<string name="groups_invitations_title">グループへ招待</string>
|
||||
<string name="groups_invitations_invitation_sent">%1$sをグループ \"%2$s\"に招待しています。</string>
|
||||
<string name="groups_invitations_invitation_received">%1$sがあなたをグループ \"%2$s\"に招待しています。</string>
|
||||
<string name="groups_invitations_invitation_sent">%1$sをグループ\"%2$s\"に招待しています。</string>
|
||||
<string name="groups_invitations_invitation_received">%1$sがあなたをグループ\"%2$s\"に招待しています。</string>
|
||||
<string name="groups_invitations_joined">グループに参加しました</string>
|
||||
<string name="groups_invitations_declined">グループへの招待を辞退しました</string>
|
||||
<plurals name="groups_invitations_open">
|
||||
@@ -419,7 +429,7 @@
|
||||
<string name="blogs_feed_empty_state">表示する投稿がありません</string>
|
||||
<string name="blogs_feed_empty_state_action">登録している連絡先やブログからの投稿がここに表示されます\n\nペンアイコンをタップして投稿を書き込みます</string>
|
||||
<string name="blogs_remove_blog">ブログを削除</string>
|
||||
<string name="blogs_remove_blog_dialog_message">このブログを削除してもよろしいですか?\n\n投稿はデバイスから削除されますが、他の人のデバイスからは削除されません。\n\nこのブログを共有した人に更新の受信を停止します。</string>
|
||||
<string name="blogs_remove_blog_dialog_message">このブログを削除してもよろしいですか?\n\n投稿は端末から削除されますが、他の人の端末からは削除されません。\n\nこのブログを共有した人に更新の受信を停止します。</string>
|
||||
<string name="blogs_remove_blog_ok">解除</string>
|
||||
<string name="blogs_blog_removed">ブログを削除しました</string>
|
||||
<string name="blogs_reblog_comment_hint">コメントを追加する(任意)</string>
|
||||
@@ -451,7 +461,7 @@
|
||||
<string name="blogs_rss_feeds_manage_author">著者:</string>
|
||||
<string name="blogs_rss_feeds_manage_updated">最終更新:</string>
|
||||
<string name="blogs_rss_remove_feed">フィードを削除</string>
|
||||
<string name="blogs_rss_remove_feed_dialog_message">このフィードを削除してもよろしいですか?\n\n投稿はデバイスから削除されますが、他の人のデバイスからは削除されません。\n\nこのフィードを共有した人は更新の受信を停止されます。</string>
|
||||
<string name="blogs_rss_remove_feed_dialog_message">このフィードを削除してもよろしいですか?\n\n投稿は端末から削除されますが、他の人の端末からは削除されません。\n\nこのフィードを共有した人は更新の受信を停止されます。</string>
|
||||
<string name="blogs_rss_remove_feed_ok">解除</string>
|
||||
<string name="blogs_rss_feeds_manage_empty_state">表示するRSSフィードはありません\n\n「+」アイコンをタップしてフィードをインポートします</string>
|
||||
<string name="blogs_rss_feeds_manage_error">フィードの読み込み中に問題が発生しました。 後でもう一度やり直してください。</string>
|
||||
@@ -473,7 +483,7 @@
|
||||
<!--Settings Connections-->
|
||||
<string name="network_settings_title">接続</string>
|
||||
<string name="bluetooth_setting">Bluetooth経由で連絡先に接続</string>
|
||||
<string name="wifi_setting">同じWi-Fiネットワークで連絡先に接続</string>
|
||||
<string name="wifi_setting">同じ Wi-Fi ネットワークで連絡先に接続</string>
|
||||
<string name="tor_enable_title">インターネット経由で連絡先に接続</string>
|
||||
<string name="tor_enable_summary">全接続をプライバシーのためにTorネットワークを通す</string>
|
||||
<string name="tor_network_setting">Torネットワークの接続方法</string>
|
||||
@@ -482,15 +492,15 @@
|
||||
<string name="tor_network_setting_with_bridges">ブリッジを通してTorネットワークを使用する</string>
|
||||
<string name="tor_network_setting_never">インターネットに接続しない</string>
|
||||
<!--How and when Briar will connect to Tor: E.g. "Don't connect to the Internet (in China)" or "Use Tor network with bridges (in Belarus)"-->
|
||||
<string name="tor_network_setting_summary">自動:%1$s(%2$sのうち)</string>
|
||||
<string name="tor_network_setting_summary">自動:%1$s(%2$s内)</string>
|
||||
<string name="tor_mobile_data_title">モバイルデータを使用する</string>
|
||||
<string name="tor_only_when_charging_title">充電時にのみインターネットに接続する</string>
|
||||
<string name="tor_only_when_charging_summary">デバイスがバッテリー使用している場合、インターネット接続を無効にする</string>
|
||||
<string name="tor_only_when_charging_summary">端末がバッテリーを使用している場合、インターネット接続を無効にする</string>
|
||||
<!--Settings Security and Panic-->
|
||||
<string name="security_settings_title">セキュリティ</string>
|
||||
<string name="pref_lock_title">アプリロック</string>
|
||||
<string name="pref_lock_summary">ログイン中にデバイスの画面ロックを使用して、Briarを保護します</string>
|
||||
<string name="pref_lock_disabled_summary">この機能を使用するには、デバイスの画面ロックを設定します</string>
|
||||
<string name="pref_lock_summary">ログイン中に端末の画面ロックを使用して、Briarを保護します</string>
|
||||
<string name="pref_lock_disabled_summary">この機能を使用するには、端末の画面ロックを設定します</string>
|
||||
<string name="pref_lock_timeout_title">\"Inactivity timeout\"された場合、アプリロックをロックする</string>
|
||||
<!--The %s placeholder is replaced with the following time spans, e.g. 5 Minutes, 1 Hour-->
|
||||
<string name="pref_lock_timeout_summary">Briarを使用しない場合、%s後に自動的にロックします</string>
|
||||
@@ -503,7 +513,7 @@
|
||||
<!--Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s"-->
|
||||
<string name="pref_lock_timeout_30">30分</string>
|
||||
<!--Will be shown in a list of lock times. Should fit into the %s of "automatically lock it after %s"-->
|
||||
<string name="pref_lock_timeout_60">1 時間</string>
|
||||
<string name="pref_lock_timeout_60">1時間</string>
|
||||
<string name="pref_lock_timeout_never">しない</string>
|
||||
<string name="pref_lock_timeout_never_summary">Briarを自動的にロックしない</string>
|
||||
<string name="change_password">パスワードの変更</string>
|
||||
@@ -578,14 +588,58 @@
|
||||
<string name="mailbox_status_connected_title">メールボックスは実行中</string>
|
||||
<string name="mailbox_status_problem_title">Briarはメールボックスへの接続が不調です</string>
|
||||
<string name="mailbox_status_failure_title">メールボックスは利用できません</string>
|
||||
<string name="mailbox_status_app_too_old_title">Briarは古すぎます</string>
|
||||
<string name="mailbox_status_app_too_old_message">Briarをアプリの最新版に更新し、再度お試しください。</string>
|
||||
<string name="mailbox_status_mailbox_too_old_title">メールボックスは古すぎます</string>
|
||||
<string name="mailbox_status_mailbox_too_old_message">メールボックスをアプリの最新版に更新し、再度お試しください。</string>
|
||||
<string name="mailbox_status_check_button">接続を確認</string>
|
||||
<!--Example for string substitution: Last connection: 3min ago-->
|
||||
<string name="mailbox_status_connected_info">最終接続: %s</string>
|
||||
<!--Indicates that there never was a connection to the mailbox. Last connection: Never-->
|
||||
<string name="mailbox_status_connected_never">しない</string>
|
||||
<string name="mailbox_status_unlink_button">リンク解除</string>
|
||||
<string name="mailbox_status_unlink_dialog_title">メールボックスをリンク解除しますか?</string>
|
||||
<string name="mailbox_status_unlink_dialog_question">本当にあなたのメールボックスをリンク解除してもよろしいですか?</string>
|
||||
<string name="mailbox_status_unlink_dialog_warning">メールボックスをリンク解除すると、Briarがオフライン中にメッセージを受け取れません。</string>
|
||||
<string name="mailbox_status_unlink_no_wipe_title">メールボックスはリンク解除されました</string>
|
||||
<string name="mailbox_status_unlink_no_wipe_message">次回、メールボックス端末にアクセスした際に、メールボックスアプリを起動し、「リンク解除」ボタンをタップして処理を完了してください。\n\nメールボックス端末にアクセスできなくなった場合でも、ご安心ください。データは暗号化されているので、処理を完了しなくても安全なままです。</string>
|
||||
<string name="mailbox_error_notification_channel_title">Briarメールボックスに問題</string>
|
||||
<string name="mailbox_error_notification_title">Briarメールボックスは利用できません</string>
|
||||
<string name="mailbox_error_notification_text">タップして問題を修正する。</string>
|
||||
<string name="mailbox_error_wizard_button">問題を修正する</string>
|
||||
<string name="mailbox_error_wizard_title">メールボックスのトラブルシューティングウィザード</string>
|
||||
<string name="mailbox_error_wizard_question1">あなたのメールボックス端末にアクセスできますか?</string>
|
||||
<string name="mailbox_error_wizard_answer1">はい、私は確かに今アクセスしています。</string>
|
||||
<string name="mailbox_error_wizard_answer2">今すぐには無理ですが、後でアクセスできるようになります。</string>
|
||||
<string name="mailbox_error_wizard_answer3">いいえ、最早アクセスできません。</string>
|
||||
<string name="mailbox_error_wizard_info1_1">メールボックス端末の電源が入っていて、インターネットに接続されているかを確認してください。</string>
|
||||
<string name="mailbox_error_wizard_question1_1">メールボックスアプリを開いてください。何が確認できますか?</string>
|
||||
<string name="mailbox_error_wizard_answer1_1">メールボックスの設定方法が表示される</string>
|
||||
<string name="mailbox_error_wizard_answer1_2">QRコードが表示される</string>
|
||||
<string name="mailbox_error_wizard_answer1_3">「メールボックスは実行中」と表示される</string>
|
||||
<string name="mailbox_error_wizard_answer1_4">「デバイスがオフライン」と表示されます</string>
|
||||
<string name="mailbox_error_wizard_info1_1_1">以下のボタンでメールボックスのリンクを解除し、メールボックスの端末の指示に従って再度リンクしてください。</string>
|
||||
<string name="mailbox_error_wizard_info_1_1_2">以下のボタンでメールボックスのリンクを解除し、QRコードを読み取って再度リンクしてください。</string>
|
||||
<string name="mailbox_error_wizard_info1_1_3">以下のボタンを使用して、Briarとメールボックスの間での接続を確認してください。\n\n
|
||||
接続が再び失敗する場合:\n
|
||||
\u2022 メールボックスとBriarアプリが最新版に更新されているか確認してください。\n
|
||||
\u2022 メールボックスとBriarの端末を再起動して、再度お試しください。</string>
|
||||
<string name="mailbox_error_wizard_info1_1_4">メールボックス端末がインターネットに適切に接続されているか、確認してください。\n\nメールボックス端末の時計が正しい時刻、日付、時間帯を表示しているか、確認してください。\n\nメールボックスとBriarアプリが最新版に更新されているか、確認してください。\n\nメールボックスとBriarの端末を再起動し、再度お試しください。</string>
|
||||
<string name="mailbox_error_wizard_info2">端末にアクセスしたら、この画面に戻って来てください。</string>
|
||||
<string name="mailbox_error_wizard_info3">以下のボタンを使用してメールボックスをリンク解除してください。\n\n古いメールボックスをリンク解除した後、いつでも新しいメールボックスをセットアップできます。</string>
|
||||
<!--Conversation Settings-->
|
||||
<string name="disappearing_messages_title">消えるメッセージ</string>
|
||||
<string name="disappearing_messages_explanation_long">この設定を有効にすると、
|
||||
この会話内での新しいメッセージは、自動的に7\u00A0日後に消えます。
|
||||
\n\nメッセージの送信者の複製用のカウントダウンは、メッセージが到着した後に始まります。
|
||||
受取人用のカウントダウンは、メッセージを読んでから始まります。
|
||||
\n\n消えるメッセージには、爆弾アイコンで印が付けられます。
|
||||
\n\n受取人は、あなたが送ったメッセージの複製を取れることに留意してください。
|
||||
\n\nこの設定を変更すると、すぐにあなたの新着メッセージで反映され、
|
||||
連絡先があなたの次のメッセージを受信した時点で、その連絡先のメッセージに適用されます。
|
||||
連絡先もあなたと二人に、この設定を変更できます。</string>
|
||||
<string name="learn_more">詳細情報</string>
|
||||
<string name="disappearing_messages_summary">この会話の今後のメッセージは、自動的に7\u00A0日後に消えます。</string>
|
||||
<!--Settings Actions-->
|
||||
<string name="pref_category_actions">操作</string>
|
||||
<string name="send_feedback">フィードバックを送信</string>
|
||||
@@ -605,18 +659,19 @@
|
||||
<string name="enter_feedback">フィードバックを入力してください</string>
|
||||
<string name="optional_contact_email">あなたのメールアドレス(任意)</string>
|
||||
<string name="include_debug_report_crash">クラッシュに関する匿名のデータを添付する</string>
|
||||
<string name="include_debug_report_feedback">このデバイスに関する匿名のデータを添付する</string>
|
||||
<string name="include_debug_report_feedback">この端末に関する匿名のデータを添付する</string>
|
||||
<string name="dev_report_user_info">ユーザー情報</string>
|
||||
<string name="dev_report_basic_info">基本情報</string>
|
||||
<string name="dev_report_device_info">デバイス情報</string>
|
||||
<string name="dev_report_device_info">端末情報</string>
|
||||
<string name="dev_report_stacktrace">スタックトレース</string>
|
||||
<string name="dev_report_time_info">時間情報</string>
|
||||
<string name="dev_report_memory">メモリー</string>
|
||||
<string name="dev_report_storage">ストレージ</string>
|
||||
<string name="dev_report_connectivity">接続</string>
|
||||
<string name="dev_report_network_usage">ネットワーク使用量</string>
|
||||
<string name="dev_report_build_config">ビルド構成</string>
|
||||
<string name="dev_report_logcat">アプリのログ</string>
|
||||
<string name="dev_report_device_features">デバイスの機能</string>
|
||||
<string name="dev_report_device_features">端末の機能</string>
|
||||
<string name="send_report">レポートを送信</string>
|
||||
<string name="close">閉じる</string>
|
||||
<string name="dev_report_sending">フィードバックを送信中…</string>
|
||||
@@ -635,19 +690,19 @@
|
||||
<string name="permission_camera_title">カメラへのアクセス許可</string>
|
||||
<string name="permission_camera_request_body">QRコードをスキャンするには、Briarはカメラにアクセスする必要があります。</string>
|
||||
<string name="permission_location_title">位置情報へのアクセスの許可</string>
|
||||
<string name="permission_location_request_body">Bluetoothデバイスを検出するには、Briarがあなたの位置情報へのアクセスを必要とします。\n\nBriarはあなたの場所を保存したり、誰とも共有したりしません。</string>
|
||||
<string name="permission_location_request_body">Bluetooth端末を検出するには、Briarがあなたの位置情報へのアクセスを必要とします。\n\nBriarはあなたの場所を保存したり、誰とも共有したりしません。</string>
|
||||
<string name="permission_camera_location_title">カメラと位置情報</string>
|
||||
<string name="permission_camera_location_request_body">QRコードをスキャンするには、Briarはカメラにアクセスする必要があります。\n\nBluetoothデバイスを検出するには、Briarは現在地情報にアクセスする許可が必要です。\n\nBriarは現在地を保存したり、誰とも共有したりしません。</string>
|
||||
<string name="permission_camera_location_request_body">QRコードをスキャンするには、Briarはカメラにアクセスする必要があります。\n\nBluetooth端末を検出するには、Briarは現在地情報にアクセスする許可が必要です。\n\nBriarは現在地を保存したり、誰とも共有したりしません。</string>
|
||||
<string name="permission_camera_denied_body">カメラへのアクセスをが拒否されましたが、連絡先を追加するにはカメラを使用する必要があります。\n\nカメラへのアクセスの許可を考えてください。</string>
|
||||
<string name="permission_location_denied_body">あなたの位置情報にアクセスすることを拒否しましたが、BriarはBluetoothデバイスを発見するのに、この権限が必要です。\n\nアクセス権を付与することを考慮願います。</string>
|
||||
<string name="permission_location_denied_body">あなたの位置情報にアクセスすることを拒否しましたが、BriarはBluetooth端末を発見するのに、この権限が必要です。\n\nアクセス権を付与することを考慮願います。</string>
|
||||
<string name="permission_location_setting_title">位置情報設定</string>
|
||||
<string name="permission_location_setting_body">デバイスの位置情報設定は、Bluetoothを介して他のデバイスを見つけるために、オンにする必要があります。続けるには位置情報を有効にしてください。その後、位置情報を無効にできます。</string>
|
||||
<string name="permission_location_setting_body">端末の位置情報設定は、Bluetoothを介して他の端末を見つけるために、オンにする必要があります。続けるには位置情報を有効にしてください。その後、位置情報を無効にできます。</string>
|
||||
<string name="permission_location_setting_button">位置情報を有効化</string>
|
||||
<string name="qr_code">QRコード</string>
|
||||
<string name="show_qr_code_fullscreen">QRコードを全画面表示する</string>
|
||||
<!--App Locking-->
|
||||
<string name="lock_unlock">Briarのロックを解除</string>
|
||||
<string name="lock_unlock_verbose">Briarのロックを解除するには、デバイスのPIN、パターン、またはパスワードを入力してください</string>
|
||||
<string name="lock_unlock_verbose">Briarのロックを解除するには、端末のPIN、パターン、またはパスワードを入力してください</string>
|
||||
<string name="lock_unlock_fingerprint_description">登録した指で指紋センサーに触れて続行します</string>
|
||||
<string name="lock_unlock_password">パスワードを使用</string>
|
||||
<string name="lock_is_locked">Briarはロックされています</string>
|
||||
@@ -673,12 +728,12 @@
|
||||
<string name="hotspot_scanning_a_qr_code">QRコードをスキャン</string>
|
||||
<!--Wi-Fi setup-->
|
||||
<!--The %s placeholder will be replaced with the translation of 'hotspot_scanning_a_qr_code'-->
|
||||
<string name="hotspot_manual_wifi">あなたの電話機はWi-Fiホットスポットを提供しています。Briarのダウンロードを希望する人は、以下の方法で端末のWi-Fi設定に追加するか、または %s によるホットスポットに接続してください。そのホットスポットに接続されたら、\'Next\'を押してください。</string>
|
||||
<string name="hotspot_manual_wifi">あなたの電話機はWi-Fiホットスポットを提供しています。Briarのダウンロードを希望する人は、以下の方法で端末のWi-Fi設定に追加するか、または %s によるホットスポットに接続してください。そのホットスポットに接続されたら、「次へ」を押してください。</string>
|
||||
<string name="hotspot_manual_wifi_ssid">ネットワーク名</string>
|
||||
<string name="hotspot_qr_wifi">あなたの電話機はWi-Fiホットスポットを提供しています。Briarのダウンロードを希望する人は、このQRコードをスキャンしてホットスポットに接続してください。そのホットスポットに接続されたら、\'Next\'を押してください。</string>
|
||||
<string name="hotspot_no_peers_connected">接続されたデバイスなし</string>
|
||||
<string name="hotspot_qr_wifi">あなたの電話機はWi-Fiホットスポットを提供しています。Briarのダウンロードを希望する人は、このQRコードをスキャンしてホットスポットに接続してください。そのホットスポットに接続されたら、「次へ」を押してください。</string>
|
||||
<string name="hotspot_no_peers_connected">接続された端末なし</string>
|
||||
<plurals name="hotspot_peers_connected">
|
||||
<item quantity="other">%s機の接続されたデバイス</item>
|
||||
<item quantity="other">%s機の接続された端末</item>
|
||||
</plurals>
|
||||
<!--Download link-->
|
||||
<!--The %s placeholder will be replaced with the translation of 'hotspot_scanning_a_qr_code'-->
|
||||
@@ -686,8 +741,9 @@
|
||||
<string name="hotspot_manual_site_address">アドレス(URL)</string>
|
||||
<string name="hotspot_qr_site">あなたの電話機はWi-Fiホットスポットを提供しています。ホットスポットに接続された人は、このQRコードをスキャンして、Briarをダウンロードできます。</string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">%s をダウンロードする</string>
|
||||
<string name="website_download_intro">近くの誰かが、あなたと %s を共有しました。</string>
|
||||
<string name="website_download_title_1">Briar %sをダウンロード</string>
|
||||
<string name="website_download_intro_1">近くの誰かが、あなたとBriarを共有しました。</string>
|
||||
<string name="website_download_button">Briarをダウンロード</string>
|
||||
<string name="website_download_outro">ダウンロードが完了した後に、ダウンロードしたファイルを開いて、インストールしてください。</string>
|
||||
<string name="website_troubleshooting_title">トラブルシューティング</string>
|
||||
<string name="website_troubleshooting_1">アプリをインストールできない場合、別のブラウザアプリで試してください。</string>
|
||||
@@ -703,13 +759,14 @@
|
||||
<string name="hotspot_help_site_3">ファイアウォールアプリを使用している場合は、それがアクセスをブロックしていないか確認してください。</string>
|
||||
<string name="hotspot_help_site_4">サイトにはアクセスできるが、Briarアプリがダウンロードできない場合は、別のウェブブラウザアプリで試してみてください。</string>
|
||||
<string name="hotspot_help_fallback_title">どれもうまくいきませんか?</string>
|
||||
<string name="hotspot_help_fallback_intro">他の方法で共有するために、アプリを.apkファイルとして保存してみてください。そのファイルをもう一方のデバイスに転送すれば、Briarをインストールすることができます。
|
||||
<string name="hotspot_help_fallback_intro">他の方法で共有するために、アプリを.apkファイルとして保存してみてください。そのファイルをもう一方の端末に転送すれば、Briarをインストールすることができます。
|
||||
\n\nヒント: Bluetoothで共有する場合は、まずファイル名を.zipで終わるように名前変更する必要があるかもしれません。</string>
|
||||
<string name="hotspot_help_fallback_button">アプリを保存する</string>
|
||||
<!--error handling-->
|
||||
<string name="hotspot_error_intro">Wi-Fiでアプリを共有しようとしたときに、何か問題が発生しました。</string>
|
||||
<string name="hotspot_error_no_wifi_direct">デバイスはWi-Fiダイレクトをサポートしていません</string>
|
||||
<string name="hotspot_error_no_wifi_direct">端末はWi-Fiダイレクトをサポートしていません</string>
|
||||
<string name="hotspot_error_start_callback_failed">ホットスポットの開始に失敗しました: エラー %s</string>
|
||||
<string name="hotspot_error_start_callback_failed_unknown">ホットスポットは未知のエラーで開始に失敗しました。理由 %d</string>
|
||||
<string name="hotspot_error_start_callback_no_group_info">ホットスポットの開始に失敗しました: グループ情報なし</string>
|
||||
<string name="hotspot_error_web_server_start">ウェブサーバー起動エラー</string>
|
||||
<string name="hotspot_error_web_server_serve">ウェブサイトの表示にエラーが発生しました。\n\n問題が解決しない場合は、Briarアプリから(匿名のデータで)フィードバックを送ってください。</string>
|
||||
|
||||
@@ -1,37 +1,31 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources>
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Sveiki atvykę į Briar</string>
|
||||
<string name="setup_name_explanation">Jūsų slapyvardis bus rodomas šalia bet kokio jūsų skelbiamo turinio. Sukūrę paskyrą, slapyvardžio pakeisti nebegalėsite.</string>
|
||||
<string name="setup_next">Kitas</string>
|
||||
<string name="setup_password_intro">Pasirinkite slaptažodį</string>
|
||||
<string name="setup_password_explanation">Jūsų Briar paskyra yra saugoma šifruotu pavidalu jūsų įrenginyje, o ne debesijoje. Jei pamiršite savo slaptažodį ar pašalinsite Briar programėlę, daugiau nebegalėsite atkurti savo paskyros.\n\nPasirinkite ilgą slaptažodį, kurį būtų sunku atspėti, pavyzdžiui, keturis atsitiktinius žodžius ar dešimt atsitiktinių raidžių, skaitmenų ir simbolių.</string>
|
||||
<string name="dnkm_doze_title">Foniniai ryšiai</string>
|
||||
<string name="dnkm_doze_intro">Norint gauti žinutes, Briar turi išlikti fone prisijungusi.</string>
|
||||
<string name="dnkm_doze_explanation">Norint gauti žinutes, Briar turi išlikti fone prisijungusi. Išjunkite akumuliatoriaus naudojimo optimizavimą, kad Briar galėtų išlikti prisijungusi.</string>
|
||||
<string name="dnkm_doze_button">Leisti ryšius</string>
|
||||
<string name="choose_nickname">Pasirinkite savo slapyvardį</string>
|
||||
<string name="choose_password">Pasirinkite savo slaptažodį</string>
|
||||
<string name="confirm_password">Pakartokite savo slaptažodį</string>
|
||||
<string name="name_too_long">Vardas yra per ilgas</string>
|
||||
<string name="password_too_weak">Slaptažodis yra per silpnas</string>
|
||||
<string name="passwords_do_not_match">Slaptažodžiai nesutampa</string>
|
||||
<string name="create_account_button">Sukurti paskyrą</string>
|
||||
<string name="more_info">Daugiau informacijos</string>
|
||||
<string name="don_t_ask_again">Daugiau nebeklausti</string>
|
||||
<string name="dnkm_huawei_protected_text">Bakstelėkite žemiau esantį mygtuką ir įsitikinkite, kad „Apsaugotų programėlių“ rodinyje Briar yra apsaugota.</string>
|
||||
<string name="dnkm_huawei_protected_button">Apsaugoti Briar</string>
|
||||
<string name="dnkm_huawei_protected_help">Jei Briar nebus pridėta į apsaugotų programėlių sąrašą, ji negalės veikti fone.</string>
|
||||
<string name="dnkm_huawei_app_launch_text">Bakstelėkite mygtuką žemiau, atverkite langą „Programų paleidimas (angl. App launch)“ ir įsitikinkite, kad Briar yra nustatyta į „Tvarkyti rankiniu būdu (angl. Manage manually)“.</string>
|
||||
<string name="dnkm_huawei_app_launch_button">Atverti akumuliatoriaus nustatymus</string>
|
||||
<string name="dnkm_huawei_app_launch_help">Jeigu „Programų paleidimo (angl. App launch)“ lange Briar nėra nustatyta į „Tvarkyti rankiniu būdu (angl. Manage manually)“, tuomet programėlė negalės veikti fone.</string>
|
||||
<string name="setup_huawei_app_launch_error_toast">Nepavyko atverti akumuliatoriaus nustatymų</string>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Sveiki atvykę į Briar</string>
|
||||
<string name="setup_name_explanation">Jūsų slapyvardis bus rodomas šalia bet kokio jūsų skelbiamo turinio. Sukūrę paskyrą, slapyvardžio pakeisti nebegalėsite.</string>
|
||||
<string name="setup_next">Kitas</string>
|
||||
<string name="setup_password_intro">Pasirinkite slaptažodį</string>
|
||||
<string name="setup_password_explanation">Jūsų Briar paskyra yra saugoma šifruotu pavidalu jūsų įrenginyje, o ne debesijoje. Jei pamiršite savo slaptažodį ar pašalinsite Briar programėlę, daugiau nebegalėsite atkurti savo paskyros.\n\nPasirinkite ilgą slaptažodį, kurį būtų sunku atspėti, pavyzdžiui, keturis atsitiktinius žodžius ar dešimt atsitiktinių raidžių, skaitmenų ir simbolių.</string>
|
||||
<string name="dnkm_doze_intro">Norint gauti žinutes, Briar turi išlikti fone prisijungusi.</string>
|
||||
<string name="dnkm_doze_explanation">Norint gauti žinutes, Briar turi išlikti fone prisijungusi. Išjunkite akumuliatoriaus naudojimo optimizavimą, kad Briar galėtų išlikti prisijungusi.</string>
|
||||
<string name="choose_nickname">Pasirinkite savo slapyvardį</string>
|
||||
<string name="choose_password">Pasirinkite savo slaptažodį</string>
|
||||
<string name="confirm_password">Pakartokite savo slaptažodį</string>
|
||||
<string name="name_too_long">Vardas yra per ilgas</string>
|
||||
<string name="password_too_weak">Slaptažodis yra per silpnas</string>
|
||||
<string name="passwords_do_not_match">Slaptažodžiai nesutampa</string>
|
||||
<string name="create_account_button">Sukurti paskyrą</string>
|
||||
<string name="more_info">Daugiau informacijos</string>
|
||||
<string name="don_t_ask_again">Daugiau nebeklausti</string>
|
||||
<string name="dnkm_huawei_protected_text">Bakstelėkite žemiau esantį mygtuką ir įsitikinkite, kad „Apsaugotų programėlių“ rodinyje Briar yra apsaugota.</string>
|
||||
<string name="dnkm_huawei_protected_button">Apsaugoti Briar</string>
|
||||
<string name="dnkm_huawei_protected_help">Jei Briar nebus pridėta į apsaugotų programėlių sąrašą, ji negalės veikti fone.</string>
|
||||
<string name="dnkm_huawei_app_launch_text">Bakstelėkite mygtuką žemiau, atverkite langą „Programų paleidimas (angl. App launch)“ ir įsitikinkite, kad Briar yra nustatyta į „Tvarkyti rankiniu būdu (angl. Manage manually)“.</string>
|
||||
<string name="dnkm_huawei_app_launch_help">Jeigu „Programų paleidimo (angl. App launch)“ lange Briar nėra nustatyta į „Tvarkyti rankiniu būdu (angl. Manage manually)“, tuomet programėlė negalės veikti fone.</string>
|
||||
<string name="dnkm_xiaomi_text">Tam, kad galėtų veikti fone, Briar turi būti prirakinta prie paskiausiųjų programėlių sąrašo.</string>
|
||||
<string name="dnkm_xiaomi_button">Apsaugoti Briar</string>
|
||||
<string name="dnkm_xiaomi_help">Jei Briar nebus prirakinta prie paskiausiųjų programėlių sąrašo, ji negalės veikti fone.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Atverkite paskiausiųjų programėlių sąrašą (dar vadinamą programėlių perjungikliu)\n\n2. Ant Briar paveiksliuko perbraukite žemyn, kad būtų rodoma pakabinamos spynos piktograma\n\n3. Jei pakabinama spyna neužrakinta, bakstelėkite, kad ją užrakintumėte</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. 1. Atverkite paskiausiųjų programėlių sąrašą (dar vadinamą programėlių perjungikliu)\n\n2. Paspauskite ir laikykite ant Briar paveiksliuko tol, kol atsiras pakabinamos spynos mygtukas\n\n3. Jei pakabinama spyna neužrakinta, bakstelėkite, kad ją užrakintumėte</string>
|
||||
<string name="dnkm_warning_dozed">%s nepavyko pasileisti fone</string>
|
||||
<string name="dnkm_xiaomi_button">Apsaugoti Briar</string>
|
||||
<string name="dnkm_xiaomi_help">Jei Briar nebus prirakinta prie paskiausiųjų programėlių sąrašo, ji negalės veikti fone.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Atverkite paskiausiųjų programėlių sąrašą (dar vadinamą programėlių perjungikliu)\n\n2. Ant Briar paveiksliuko perbraukite žemyn, kad būtų rodoma pakabinamos spynos piktograma\n\n3. Jei pakabinama spyna neužrakinta, bakstelėkite, kad ją užrakintumėte</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">Slaptažodis</string>
|
||||
<string name="try_again">Neteisingas slaptažodis, bandykite dar kartą</string>
|
||||
@@ -253,8 +247,6 @@
|
||||
<string name="contact_added_toast">Adresatas pridėtas: %s</string>
|
||||
<string name="contact_already_exists">Adresatas %s jau yra</string>
|
||||
<string name="qr_code_invalid">QR kodas yra neteisingas</string>
|
||||
<string name="qr_code_too_old">Jūsų nuskenuotas QR kodas yra iš senesnės %s versijos.\n\nPaprašykite adresato, kad atsinaujintų į naujausią versiją, o tuomet bandykite dar kartą.</string>
|
||||
<string name="qr_code_too_new">Jūsų nuskenuotas QR kodas yra iš naujesnės %s versijos.\n\nAtsinaujinkite į naujausią versiją, o tuomet bandykite dar kartą.</string>
|
||||
<string name="camera_error">Kameros klaida</string>
|
||||
<string name="connecting_to_device">Jungiamasi prie įrenginio\u2026</string>
|
||||
<string name="authenticating_with_device">Tapatybės nustatymas su įrenginiu\u2026</string>
|
||||
@@ -623,6 +615,8 @@
|
||||
<string name="tor_offline_button_check">Tikrinti ryšio nustatymus</string>
|
||||
<string name="mailbox_status_title">Pašto dėžutės būsena</string>
|
||||
<string name="mailbox_status_connected_title">Pašto dėžutė veikia</string>
|
||||
<string name="mailbox_status_app_too_old_title">Briar yra per sena</string>
|
||||
<string name="mailbox_status_app_too_old_message">Atnaujinkite Briar programėlę iki naujausios versijos ir bandykite dar kartą.</string>
|
||||
<string name="mailbox_status_check_button">Tikrinti ryšį</string>
|
||||
<!--Example for string substitution: Last connection: 3min ago-->
|
||||
<string name="mailbox_status_connected_info">Paskutinis prisijungimas: %s</string>
|
||||
@@ -746,8 +740,6 @@
|
||||
<string name="hotspot_manual_site_address">Adresas (URL)</string>
|
||||
<string name="hotspot_qr_site">Jūsų telefonas teikia belaidį (Wi-Fi) prieigos tašką. Žmonės, prisijungę prie prieigos taško, gali atsisiųsti Briar, skenuodami šį QR kodą.</string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">Atsisiųsti %s</string>
|
||||
<string name="website_download_intro">Kažkas iš šalia esančių pradėjo bendrinti su jumis %s.</string>
|
||||
<string name="website_download_outro">Kai atsisiuntimas pasibaigs, atverkite atsisiųstą failą ir jį įdiekite.</string>
|
||||
<string name="website_troubleshooting_title">Nesklandumų šalinimas</string>
|
||||
<string name="website_troubleshooting_1">Jei negalite atsisiųsti programėlės, pabandykite naudoti kitą saityno naršyklės programėlę.</string>
|
||||
|
||||
@@ -1,36 +1,31 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources>
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Briar မှ ကြိုဆိုပါသည်</string>
|
||||
<string name="setup_name_explanation">သင့်နာမည်ပြောင်သည် သင်တင်ထားသမျှ၏ ဘေးတွင် ပေါ်နေပါလိမ့်မည်။ သို့ပါ၍ သင့်နာမည်ပြောင်အား အကောင့်ဖွင့်ပြီးနောက် ပြောင်း၍ မရတော့ပါ။</string>
|
||||
<string name="setup_next">ရှေ့သို့</string>
|
||||
<string name="setup_password_intro">စကားဝှက်တစ်ခု ရွေးပါ</string>
|
||||
<string name="setup_password_explanation">သင့် Briar အကောင့်ကို ကလောက်တွင်မဟုတ်ဘဲ သင့်ကိရိယာတွင်သာ လျှို့ဝှက်ကုဒ်ပြောင်း သိမ်းဆည်းထားပါသည်။ သင့်စကားဝှက်ကို မေ့သွားလျှင် (သို့) Briar ကို ဖြုတ်လိုက်လျှင် သင့်အကောင့်ကို မည်သည့်နည်းနှင့်မျှ ပြန်မရယူနိုင်ပါ။\n\nကြုံရာစကားလုံးလေးလုံး (သို့) ကြုံရာအက္ခရာဆယ်လုံး၊ နံပါတ်များနှင့် သင်္ကေတများကဲ့သို့ ခန့်မှန်းရခက်သည့် ရှည်လျားသောစကားဝှက်ကို ရွေးချယ်ပါ။</string>
|
||||
<string name="dnkm_doze_title">နောက်ခံ ချိတ်ဆက်မှုများ</string>
|
||||
<string name="dnkm_doze_intro">မက်ဆေ့ချ်များ လက်ခံရယူနိုင်ရန် Briar သည် နောက်ခံ၌ ချိတ်ဆက်နေရန် လိုအပ်သည်။</string>
|
||||
<string name="dnkm_doze_explanation">မက်ဆေ့ချ်များ လက်ခံရယူနိုင်ရန် Briar သည် နောက်ခံ၌ ချိတ်ဆက်နေရန် လိုအပ်သည်။ Briar အနေဖြင့် ချိတ်ဆက်မှု မပြတ်ရှိနေစေရန် ဘတ္ထရီအား အကောင်းဆုံး ထိန်းညှိခြင်းကို ကျေးဇူးပြု၍ ပိတ်ထားပေးပါ။</string>
|
||||
<string name="dnkm_doze_button">ချိတ်ဆက်မှုများကို ခွင့်ပြုပါ</string>
|
||||
<string name="choose_nickname">သင့်နာမည်ပြောင်ကို ရွေးပါ</string>
|
||||
<string name="choose_password">သင့်စကားဝှက်ကို ရွေးပါ</string>
|
||||
<string name="confirm_password">သင့်စကားဝှက်ကို အတည်ပြုပါ</string>
|
||||
<string name="name_too_long">နာမည် ရှည်လွန်းသည်</string>
|
||||
<string name="password_too_weak">စကားဝှက်က အားနည်းလွန်းသည်</string>
|
||||
<string name="passwords_do_not_match">စကားဝှက်များ မတူကြပါ</string>
|
||||
<string name="create_account_button">အကောင့်ဖွင့်ပါ</string>
|
||||
<string name="more_info">ပိုမိုသိရှိရန်</string>
|
||||
<string name="don_t_ask_again">ထပ်မမေးပါနဲ့</string>
|
||||
<string name="dnkm_huawei_protected_text">အောက်ပါခလုတ်ကိုနှိပ်၍ \"ကာကွယ်မှုပေးထားသောအက်ပ်များ\" စခရင်တွင် Briar ကို ကာကွယ်ထားကြောင်း သေချာစေပါ။</string>
|
||||
<string name="dnkm_huawei_protected_button">Briar ကို ကာကွယ်ပါ</string>
|
||||
<string name="dnkm_huawei_protected_help">ကာကွယ်မှုပေးထားသောအက်ပ်များစာရင်းတွင် ထည့်မထားလျှင် Briar ကို နောက်ကွယ်တွင် ဖွင့်ထားနိုင်မည်မဟုတ်ပါ။</string>
|
||||
<string name="dnkm_huawei_app_launch_text">အောက်ပါခလုတ်ကိုနှိပ်ပြီး \"အက်ပ်စတင်ခြင်း\" စခရင်ကို ဖွင့်၍ Briar ကို \"ကိုယ်တိုင်စီမံမည်\" ဟု သတ်မှတ်ပါ။</string>
|
||||
<string name="dnkm_huawei_app_launch_button">ဘတ္ထရီဆက်တင်များကို ဖွင့်ပါ</string>
|
||||
<string name="dnkm_huawei_app_launch_help">\"အက်ပ်စတင်ခြင်း\" စခရင်တွင် \"ကိုယ်တိုင်စီမံမည်\" ဟု သတ်မှတ်မထားလျှင် Briar ကို နောက်ကွယ်တွင် ဖွင့်ထားနိုင်မည်မဟုတ်ပါ။</string>
|
||||
<string name="dnkm_xiaomi_text">ဖွင့်ထားသောအက်ပ်များစာရင်းတွင် Briar ကို လော့ခ်ချထားမှ နောက်ကွယ်တွင် ဖွင့်ထားနိုင်မည်။</string>
|
||||
<string name="dnkm_xiaomi_button">Briar ကို ကာကွယ်မည်</string>
|
||||
<string name="dnkm_xiaomi_help">ဖွင့်ထားသောအက်ပ်များစာရင်းတွင် လော့ခ်ချမထားပါက Briar ကို နောက်ကွယ်တွင် ဖွင့်ထားနိုင်မည်မဟုတ်ပါ။</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">၁။ ဖွင့်ထားသောအက်ပ်များစာရင်း (တစ်နည်းအားဖြင့် အက်ပ်ပြောင်းရာ) ကို ဖွင့်ပါ\n\n၂။ သော့ခလောက်အိုင်ကွန်ပေါ်လာရန် Briar ပုံပေါ်မှ ပွတ်ဆွဲချပါ\n\n၃။ သော့ခတ်မထားပါက သော့ခတ်ရန်နှိပ်လိုက်ပါ</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">၁။ ဖွင့်ထားသောအက်ပ်များစာရင်း (တစ်နည်းအားဖြင့် အက်ပ်ပြောင်းရာ) ကို ဖွင့်ပါ\n\n ၂။ သော့ခလောက်ခလုတ်ပေါ်လာသည်အထိ Briar ပုံကို နှိပ်ထားပါ\n\n ၃။ သော့ခတ်မထားပါက သော့ခတ်ရန်နှိပ်လိုက်ပါ</string>
|
||||
<string name="dnkm_warning_dozed">%s ကို နောက်ကွယ်တွင် ဖွင့်မထားနိုင်ပါ</string>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Briar မှ ကြိုဆိုပါသည်</string>
|
||||
<string name="setup_name_explanation">သင့်နာမည်ပြောင်သည် သင်တင်ထားသမျှ၏ ဘေးတွင် ပေါ်နေပါလိမ့်မည်။ သို့ပါ၍ သင့်နာမည်ပြောင်အား အကောင့်ဖွင့်ပြီးနောက် ပြောင်း၍ မရတော့ပါ။</string>
|
||||
<string name="setup_next">ရှေ့သို့</string>
|
||||
<string name="setup_password_intro">စကားဝှက်တစ်ခု ရွေးပါ</string>
|
||||
<string name="setup_password_explanation">သင့် Briar အကောင့်ကို ကလောက်တွင်မဟုတ်ဘဲ သင့်ကိရိယာတွင်သာ လျှို့ဝှက်ကုဒ်ပြောင်း သိမ်းဆည်းထားပါသည်။ သင့်စကားဝှက်ကို မေ့သွားလျှင် (သို့) Briar ကို ဖြုတ်လိုက်လျှင် သင့်အကောင့်ကို မည်သည့်နည်းနှင့်မျှ ပြန်မရယူနိုင်ပါ။\n\nကြုံရာစကားလုံးလေးလုံး (သို့) ကြုံရာအက္ခရာဆယ်လုံး၊ နံပါတ်များနှင့် သင်္ကေတများကဲ့သို့ ခန့်မှန်းရခက်သည့် ရှည်လျားသောစကားဝှက်ကို ရွေးချယ်ပါ။</string>
|
||||
<string name="dnkm_doze_intro">မက်ဆေ့ချ်များ လက်ခံရယူနိုင်ရန် Briar သည် နောက်ခံ၌ ချိတ်ဆက်နေရန် လိုအပ်သည်။</string>
|
||||
<string name="dnkm_doze_explanation">မက်ဆေ့ချ်များ လက်ခံရယူနိုင်ရန် Briar သည် နောက်ခံ၌ ချိတ်ဆက်နေရန် လိုအပ်သည်။ Briar အနေဖြင့် ချိတ်ဆက်မှု မပြတ်ရှိနေစေရန် ဘတ္ထရီအား အကောင်းဆုံး ထိန်းညှိခြင်းကို ကျေးဇူးပြု၍ ပိတ်ထားပေးပါ။</string>
|
||||
<string name="choose_nickname">သင့်နာမည်ပြောင်ကို ရွေးပါ</string>
|
||||
<string name="choose_password">သင့်စကားဝှက်ကို ရွေးပါ</string>
|
||||
<string name="confirm_password">သင့်စကားဝှက်ကို အတည်ပြုပါ</string>
|
||||
<string name="name_too_long">နာမည် ရှည်လွန်းသည်</string>
|
||||
<string name="password_too_weak">စကားဝှက်က အားနည်းလွန်းသည်</string>
|
||||
<string name="passwords_do_not_match">စကားဝှက်များ မတူကြပါ</string>
|
||||
<string name="create_account_button">အကောင့်ဖွင့်ပါ</string>
|
||||
<string name="more_info">ပိုမိုသိရှိရန်</string>
|
||||
<string name="don_t_ask_again">ထပ်မမေးပါနဲ့</string>
|
||||
<string name="dnkm_huawei_protected_text">အောက်ပါခလုတ်ကိုနှိပ်၍ \"ကာကွယ်မှုပေးထားသောအက်ပ်များ\" စခရင်တွင် Briar ကို ကာကွယ်ထားကြောင်း သေချာစေပါ။</string>
|
||||
<string name="dnkm_huawei_protected_button">Briar ကို ကာကွယ်မည်</string>
|
||||
<string name="dnkm_huawei_protected_help">ကာကွယ်မှုပေးထားသောအက်ပ်များစာရင်းတွင် ထည့်မထားလျှင် Briar ကို နောက်ကွယ်တွင် ဖွင့်ထားနိုင်မည်မဟုတ်ပါ။</string>
|
||||
<string name="dnkm_huawei_app_launch_text">အောက်ပါခလုတ်ကိုနှိပ်ပြီး \"အက်ပ်စတင်ခြင်း\" စခရင်ကို ဖွင့်၍ Briar ကို \"ကိုယ်တိုင်စီမံမည်\" ဟု သတ်မှတ်ပါ။</string>
|
||||
<string name="dnkm_huawei_app_launch_help">\"အက်ပ်စတင်ခြင်း\" စခရင်တွင် \"ကိုယ်တိုင်စီမံမည်\" ဟု သတ်မှတ်မထားလျှင် Briar ကို နောက်ကွယ်တွင် ဖွင့်ထားနိုင်မည်မဟုတ်ပါ။</string>
|
||||
<string name="dnkm_xiaomi_text">ဖွင့်ထားသောအက်ပ်များစာရင်းတွင် Briar ကို လော့ခ်ချထားမှ နောက်ကွယ်တွင် ဖွင့်ထားနိုင်မည်။</string>
|
||||
<string name="dnkm_xiaomi_button">Briar ကို ကာကွယ်မည်</string>
|
||||
<string name="dnkm_xiaomi_help">ဖွင့်ထားသောအက်ပ်များစာရင်းတွင် လော့ခ်ချမထားပါက Briar ကို နောက်ကွယ်တွင် ဖွင့်ထားနိုင်မည်မဟုတ်ပါ။</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">၁။ ဖွင့်ထားသောအက်ပ်များစာရင်း (တစ်နည်းအားဖြင့် အက်ပ်ပြောင်းရာ) ကို ဖွင့်ပါ\n\n၂။ သော့ခလောက်အိုင်ကွန်ပေါ်လာရန် Briar ပုံပေါ်မှ ပွတ်ဆွဲချပါ\n\n၃။ သော့ခတ်မထားပါက သော့ခတ်ရန်နှိပ်လိုက်ပါ</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">စကားဝှက်</string>
|
||||
<string name="try_again">စကားဝှက်မှားနေတယ်၊ ထပ်စမ်းကြည့်ပါ</string>
|
||||
@@ -225,8 +220,6 @@
|
||||
<string name="contact_added_toast">ထည့်ပြီးသောအဆက်အသွယ် - %s ခု</string>
|
||||
<string name="contact_already_exists">အဆက်အသွယ်လိပ်စာ %s သည် ရှိနှင့်ပြီးဖြစ်သည်</string>
|
||||
<string name="qr_code_invalid">ဒီ QR ကုဒ်သည် အသုံးပြုလို့ မဆီလျော်ပါ</string>
|
||||
<string name="qr_code_too_old">သင် စကန်ဖတ်ထားသော QR ကုဒ်သည် %s အရင်ဗားရှင်းအဟောင်းမှ ဖြစ်ပါသည်။ \n\n ကျေးဇူးပြု၍ သင့် အဆက်အသွယ်အား နောက်ဆုံးဗားရှင်းသို့ အဆင့်မြှင့်ရန် တောင်းဆိုပေးပြီး ပြန်စမ်းကြည့်ပေးပါ။</string>
|
||||
<string name="qr_code_too_new">သင် စကန်ဖတ်ထားသော QR ကုဒ်သည် %s ဗားရှင်းအသစ်မှ ဖြစ်ပါသည်။ \n\n ကျေးဇူးပြု၍ နောက်ဆုံးဗားရှင်းသို့ အဆင့်မြှင့်ပြီး ပြန်စမ်းကြည့်ပေးပါ။</string>
|
||||
<string name="camera_error">ကင်မရာ ပြဿနာ</string>
|
||||
<string name="connecting_to_device">ဤစက်ပစ္စည်း \u2026 နှင့် ချိတ်ဆက်နေပါသည်</string>
|
||||
<string name="authenticating_with_device">ဤစက် \u2026 ကို စစ်မှန်ကြောင်း စစ်ဆေးနေပါသည်</string>
|
||||
@@ -290,7 +283,6 @@
|
||||
<string name="pending_contact_updated_toast">ဆိုင်းငံ့ထားသော အဆက်အသွယ်ကို အပ်ဒိတ်လုပ်ပြီး</string>
|
||||
<!--Introductions-->
|
||||
<string name="introduction_onboarding_title">သင့်ရဲ့ အဆက်အသွယ်လိပ်စာများကို မိတ်ဆက်ပါ</string>
|
||||
<string name="introduction_onboarding_text">သင်၏ အဆက်အသွယ်လိပ်စာများကို အချင်းချင်း မိတ်ဆက်နိုင်ပါသောကြောင့် သူတို့အချင်းချင်း အပြင်မှာတွေ့စရာမလိုပဲ Briar ပေါ်မှာတွင် ချိတ်ဆက်နိုင်ပါသည်။</string>
|
||||
<string name="introduction_menu_item">မိတ်ဆက်ခြင်း ပြုလုပ်ပါ</string>
|
||||
<string name="introduction_activity_title">အဆက်အသွယ်လိပ်စာကို ရွေးထားပါ</string>
|
||||
<string name="introduction_not_possible">ဤအဆက်အသွယ်များနှင့် သင့်စီတွင် မိတ်ဆက်ခြင်းတစ်ခု ရှိလျက်ဖြစ်ပါသည်။ ပြီးစီးရန် ခွင့်ပြုပေးပါ။ သင်မှ သို့မဟုတ် သင့်အဆက်အသွယ်များမှ အွန်လိုင်းမတက်ရှိလျှင် ဤလုပ်ငန်းစဥ်သည် ကြန့်ကြာနိုင်ပါသည်။</string>
|
||||
@@ -691,8 +683,6 @@
|
||||
<string name="hotspot_manual_site_address">လိပ်စာ (URL)</string>
|
||||
<string name="hotspot_qr_site">သင့်ဖုန်းသည် ဝိုင်ဖိုင်ဟော့စပေါ့ကို ပံ့ပိုးပေးနေသည်။ ဟော့စပေါ့သို့ ချိတ်ဆက်ထားသူများသည် ဤ QR ကုဒ်ကို စကင်န်ဖတ်ခြင်းဖြင့် Briar ကို ဒေါင်းလုဒ်လုပ်နိုင်ပါသည်။</string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">ဒေါင်းလုဒ်%s</string>
|
||||
<string name="website_download_intro">အနီးတစ်ဝိုက်တွင် တစ်စုံတစ်ဦးမှ %sသင်နှင့် မျှဝေခဲ့သည်။</string>
|
||||
<string name="website_download_outro">ဒေါင်းလုဒ်ပြီးပါက ဒေါင်းလုဒ်လုပ်ထားသော ဖိုင်ကိုဖွင့်ပြီး ထည့်သွင်းပါ။</string>
|
||||
<string name="website_troubleshooting_title">ပြဿနာရှာဖွေပြင်ဆင်ခြင်း</string>
|
||||
<string name="website_troubleshooting_1">အက်ပ်ကို သင်ဒေါင်းလုဒ် မလုပ်နိုင်ပါက အခြား ဝဘ်ဘရောက်ဆာ အက်ပ်ဖြင့် ၎င်းကို စမ်းကြည့်ပါ။</string>
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
<string name="dnkm_xiaomi_button">Chroń Briar</string>
|
||||
<string name="dnkm_xiaomi_help">Jeżeli Briar nie jest zablokowany na liście ostatnich aplikacji, nie będzie mógł działać w tle.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Otwórz listę ostatnich aplikacji (często nazywaną też przełącznikiem aplikacji)\n\n2. Przewiń w dół na obrazku Briara aby ukazała się ikonka kłódki\n\n3. Jeśli kłódka nie jest zablokowana, dotknij, aby ją zablokować</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Otwórz listę ostatnich aplikacji (często nazywaną też przełącznikiem aplikacji)\n\n2. Przyciśnij i przytrzymaj obrazek Briara aby ukazała się ikonka kłódki\n\n3. Jeśli kłódka nie jest zablokowana, dotknij, aby ją zablokować</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">Hasło</string>
|
||||
<string name="try_again">Złe hasło, spróbuj ponownie</string>
|
||||
@@ -248,8 +247,6 @@
|
||||
<string name="contact_added_toast">Kontakt dodany: %s</string>
|
||||
<string name="contact_already_exists">Kontakt %s już istnieje</string>
|
||||
<string name="qr_code_invalid">Kod QR jest nieprawidłowy</string>
|
||||
<string name="qr_code_too_old">Kod QR, który zeskanowałeś pochodzi od starszej wersji %s.\n\nPoproś swój kontakt o zaktualizowanie do najnowszej wersji i wtedy spróbuj ponownie.</string>
|
||||
<string name="qr_code_too_new">Kod QR, który zeskanowałeś pochodzi od nowszej wersji %s.\n\n Wykonaj aktualizację do najnowszej wersji i spróbuj ponownie.</string>
|
||||
<string name="camera_error">Błąd aparatu</string>
|
||||
<string name="connecting_to_device">Łączenie z urządzeniem\u2026</string>
|
||||
<string name="authenticating_with_device">Autoryzowanie z urządzeniem\u2026</string>
|
||||
@@ -765,8 +762,6 @@ Brak dostępu do aparatu. Spróbuj ponownie, może po ponownym uruchomieniu urz
|
||||
<string name="hotspot_manual_site_address">Adres (URL)</string>
|
||||
<string name="hotspot_qr_site">Twój telefon udostępnia hotspot Wi-Fi. Osoby połączone z hotspotem mogą pobrać Briar, skanując ten kod QR.</string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">Pobierz %s</string>
|
||||
<string name="website_download_intro"> Ktoś w pobliżu udostępnił Ci %s.</string>
|
||||
<string name="website_download_outro">Po zakończeniu pobierania otwórz pobrany plik i zainstaluj go.</string>
|
||||
<string name="website_troubleshooting_title">Rozwiązywanie problemów</string>
|
||||
<string name="website_troubleshooting_1">Jeśli nie możesz pobrać aplikacji, spróbuj za pomocą innej przeglądarki internetowej.</string>
|
||||
|
||||
@@ -1,44 +1,38 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources>
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Boas-vindas ao Briar</string>
|
||||
<string name="setup_name_explanation">Seu nome de usuária será mostrado próximo a qualquer conteúdo que você publicar. Você não pode mudá-lo depois que criar sua conta,</string>
|
||||
<string name="setup_next">Próximo</string>
|
||||
<string name="setup_password_intro">Escolha uma senha</string>
|
||||
<string name="setup_password_explanation">A sua conta do Briar está salva de modo criptografado no seu dispositivo, não na nuvem. Se você esquecer sua senha nou desinstalar o Briar não há como recuperar sua conta.\n\nEscolha uma senha longa que seja difícil de ser adivinhada, como cinco palavras aleatórias ou dez letras, números e símbolos aleatórios.</string>
|
||||
<string name="dnkm_doze_title">Conexões em segundo plano</string>
|
||||
<string name="dnkm_doze_intro">Para receber mensagens, o Briar precisa permanecer conectado em segundo plano.</string>
|
||||
<string name="dnkm_doze_explanation">Para receber mensagens, o Briar precisa permanecer conectado em segundo plano. Por favor, desative as otimizações da bateria para que o Briar possa permanecer conectado.</string>
|
||||
<string name="dnkm_doze_button">Pemitir conexões</string>
|
||||
<string name="choose_nickname">Escolha seu apelido</string>
|
||||
<string name="choose_password">Escolha sua senha</string>
|
||||
<string name="confirm_password">Confirme sua senha</string>
|
||||
<string name="name_too_long">O nome está muito grande</string>
|
||||
<string name="password_too_weak">A senha está muito fraca</string>
|
||||
<string name="passwords_do_not_match">As senhas não conferem</string>
|
||||
<string name="create_account_button">Criar conta</string>
|
||||
<string name="more_info">Informações adicionais</string>
|
||||
<string name="don_t_ask_again">Não perguntar novamente</string>
|
||||
<string name="dnkm_huawei_protected_text">Toque no botão abaixo e verifique se o Briar está protegido na tela \"Aplicativos Protegidos\"</string>
|
||||
<string name="dnkm_huawei_protected_button">Proteger o Briar</string>
|
||||
<string name="dnkm_huawei_protected_help">Se o Briar não for adicionado à lista de aplicativos protegidos ele não poderá ser executado em segundo plano.</string>
|
||||
<string name="setup_huawei_app_launch_text">Por favor, toque no botão abaixo, abra a tela de \"Lançamento de apps\" e certifique que o Briar está definido para \"Gerenciar manualmente\".</string>
|
||||
<string name="setup_huawei_app_launch_button">Abrir Configurações de Bateria</string>
|
||||
<string name="setup_huawei_app_launch_help">Se o Briar não estiver definido como \"Gerenciar manualmente\" na tela de \"Lançamento de apps\", ele não poderá ser executado em segundo plano.</string>
|
||||
<string name="setup_huawei_app_launch_error_toast">Não pôde abrir configurações de bateria</string>
|
||||
<string name="setup_xiaomi_text">Para ser executado em segundo plano, o Briar deve estar fixado à lista de apps recentes.</string>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Boas-vindas ao Briar</string>
|
||||
<string name="setup_name_explanation">Seu nome de usuária será mostrado próximo a qualquer conteúdo que você publicar. Você não pode mudá-lo depois que criar sua conta,</string>
|
||||
<string name="setup_next">Próximo</string>
|
||||
<string name="setup_password_intro">Escolha uma senha</string>
|
||||
<string name="setup_password_explanation">A sua conta do Briar está salva de modo criptografado no seu dispositivo, não na nuvem. Se você esquecer sua senha nou desinstalar o Briar não há como recuperar sua conta.\n\nEscolha uma senha longa que seja difícil de ser adivinhada, como cinco palavras aleatórias ou dez letras, números e símbolos aleatórios.</string>
|
||||
<string name="dnkm_doze_intro">Para receber mensagens, o Briar precisa permanecer conectado em segundo plano.</string>
|
||||
<string name="dnkm_doze_explanation">Para receber mensagens, o Briar precisa permanecer conectado em segundo plano. Por favor, desative as otimizações da bateria para que o Briar possa permanecer conectado.</string>
|
||||
<string name="choose_nickname">Escolha seu apelido</string>
|
||||
<string name="choose_password">Escolha sua senha</string>
|
||||
<string name="confirm_password">Confirme sua senha</string>
|
||||
<string name="name_too_long">O nome está muito grande</string>
|
||||
<string name="password_too_weak">A senha está muito fraca</string>
|
||||
<string name="passwords_do_not_match">As senhas não conferem</string>
|
||||
<string name="create_account_button">Criar conta</string>
|
||||
<string name="more_info">Informações adicionais</string>
|
||||
<string name="don_t_ask_again">Não perguntar novamente</string>
|
||||
<string name="dnkm_huawei_protected_text">Toque no botão abaixo e verifique se o Briar está protegido na tela \"Aplicativos Protegidos\"</string>
|
||||
<string name="dnkm_huawei_protected_button">Proteger o Briar</string>
|
||||
<string name="dnkm_huawei_protected_help">Se o Briar não for adicionado à lista de aplicativos protegidos ele não poderá ser executado em segundo plano.</string>
|
||||
<string name="dnkm_huawei_app_launch_text">Por favor, toque no botão abaixo, abra a tela de \"Lançamento de apps\" e certifique que o Briar está definido para \"Gerenciar manualmente\".</string>
|
||||
<string name="dnkm_huawei_app_launch_help">Se o Briar não estiver definido como \"Gerenciar manualmente\" na tela de \"Lançamento de apps\", ele não poderá ser executado em segundo plano.</string>
|
||||
<string name="dnkm_xiaomi_text">Para ser executado em segundo plano, o Briar deve estar fixado à lista de apps recentes.</string>
|
||||
<string name="dnkm_xiaomi_button">Proteger o Briar</string>
|
||||
<string name="setup_xiaomi_help">Se o Briar não estiver fixado na lista de aplicativos recentes, ele não será capaz de rodar em segundo plano.</string>
|
||||
<string name="setup_xiaomi_dialog_body_old">1. Abra a lista de aplicativos recentes (também chamada de alternador de aplicativos)\n\n2. Deslize para baixo na imagem do Briar para mostrar o ícone de cadeado\n\n3. Se o cadeado não estiver trancado, toque para trancá-lo</string>
|
||||
<string name="setup_xiaomi_dialog_body_new">1. Abra a lista de aplicativos recentes (também chamada de alternador de aplicativos)\n\n2. Pressione e segure na imagem do Briar para mostrar o ícone de cadeado\n\n3. Se o cadeado não estiver trancado, toque para trancá-lo</string>
|
||||
<string name="dnkm_warning_dozed">%s não pôde ser executado em segundo plano</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">Senha</string>
|
||||
<string name="try_again">Senha Incorreta, tente novamente</string>
|
||||
<string name="dialog_title_cannot_check_password">Não foi possível verificar sua senha</string>
|
||||
<string name="dialog_message_cannot_check_password">O Briar não conseguiu verificar sua senha. Por favor, tente reiniciar o aparelho para resolver o problema.</string>
|
||||
<string name="sign_in_button">Entrar</string>
|
||||
<string name="forgotten_password">Esqueci minha senha</string>
|
||||
<string name="dnkm_xiaomi_help">Se o Briar não estiver fixado à lista de aplicativos recentes, ele não poderá ser executado em segundo plano.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Abra a lista de aplicativos recentes (também chamada de alternador de aplicativos)\n\n2. Deslize para baixo na imagem do Briar para mostrar o ícone de cadeado\n\n3. Se o cadeado não estiver trancado, toque para trancá-lo</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">Senha</string>
|
||||
<string name="try_again">Senha Incorreta, tente novamente</string>
|
||||
<string name="dialog_title_cannot_check_password">Não foi possível verificar sua senha</string>
|
||||
<string name="dialog_message_cannot_check_password">Briar não conseguiu verificar sua senha. Por favor, tente reiniciar o dispositivo para resolver o problema.</string>
|
||||
<string name="sign_in_button">Entrar</string>
|
||||
<string name="forgotten_password">Esqueci minha 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="startup_failed_activity_title">Inicialização do Briar falhou</string>
|
||||
@@ -49,10 +43,12 @@
|
||||
<string name="startup_failed_service_error">Briar não foi capaz de inicializar um componente necessário.\n\nPor favor, atualize o aplicativo para uma versão mais recente e tente novamente.</string>
|
||||
<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="many">Esta é uma versão de teste do Briar. Sua conta irá expirar em %d dias e não poderá ser renovada.</item>
|
||||
<item quantity="other">Esta é uma versão de teste do Briar. Sua conta irá expirar em %d dias e não poderá ser renovada.</item>
|
||||
</plurals>
|
||||
<plurals name="old_android_expiry_warning">
|
||||
<item quantity="one">A versão 4 do Android já não é mais compatível. Briar deixará de funcionar em %s (dentro de %d dias). Por favor, instale Briar em um novo aparelho e crie uma nova conta.</item>
|
||||
<item quantity="many">A versão 4 do Android já não é mais compatível. Briar deixará de funcionar em %s (dentro de %d dias). Por favor, instale Briar em um novo dispositivo e crie uma nova conta.</item>
|
||||
<item quantity="other">A versão 4 do Android já não é mais compatível. Briar deixará de funcionar em %s (dentro de %d dias). Por favor, instale Briar em um novo dispositivo e crie uma nova conta.</item>
|
||||
</plurals>
|
||||
<string name="expiry_date_reached">Este software expirou.\nObrigado por testar!</string>
|
||||
@@ -91,7 +87,7 @@
|
||||
<string name="tor_plugin_status_disabled_country_blocked">Briar está configurado para não usar a Internet neste país</string>
|
||||
<!--Transports: Wi-Fi-->
|
||||
<string name="transport_lan">Wi-fi</string>
|
||||
<string name="transport_lan_long">Mesma rede de Wi-Fi</string>
|
||||
<string name="transport_lan_long">Mesma rede Wi-Fi</string>
|
||||
<string name="lan_device_status_on">Seu celular está conectado ao Wi-Fi</string>
|
||||
<string name="lan_device_status_off">Seu celular não está conectado ao Wi-Fi</string>
|
||||
<string name="lan_plugin_status_enabling">Briar está se conectando à rede Wi-Fi</string>
|
||||
@@ -115,18 +111,22 @@
|
||||
<string name="ongoing_notification_text">Toque para abrir o Briar</string>
|
||||
<plurals name="private_message_notification_text">
|
||||
<item quantity="one">Nova mensagem privada.</item>
|
||||
<item quantity="many">%d novas mensagens privadas.</item>
|
||||
<item quantity="other">%d novas mensagens privadas.</item>
|
||||
</plurals>
|
||||
<plurals name="group_message_notification_text">
|
||||
<item quantity="one">Nova mensagem de um Grupo.</item>
|
||||
<item quantity="many">%d novas mensagens de Grupos.</item>
|
||||
<item quantity="other">%d novas mensagens de Grupos.</item>
|
||||
</plurals>
|
||||
<plurals name="forum_post_notification_text">
|
||||
<item quantity="one">Nova postagem de fórum</item>
|
||||
<item quantity="many">%d novas postagens em fóruns.</item>
|
||||
<item quantity="other">%d novas postagens em fóruns.</item>
|
||||
</plurals>
|
||||
<plurals name="blog_post_notification_text">
|
||||
<item quantity="one">Novo post em Blog.</item>
|
||||
<item quantity="many">%d novos posts em Blogs.</item>
|
||||
<item quantity="other">%d novos posts em Blogs.</item>
|
||||
</plurals>
|
||||
<!--Misc-->
|
||||
@@ -174,21 +174,24 @@
|
||||
<string name="set_contact_alias_hint">Nome de contato</string>
|
||||
<string name="menu_item_disappearing_messages">Mensagens efêmeras</string>
|
||||
<!--The first placeholder will show a duration like "7 days". The second placeholder at the end will add "Tap to learn more."-->
|
||||
<string name="auto_delete_msg_you_enabled">Suas mensagens irão desaparecer após %1$s. %2$s</string>
|
||||
<string name="auto_delete_msg_you_enabled">Suas mensagens vão desaparecer após %1$s. %2$s</string>
|
||||
<!--The placeholder at the end will add "Tap to learn more."-->
|
||||
<string name="auto_delete_msg_you_disabled">Suas mensagens não vão desaparecer. %1$s</string>
|
||||
<!--The first placeholder will show a contact's name. The second placeholder will show a duration like "7 days". The third placeholder at the end will add "Tap to learn more."-->
|
||||
<string name="auto_delete_msg_contact_enabled">As mensagens de %1$s vão desaparecer em %2$s. %3$s</string>
|
||||
<plurals name="duration_minutes">
|
||||
<item quantity="one">%d minuto</item>
|
||||
<item quantity="many">%d minutos</item>
|
||||
<item quantity="other">%d minutos</item>
|
||||
</plurals>
|
||||
<plurals name="duration_hours">
|
||||
<item quantity="one">%d hora</item>
|
||||
<item quantity="many">%d horas</item>
|
||||
<item quantity="other">%d horas</item>
|
||||
</plurals>
|
||||
<plurals name="duration_days">
|
||||
<item quantity="one">%d dia</item>
|
||||
<item quantity="many">%d dias</item>
|
||||
<item quantity="other">%d dias</item>
|
||||
</plurals>
|
||||
<!--The first placeholder will show a contact's name. The second placeholder at the end will add "Tap to learn more."-->
|
||||
@@ -199,9 +202,9 @@
|
||||
<string name="auto_delete_changed_warning_message_disabled">Após você começar a escrever sua mensagem, as mensagens efêmeras foram desativadas.</string>
|
||||
<string name="auto_delete_changed_warning_send">Mandar mesmo assim</string>
|
||||
<string name="delete_all_messages">Deletar todas as mensagens</string>
|
||||
<string name="dialog_title_delete_all_messages">Confirmar exclusão de mensagem</string>
|
||||
<string name="dialog_message_delete_all_messages">Você tem certeza que deseja excluir todas as mensagens?</string>
|
||||
<string name="dialog_title_not_all_messages_deleted">Não foi possível apagar todas as mensagens</string>
|
||||
<string name="dialog_title_delete_all_messages">Confirmar exclusão de mensagens</string>
|
||||
<string name="dialog_message_delete_all_messages">Você tem certeza que deseja deletar todas as mensagens?</string>
|
||||
<string name="dialog_title_not_all_messages_deleted">Não foi possível deletar todas as mensagens</string>
|
||||
<string name="dialog_message_not_deleted_ongoing_both">Mensagens relacionadas a convites e apresentações em andamento não podem ser deletadas até que o convite ou apresentação seja concluído. </string>
|
||||
<string name="dialog_message_not_deleted_ongoing_introductions">Mensagens relacionadas a apresentações em andamento não podem ser deletadas até que a apresentação seja concluída.</string>
|
||||
<string name="dialog_message_not_deleted_ongoing_invitations">Mensagens relacionadas a apresentações em andamento não podem ser deletadas até que a apresentação seja concluída.</string>
|
||||
@@ -216,12 +219,12 @@
|
||||
<string name="you">Você</string>
|
||||
<string name="save_image">Salvar imagem</string>
|
||||
<string name="dialog_title_save_image">Salvar imagem?</string>
|
||||
<string name="dialog_message_save_image">Salvando essa imagem você irá permitir que outros aplicativos a acessem.\n\nTem certeza que quer salvar? </string>
|
||||
<string name="dialog_message_save_image">Salvar essa imagem permitirá que outros aplicativos a acessem.\n\nTem certeza que quer salvar? </string>
|
||||
<string name="save_image_success">Imagem salva</string>
|
||||
<string name="save_image_error">Não foi possível salvar imagem</string>
|
||||
<string name="dialog_title_no_image_support">Imagens indisponíveis</string>
|
||||
<string name="dialog_message_no_image_support">O Briar do seu contato ainda não suporta o anexo de imagens. Quando ele estiver atualizado, você verá um ícone diferente.</string>
|
||||
<string name="dialog_title_image_support">Você agora pode enviar imagens para esse contato</string>
|
||||
<string name="dialog_title_image_support">Agora você pode enviar imagens a esse contato</string>
|
||||
<string name="dialog_message_image_support">Toque nesse ícone para anexar imagens.</string>
|
||||
<string name="messaging_too_many_attachments_toast">Apenas as primeiras %d imagens serão enviadas</string>
|
||||
<string name="menu_contact">Contato</string>
|
||||
@@ -235,8 +238,6 @@
|
||||
<string name="contact_added_toast">Contato adicionado: %s</string>
|
||||
<string name="contact_already_exists">Contato %s já existe</string>
|
||||
<string name="qr_code_invalid">O código QR é inválido</string>
|
||||
<string name="qr_code_too_old">O código QR que você escaneou está em uma versão mais antiga de %s.\n\nPor favor informe o seu contato para atualizar para a última versão e tente novamente.</string>
|
||||
<string name="qr_code_too_new">O código QR que você escaneou está em uma versão mais recente de %s.\n\nPor favor atualize para a última versão e tente novamente.</string>
|
||||
<string name="camera_error">Erro da câmera</string>
|
||||
<string name="connecting_to_device">Conectando a device\u2026</string>
|
||||
<string name="authenticating_with_device">Autenticando com o dispositivo\u2026</string>
|
||||
@@ -253,7 +254,7 @@
|
||||
<string name="copy_button">Copiar</string>
|
||||
<string name="share_button">Compartilhar</string>
|
||||
<string name="send_link_title">Troquem os links</string>
|
||||
<string name="add_contact_choose_nickname">Escolha um Apelido</string>
|
||||
<string name="add_contact_choose_nickname">Escolha um apelido</string>
|
||||
<string name="add_contact_choose_a_nickname">Insira um apelido</string>
|
||||
<string name="nickname_intro">Dê um apelido ao contato. Somente você pode ver esse apelido. </string>
|
||||
<string name="your_link">Passe esse link para o contato que você quer adicionar</string>
|
||||
@@ -263,10 +264,10 @@
|
||||
<string name="pending_contact_requests_snackbar">Existem solicitações de contato pendentes</string>
|
||||
<string name="pending_contact_requests">Solicitações de contatos pendentes</string>
|
||||
<string name="no_pending_contacts">Sem contatos pendentes</string>
|
||||
<string name="waiting_for_contact_to_come_online">Esperando pelo usuário estar online ...</string>
|
||||
<string name="waiting_for_contact_to_come_online">Esperando o usuário estar online...</string>
|
||||
<string name="connecting">Conectando...</string>
|
||||
<string name="adding_contact">Adicionando contato ...</string>
|
||||
<string name="adding_contact_failed">Adicionar o contato falhou</string>
|
||||
<string name="adding_contact_failed">Falha ao adicionar contato</string>
|
||||
<string name="dialog_title_remove_pending_contact">Confirme a remoção </string>
|
||||
<string name="dialog_message_remove_pending_contact">Esse contato ainda está sendo adicionado. Se você removê-lo agora, o mesmo não será adicionado</string>
|
||||
<string name="own_link_error">Insira o link do seu contato, não o seu próprio </string>
|
||||
@@ -274,14 +275,15 @@
|
||||
<string name="invalid_link">Link invalido</string>
|
||||
<string name="unsupported_link">Esse link veio de uma versão mais recente do Briar. Por favor atualize para a versão mais recente e tente novamente </string>
|
||||
<string name="intent_own_link">Você abriu seu próprio link. Utilize o link do contato que quer adicionar!</string>
|
||||
<string name="missing_link">Por favor insira um link</string>
|
||||
<string name="missing_link">Por favor, insira um link</string>
|
||||
<!--This is a numeral indicating the first step in a series of screens-->
|
||||
<string name="step_1">1</string>
|
||||
<!--This is a numeral indicating the second step in a series of screens-->
|
||||
<string name="step_2">2</string>
|
||||
<plurals name="contact_added_notification_text">
|
||||
<item quantity="one">Novo contato adicionado.</item>
|
||||
<item quantity="other">%dnovos contados adicionados.</item>
|
||||
<item quantity="many">%d novos contados adicionados.</item>
|
||||
<item quantity="other">%d novos contados adicionados.</item>
|
||||
</plurals>
|
||||
<string name="offline_state">Sem conexão à Internet</string>
|
||||
<string name="duplicate_link_dialog_title">Link duplicado</string>
|
||||
@@ -302,7 +304,7 @@
|
||||
<!--Introductions-->
|
||||
<string name="introduction_onboarding_title">Apresente seus contatos</string>
|
||||
<string name="introduction_onboarding_text">Apresente seus contatos entre si para que eles possam se conectar no Briar.</string>
|
||||
<string name="introduction_menu_item">Fazer apresentação</string>
|
||||
<string name="introduction_menu_item">Fazer Apresentação</string>
|
||||
<string name="introduction_activity_title">Selecionar contato</string>
|
||||
<string name="introduction_not_possible">Você já tem uma apresentação em andamento com esses contatos. Por favor, permita que isso termine primeiro. Se você ou seus contatos raramente ficam on-line, isso pode levar algum tempo.</string>
|
||||
<string name="introduction_message_title">Apresentar contatos</string>
|
||||
@@ -329,7 +331,7 @@
|
||||
<string name="connect_via_bluetooth_no_location_permission">Não há como continuar sem a permissão de localização</string>
|
||||
<string name="connect_via_bluetooth_start">Conectando-se via Bluetooth...</string>
|
||||
<string name="connect_via_bluetooth_success">Conectado com sucesso via Bluetooth</string>
|
||||
<string name="connect_via_bluetooth_error">Não pôde se conectar via Bluetooth.</string>
|
||||
<string name="connect_via_bluetooth_error">Não foi possível se conectar via Bluetooth.</string>
|
||||
<string name="connect_via_bluetooth_error_not_supported">Bluetooth não suportado pelo dispositivo.</string>
|
||||
<!--Private Groups-->
|
||||
<string name="groups_list_empty">Sem grupos para exibir</string>
|
||||
@@ -337,6 +339,7 @@
|
||||
<string name="groups_created_by">Criado por %s.</string>
|
||||
<plurals name="messages">
|
||||
<item quantity="one">%d mensagem</item>
|
||||
<item quantity="many">%d mensagens</item>
|
||||
<item quantity="other">%d mensagens</item>
|
||||
</plurals>
|
||||
<string name="groups_group_is_empty">Esse grupo está vazio</string>
|
||||
@@ -370,6 +373,7 @@
|
||||
<string name="groups_invitations_declined">Convite do Grupo recusado</string>
|
||||
<plurals name="groups_invitations_open">
|
||||
<item quantity="one">%d convite para Grupo aberto</item>
|
||||
<item quantity="many">%d convites para Grupos abertos</item>
|
||||
<item quantity="other">%d convites para Grupos abertos</item>
|
||||
</plurals>
|
||||
<string name="groups_invitations_response_accepted_sent">Você aceitou o convite do Grupo de %s.</string>
|
||||
@@ -396,6 +400,7 @@
|
||||
<string name="no_posts">Sem Posts</string>
|
||||
<plurals name="posts">
|
||||
<item quantity="one">%d Post</item>
|
||||
<item quantity="many">%d Posts</item>
|
||||
<item quantity="other">%d Posts</item>
|
||||
</plurals>
|
||||
<string name="forum_new_message_hint">Novo Post</string>
|
||||
@@ -418,7 +423,7 @@
|
||||
<string name="forum_invitation_received">%1$s compartilhou o fórum \"%2$s\" com você.</string>
|
||||
<string name="forum_invitation_sent">Você compartilhou o fórum \"%1$s\" com %2$s.</string>
|
||||
<string name="forum_invitations_title">Convites para Foruns</string>
|
||||
<string name="forum_invitation_exists">Você já aceitou um convite para este fórum.\n\nPorém, aceitar mais convites fará com que sua conexão ao fórum fique mais rápida e mais confiável.</string>
|
||||
<string name="forum_invitation_exists">Você já aceitou um convite para este fórum.\n\nAceitar mais convites fará sua conexão ao fórum ficar mais rápida e confiável.</string>
|
||||
<string name="forum_joined_toast">Entrou no fórum</string>
|
||||
<string name="forum_declined_toast">Convite recusado</string>
|
||||
<string name="shared_by_format">Compartilhado por %s</string>
|
||||
@@ -433,6 +438,7 @@
|
||||
<string name="shared_with">Compartilhado com %1$d (%2$d online)</string>
|
||||
<plurals name="forums_shared">
|
||||
<item quantity="one">%d fórum compartilhado por contatos</item>
|
||||
<item quantity="many">%d fóruns compartilhados por contatos</item>
|
||||
<item quantity="other">%d fóruns compartilhados por contatos</item>
|
||||
</plurals>
|
||||
<string name="nobody">Ninguém</string>
|
||||
@@ -448,7 +454,7 @@
|
||||
<string name="blogs_feed_empty_state">Sem posts para exibir</string>
|
||||
<string name="blogs_feed_empty_state_action">Posts de seus contatos e de blogs em que você está inscrito aparecerão aqui\n\nToque no ícone da caneta para escrever um post </string>
|
||||
<string name="blogs_remove_blog">Remover Blog</string>
|
||||
<string name="blogs_remove_blog_dialog_message">Você tem certeza que quer remover este blog?\n\nOs posts serão removidos do seu dispositivo mas não dos dispositivos das outras pessoas.\n\nContatos com quem você tenha compartilhado este blog vão parar de receber atualizações dele.</string>
|
||||
<string name="blogs_remove_blog_dialog_message">Você tem certeza que quer remover esse blog?\n\nOs posts serão removidos do seu dispositivo, mas não dos dispositivos das outras pessoas.\n\nContatos com quem você compartilhou este blog podem parar de receber atualizações.</string>
|
||||
<string name="blogs_remove_blog_ok">Remover</string>
|
||||
<string name="blogs_blog_removed">Blog removido</string>
|
||||
<string name="blogs_reblog_comment_hint">Adicionar um comentário (opcional)</string>
|
||||
@@ -466,7 +472,7 @@
|
||||
<string name="blogs_sharing_invitation_received">%1$s compartilhou o blog \"%2$s\" com você.</string>
|
||||
<string name="blogs_sharing_invitation_sent">Você compartilhou o blog \"%1$s\" com %2$s.</string>
|
||||
<string name="blogs_sharing_invitations_title">Convites para Fóruns</string>
|
||||
<string name="blogs_sharing_joined_toast">Inscrita ao blog</string>
|
||||
<string name="blogs_sharing_joined_toast">Inscreveu-se no blog</string>
|
||||
<string name="blogs_sharing_declined_toast">Convite recusado</string>
|
||||
<string name="sharing_status_blog">Qualquer pessoa que se inscreva em um blog pode compartilhá-lo com seus contatos. Você está compartilhando este blog com os seguintes contatos. Também podem haver outras pessoas inscritas que você não consegue visualizar.</string>
|
||||
<!--RSS Feeds-->
|
||||
@@ -480,7 +486,7 @@
|
||||
<string name="blogs_rss_feeds_manage_author">Autor:</string>
|
||||
<string name="blogs_rss_feeds_manage_updated">Última Atualização:</string>
|
||||
<string name="blogs_rss_remove_feed">Remover Feed</string>
|
||||
<string name="blogs_rss_remove_feed_dialog_message">Você tem certeza que deseja remover este feed?\n\nOs posts serão removidos do seus dispositivo mas não dos dispositivos de outras pessoas.\n\nContatos com quem você tenha compartilhado este feed vão parar de receber atualizações dele.</string>
|
||||
<string name="blogs_rss_remove_feed_dialog_message">Você tem certeza que deseja remover esse feed?\n\nOs posts serão removidos do seus dispositivo, mas não dos dispositivos de outras pessoas.\n\nContatos com quem você compartilhou esse feed podem parar de receber atualizações.</string>
|
||||
<string name="blogs_rss_remove_feed_ok">Remover</string>
|
||||
<string name="blogs_rss_feeds_manage_empty_state">Sem feeds RSS para exibir\n\nToque no ícone + para importar um feed</string>
|
||||
<string name="blogs_rss_feeds_manage_error">Houve um problema ao carregar seus Feeds. Por favor tente novamente.</string>
|
||||
@@ -491,7 +497,7 @@
|
||||
<string name="change_profile_picture_failed_message">Sentimos muito, mas algo deu errado ao atualizar sua foto de perfil</string>
|
||||
<!--Settings Display-->
|
||||
<string name="pref_language_title">Linguagem & região</string>
|
||||
<string name="pref_language_changed">Essa definição vai valer quando você reiniciar o Briar. Por favor saia e reinicie o Briar.</string>
|
||||
<string name="pref_language_changed">Essa mudança vai valer quando você reiniciar o Briar. Por favor, saia e reinicie o Briar.</string>
|
||||
<string name="pref_language_default">Padrão do sistema</string>
|
||||
<string name="display_settings_title">Aparência</string>
|
||||
<string name="pref_theme_title">Tema</string>
|
||||
@@ -502,7 +508,7 @@
|
||||
<!--Settings Connections-->
|
||||
<string name="network_settings_title">Conexões</string>
|
||||
<string name="bluetooth_setting">Acessar contatos via Bluetooth</string>
|
||||
<string name="wifi_setting">Acessar contatos usando a mesma rede Wi-Fi</string>
|
||||
<string name="wifi_setting">Acessar contatos na mesma rede Wi-Fi</string>
|
||||
<string name="tor_enable_title">Acessar contatos via Internet</string>
|
||||
<string name="tor_enable_summary">Por privacidade, todas as conexões passam pela rede Tor</string>
|
||||
<string name="tor_network_setting">Método de conexão para a rede Tor</string>
|
||||
@@ -514,7 +520,7 @@
|
||||
<string name="tor_network_setting_summary">Automático: %1$s (em %2$s) </string>
|
||||
<string name="tor_mobile_data_title">Usar dados móveis</string>
|
||||
<string name="tor_only_when_charging_title">Conectar à Internet apenas durante o carregamento</string>
|
||||
<string name="tor_only_when_charging_summary">Desabilita conexão à Internet quando seu dispositivo estiver somente na bateria</string>
|
||||
<string name="tor_only_when_charging_summary">Desabilita conexão à Internet quando seu dispositivo estiver descarregando</string>
|
||||
<!--Settings Security and Panic-->
|
||||
<string name="security_settings_title">Segurança</string>
|
||||
<string name="pref_lock_title">Bloqueio de app</string>
|
||||
@@ -605,7 +611,7 @@
|
||||
<string name="tor_offline_button_check">Cheque as configurações de conexão</string>
|
||||
<string name="mailbox_status_title">Status do Mailbox</string>
|
||||
<string name="mailbox_status_connected_title">Mailbox está em execução</string>
|
||||
<string name="mailbox_status_problem_title">Estamos tendo dificuldades ao conectar ao Mailbox</string>
|
||||
<string name="mailbox_status_problem_title">Briar está tendo problemas em se conectar ao Mailbox</string>
|
||||
<string name="mailbox_status_failure_title">Mailbox está indisponível</string>
|
||||
<string name="mailbox_status_check_button">Verificar Conexão</string>
|
||||
<!--Example for string substitution: Last connection: 3min ago-->
|
||||
@@ -613,6 +619,11 @@
|
||||
<!--Indicates that there never was a connection to the mailbox. Last connection: Never-->
|
||||
<string name="mailbox_status_connected_never">Nunca</string>
|
||||
<string name="mailbox_status_unlink_button">Desvincular</string>
|
||||
<string name="mailbox_status_unlink_dialog_title">Desvincular Mailbox?</string>
|
||||
<string name="mailbox_status_unlink_dialog_question">Você tem certeza que quer desvincular seu Mailbox?</string>
|
||||
<string name="mailbox_status_unlink_dialog_warning">Se você desvincular seu Mailbox, você não poderá receber mensagens enquanto o Briar estiver offline.</string>
|
||||
<string name="mailbox_status_unlink_no_wipe_title">Seu Mailbox foi desvinculado</string>
|
||||
<string name="mailbox_status_unlink_no_wipe_message">Na próxima vez que você acessar seu dispositivo de Mailbox, por favor, abra o app Mailbox e toque no botão \"Desvincular\" para completar o processo. \n\nSe você não tem mais acesso ao seu dispositivo de Mailbox, não se preocupe. Seus dados estão criptografados, logo, continuarão seguros mesmo que você não complete o processo.</string>
|
||||
<!--Conversation Settings-->
|
||||
<string name="disappearing_messages_title">Mensagens efêmeras</string>
|
||||
<string name="disappearing_messages_explanation_long">Ativar essa opção fará novas
|
||||
@@ -621,18 +632,18 @@
|
||||
O temporizador para o destinatário começa após ele ter lido a mensagem.
|
||||
\n\nMensagens efêmeras são marcadas com um ícone de bomba.
|
||||
\n\nNote que destinatários ainda podem fazer cópias das mensagens que você envia.
|
||||
\n\nSe você alterar essa opção, ela se aplicará à novas mensagens imediatamente e para
|
||||
\n\nSe você alterar essa opção, ela se aplicará a novas mensagens imediatamente e para
|
||||
mensagens de contatos após receberem sua próxima mensagem.
|
||||
Seu contato tambem pode alterar essa opção por vocês.</string>
|
||||
<string name="learn_more">Saiba Mais</string>
|
||||
<string name="disappearing_messages_summary">Faça as futuras mensagens nessa conversa desaparecerem automaticamente após 7\u00A0dias.</string>
|
||||
<string name="learn_more">Saiba mais</string>
|
||||
<string name="disappearing_messages_summary">Fazer as mensagens futuras nessa conversa desaparecerem automaticamente após 7\u00A0dias.</string>
|
||||
<!--Settings Actions-->
|
||||
<string name="pref_category_actions">Ações</string>
|
||||
<string name="send_feedback">Enviar feedback</string>
|
||||
<!--Link Warning-->
|
||||
<string name="link_warning_title">Aviso sobre Link</string>
|
||||
<string name="link_warning_intro">Você está prestes a abrir esse link em um Aplicativo Externo.</string>
|
||||
<string name="link_warning_text">Isso pode ser usado para identificar você. Pense sobre se quer ou não confiar na pessoa que te enviou esse link e considere abri-lo no Tor Browser.</string>
|
||||
<string name="link_warning_text">Isso pode ser usado para identificar você. Pense se você confia em quem te enviou esse link e considere abri-lo no Navegador Tor.</string>
|
||||
<string name="link_warning_open_link">Abrir Link</string>
|
||||
<!--Crash Reporter-->
|
||||
<string name="crash_report_title">Relatório de falhas do Briar</string>
|
||||
@@ -647,15 +658,15 @@
|
||||
<string name="include_debug_report_crash">Incluir informações anonimas sobre o </string>
|
||||
<string name="include_debug_report_feedback">Incluir dados anônimos sobre esse dispositivo </string>
|
||||
<string name="dev_report_user_info">Informações do usuário</string>
|
||||
<string name="dev_report_basic_info">Informação Básica</string>
|
||||
<string name="dev_report_basic_info">Informações básicas</string>
|
||||
<string name="dev_report_device_info">Informações do dispositivo</string>
|
||||
<string name="dev_report_stacktrace">Rastreamento de pilha</string>
|
||||
<string name="dev_report_time_info">Informação de tempo</string>
|
||||
<string name="dev_report_memory">Memória</string>
|
||||
<string name="dev_report_storage">Armazenamento</string>
|
||||
<string name="dev_report_connectivity">Conectividade</string>
|
||||
<string name="dev_report_network_usage">Uso da rede</string>
|
||||
<string name="dev_report_build_config">Configuração de execução</string>
|
||||
<string name="dev_report_network_usage">Uso de rede</string>
|
||||
<string name="dev_report_build_config">Configuração de build</string>
|
||||
<string name="dev_report_logcat">Log do App</string>
|
||||
<string name="dev_report_device_features">Características do dispositivo</string>
|
||||
<string name="send_report">Enviar relatório </string>
|
||||
@@ -676,9 +687,9 @@
|
||||
<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 código QR.</string>
|
||||
<string name="permission_location_title">Permissão para localização</string>
|
||||
<string name="permission_location_request_body">Para encontrar dispositivos Bluetooth, o Briar precisa de permissão para acessar sua localização.\n\nO Briar não armazena sua localização ou a compartilha com qualquer pessoa.</string>
|
||||
<string name="permission_location_request_body">Para encontrar dispositivos Bluetooth, o Briar precisa de permissão para acessar sua localização.\n\nBriar não armazena sua localização nem a compartilha com ninguém.</string>
|
||||
<string name="permission_camera_location_title">Câmera e localização</string>
|
||||
<string name="permission_camera_location_request_body">Para escanear o código QR, O Briar precisa de acesso à câmera.\n\nPara encontrar dispositivos Bluetooth, O Briar precisa de permissão para acessar a localização.\n\nO Briar não armazena seu localização ou a compartilhar com qualquer pessoa.</string>
|
||||
<string name="permission_camera_location_request_body">Para escanear o código QR, o Briar precisa de acesso à câmera.\n\nPara encontrar dispositivos Bluetooth, o Briar precisa de permissão para acessar a localização.\n\nBriar não armazena sua localização nem a compartilha com ninguém.</string>
|
||||
<string name="permission_camera_denied_body">Você negou acesso à câmera, mas para adicionar contatos você precisa da câmera.\n\nPor favor, pense em liberar o acesso a ela.</string>
|
||||
<string name="permission_location_denied_body">Você desabilitou o acesso à sua localização, no entanto o Briar precisa da permissão para saber se há dispositivos Bluetooth.\n\nPor favor, considere liberar o acesso.</string>
|
||||
<string name="permission_location_setting_title">Configuração de localização</string>
|
||||
@@ -691,13 +702,13 @@
|
||||
<string name="lock_unlock_verbose">Insira o PIN, padrão ou senha do seu dispositivo para desbloquear o Briar</string>
|
||||
<string name="lock_unlock_fingerprint_description">Encoste no leitor de impressão digital com o dedo cadastrado para continuar</string>
|
||||
<string name="lock_unlock_password">Usar senha</string>
|
||||
<string name="lock_is_locked">O Briar está bloqueado</string>
|
||||
<string name="lock_is_locked">Briar está bloqueado</string>
|
||||
<string name="lock_tap_to_unlock">Toque para desbloquear</string>
|
||||
<!--Connections Screen-->
|
||||
<string name="transports_help_text">Briar pode se conectar aos seus contatos via Internet, Wi-Fi ou Bluetooth.\n\nTodas as conexões com a Internet acontecem via rede do Tor, por privacidade.\n\nSe um contato pode ser alcançado de várias formas, Briar as utilizará em paralelo.</string>
|
||||
<string name="transports_help_text">Briar pode se conectar aos seus contatos via Internet, Wi-Fi ou Bluetooth.\n\nTodas as conexões com a Internet acontecem pela rede Tor, por privacidade.\n\nSe um contato pode ser alcançado de várias formas, o Briar as utilizará em paralelo.</string>
|
||||
<!--Share app offline-->
|
||||
<string name="hotspot_title">Compartilhar esse app offline</string>
|
||||
<string name="hotspot_intro">Compartilhe esse app com alguém próximo sem uma conexão à Internet usando o Wi-Fi do seu celular
|
||||
<string name="hotspot_intro">Compartilhe esse app com alguém próximo sem uma conexão à Internet usando o Wi-Fi do seu celular.
|
||||
\n\nSeu celular vai iniciar um hotspot Wi-Fi. Pessoas próximas podem se conectar ao hotspot e baixar o app Briar pelo seu celular.</string>
|
||||
<string name="hotspot_button_start_sharing">Iniciar hotspot</string>
|
||||
<string name="hotspot_button_stop_sharing">Parar hotspot</string>
|
||||
@@ -705,7 +716,7 @@
|
||||
<string name="hotspot_notification_channel_title">Hotspot Wi-Fi</string>
|
||||
<string name="hotspot_notification_title">Compartilhando Briar offline</string>
|
||||
<string name="hotspot_button_connected">Próximo</string>
|
||||
<string name="permission_hotspot_location_request_body">Para criar um hotspot Wi-Fi, o Briar precisa de permissão para acessar sua localização.\n\nO Briar não armazena sua localização nem a compartilha.</string>
|
||||
<string name="permission_hotspot_location_request_body">Para criar um hotspot Wi-Fi, o Briar precisa de permissão para acessar sua localização.\n\nBriar não armazena sua localização nem a compartilha com ninguém.</string>
|
||||
<string name="permission_hotspot_location_denied_body">Você negou acesso à sua localização, mas o Briar precisa dessa permissão para criar um hotspot Wi-Fi.\n\nPor favor, considere conceder acesso.</string>
|
||||
<string name="wifi_settings_title">Configurações de Wi-Fi</string>
|
||||
<string name="wifi_settings_request_enable_body">Para criar um hotspot Wi-Fi, o Briar precisa usar o Wi-Fi. Por favor, ative ele.</string>
|
||||
@@ -720,6 +731,7 @@
|
||||
<string name="hotspot_no_peers_connected">Sem dispositivos conectados</string>
|
||||
<plurals name="hotspot_peers_connected">
|
||||
<item quantity="one">%s dispositivo conectado</item>
|
||||
<item quantity="many">%s dispositivos conectados</item>
|
||||
<item quantity="other">%s dispositivos conectados</item>
|
||||
</plurals>
|
||||
<!--Download link-->
|
||||
@@ -728,22 +740,20 @@
|
||||
<string name="hotspot_manual_site_address">Endereço (URL)</string>
|
||||
<string name="hotspot_qr_site">Seu celular está fornecendo um hotspot Wi-Fi. Pessoas que estão conectadas ao hotspot podem baixar o Briar escaneando esse código QR. </string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">Baixar %s</string>
|
||||
<string name="website_download_intro">Alguém próximo compartilhou %s com você.</string>
|
||||
<string name="website_download_outro">Após baixar o arquivo, abra-o e instale-o.</string>
|
||||
<string name="website_troubleshooting_title">Solução de Problemas</string>
|
||||
<string name="website_troubleshooting_1">Se você não conseguir baixar o app, tente em um app de navegador de internet diferente.</string>
|
||||
<string name="website_troubleshooting_1">Se você não conseguir baixar o app, tente em outro app de navegador de internet.</string>
|
||||
<string name="website_troubleshooting_2_old">Para instalar o app baixado, você talvez precise permitir a instalação de apps de \"Fontes desconhecidas\" nas configurações do sistema. Após isso, você pode precisar baixar o app novamente. Recomendamos desativar a permissão de \"Fontes desconhecidas\" após instalar o app.</string>
|
||||
<string name="website_troubleshooting_2_new">Para instalar o app baixado, você talvez precise permitir que seu navegador instale apps desconhecidos. Após instalar o app, recomendamos remover a permissão do navegador de instalar apps desconhecidos.</string>
|
||||
<string name="hotspot_help_wifi_title">Problemas ao conectar ao Wi-Fi:</string>
|
||||
<string name="hotspot_help_wifi_1">Tente desativar e reativar o Wi-Fi nos dois celulares e tente de novo.</string>
|
||||
<string name="website_troubleshooting_2_new">Para instalar o app baixado, você talvez precise permitir que seu navegador instale apps desconhecidos. Após a instalação do app, recomendamos remover a permissão do navegador de instalar apps desconhecidos.</string>
|
||||
<string name="hotspot_help_wifi_title">Problemas em conectar ao Wi-Fi:</string>
|
||||
<string name="hotspot_help_wifi_1">Desative e reative o Wi-Fi nos dois celulares e tente de novo.</string>
|
||||
<string name="hotspot_help_wifi_2">Se seu celular reclama que o Wi-Fi não tem Internet, diga que você quer ficar conectado mesmo assim.</string>
|
||||
<string name="hotspot_help_wifi_3">Reinicie o celular que está rodando o hotspot Wi-Fi, depois abra o Briar e tente compartilhar de novo.</string>
|
||||
<string name="hotspot_help_site_title">Problemas visitando o website local:</string>
|
||||
<string name="hotspot_help_site_1">Verifique se você inseriu o endereço exatamente como mostrado. Um pequeno erro pode fazê-lo falhar.</string>
|
||||
<string name="hotspot_help_site_2">Garanta que seu celular ainda está conectado ao Wi-Fi correto (veja acima) quando você tentar acessar o site.</string>
|
||||
<string name="hotspot_help_site_3">Se você tem um app de firewall, verifique se ele não está bloqueando o acesso.</string>
|
||||
<string name="hotspot_help_site_4">Se você consegue visitar o site, mas não baixar o app Briar, tente em um app navegador de internet diferente.</string>
|
||||
<string name="hotspot_help_site_4">Se você consegue visitar o site, mas não baixar o app Briar, tente em outro app de navegador de internet.</string>
|
||||
<string name="hotspot_help_fallback_title">Nada funciona?</string>
|
||||
<string name="hotspot_help_fallback_intro">Você pode tentar salvar o app como um arquivo .apk para compartilhar de outra forma. Após o arquivo ser transferido para o outro dispositivo, ele pode ser usado para instalar o Briar.
|
||||
\n\nDica: Para transferir via Bluetooth, você talvez precise renomear o arquivo para finalizar com .zip primeiro.</string>
|
||||
@@ -757,11 +767,11 @@
|
||||
<string name="hotspot_error_web_server_start">Erro ao iniciar servidor web</string>
|
||||
<string name="hotspot_error_web_server_serve">Erro ao apresentar website.\n\nPor favor envie feedback (com dados anônimos) pelo app Briar se o problema persistir.</string>
|
||||
<string name="hotspot_flag_test">Aviso: Esse app foi instalado com Android Studio e NÃO pode ser instalado em outro dispositivo.</string>
|
||||
<string name="hotspot_error_framework_busy">Não pôde iniciar o hotspot.\n\nSe você tem outro hotspot rodando ou está compartilhando sua conexão à Internet por Wi-Fi, tente parar isso e tentar de novo em seguida.</string>
|
||||
<string name="hotspot_error_framework_busy">Não foi possível iniciar o hotspot.\n\nSe você tem outro hotspot rodando ou está compartilhando sua conexão à Internet por Wi-Fi, tente parar isso e tentar de novo em seguida.</string>
|
||||
<!--Transfer Data via Removable Drives-->
|
||||
<string name="removable_drive_menu_title">Conectar via Unidade Removível</string>
|
||||
<string name="removable_drive_intro">Se você não puder se conectar ao seu contato via Internet, Wi-Fi ou Bluetooth, o Briar tambem pode transferir mensagens em uma unidade removível como um pendrive USB ou cartão SD.</string>
|
||||
<string name="removable_drive_explanation">Se você não pode se conectar ao seu contato por Internet, Wi-Fi ou Bluetooth, o Briar tambem pode transferir mensagens em uma unidade removível como um pendrive USB ou um cartão SD.\n\nQuando você usar o botão \"Enviar Dados\", qualquer dado que esteja aguardando envio ao seu contato será gravado na unidade removível. Isso inclui mensagens privadas, anexos, blogs, fóruns e grupos privados.\n\nTudo será criptografado antes de ser gravado na unidade removível.\n\nQuando seu contato receber a unidade removível, poderá usar o botão \"Receber Dados\" para importar as mensagens ao Briar.</string>
|
||||
<string name="removable_drive_intro">Se você não pode se conectar ao seu contato via Internet, Wi-Fi ou Bluetooth, o Briar tambem pode transferir mensagens em uma unidade removível como um pendrive USB ou cartão SD.</string>
|
||||
<string name="removable_drive_explanation">Se você não pode se conectar ao seu contato via Internet, Wi-Fi ou Bluetooth, o Briar tambem pode transferir mensagens em uma unidade removível como um pendrive USB ou cartão SD.\n\nQuando você usar o botão \"Enviar Dados\", qualquer dado que esteja aguardando envio ao seu contato será gravado na unidade removível. Isso inclui mensagens privadas, anexos, blogs, fóruns e grupos privados.\n\nTudo será criptografado antes de ser gravado na unidade removível.\n\nQuando seu contato receber a unidade removível, poderá usar o botão \"Receber Dados\" para importar as mensagens ao Briar.</string>
|
||||
<string name="removable_drive_title_send">Enviar dados</string>
|
||||
<string name="removable_drive_title_receive">Receber dados</string>
|
||||
<string name="removable_drive_send_intro">Toque no botão abaixo para criar um novo arquivo contendo as mensagens criptografadas. Você pode escolher onde o arquivo será salvo.\n\nSe você quer salvar o arquivo numa unidade removível, insira a unidade agora.</string>
|
||||
|
||||
@@ -26,7 +26,10 @@
|
||||
<string name="dnkm_xiaomi_button">Protejează Briar</string>
|
||||
<string name="dnkm_xiaomi_help">Dacă Briar nu este blocat în lista de aplicații recente, acesta nu va putea rula în fundal.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Deschideți lista de aplicații recente (denumită și comutatorul de aplicații)\n\n2. Trageți cu degetul în jos pe imaginea lui Briar pentru a afișa pictograma lacătului\n\n3. Dacă lacătul nu este blocat, atingeți pentru a-l bloca</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Deschideți lista de aplicații recente (denumită și comutatorul de aplicatii)\n\n2. Țineți apăsată imaginea lui Briar până când apare butonul cu lacăt\n\n3. Dacă lacătul nu este blocat, apăsați pentru a-l bloca</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Deschideți lista de aplicații recente (denumită și comutatorul de aplicatii)\n\n2. Dacă Briar are o mică imagine cu un lacăt lângă nume atunci nu este nevoie să faceți nimic.\n\n3. Dacă lacătul lipsește atunci atingeți și țineți apăsat pe imaginea Briar până când lacătul apare, apoi atingeți-l.</string>
|
||||
<string name="dnkm_xiaomi_lock_apps_text">Vă rugăm să atingeți butonul de mai jos pentru a deschide setările de securitate. Atingeți \"\"Boost Speed\", apoi atingeți \"Aplicații blocate\" și asigurați-vă că Briar e setat ca \"Blocat\".</string>
|
||||
<string name="dnkm_xiaomi_lock_apps_help">Dacă Briar nu este setat ca \"Blocat\" în ecranul de \"Aplicații blocate\" atunci nu v-a putea să ruleze în fundal.</string>
|
||||
<string name="dnkm_warning_dozed_1">Briar nu a putut rula în fundal</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">Parola</string>
|
||||
<string name="try_again">Parolă greșită, reîncercați</string>
|
||||
@@ -239,8 +242,8 @@
|
||||
<string name="contact_added_toast">Contact adăugat: %s</string>
|
||||
<string name="contact_already_exists">Contactul %s există deja</string>
|
||||
<string name="qr_code_invalid">Codul QR este invalid!</string>
|
||||
<string name="qr_code_too_old">Codul QR pe care l-ați scanat aparține unei versiuni vechi %s.\n\nRugați-vă contactul să actualizeze aplicația la cea mai recentă versiune și apoi încercați din nou.</string>
|
||||
<string name="qr_code_too_new">Codul QR pe care l-ați scanat aparține unei versiuni mai noi %s.\n\nVă rugăm să actualizați aplicația la cea mai recentă versiune și apoi încercați din nou.</string>
|
||||
<string name="qr_code_too_old_1">Codul QR pe care l-ați scanat aparține unei versiuni vechi de Briar.\n\nRugați-vă contactul să actualizeze aplicația la cea mai recentă versiune și apoi încercați din nou.</string>
|
||||
<string name="qr_code_too_new_1">Codul QR pe care l-ați scanat aparține unei versiuni mai noi de Briar.\n\nVă rugăm să actualizați aplicația la cea mai recentă versiune și apoi încercați din nou.</string>
|
||||
<string name="camera_error">Eroare la camera foto</string>
|
||||
<string name="connecting_to_device">Conectare la dispozitiv\u2026</string>
|
||||
<string name="authenticating_with_device">Autentificare cu dispozitivul\u2026</string>
|
||||
@@ -616,6 +619,10 @@
|
||||
<string name="mailbox_status_connected_title">Cutia poștală este în funcțiune</string>
|
||||
<string name="mailbox_status_problem_title">Briar nu se poate conecta la Cutia poștală.</string>
|
||||
<string name="mailbox_status_failure_title">Cutia poștală este indisponibilă</string>
|
||||
<string name="mailbox_status_app_too_old_title">Briar este prea vechi</string>
|
||||
<string name="mailbox_status_app_too_old_message">Actualizați Briar la cea mai nouă versiune și reîncercați.</string>
|
||||
<string name="mailbox_status_mailbox_too_old_title">Cutia poștală este prea veche</string>
|
||||
<string name="mailbox_status_mailbox_too_old_message">Actualizați-vă Cutia poștală la cea mai nouă versiune și încercați din nou.</string>
|
||||
<string name="mailbox_status_check_button">Verificare conexiune</string>
|
||||
<!--Example for string substitution: Last connection: 3min ago-->
|
||||
<string name="mailbox_status_connected_info">Ultima conectare: %s</string>
|
||||
@@ -643,6 +650,14 @@
|
||||
<string name="mailbox_error_wizard_answer1_3">Văd \"Cutia poștală e pornită\"</string>
|
||||
<string name="mailbox_error_wizard_answer1_4">Văd \"Dispozitivul este deconectat\"</string>
|
||||
<string name="mailbox_error_wizard_info1_1_1">Vă rugăm să vă detașați de la Căsuța poștală folosind butonul de mai jos, apoi urmăriți instrucțiunile de pe dispozitivul Căsuță poștală pentru a o atașa din nou.</string>
|
||||
<string name="mailbox_error_wizard_info_1_1_2">Vă rugăm să detașați Cutia poștală folosind butonul de mai jos, apoi scanați codul QR pentru a o atașa din nou.</string>
|
||||
<string name="mailbox_error_wizard_info1_1_3">Vă rugăm să folosiți butonul de mai jos pentru a verifica conexiunea dintre Briar și Cutia poștală.\n\n
|
||||
Dacă eșuează din nou conexiunea :\n
|
||||
\u2022 Verificați dacă aplicațiile Cutie poștală și Briar sunt actualizate la cea mai recentă versiune.\n
|
||||
\u2022 Reporniți dispozitivele Cutie poștală și Briar și încercați din nou.</string>
|
||||
<string name="mailbox_error_wizard_info1_1_4">Verificați dacă dispozitivul de Cutie poștală este conectat corect la Internet.\n\nVerificați dacă ceasul de pe dispozitivul de Cutie poștală indică ora, data și fusul orar corect.\n\nVerificați dacă aplicațiile Cutie poștală și Briar sunt actualizate la cea mai recentă versiune.\n\nReporniți dispozitivele Cutie poștală și Briar și încercați din nou.</string>
|
||||
<string name="mailbox_error_wizard_info2">Vă rugăm să reveniți la acest ecran atunci când aveți acces la dispozitiv.</string>
|
||||
<string name="mailbox_error_wizard_info3">Vă rugăm să detașați Cutia poștală folosind butonul de mai jos\n\nDupă ce ați detașat vechea Cutie poștală puteți configura una nouă în orice moment.</string>
|
||||
<!--Conversation Settings-->
|
||||
<string name="disappearing_messages_title">Mesaje ce dispar</string>
|
||||
<string name="disappearing_messages_explanation_long">Activarea acestei setări va face ca noile
|
||||
@@ -759,8 +774,9 @@ De asemenea, contactul dvs. poate modifica această setare pentru amândoi.</str
|
||||
<string name="hotspot_manual_site_address">Adresă (URL)</string>
|
||||
<string name="hotspot_qr_site">Dispozitivul dumneavoastră oferă un hotspot Wi-Fi. Persoanele care sunt conectate la hotspot pot descărca Briar scanând acest cod QR.</string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">Descărcare %s</string>
|
||||
<string name="website_download_intro">Cineva din apropiere a partajat %scu dumneavoastră.</string>
|
||||
<string name="website_download_title_1">Descarcă Briar %s</string>
|
||||
<string name="website_download_intro_1">Cineva din apropiere a partajat Briar cu dumneavoastră.</string>
|
||||
<string name="website_download_button">Descarcă Briar</string>
|
||||
<string name="website_download_outro">După ce descărcarea a luat sfârșit, deschideți și instalați fișierul descărcat.</string>
|
||||
<string name="website_troubleshooting_title">Depanare</string>
|
||||
<string name="website_troubleshooting_1">Dacă nu puteți descărca aplicația încercați cu un alt browser.</string>
|
||||
|
||||
@@ -26,7 +26,10 @@
|
||||
<string name="dnkm_xiaomi_button">Защитить Briar</string>
|
||||
<string name="dnkm_xiaomi_help">Если Briar не закреплен в списке последних приложений, он не сможет работать в фоновом режиме.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Откройте список недавних приложений (также называемый переключателем приложений)\n\n2. Проведите пальцем вниз по изображению этого приложения, чтобы появился значок замка\n\n3. Если замок не заблокирован, коснитесь его, чтобы заблокировать.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Откройте список недавних приложений (также называемый переключателем приложений)\n\n2. Нажмите и удерживайте изображение этого приложения, пока не появится кнопка с замком\n\n3. Если замок не заблокирован, коснитесь его, чтобы заблокировать.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Откройте список недавних приложений (также именуемый переключателем приложений)\n\n2. Если рядом с названием Briar есть маленький значок замка, то ничего делать не нужно\n\n\n3. Если замка нет, нажмите и удерживайте изображение Briar, пока не появится кнопка замка, затем нажмите на нее.</string>
|
||||
<string name="dnkm_xiaomi_lock_apps_text">Нажмите кнопку ниже, чтобы открыть настройки безопасности. Нажмите \"Повышение производительности\", затем нажмите \"Блокировка приложений\" и убедитесь, что для Briar установлено значение \"Заблокировано\".</string>
|
||||
<string name="dnkm_xiaomi_lock_apps_help">Если для Briar не установлено значение \"Заблокировано\" на экране \"Блокировка приложений\", то оно не сможет работать в фоновом режиме.</string>
|
||||
<string name="dnkm_warning_dozed_1">Briar не может работать в фоновом режиме</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">Пароль</string>
|
||||
<string name="try_again">Неверный пароль, повторите попытку</string>
|
||||
@@ -248,8 +251,8 @@
|
||||
<string name="contact_added_toast">Контакт добавлен: %s</string>
|
||||
<string name="contact_already_exists">Контакт %s уже существует</string>
|
||||
<string name="qr_code_invalid">Неверный QR-код</string>
|
||||
<string name="qr_code_too_old">QR-код, который вы сосканировали, сгенерирован в старой версии %s.\n\nПопросите вашего собеседника обновиться до последней версии и повторите попытку.</string>
|
||||
<string name="qr_code_too_new">QR-код, который вы сосканировали, сгенерирован в новой версии %s.\n\nОбновите приложение до последней версии и повторите попытку.</string>
|
||||
<string name="qr_code_too_old_1">QR-код, который вы сосканировали, сгенерирован в старой версии Briar.\n\nПопросите вашего собеседника обновиться до последней версии и повторите попытку.</string>
|
||||
<string name="qr_code_too_new_1">QR-код, который вы сосканировали, сгенерирован в новой версии Briar.\n\nОбновите приложение до последней версии и повторите попытку.</string>
|
||||
<string name="camera_error">Ошибка камеры</string>
|
||||
<string name="connecting_to_device">Подключение к устройству\u2026</string>
|
||||
<string name="authenticating_with_device">Аутентификация с устройством\u2026</string>
|
||||
@@ -630,6 +633,10 @@
|
||||
<string name="mailbox_status_connected_title">Mailbox запущен</string>
|
||||
<string name="mailbox_status_problem_title">Briar испытывает проблемы с подключением к Mailbox</string>
|
||||
<string name="mailbox_status_failure_title">Mailbox недоступен</string>
|
||||
<string name="mailbox_status_app_too_old_title">Briar устарел</string>
|
||||
<string name="mailbox_status_app_too_old_message">Обновите Briar до последней версии и повторите попытку.</string>
|
||||
<string name="mailbox_status_mailbox_too_old_title">Mailbox устарел</string>
|
||||
<string name="mailbox_status_mailbox_too_old_message">Обновите Mailbox до последней версии и повторите попытку.</string>
|
||||
<string name="mailbox_status_check_button">Проверьте подключение</string>
|
||||
<!--Example for string substitution: Last connection: 3min ago-->
|
||||
<string name="mailbox_status_connected_info">Последнее подключение: %s</string>
|
||||
@@ -641,6 +648,9 @@
|
||||
<string name="mailbox_status_unlink_dialog_warning">Если вы отвяжете свой Mailbox, вы не сможете получать сообщения, пока Briar находится в оффлайн.</string>
|
||||
<string name="mailbox_status_unlink_no_wipe_title">Ваш Mailbox был отвязан</string>
|
||||
<string name="mailbox_status_unlink_no_wipe_message">В следующий раз, когда у вас будет доступ к устройству Mailbox, откройте приложение Mailbox и нажмите кнопку \"Unlink\", чтобы завершить процесс.\n\nЕсли у вас больше нет доступа к устройству Mailbox, не волнуйтесь. Ваши данные зашифрованы, поэтому они останутся в безопасности, даже если вы не завершите процесс.</string>
|
||||
<string name="mailbox_error_notification_channel_title">Проблема с Briar Mailbox</string>
|
||||
<string name="mailbox_error_notification_title">Briar Mailbox недоступен</string>
|
||||
<string name="mailbox_error_notification_text">Нажмите, чтобы устранить проблему.</string>
|
||||
<string name="mailbox_error_wizard_button">Исправить проблему</string>
|
||||
<string name="mailbox_error_wizard_title">Мастер устранения неисправностей Mailbox</string>
|
||||
<string name="mailbox_error_wizard_question1">Есть ли у вас доступ к устройству Mailbox?</string>
|
||||
@@ -779,8 +789,9 @@
|
||||
<string name="hotspot_manual_site_address">Адрес (URL)</string>
|
||||
<string name="hotspot_qr_site">Ваш телефон работает в режиме точки доступа Wi-Fi. Пользователи, подключенные к ней, могут загрузить Briar, просканировав этот QR-код.</string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">Скачать %s</string>
|
||||
<string name="website_download_intro">Кто-то рядом поделился %s с вами.</string>
|
||||
<string name="website_download_title_1">Загрузить Briar %s</string>
|
||||
<string name="website_download_intro_1">Кто-то рядом поделился Briar с вами.</string>
|
||||
<string name="website_download_button">Загрузить Briar</string>
|
||||
<string name="website_download_outro">После завершения загрузки откройте загруженный файл и установите его.</string>
|
||||
<string name="website_troubleshooting_title">Устранение неполадок</string>
|
||||
<string name="website_troubleshooting_1">Если вы не можете загрузить приложение, попробуйте сделать это с помощью другого веб-браузера.</string>
|
||||
|
||||
@@ -1,38 +1,35 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources>
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Mirë se vini në Briar</string>
|
||||
<string name="setup_name_explanation">Nofka juaj do të shfaqet në krah të çfarëdo gjëje që postoni. S\’mund ta ndryshoni më, pas krijimit të llogarisë tuaj.</string>
|
||||
<string name="setup_next">Pasuesi</string>
|
||||
<string name="setup_password_intro">Zgjidhni një Fjalëkalim</string>
|
||||
<string name="setup_password_explanation">Llogaria juaj Briar depozitohet e fshehtëzuar në pajisjen tuaj, jo në re. Nëse harroni fjalëkalimin tuaj apo e çinstaloni Briar-in, nuk ka ndonjë mënyrë për të ringjallur llogarinë tuaj.\n\nZgjidhni një fjalëkalim të gjatë, që është i vështirë për t\’u marrë me mend, f.v., katër fjalë kuturu, ose dhjetë shkronja, numra dhe shenja kuturu.</string>
|
||||
<string name="dnkm_doze_title">Lidhje Në Prapaskenë</string>
|
||||
<string name="dnkm_doze_intro">Për të marrë mesazhe, Briar-i lypset të qëndrojë i lidhur në prapaskenë.</string>
|
||||
<string name="dnkm_doze_explanation">Për të marrë mesazhe, Briar-i lypset të mbetet i lidhur në prapaskenë. Ju lutemi, çaktivizoni optimizime baterie, që kështu Briar-i të mund të qëndrojë i lidhur.</string>
|
||||
<string name="dnkm_doze_button">Lejo Lidhje</string>
|
||||
<string name="choose_nickname">Zgjidhni nofkën tuaj</string>
|
||||
<string name="choose_password">Zgjidhni fjalëkalimin tuaj</string>
|
||||
<string name="confirm_password">Ripohoni fjalëkalimin tuaj</string>
|
||||
<string name="name_too_long">Emri është shumë i gjatë</string>
|
||||
<string name="password_too_weak">Fjalëkalimi është shumë i dobët</string>
|
||||
<string name="passwords_do_not_match">Fjalëkalimet nuk përputhen</string>
|
||||
<string name="create_account_button">Krijoje Llogarinë</string>
|
||||
<string name="more_info">Më Tepër të Dhëna</string>
|
||||
<string name="don_t_ask_again">Mos pyet sërish</string>
|
||||
<string name="dnkm_huawei_protected_text">Ju lutemi, prekni butoni më poshtë dhe sigurohuni që Briar-i të jetë i mbrojtur, te skena \"Aplikacione të Mbrojtur\".</string>
|
||||
<string name="dnkm_huawei_protected_button">Mbroje Briar-in</string>
|
||||
<string name="dnkm_huawei_protected_help">Nëse Briar-i s\’është shtuar te lista e aplikacioneve të mbrojtur, s\’do të jetë në gjendje të xhirojë në prapaskenë.</string>
|
||||
<string name="dnkm_huawei_app_launch_text">Ju lutemi, prekni butonin më poshtë, hapni skenën “Nisje aplikacioni” dhe sigurohuni se për Briar-in është zgjedhur “Administrojeni dorazi”.</string>
|
||||
<string name="dnkm_huawei_app_launch_button">Hapni Rregullime Baterie</string>
|
||||
<string name="dnkm_huawei_app_launch_help">Nëse për Briar-in s’është zgjedhur “Administroje Dorazi” te skena “Nisje Aplikacioni”, s’do të jetë në gjendje të xhirojë në prapaskenë.</string>
|
||||
<string name="dnkm_huawei_app_launch_error_toast">S’u hapën dot rregullimet e baterisë</string>
|
||||
<string name="dnkm_xiaomi_text">Për të xhiruar në prapaskenë, Briar-i lyp të jetë i kyçur te lista e aplikacioneve të përdorur së fundi.</string>
|
||||
<string name="dnkm_xiaomi_button">Mbroje Briar-in</string>
|
||||
<string name="dnkm_xiaomi_help">Nëse Briar-i s’është i kyçur te lista e aplikacioneve të përdorur së fundi, s’do të jetë në gjendje të xhirojë në prapaskenë.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Hapni listën e aplikacioneve përdorur së fundi (e quajtur edhe këmbyes aplikacionesh)\n\n2. Fërkojeni për poshtë te figura për Briar-in, që të shfaqet ikona e drynit\n\n3. Nëse dryni s’është o kyçur, prekeni që të kyçet</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Hapni listën e aplikacioneve përdorur së fundi (e quajtur edhe
|
||||
këmbyes aplikacionesh)\n\n2. Shtypni dhe mbajeni të shtypur figurën e Briar-it, deri sa të shfaqet butoni i drynit\n\n3. Nëse dryni s’është o kyçur, prekeni që të kyçet</string>
|
||||
<string name="dnkm_warning_dozed">%s s\’qe në gjendje të xhirojë në prapaskenë</string>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Mirë se vini në Briar</string>
|
||||
<string name="setup_name_explanation">Nofka juaj do të shfaqet në krah të çfarëdo gjëje që postoni. S\’mund ta ndryshoni më, pas krijimit të llogarisë tuaj.</string>
|
||||
<string name="setup_next">Pasuesi</string>
|
||||
<string name="setup_password_intro">Zgjidhni një Fjalëkalim</string>
|
||||
<string name="setup_password_explanation">Llogaria juaj Briar depozitohet e fshehtëzuar në pajisjen tuaj, jo në re. Nëse harroni fjalëkalimin tuaj apo e çinstaloni Briar-in, nuk ka ndonjë mënyrë për të ringjallur llogarinë tuaj.\n\nZgjidhni një fjalëkalim të gjatë, që është i vështirë për t\’u marrë me mend, f.v., katër fjalë kuturu, ose dhjetë shkronja, numra dhe shenja kuturu.</string>
|
||||
<string name="dnkm_doze_intro">Për të marrë mesazhe, Briar-i lypset të qëndrojë i lidhur në prapaskenë.</string>
|
||||
<string name="dnkm_doze_explanation">Për të marrë mesazhe, Briar-i lypset të mbetet i lidhur në prapaskenë. Ju lutemi, çaktivizoni optimizime baterie, që kështu Briar-i të mund të qëndrojë i lidhur.</string>
|
||||
<string name="choose_nickname">Zgjidhni nofkën tuaj</string>
|
||||
<string name="choose_password">Zgjidhni fjalëkalimin tuaj</string>
|
||||
<string name="confirm_password">Ripohoni fjalëkalimin tuaj</string>
|
||||
<string name="name_too_long">Emri është shumë i gjatë</string>
|
||||
<string name="password_too_weak">Fjalëkalimi është shumë i dobët</string>
|
||||
<string name="passwords_do_not_match">Fjalëkalimet nuk përputhen</string>
|
||||
<string name="create_account_button">Krijoje Llogarinë</string>
|
||||
<string name="more_info">Më Tepër të Dhëna</string>
|
||||
<string name="don_t_ask_again">Mos pyet sërish</string>
|
||||
<string name="dnkm_huawei_protected_text">Ju lutemi, prekni butoni më poshtë dhe sigurohuni që Briar-i të jetë i mbrojtur, te skena \"Aplikacione të Mbrojtur\".</string>
|
||||
<string name="dnkm_huawei_protected_button">Mbroje Briar-in</string>
|
||||
<string name="dnkm_huawei_protected_help">Nëse Briar-i s\’është shtuar te lista e aplikacioneve të mbrojtur, s\’do të jetë në gjendje të xhirojë në prapaskenë.</string>
|
||||
<string name="dnkm_huawei_app_launch_text">Ju lutemi, prekni butonin më poshtë, hapni skenën “Nisje aplikacioni” dhe sigurohuni se për Briar-in është zgjedhur “Administrojeni dorazi”.</string>
|
||||
<string name="dnkm_huawei_app_launch_help">Nëse për Briar-in s’është zgjedhur “Administroje Dorazi” te skena “Nisje Aplikacioni”, s’do të jetë në gjendje të xhirojë në prapaskenë.</string>
|
||||
<string name="dnkm_xiaomi_text">Për të xhiruar në prapaskenë, Briar-i lyp të jetë i kyçur te lista e aplikacioneve të përdorur së fundi.</string>
|
||||
<string name="dnkm_xiaomi_button">Mbroje Briar-in</string>
|
||||
<string name="dnkm_xiaomi_help">Nëse Briar-i s’është i kyçur te lista e aplikacioneve të përdorur së fundi, s’do të jetë në gjendje të xhirojë në prapaskenë.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Hapni listën e aplikacioneve përdorur së fundi (e quajtur edhe këmbyes aplikacionesh)\n\n2. Fërkojeni për poshtë te figura për Briar-in, që të shfaqet ikona e drynit\n\n3. Nëse dryni s’është o kyçur, prekeni që të kyçet</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Hapni listën e aplikacioneve të përdorur së fundi (e quajtur edhe këmbyes aplikacionesh)\n\n2. Nëse Briar-i ka një figurë dry të vogël në krah të emrit të vet, s’keni nevojë të bëni gjë\n\n3. Nëse s’ka dry, shtypni dhe mbajeni të shtypur mbi figurën e Briar-it derisa të shfaqet butoni dry, mandej prekeni</string>
|
||||
<string name="dnkm_xiaomi_lock_apps_text">Ju lutemi, prekni butonin më poshtë që të hapen rregullimet e sigurisë. Prekni “Përforcim shpejtësie”, mandej prekni “Kyçje aplikacionesh” dhe sigurohuni se për Briar-in është zgjedhur “I kyçur”.</string>
|
||||
<string name="dnkm_xiaomi_lock_apps_help">Nëse për Briar-in s’është zgjedhur “I kyçur” te skena “Kyçje aplikacionesh”, s’do të jetë në gjendje të xhirojë në prapaskenë.</string>
|
||||
<string name="dnkm_warning_dozed_1">Briar-i s’qe në gjendje të xhirojë në prapaskenë</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">Fjalëkalim</string>
|
||||
<string name="try_again">Fjalëkalim i gabuar, riprovoni</string>
|
||||
@@ -48,7 +45,7 @@ këmbyes aplikacionesh)\n\n2. Shtypni dhe mbajeni të shtypur figurën e Briar-i
|
||||
<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.\n\nDuhet ose të riinstaloni versionin e vjetër, ose të ujdisni llogari të re duke zgjedhur “Kam harruar fjalëkalimin tim”, kur ju kërkohet fjalëkalimi.</string>
|
||||
<string name="startup_failed_data_too_new_error">Llogaria juaj qe krijuar me një version më të ri të këtij aplikacioni
|
||||
dhe s’mund të hapet me këtë version.\n\nJu lutemi, përmirësojeni me versionin më të ri dhe riprovoni.</string>
|
||||
<string name="startup_failed_service_error">Briar-i nuk arriti të nisë një përbërës të domosdoshëm.\n\nJu lutemi, përmirësojeni me versionin më të ri të aplikacionit dhe riprovoni. </string>
|
||||
<string name="startup_failed_service_error">Briar-i nuk arriti të nisë një përbërës të domosdoshëm.\n\nJu lutemi, përmirësojeni me versionin më të ri të aplikacionit dhe riprovoni.</string>
|
||||
<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="other">Ky është një version beta i Briar-it. Llogaria juaj do të skadojë për %d ditë dhe s\’mund të rinovohet.</item>
|
||||
@@ -157,7 +154,7 @@ dhe s’mund të hapet me këtë version.\n\nJu lutemi, përmirësojeni me versi
|
||||
<string name="help">Ndihmë</string>
|
||||
<string name="sorry">Na ndjeni</string>
|
||||
<string name="error_start_activity">Jo i passhëm në sistemin tuaj</string>
|
||||
<string name="status_heading">Gjëndja</string>
|
||||
<string name="status_heading">Gjendje:</string>
|
||||
<string name="error">Gabim</string>
|
||||
<!--Contacts and Private Conversations-->
|
||||
<string name="no_contacts">S’ka kontakte për shfaqje</string>
|
||||
@@ -228,7 +225,7 @@ dhe s’mund të hapet me këtë version.\n\nJu lutemi, përmirësojeni me versi
|
||||
<string name="messaging_too_many_attachments_toast">Do të dërgohen vetëm %d figurat e para</string>
|
||||
<string name="menu_contact">Kontakt</string>
|
||||
<!--Adding Contacts-->
|
||||
<string name="add_contact_title">Shtoni Kontakt Atypari </string>
|
||||
<string name="add_contact_title">Shtoni Kontakt Atypari</string>
|
||||
<string name="face_to_face">Duhet të takoheni me personin që doni ta shtoni si kontakt.\n\nKjo do të pengojë cilindo të hiqet si ju ose të lexojë në të ardhmen mesazhet tuaj.</string>
|
||||
<string name="continue_button">Vazhdo</string>
|
||||
<string name="try_again_button">Riprovoni</string>
|
||||
@@ -237,8 +234,8 @@ dhe s’mund të hapet me këtë version.\n\nJu lutemi, përmirësojeni me versi
|
||||
<string name="contact_added_toast">Kontakti u shtua: %s</string>
|
||||
<string name="contact_already_exists">Kontakti %s ekziston tashmë</string>
|
||||
<string name="qr_code_invalid">Kodi QR është i pavlefshëm</string>
|
||||
<string name="qr_code_too_old">Kodi QR që keni skanuar vjen prej një versioni të vjetër të %s-it.\n\nJu lutemi, kërkojini kontaktit tuaj ta përmirësojë me versionin më të ri dhe mandej riprovoni.</string>
|
||||
<string name="qr_code_too_new">Kodi QR që keni skanuar vjen prej një versioni më të ri të %s-it.\n\nJu lutemi, përmirësojeni me versionin më të ri dhe mandej riprovoni.</string>
|
||||
<string name="qr_code_too_old_1">Kodi QR që keni skanuar vjen prej një versioni të vjetër të Briar-it.\n\nJu lutemi, kërkojini kontaktit tuaj ta përmirësojë me versionin më të ri dhe mandej riprovoni.</string>
|
||||
<string name="qr_code_too_new_1">Kodi QR që keni skanuar vjen prej një versioni më të ri të Briar-it.\n\nJu lutemi, përmirësojeni me versionin më të ri dhe mandej riprovoni.</string>
|
||||
<string name="camera_error">Gabim kamere</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>
|
||||
@@ -246,7 +243,7 @@ dhe s’mund të hapet me këtë version.\n\nJu lutemi, përmirësojeni me versi
|
||||
<string name="connection_error_feedback">Nëse problemi vazhdon, ju lutemi, <a href="feedback">na njoftoni</a>, që të mund të përmirësojmë aplikacionin.</string>
|
||||
<!--Adding Contacts Remotely-->
|
||||
<string name="add_contact_remotely_title_case">Shtoni Kontakt në Largësi</string>
|
||||
<string name="add_contact_nearby_title">Shtoni kontakt atypari </string>
|
||||
<string name="add_contact_nearby_title">Shtoni kontakt atypari</string>
|
||||
<string name="add_contact_remotely_title">Shtoni kontakt në largësi</string>
|
||||
<string name="contact_link_intro">Jepni këtu lidhjen prej kontaktit tuaj</string>
|
||||
<string name="contact_link_hint">Lidhje e kontaktit</string>
|
||||
@@ -260,13 +257,13 @@ dhe s’mund të hapet me këtë version.\n\nJu lutemi, përmirësojeni me versi
|
||||
<string name="nickname_intro">Jepini kontaktit tuaj një nofkë. Vetëm ju mund ta shihni.</string>
|
||||
<string name="your_link">Jepjani këtë lidhje kontaktit që doni të shtoni</string>
|
||||
<string name="link_clip_label">Lidhje Briar</string>
|
||||
<string name="link_copied_toast">Lidhja i kopjua</string>
|
||||
<string name="link_copied_toast">Lidhja u kopjua</string>
|
||||
<string name="adding_contact_error">Pati një gabim në shtimin e kontaktit.</string>
|
||||
<string name="pending_contact_requests_snackbar">Ka kërkesa kontakti pezull</string>
|
||||
<string name="pending_contact_requests">Kërkesa Kontakti Pezull</string>
|
||||
<string name="no_pending_contacts">S\’ka kontakte pezull</string>
|
||||
<string name="waiting_for_contact_to_come_online">Po pritet që kontakti të jetë në linjë…</string>
|
||||
<string name="connecting">Duke u kyqur...</string>
|
||||
<string name="connecting">Po lidhet…</string>
|
||||
<string name="adding_contact">Po shtohet kontakti…</string>
|
||||
<string name="adding_contact_failed">Shtimi i kontaktit dështoi</string>
|
||||
<string name="dialog_title_remove_pending_contact">Ripohoni Heqjen</string>
|
||||
@@ -303,7 +300,7 @@ dhe s’mund të hapet me këtë version.\n\nJu lutemi, përmirësojeni me versi
|
||||
<string name="pending_contact_updated_toast">Kontakti pezull u përditësua</string>
|
||||
<!--Introductions-->
|
||||
<string name="introduction_onboarding_title">Prezantoni kontaktet tuaja</string>
|
||||
<string name="introduction_onboarding_text">Kontaktet tuaja mund t\’ia prezantoni njëri-tjetrit, që kështu të mos u duhet të takohen realisht për të mundur të lidhen në Briar.</string>
|
||||
<string name="introduction_onboarding_text">Prezantoni kontaktet tuaj me njëri-tjetrin, që të mund të lidhen me Briar.</string>
|
||||
<string name="introduction_menu_item">Bëje prezantimin</string>
|
||||
<string name="introduction_activity_title">Përzgjidhni Kontakt</string>
|
||||
<string name="introduction_not_possible">Keni filluar tashmë një prezantim me këto kontakte. Ju lutemi, lëreni të përfundojë së pari. Nëse ju ose kontaktet tuaja rrallë gjenden <em>online</em>, kjo mund të dojë ca kohë.</string>
|
||||
@@ -607,10 +604,47 @@ dhe s’mund të hapet me këtë version.\n\nJu lutemi, përmirësojeni me versi
|
||||
<string name="tor_offline_button_check">Kontrolloni rregullime lidhjeje</string>
|
||||
<string name="mailbox_status_title">Gjendje kutie postare</string>
|
||||
<string name="mailbox_status_connected_title">Kutia postare po punon</string>
|
||||
<string name="mailbox_status_problem_title">Briar-i po ka probleme në lidhjen me Kutinë postare</string>
|
||||
<string name="mailbox_status_failure_title">S’ka Kuti postare</string>
|
||||
<string name="mailbox_status_app_too_old_title">Briar-i është shumë i vjetër</string>
|
||||
<string name="mailbox_status_app_too_old_message">Përditësojeni Briar-in me versionin më të ri të aplikacionit dhe riprovoni.</string>
|
||||
<string name="mailbox_status_mailbox_too_old_title">Kutia postare është shumë e vjetër</string>
|
||||
<string name="mailbox_status_mailbox_too_old_message">Përditësoni Kutinë tuaj postare me versionin më të ri të aplikacionit dhe riprovoni.</string>
|
||||
<string name="mailbox_status_check_button">Kontrolloni Lidhjen</string>
|
||||
<!--Example for string substitution: Last connection: 3min ago-->
|
||||
<string name="mailbox_status_connected_info">Lidhja e fundit: %s</string>
|
||||
<!--Indicates that there never was a connection to the mailbox. Last connection: Never-->
|
||||
<string name="mailbox_status_connected_never">Kurrë</string>
|
||||
<string name="mailbox_status_unlink_button">Shkëpute</string>
|
||||
<string name="mailbox_status_unlink_dialog_title">Të hiqet lidhja për kutinë postare?</string>
|
||||
<string name="mailbox_status_unlink_dialog_question">Jeni i sigurt se doni të hiqet lidhja për Kutinë tuaj postare?</string>
|
||||
<string name="mailbox_status_unlink_dialog_warning">Nëse hiqni lidhjen e Kutisë tuaj postare, s’do të jeni në gjendje të merrni mesazhe, ndërkohë që Briar-i është i palidhur në internet.</string>
|
||||
<string name="mailbox_status_unlink_no_wipe_title">U hoq lidhja e Kutisë tuaj postare</string>
|
||||
<string name="mailbox_status_unlink_no_wipe_message">Herës tjetër që mundeni të hyni te pajisja e Kutisë tuaj postare, ju lutemi, hapni aplikacionin “Kuti postare” dhe prekni butonin “Hiqi lidhjen”, që të plotësohet procesi.\n\nNëse pajisjen e Kutisë tuaj postare s’e përdorni dot më, mos u shqetësoni. Të dhënat tuaja janë të fshehtëzuara, ndaj do të mbeten të sigurta, edhe nëse nuk e plotësoni procesin.</string>
|
||||
<string name="mailbox_error_notification_channel_title">Problem me Kuti postare Briar-i</string>
|
||||
<string name="mailbox_error_notification_title">Kutia postare Briar s’është e passhme</string>
|
||||
<string name="mailbox_error_notification_text">Prekeni që të ndreqet problemi.</string>
|
||||
<string name="mailbox_error_wizard_button">Ndreqe problemin</string>
|
||||
<string name="mailbox_error_wizard_title">Ndihmës diagnostikimi Kutie postare</string>
|
||||
<string name="mailbox_error_wizard_question1">A mund të përdorni pajisjen tuaj Kuti postare?</string>
|
||||
<string name="mailbox_error_wizard_answer1">Po, mund ta përdor atë tani.</string>
|
||||
<string name="mailbox_error_wizard_answer2">Jo tani, por mund të marr leje ta përdor më vonë.</string>
|
||||
<string name="mailbox_error_wizard_answer3">Jo, s’e përdor dot më.</string>
|
||||
<string name="mailbox_error_wizard_info1_1">Shihni që pajisja Kuti postare të jetë në punë dhe e lidhur në Internet.</string>
|
||||
<string name="mailbox_error_wizard_question1_1">Hapni aplikacionin Kuti postare. Çfarë shihni?</string>
|
||||
<string name="mailbox_error_wizard_answer1_1">Shoh udhëzime për ujdisje të Kutisë postare</string>
|
||||
<string name="mailbox_error_wizard_answer1_2">Shoh një kod QR</string>
|
||||
<string name="mailbox_error_wizard_answer1_3">Shoh “Kutia postare po punon”</string>
|
||||
<string name="mailbox_error_wizard_answer1_4">Shoh “Pajisje jo në linjë”</string>
|
||||
<string name="mailbox_error_wizard_info1_1_1">Ju lutemi, shkëputeni Kutinë tuaj postare duke përdorur butonin më poshtë, mandej ndiqni udhëzimet te pajisja Kuti postare për ta rilidhur.</string>
|
||||
<string name="mailbox_error_wizard_info_1_1_2">Ju lutemi, shkëputeni Kutinë tuaj postare duke përdorur butonin më poshtë, mandej skanoni kodin QR për ta rilidhur.</string>
|
||||
<string name="mailbox_error_wizard_info1_1_3">Ju lutemi, përdorni butonin më poshtë për të kontrolluar lidhjen mes Briar-it dhe Mailbox-it.\n\n
|
||||
Nëse lidhja dështon sërish:\n
|
||||
\u2022 Shihni që aplikacionet Kuti postare dhe Briar të jenë ët përditësuar me versionin më të ri.\n
|
||||
\u2022 Rinisni pajisjet tuaja Kuti postare dhe Briar dhe riprovoni.</string>
|
||||
<string name="mailbox_error_wizard_info1_1_4">Shihni që pajisja kuti postare të jetë lidhur si duhet në Internet.\n\nKontrolloni që sahati te pajisja Kuti postare shfaq kohën, datën dhe zonën kohore të saktë.\n\nShihni që aplikacionet Kuti postare dhe Briar të jenë të përditësuar me versionin më të ri.\n\nRinisni pajisjet tuaja Kuti postare dhe Briar dhe riprovoni.</string>
|
||||
<string name="mailbox_error_wizard_info2">Ju lutemi, rikthejuni kësaj skene kur të keni mundësi të përdorni pajisjen.</string>
|
||||
<string name="mailbox_error_wizard_info3">Ju lutemi, shkëputeni kutinë tuaj postare duke përdorur butonin më poshtë.\n\nPasi të shkëputni Kutinë tuaj të vjetër postare, mund të ujdisni kurdo një Kuti të re postare.</string>
|
||||
<!--Conversation Settings-->
|
||||
<string name="disappearing_messages_title">Mesazhe që treten</string>
|
||||
<string name="disappearing_messages_explanation_long">Aktivizimi i këtij rregullimi do të bëjë që
|
||||
@@ -728,8 +762,9 @@ Briar-i i përdor ato paralelisht.</string>
|
||||
<string name="hotspot_manual_site_address">Adresë (URL)</string>
|
||||
<string name="hotspot_qr_site">Telefoni juaj po ofron një hotspot Wi-Fi. Persona që janë të lidhur me hotspot-in mund të shkarkojnë Briar-in duke skanuar këtë kod QR.</string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">Shkarkoni %s</string>
|
||||
<string name="website_download_intro">Dikush atypari ndau %s me ju.</string>
|
||||
<string name="website_download_title_1">Shkarkoni Briar %s</string>
|
||||
<string name="website_download_intro_1">Dikush atyparu ju dha Briar-in</string>
|
||||
<string name="website_download_button">Shkarkojeni Briar-in</string>
|
||||
<string name="website_download_outro">Pasi të jetë plotësuar shkarkimi, hapni kartelën e shkarkuar dhe instalojeni.</string>
|
||||
<string name="website_troubleshooting_title">Diagnostikim</string>
|
||||
<string name="website_troubleshooting_1">Nëse s’mund të shkarkoni aplikacionin, provoni me një aplikacion tjetër shfletuesi.</string>
|
||||
|
||||
@@ -1,36 +1,31 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources>
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Välkommen till Briar</string>
|
||||
<string name="setup_name_explanation">Ditt användarnamn kommer att visas bredvid allt innehåll som du lägger upp. Du kan inte ändra ditt användarnamn efter att ditt konto skapats.</string>
|
||||
<string name="setup_next">Nästa</string>
|
||||
<string name="setup_password_intro">Skapa lösenord</string>
|
||||
<string name="setup_password_explanation">Ditt Briar-konto lagras krypterat på din mobil eller läsplatta, inte hos en molntjänst. Om du glömmer ditt lösenord eller avinstallerar Briar är det därför inte möjligt att återställa ditt konto.\n\nSkapa ett långt lösenord som är svårgissat, till exempel fyra slumpvalda ord eller en kombination av tio slumpvalda bokstäver, siffror och andra tecken.</string>
|
||||
<string name="dnkm_doze_title">Dataanslutningar i bakgrunden</string>
|
||||
<string name="dnkm_doze_intro">För att kunna ta emot meddelanden måste Briar vara anslutet i bakgrunden.</string>
|
||||
<string name="dnkm_doze_explanation">För att kunna ta emot meddelanden måste Briar vara anslutet i bakgrunden. Avaktivera batterioptimering så att Briar kan hålla sig anslutet.</string>
|
||||
<string name="dnkm_doze_button">Tillåt dataanslutningar</string>
|
||||
<string name="choose_nickname">Skapa användarnamn </string>
|
||||
<string name="choose_password">Skapa lösenord</string>
|
||||
<string name="confirm_password">Bekräfta lösenordet</string>
|
||||
<string name="name_too_long">Namnet har för många tecken </string>
|
||||
<string name="password_too_weak">Lösenordet är för svagt</string>
|
||||
<string name="passwords_do_not_match">Lösenorden överensstämmer inte </string>
|
||||
<string name="create_account_button">Skapa konto </string>
|
||||
<string name="more_info">Mer information</string>
|
||||
<string name="don_t_ask_again">Fråga inte igen</string>
|
||||
<string name="dnkm_huawei_protected_text">Tryck på knappen längre ner för att lägga till Briar till listan över \"skyddade appar\".</string>
|
||||
<string name="dnkm_huawei_protected_button">Skydda Briar</string>
|
||||
<string name="dnkm_huawei_protected_help">Om Briar inte läggs till listan över skyddade appar kan det inte köras i bakgrunden.</string>
|
||||
<string name="dnkm_huawei_app_launch_text">Klicka på knappen nedan, öppna skärmen ”App-start” och säkerställ att Briar är inställt på ”Hantera manuellt”</string>
|
||||
<string name="dnkm_huawei_app_launch_button">Öppna batteriinställningar</string>
|
||||
<string name="dnkm_huawei_app_launch_help">Om Briar inte är inställt på ”Hantera manuellt” i skärmen ”App-start” kommer den inte att kunna köra i bakgrunden.</string>
|
||||
<string name="dnkm_xiaomi_text">För att köra i bakgrunden måste Briar låsas in i listan över senaste appar.</string>
|
||||
<string name="dnkm_xiaomi_button">Skydda Briar</string>
|
||||
<string name="dnkm_xiaomi_help">Om Briar inte låsas in i listan över senaste appar kommer det inte att kunna köra i bakgrunden.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Öppna listan över senaste appar (också kallade appväxlaren)\n\n2. Svep nedåt vid bilden av Briar för att visa hänglåsikonen\n\n3. Om hänglåsikonen inte är låst, klicka för att låsa den</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Öppna listan över senaste appar (också kallade appväxlaren)\n\n2. Tryck och håll på bilden av Briar tills hänglåsikonen dyker upp\n\n3. Om hänglåsikonen inte är låst, klicka för att låsa den</string>
|
||||
<string name="dnkm_warning_dozed">%s kunde inte köras i bakgrunden</string>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Välkommen till Briar</string>
|
||||
<string name="setup_name_explanation">Ditt användarnamn kommer att visas bredvid allt innehåll som du lägger upp. Du kan inte ändra ditt användarnamn efter att ditt konto skapats.</string>
|
||||
<string name="setup_next">Nästa</string>
|
||||
<string name="setup_password_intro">Skapa lösenord</string>
|
||||
<string name="setup_password_explanation">Ditt Briar-konto lagras krypterat på din mobil eller läsplatta, inte hos en molntjänst. Om du glömmer ditt lösenord eller avinstallerar Briar är det därför inte möjligt att återställa ditt konto.\n\nSkapa ett långt lösenord som är svårgissat, till exempel fyra slumpvalda ord eller en kombination av tio slumpvalda bokstäver, siffror och andra tecken.</string>
|
||||
<string name="dnkm_doze_intro">För att kunna ta emot meddelanden måste Briar vara anslutet i bakgrunden.</string>
|
||||
<string name="dnkm_doze_explanation">För att kunna ta emot meddelanden måste Briar vara anslutet i bakgrunden. Avaktivera batterioptimering så att Briar kan hålla sig anslutet.</string>
|
||||
<string name="choose_nickname">Välj ditt användarnamn</string>
|
||||
<string name="choose_password">Skapa lösenord</string>
|
||||
<string name="confirm_password">Bekräfta lösenordet</string>
|
||||
<string name="name_too_long">Namnet har för många tecken </string>
|
||||
<string name="password_too_weak">Lösenordet är för svagt</string>
|
||||
<string name="passwords_do_not_match">Lösenorden överensstämmer inte </string>
|
||||
<string name="create_account_button">Skapa konto </string>
|
||||
<string name="more_info">Mer information</string>
|
||||
<string name="don_t_ask_again">Fråga inte igen</string>
|
||||
<string name="dnkm_huawei_protected_text">Tryck på knappen längre ner för att lägga till Briar till listan över \"skyddade appar\".</string>
|
||||
<string name="dnkm_huawei_protected_button">Skydda Briar</string>
|
||||
<string name="dnkm_huawei_protected_help">Om Briar inte läggs till listan över skyddade appar kan det inte köras i bakgrunden.</string>
|
||||
<string name="dnkm_huawei_app_launch_text">Klicka på knappen nedan, öppna skärmen ”App-start” och säkerställ att Briar är inställt på ”Hantera manuellt”</string>
|
||||
<string name="dnkm_huawei_app_launch_help">Om Briar inte är inställt på ”Hantera manuellt” i skärmen ”App-start” kommer den inte att kunna köra i bakgrunden.</string>
|
||||
<string name="dnkm_xiaomi_text">För att köra i bakgrunden måste Briar låsas in i listan över senaste appar.</string>
|
||||
<string name="dnkm_xiaomi_button">Skydda Briar</string>
|
||||
<string name="dnkm_xiaomi_help">Om Briar inte låsas in i listan över senaste appar kommer det inte att kunna köra i bakgrunden.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Öppna listan över senaste appar (också kallade appväxlaren)\n\n2. Svep nedåt vid bilden av Briar för att visa hänglåsikonen\n\n3. Om hänglåsikonen inte är låst, klicka för att låsa den</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">Lösenord</string>
|
||||
<string name="try_again">Felaktigt lösenord, försök igen </string>
|
||||
@@ -56,7 +51,7 @@
|
||||
</plurals>
|
||||
<string name="expiry_date_reached">Mjukvaran har gått ut.\nTack för att du bidragit till att testa!</string>
|
||||
<string name="download_briar">För att fortsätta använda Briar, hämta den senaste utgåvan.</string>
|
||||
<string name="create_new_account">Du måste skapa ett nytt konto, men du kan använda samma smeknamn.</string>
|
||||
<string name="create_new_account">Du måste skapa ett nytt konto, men du kan använda samma användarnamn.</string>
|
||||
<string name="download_briar_button">Hämta senaste utgåvan</string>
|
||||
<string name="old_android_expiry_date_reached">Briar kan inte längre användas på Android 4.
|
||||
Vänlige installera Briar på en nyare enhet.</string>
|
||||
@@ -235,8 +230,6 @@ Vänlige installera Briar på en nyare enhet.</string>
|
||||
<string name="contact_added_toast">Kontakt tillagd: %s</string>
|
||||
<string name="contact_already_exists">Kontakten %s finns redan</string>
|
||||
<string name="qr_code_invalid">QR-koden är felaktig</string>
|
||||
<string name="qr_code_too_old">QR-koden som du har skannat kommer från en äldre version av %s.\n\nBe din kontakt att uppgradera till den senaste versionen och försök sedan igen.</string>
|
||||
<string name="qr_code_too_new">QR-koden som du har skannat kommer från en äldre version av %s.\n\nUppgradera till senaste versionen och försök sedan igen.</string>
|
||||
<string name="camera_error">Kamerafel</string>
|
||||
<string name="connecting_to_device">Ansluter till enhet\u2026</string>
|
||||
<string name="authenticating_with_device">Autentiserar med enhet\u2026</string>
|
||||
@@ -253,9 +246,9 @@ Vänlige installera Briar på en nyare enhet.</string>
|
||||
<string name="copy_button">Kopiera</string>
|
||||
<string name="share_button">Dela</string>
|
||||
<string name="send_link_title">Utbyt länkar</string>
|
||||
<string name="add_contact_choose_nickname">Välj smeknamn</string>
|
||||
<string name="add_contact_choose_a_nickname">Skriv ett smeknamn</string>
|
||||
<string name="nickname_intro">Ge din kontakt ett smeknamn. Bara du kan se detta.</string>
|
||||
<string name="add_contact_choose_nickname">Välj användarnamn</string>
|
||||
<string name="add_contact_choose_a_nickname">Skriv ett användarnamn</string>
|
||||
<string name="nickname_intro">Ge din kontakt ett användarnamn. Bara du kan se detta.</string>
|
||||
<string name="your_link">Ge den här länken till kontakten du vill lägga till</string>
|
||||
<string name="link_clip_label">Briar-länk</string>
|
||||
<string name="link_copied_toast">Länken kopierades</string>
|
||||
@@ -270,7 +263,7 @@ Vänlige installera Briar på en nyare enhet.</string>
|
||||
<string name="dialog_title_remove_pending_contact">Bekräfta borttagning</string>
|
||||
<string name="dialog_message_remove_pending_contact">Denna kontakt håller på att läggas till. Om du tar bort den nu kommer den ej läggas till.</string>
|
||||
<string name="own_link_error">Skriv in länken du fick från din kontakt, inte din egna länk</string>
|
||||
<string name="nickname_missing">Skriv in ett smeknamn</string>
|
||||
<string name="nickname_missing">Skriv in ett användarnamn</string>
|
||||
<string name="invalid_link">Felakting länk</string>
|
||||
<string name="unsupported_link">Denna länk kommer från en nyare version av Briar. Var snäll och uppgradera till den senaste versionen och försök igen.</string>
|
||||
<string name="intent_own_link">Du har öppnat din egna länk. Använd länken du fick från kontakten du vill lägga till!</string>
|
||||
@@ -301,7 +294,7 @@ Vänlige installera Briar på en nyare enhet.</string>
|
||||
<string name="pending_contact_updated_toast">Väntande kontakt har uppdaterats</string>
|
||||
<!--Introductions-->
|
||||
<string name="introduction_onboarding_title">Presentera dina kontakter</string>
|
||||
<string name="introduction_onboarding_text">Du kan presentera dina kontakter för varandra, på så sätt behöver de inte träffas personligen för att lägga till varandra på Briar.</string>
|
||||
<string name="introduction_onboarding_text">Introducera dina kontakter för varandra så att de kan ansluta sig till varandra via Briar.</string>
|
||||
<string name="introduction_menu_item">Presentera kontakt</string>
|
||||
<string name="introduction_activity_title">Välj kontakt</string>
|
||||
<string name="introduction_not_possible">Du har redan påbörjat en presentation mellan dessa kontakter. Vänligen vänta tills detta är klart. Om du eller dina kontakter är online sällan så kan det ta ett tag.</string>
|
||||
@@ -577,8 +570,42 @@ Vänlige installera Briar på en nyare enhet.</string>
|
||||
<string name="choose_ringtone_title">Välj ringsignal</string>
|
||||
<string name="cannot_load_ringtone">Kan ej ladda ringsignal</string>
|
||||
<!--Mailbox-->
|
||||
<string name="mailbox_settings_title">Mailbox</string>
|
||||
<string name="mailbox_setup_title">Mailbox-inställning</string>
|
||||
<string name="mailbox_setup_intro">En Mailbox låter dina kontakter skicka dig meddelanden medan du är nedkopplad. Mailbox kommer att ta emot dina meddelanden och spara dem tills du är uppkopplad.\n
|
||||
\nDu kan installera appen Briar Mailbox på en extraenhet. Låt den vara ansluten till ström och Wi-Fi så att den alltid är uppkopplad.</string>
|
||||
<string name="mailbox_setup_download">Installera först Mailbox-appen på en annan enhet genom att söka efter ”Briar Mailbox” på Google Play eller där du hämtat Briar.\n
|
||||
\nLänka sedan din Mailbox med Briar genom att skanna QR-koden som visas i Mailbox-appen.</string>
|
||||
<string name="mailbox_setup_download_link">Dela hämtningslänk</string>
|
||||
<string name="mailbox_setup_button_scan">Skanna Mailbox QR-kod</string>
|
||||
<string name="permission_camera_qr_denied_body">Du har nekat åtkomst till kameran, men att skanna en QR-kod kräver användning av kameran.\n\nÖverväg att bevilja tillstånd.</string>
|
||||
<string name="mailbox_setup_connecting">Ansluter...</string>
|
||||
<string name="mailbox_setup_qr_code_wrong_title">Felaktig QR-kod</string>
|
||||
<string name="mailbox_setup_qr_code_wrong_description">Den skannade koden är ogiltig. Öppna Briar Mailbox-appen på din Mailbox-enhet och skanna QR-koden som visas.</string>
|
||||
<string name="mailbox_setup_already_paired_title">Mailbox redan länkad</string>
|
||||
<string name="mailbox_setup_already_paired_description">Avlänka Mailbox på din andra enhet och försök igen.</string>
|
||||
<string name="mailbox_setup_io_error_title">Kunde inte ansluta</string>
|
||||
<string name="mailbox_setup_io_error_description">Säkerställ att båda enheterna är anslutna till internet och försök igen.</string>
|
||||
<string name="mailbox_setup_assertion_error_title">Mailbox-fel</string>
|
||||
<string name="mailbox_setup_assertion_error_description">Skicka återkoppling (med anonymiserad data) via Briar-appen om felet kvarstår.</string>
|
||||
<string name="mailbox_setup_camera_error_description">Kunde inte komma åt kamera. Försök igen, eventuellt efter att ha startat om enheten.</string>
|
||||
<string name="mailbox_setup_paired_title">Ansluten</string>
|
||||
<string name="mailbox_setup_paired_description">Din Mailbox har framgångsrikt länkats med Briar.\n
|
||||
\nHåll din Mailbox ansluten till ström och Wi-Fi så att den alltid är uppkopplad.</string>
|
||||
<string name="tor_offline_title">Nedkopplad</string>
|
||||
<string name="tor_offline_description">Säkerställ att denna enhet är uppkopplad och att anslutningar till internet är tillåtna.\n
|
||||
\nEfteråt, vänta på att ikonen med en glob bland på skärmen för anslutningsinställningar blir grön.</string>
|
||||
<string name="tor_offline_button_check">Kontrollera anslutningsinställningar</string>
|
||||
<string name="mailbox_status_title">Mailbox-status</string>
|
||||
<string name="mailbox_status_connected_title">Mailbox kör</string>
|
||||
<string name="mailbox_status_problem_title">Briar har problem med att ansluta till Mailbox</string>
|
||||
<string name="mailbox_status_failure_title">Mailbox är ogilltänglig</string>
|
||||
<string name="mailbox_status_check_button">Kontrollera anslutning</string>
|
||||
<!--Example for string substitution: Last connection: 3min ago-->
|
||||
<string name="mailbox_status_connected_info">Senaste anslutning: %s</string>
|
||||
<!--Indicates that there never was a connection to the mailbox. Last connection: Never-->
|
||||
<string name="mailbox_status_connected_never">Aldrig</string>
|
||||
<string name="mailbox_status_unlink_button">Avlänka</string>
|
||||
<!--Conversation Settings-->
|
||||
<string name="disappearing_messages_title">Försvinnande meddelanden</string>
|
||||
<string name="disappearing_messages_explanation_long">Att slå på denna inställning kommer att få nya
|
||||
@@ -662,14 +689,14 @@ Vänlige installera Briar på en nyare enhet.</string>
|
||||
<!--Connections Screen-->
|
||||
<string name="transports_help_text">Briar kan ansluta till dina kontakter via internet, Wi-Fi eller Bluetooth.\n\nAlla internetanslutningar går via Tor-nätverket av integritetsskäl.\n\nOm en kontakt kan nås via flera metoder kommer Briar att använda dem parallellt.</string>
|
||||
<!--Share app offline-->
|
||||
<string name="hotspot_title">Dela denna app off-line</string>
|
||||
<string name="hotspot_title">Dela denna app nedkopplat</string>
|
||||
<string name="hotspot_intro">Dela denna app med någon i närheten utan en internetanslutning via din telefons Wi-Fi.
|
||||
\n\nDin telefon kommer att starta en Wi-Fi-hostpot. Personer i närheten kan ansluta till hotspoten och hämta Briar-appen från din telefon.</string>
|
||||
\n\nDin telefon kommer att starta en Wi-Fi-hotspot. Personer i närheten kan ansluta till hotspoten och hämta Briar-appen från din telefon.</string>
|
||||
<string name="hotspot_button_start_sharing">Starta hotspot</string>
|
||||
<string name="hotspot_button_stop_sharing">Stoppa hotspot</string>
|
||||
<string name="hotspot_progress_text_start">Ställer in hotspot…</string>
|
||||
<string name="hotspot_notification_channel_title">Wi-Fi-hotspot</string>
|
||||
<string name="hotspot_notification_title">Dela Briar off-line</string>
|
||||
<string name="hotspot_notification_title">Delar Briar nedkopplat</string>
|
||||
<string name="hotspot_button_connected">Nästa</string>
|
||||
<string name="permission_hotspot_location_request_body">För att skapa en Wi-Fi-hotspot måste Briar ha tillåtelse att komma åt din plats.\n\nBriar sparar inte din plats eller delar den med någon.</string>
|
||||
<string name="permission_hotspot_location_denied_body">Du har nekat åtkomst till din plats, men Briar behöver denna tilltåelse för att skapa en Wi-Fi-hotspot.\n\nÖverväg att bevilja åtkomst.</string>
|
||||
@@ -694,8 +721,6 @@ Vänlige installera Briar på en nyare enhet.</string>
|
||||
<string name="hotspot_manual_site_address">Adress (URL)</string>
|
||||
<string name="hotspot_qr_site">Din telfon tillhandahåller en Wi-Fi-hotspot. Personer som är anslutna till hotstpoen kan hämta Briar genom att skanna denna QR-kod.</string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">Hämta %s</string>
|
||||
<string name="website_download_intro">Någon i närheten delade %s med dig.</string>
|
||||
<string name="website_download_outro">Efter att hämtningen är slutför öppna den hämtade filen och installera den.</string>
|
||||
<string name="website_troubleshooting_title">Felsökning</string>
|
||||
<string name="website_troubleshooting_1">Om du inte kan hämta appen, prova med en annan webbläsarapp.</string>
|
||||
|
||||
@@ -1,36 +1,31 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources>
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Briar\'a Hoşgeldiniz</string>
|
||||
<string name="setup_name_explanation">Takma adınız, gönderdiğiniz herhangi bir içeriğin yanında gösterilecek. Hesabınızı oluşturduktan sonra onu değiştiremezsiniz.</string>
|
||||
<string name="setup_next">Sonraki</string>
|
||||
<string name="setup_password_intro">Bir Parola Seçin</string>
|
||||
<string name="setup_password_explanation">Briar hesabınız bulutta değil aygıtınızda şifreli olarak saklanır. Parolanızı unutursanız veya Briar\'ı kaldırırsanız hesabınızı kurtarmanın bir yolu yoktur. Tahmin edilmesi zor rastgele dört sözcük, on harf, sayı ve simgeden oluşan uzun bir parola \n\n\Seçin</string>
|
||||
<string name="dnkm_doze_title">Arka plan Bağlantıları</string>
|
||||
<string name="dnkm_doze_intro">İletileri almak için Briar\'ın arkaplanda bağlı kalması gerekir.</string>
|
||||
<string name="dnkm_doze_explanation">İletileri almak için Briar\'ın arkaplanda bağlı olması gerekir. Briar\'ın bağlı kalabilmesi için lütfen pil eniyilemesini devre dışı bırakın.</string>
|
||||
<string name="dnkm_doze_button">Bağlantılara İzin Ver</string>
|
||||
<string name="choose_nickname">Kullanıcı adınızı belirleyin</string>
|
||||
<string name="choose_password">Parolanızı belirleyin</string>
|
||||
<string name="confirm_password">Parolanızı doğrulayın</string>
|
||||
<string name="name_too_long">İsim çok uzun</string>
|
||||
<string name="password_too_weak">Parola çok zayıf</string>
|
||||
<string name="passwords_do_not_match">Parolalar uyuşmuyor</string>
|
||||
<string name="create_account_button">Hesap Oluştur</string>
|
||||
<string name="more_info">Daha Fazla Bilgi</string>
|
||||
<string name="don_t_ask_again">Tekrar sorma</string>
|
||||
<string name="dnkm_huawei_protected_text">Lütfen aşağıdaki düğmeye dokunun ve Briar\'ın \"Korunan Uygulamalar\" ekranında korunduğundan emin olun.</string>
|
||||
<string name="dnkm_huawei_protected_button">Briar\'ı Koru</string>
|
||||
<string name="dnkm_huawei_protected_help">Briar korunan uygulamalar listesine eklenmezse, arka planda çalışamaz.</string>
|
||||
<string name="dnkm_huawei_app_launch_text">Lütfen aşağıdaki düğmeye dokunun, \"Uygulama başlatma\" ekranını açın ve Briar için \"Manuel olarak yönet\" şeklinde ayarlanmış olduğundan emin olun.</string>
|
||||
<string name="dnkm_huawei_app_launch_button">Pil Ayarlarını Aç</string>
|
||||
<string name="dnkm_huawei_app_launch_help">Eğer Briar, \"Uygulama Başlatma\" ekranında \"Manuel olarak yönet\" olarak ayarlanmamışsa, arka planda çalışmayabilir.</string>
|
||||
<string name="dnkm_xiaomi_text">Briar\'ın arka planda çalışması için korunan uygulamalar listesine listesine eklenmesi gerekiyor.</string>
|
||||
<string name="dnkm_xiaomi_button">Briar\'ı Koru</string>
|
||||
<string name="dnkm_xiaomi_help">Briar korunan uygulamalar listesine eklenmezse, arka planda çalışamaz.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Geçmiş uygulamalar listesini açın (uygulama değiştirici de deniyor)\n\n2. Briar resmini kilit simgesini görene kadar aşağı kaydırın\n\n3. Eğer kilit simgesi seçili değilse, kilitlemek için dokunun</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Geçmiş uygulamalar listesini açın (uygulama değiştirici de deniyor)\n\n2. Kilit simgesini görene kadar Briar resmine tıklayın ve tutun\n\n3. Eğer kilit simgesi seçili değilse, kilitlemek için dokunun</string>
|
||||
<string name="dnkm_warning_dozed">%s arka planda çalışamadı</string>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!--Setup-->
|
||||
<string name="setup_title">Briar\'a Hoşgeldiniz</string>
|
||||
<string name="setup_name_explanation">Takma adınız, gönderdiğiniz herhangi bir içeriğin yanında gösterilecek. Hesabınızı oluşturduktan sonra onu değiştiremezsiniz.</string>
|
||||
<string name="setup_next">Sonraki</string>
|
||||
<string name="setup_password_intro">Bir Parola Seçin</string>
|
||||
<string name="setup_password_explanation">Briar hesabınız bulutta değil aygıtınızda şifreli olarak saklanır. Parolanızı unutursanız veya Briar\'ı kaldırırsanız hesabınızı kurtarmanın bir yolu yoktur. Tahmin edilmesi zor rastgele dört sözcük, on harf, sayı ve simgeden oluşan uzun bir parola \n\n\Seçin</string>
|
||||
<string name="dnkm_doze_intro">İletileri almak için Briar\'ın arkaplanda bağlı kalması gerekir.</string>
|
||||
<string name="dnkm_doze_explanation">İletileri almak için Briar\'ın arkaplanda bağlı olması gerekir. Briar\'ın bağlı kalabilmesi için lütfen pil eniyilemesini devre dışı bırakın.</string>
|
||||
<string name="choose_nickname">Kullanıcı adınızı belirleyin</string>
|
||||
<string name="choose_password">Parolanızı belirleyin</string>
|
||||
<string name="confirm_password">Parolanızı doğrulayın</string>
|
||||
<string name="name_too_long">İsim çok uzun</string>
|
||||
<string name="password_too_weak">Parola çok zayıf</string>
|
||||
<string name="passwords_do_not_match">Parolalar uyuşmuyor</string>
|
||||
<string name="create_account_button">Hesap Oluştur</string>
|
||||
<string name="more_info">Daha Fazla Bilgi</string>
|
||||
<string name="don_t_ask_again">Tekrar sorma</string>
|
||||
<string name="dnkm_huawei_protected_text">Lütfen aşağıdaki düğmeye dokunun ve Briar\'ın \"Korunan Uygulamalar\" ekranında korunduğundan emin olun.</string>
|
||||
<string name="dnkm_huawei_protected_button">Briar\'ı Koru</string>
|
||||
<string name="dnkm_huawei_protected_help">Briar korunan uygulamalar listesine eklenmezse, arka planda çalışamaz.</string>
|
||||
<string name="dnkm_huawei_app_launch_text">Lütfen aşağıdaki düğmeye dokunun, \"Uygulama başlatma\" ekranını açın ve Briar için \"Manuel olarak yönet\" şeklinde ayarlanmış olduğundan emin olun.</string>
|
||||
<string name="dnkm_huawei_app_launch_help">Eğer Briar, \"Uygulama Başlatma\" ekranında \"Manuel olarak yönet\" olarak ayarlanmamışsa, arka planda çalışmayabilir.</string>
|
||||
<string name="dnkm_xiaomi_text">Briar\'ın arka planda çalışması için korunan uygulamalar listesine listesine eklenmesi gerekiyor.</string>
|
||||
<string name="dnkm_xiaomi_button">Briar\'ı Koru</string>
|
||||
<string name="dnkm_xiaomi_help">Briar korunan uygulamalar listesine eklenmezse, arka planda çalışamaz.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Geçmiş uygulamalar listesini açın (uygulama değiştirici de deniyor)\n\n2. Briar resmini kilit simgesini görene kadar aşağı kaydırın\n\n3. Eğer kilit simgesi seçili değilse, kilitlemek için dokunun</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">Parola</string>
|
||||
<string name="try_again">Parola yanlış, tekrar deneyin</string>
|
||||
@@ -50,10 +45,16 @@
|
||||
<item quantity="one">Bu Briar\'ın deneme sürümüdür. Hesabınız %d gün içinde sona erecek ve yenilenemez.</item>
|
||||
<item quantity="other">Bu Briar\'ın deneme sürümüdür. Hesabınız %d gün içinde geçersiz olacak ve yenilenmeyecektir.</item>
|
||||
</plurals>
|
||||
<plurals name="old_android_expiry_warning">
|
||||
<item quantity="one">Android 4 artık desteklenmiyor. Briar %s tarihinde (%d gün sonra) çalışmayı durduracaktır. Lütfen Briar\'ı daha yeni bir aygıta yükleyin ve yeni bir hesap oluşturun.</item>
|
||||
<item quantity="other">Android 4 artık desteklenmiyor. Briar %s tarihinde (%d gün sonra) çalışmayı durduracaktır. Lütfen Briar\'ı daha yeni bir aygıta yükleyin ve yeni bir hesap oluşturun.</item>
|
||||
</plurals>
|
||||
<string name="expiry_date_reached">Bu yazılımın süresi doldu.\nDenediğiniz için teşekkürler!</string>
|
||||
<string name="download_briar">Briar\'ı kullanmaya devam etmek için lütfen en son sürümü indirin.</string>
|
||||
<string name="create_new_account">Yeni bir hesap oluşturmanız gerekecek, fakat aynı takma adı kullanabilirsiniz.</string>
|
||||
<string name="download_briar_button">En Son Sürümü İndir</string>
|
||||
<string name="old_android_expiry_date_reached">Briar artık Android 4 üzerinde çalışmıyor.\nLütfen Briar\'ı daha yeni bir aygıta kurun.</string>
|
||||
<string name="old_android_delete_account">Bu aygıttan hesabınızı silmek için aşağıdaki düğmeye dokunabilirsiniz.</string>
|
||||
<string name="delete_account_button">Hesabı Sil</string>
|
||||
<string name="startup_open_database">Veritabanı Şifresi Çözülüyor...</string>
|
||||
<string name="startup_migrate_database">Veritabanı Yükseltiliyor...</string>
|
||||
@@ -228,8 +229,6 @@
|
||||
<string name="contact_added_toast">Kişi eklendi: %s</string>
|
||||
<string name="contact_already_exists"> %s kişisi zaten var</string>
|
||||
<string name="qr_code_invalid">QR kodu hatalı</string>
|
||||
<string name="qr_code_too_old">Taradığınız QR kodu eski bir%s sürümünden geliyor. Lütfen kişinize en son sürüme yükseltmesini ve tekrar denemesini söyleyin.</string>
|
||||
<string name="qr_code_too_new">Taradığınız QR kodu daha yeni bir %s sürümünden geliyor. Lütfen en son sürüme yükseltin ve yeniden deneyin.</string>
|
||||
<string name="camera_error">Kamera hatası</string>
|
||||
<string name="connecting_to_device">Aygıta bağlanıyor\u2026</string>
|
||||
<string name="authenticating_with_device">Aygıtla kimlik doğrulama\u2026</string>
|
||||
@@ -294,7 +293,7 @@
|
||||
<string name="pending_contact_updated_toast">Bekleyen kişi güncellendi</string>
|
||||
<!--Introductions-->
|
||||
<string name="introduction_onboarding_title">Kişilerinizi tanıştırın</string>
|
||||
<string name="introduction_onboarding_text">Kişilerinizi birbirlerine tanıtabilirsiniz, bu nedenle Briar\'a bağlanmak için şahsen bir araya gelmeniz gerekmez.</string>
|
||||
<string name="introduction_onboarding_text">Kişilerinizi birbirlerine tanıtın, böylece Briar üzerinden bağlantı kurabilirler.</string>
|
||||
<string name="introduction_menu_item">Tanıştır</string>
|
||||
<string name="introduction_activity_title">Kişi seç</string>
|
||||
<string name="introduction_not_possible">Bu kişilerle hala devam eden tanıştırma süreciniz var. Lütfen bu sürecin tamamlanmasını bekleyin. Eğer kişileriniz nadiren çevrimiçi oluyorsa, bu biraz zaman alabilir. </string>
|
||||
@@ -570,8 +569,47 @@
|
||||
<string name="choose_ringtone_title">Zil sesi seçin</string>
|
||||
<string name="cannot_load_ringtone">Zil sesi yüklenemiyor</string>
|
||||
<!--Mailbox-->
|
||||
<string name="mailbox_settings_title">Mailbox</string>
|
||||
<string name="mailbox_setup_title">Mailbox kurulumu</string>
|
||||
<string name="mailbox_setup_intro">Mailbox siz çevrimdışıyken kişilerinizin size ileti göndermesini sağlar. Posta Kutusu iletilerinizi alır ve siz çevrimiçi olana kadar saklar.\n
|
||||
\n*Briar Posta Kutusu uygulamasını yedek bir aygıta kurabilirsiniz. Aygıtı enerjiye ve Wi-Fi\'ya bağlı tutun ki sürekli çevrimiçi olsun.</string>
|
||||
<string name="mailbox_setup_download">İlk olarak, Mailbox uygulamasını bir başka aygıtta Google Play veya Briar\'ı nereden indirdiyseniz orada \"Briar Mailbox\" aratarak kurun.\n
|
||||
\nDaha sonra Mailbox\'u Briar ile Mailbox uygulamasında görüntülenen karekodu tarayarak bağlantılandırın.</string>
|
||||
<string name="mailbox_setup_download_link">İndirme Bağlantısını Paylaş</string>
|
||||
<string name="mailbox_setup_button_scan">Mailbox Karekodunu Tara</string>
|
||||
<string name="permission_camera_qr_denied_body">Kameraya erişimi engellediniz, ancak Mailbox karekodunu taramak için kamerayı kullanmanız gerekiyor.\n\nLütfen erişim izni vermeyi düşünün.</string>
|
||||
<string name="mailbox_setup_connecting">Bağlantı kuruluyor…</string>
|
||||
<string name="mailbox_setup_qr_code_wrong_title">Yanlış Karekod</string>
|
||||
<string name="mailbox_setup_qr_code_wrong_description">Taranan kod geçersiz. Lütfen Briar Mailbox uygulamasını Mailbox aygıtınızda açın ve gösterdiği Karekodu tarayın.</string>
|
||||
<string name="mailbox_setup_already_paired_title">Mailbox zaten bağlanmış</string>
|
||||
<string name="mailbox_setup_already_paired_description">Diğer aygıttan Mailbox bağlantısını kaldırın ve tekrar deneyin</string>
|
||||
<string name="mailbox_setup_io_error_title">Bağlantı kurulamıyor</string>
|
||||
<string name="mailbox_setup_io_error_description">Her iki aygıtında İnternete bağlı olduğundan emin olun ve tekrar deneyin.</string>
|
||||
<string name="mailbox_setup_assertion_error_title">Mailbox hatası</string>
|
||||
<string name="mailbox_setup_assertion_error_description">Eğer sorun devam ederse lütfen Briar uygulaması aracılığıyla (anonim veri kullanarak) geri bildirim gönderin.</string>
|
||||
<string name="mailbox_setup_camera_error_description">Kameraya erişilemiyor. Aygıtı yeniden başlatarak tekrar deneyin.</string>
|
||||
<string name="mailbox_setup_paired_title">Bağlantı kuruldu</string>
|
||||
<string name="mailbox_setup_paired_description">Mailbox\'unuz Briar ile başarılı bir şekilde bağlandı.\n
|
||||
Mailbox\'unuzu enerjiye ve Wi-Fi\'ye bağlı tutun, böylece sürekli çevrimiçi kalır.</string>
|
||||
<string name="tor_offline_title">Çevrimdışı</string>
|
||||
<string name="tor_offline_description">Aygıtın çevrimiçi olduğundan ve İnternet bağlantılarına izin verildiğinden emin olun.\n
|
||||
\nDaha sonra bağlantı ayarları ekranındaki yerküre simgesinin yeşil olmasını bekleyin..</string>
|
||||
<string name="tor_offline_button_check">Bağlantı ayarlarını denetle</string>
|
||||
<string name="mailbox_status_title">Mailbox durumu</string>
|
||||
<string name="mailbox_status_connected_title">Mailbox çalışıyor</string>
|
||||
<string name="mailbox_status_problem_title">Briar Mailbox\'a bağlantı kurmakta zorluk yaşıyor.</string>
|
||||
<string name="mailbox_status_failure_title">Mailbox kullanılamıyor</string>
|
||||
<string name="mailbox_status_check_button">Bağlantıyı denetle</string>
|
||||
<!--Example for string substitution: Last connection: 3min ago-->
|
||||
<string name="mailbox_status_connected_info">Son bağlantı: %s</string>
|
||||
<!--Indicates that there never was a connection to the mailbox. Last connection: Never-->
|
||||
<string name="mailbox_status_connected_never">Hiç bir zaman</string>
|
||||
<string name="mailbox_status_unlink_button">Bağlantıyı kaldır</string>
|
||||
<string name="mailbox_status_unlink_dialog_title">Mailbox bağlantısını kaldır?</string>
|
||||
<string name="mailbox_status_unlink_dialog_question">Mailbox bağlantısını kaldırmak istediğinizden emin misiniz?</string>
|
||||
<string name="mailbox_status_unlink_dialog_warning">Mailbox bağlantısını kaldırırsanız, Briar çevrimdışı iken ileti alamayacaksınız.</string>
|
||||
<string name="mailbox_status_unlink_no_wipe_title">Mailbox bağlantısı kaldırıldı.</string>
|
||||
<string name="mailbox_status_unlink_no_wipe_message">Mailbox aygıtınıza sonraki erişiminizde lütfen Mailbox uygulamasını açın ve \"Bağlantıyı Kaldır\" düğmesine dokunarak işlemi tamamlayın.\n\nEğer Mailbox aygıtınıza artık erişiminiz yoksa endişelenmeyin. Veriniz şifrelenmiştir ve bu süreci tamamlamasanız bile güvenli kalacaktır.</string>
|
||||
<!--Conversation Settings-->
|
||||
<string name="disappearing_messages_title">Kaybolan iletiler</string>
|
||||
<string name="disappearing_messages_explanation_long">Bu ayarı etkinleştirmeniz durumunda
|
||||
@@ -687,8 +725,6 @@
|
||||
<string name="hotspot_manual_site_address">Adres (URL)</string>
|
||||
<string name="hotspot_qr_site">Telefonunuz bir kablosuz erişim noktası sunuyor. Erişim noktasına bağlı kişiler Briar\'ı QR kodunu tarayarak indirebilirler. </string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">%s İndir</string>
|
||||
<string name="website_download_intro">Yakınınızda olan biri sizinle %s paylaştı</string>
|
||||
<string name="website_download_outro">İndirme tamamlandıktan sonra, indirdiğiniz dosyayı açın ve kurun.</string>
|
||||
<string name="website_troubleshooting_title">Sorun çözme</string>
|
||||
<string name="website_troubleshooting_1">Uygulamayı indiremiyorsanız, başka bir tarayıcı uygulamasıyla deneyin.</string>
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
<string name="dnkm_xiaomi_button">Захистити Briar</string>
|
||||
<string name="dnkm_xiaomi_help">Якщо не закріпити Briar у переліку недавніх застосунків, він не зможе працювати в фоновому режимі.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Відкрийте перелік недавніх застосунків (також називається перемикачем додатків)\n\n2. Проведіть униз по зображенню Briar, щоб з\'явився значок замка\n\n3. Якщо замок не замкнений, замкніть його дотиком</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Відкрийте перелік недавніх застосунків (також називається перемикачем додатків)\n\n2. Затисніть зображення Briar до появи значка замка.\n\n3. Якщо замок не замкнений, замкніть його дотиком</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">Пароль</string>
|
||||
<string name="try_again">Неправильний пароль, спробуйте ще раз</string>
|
||||
@@ -248,8 +247,6 @@
|
||||
<string name="contact_added_toast">Додали контакт: %s</string>
|
||||
<string name="contact_already_exists">Контакт %s вже існує</string>
|
||||
<string name="qr_code_invalid">QR-код неправильний</string>
|
||||
<string name="qr_code_too_old">QR-код, який ви просканували, надійшов зі старішої версії від %s.\n\nБудь ласка, попросіть у свого контакту оновитися до останньої версії, а тоді спробуйте знову.</string>
|
||||
<string name="qr_code_too_new">QR-код, який ви просканували, надійшов з новішої версії від %s.\n\nБудь ласка, оновіться до останньої версії, а тоді спробуйте знову.</string>
|
||||
<string name="camera_error">Помилка камери</string>
|
||||
<string name="connecting_to_device">З\'єднання з пристроєм\u2026</string>
|
||||
<string name="authenticating_with_device">Автентифікація з пристроєм\u2026</string>
|
||||
@@ -756,8 +753,6 @@
|
||||
<string name="hotspot_manual_site_address">Адреса (URL)</string>
|
||||
<string name="hotspot_qr_site">Ваш телефон надає точку доступу Wi-Fi. З\'єднані з нею можуть завантажити Briar, просканувавши цей QR-код.</string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">Завантажте %s</string>
|
||||
<string name="website_download_intro">Хтось поруч поширює вам %s.</string>
|
||||
<string name="website_download_outro">Після завантаження, відкрийте завантажений файл і встановіть його.</string>
|
||||
<string name="website_troubleshooting_title">Виправлення неполадок</string>
|
||||
<string name="website_troubleshooting_1">Якщо не вдається завантажити застосунок, повторіть спробу іншим вебпереглядачем.</string>
|
||||
|
||||
@@ -26,7 +26,10 @@
|
||||
<string name="dnkm_xiaomi_button">保护 Briar</string>
|
||||
<string name="dnkm_xiaomi_help">如果未将 Briar 锁定到最近的应用列表,它将无法在后台运行。</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. 打开最近的应用列表(也称为应用切换器)\n\n2. 向下滑动 Briar 的图像,显示挂锁图标\n\n3.如果挂锁没有被锁上,轻按锁定它</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. 打开最近的应用列表(也称为应用切换器)\n\n2. 按住 Briar 的图像,直到挂锁按钮出现\n\n3. 如果挂锁没有被锁上,轻按锁定它</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. 打开最近的应用列表 (也称为应用切换器)\n\n2. 如果 Briar 名称边上有挂锁图片,那么你无需做任何事 \n\n3. 如果没有挂锁图片,按住 Briar 图片直到挂锁按钮出现,接着轻按它</string>
|
||||
<string name="dnkm_xiaomi_lock_apps_text">请轻按下方图片打开安全性设置。轻按 “提高速度”,接着轻按 “锁定应用”,并确保 Briar 状态被设为 “已锁定”</string>
|
||||
<string name="dnkm_xiaomi_lock_apps_help">如 Briar 未在“锁定应用”屏幕中被设为“已锁定”,它将无法在后台运行。</string>
|
||||
<string name="dnkm_warning_dozed_1">Briar 无法在后台运行</string>
|
||||
<!--Login-->
|
||||
<string name="enter_password">密码</string>
|
||||
<string name="try_again">密码错误,请重试</string>
|
||||
@@ -221,8 +224,8 @@
|
||||
<string name="contact_added_toast">联系人已添加:%s</string>
|
||||
<string name="contact_already_exists">联系人 %s 已存在</string>
|
||||
<string name="qr_code_invalid">二维码无效</string>
|
||||
<string name="qr_code_too_old">您所扫描的二维码来自旧版本 %s 。\n\n请让您的联系人升级到最新版本并重试。</string>
|
||||
<string name="qr_code_too_new">您所扫描的二维码来自新版本 %s 。\n\n请升级到最新版本并重试。</string>
|
||||
<string name="qr_code_too_old_1">你已扫描的二维码来自旧版本的 Briar 。\n\n请让你的联系人升级到最新版本,然后重试。</string>
|
||||
<string name="qr_code_too_new_1">你已扫描的二维码来自较新版本的 Briar。\n\n请升级到最新版本,然后重试。</string>
|
||||
<string name="camera_error">相机出错</string>
|
||||
<string name="connecting_to_device">正在连接至设备\u2026</string>
|
||||
<string name="authenticating_with_device">正在验证设备\u2026</string>
|
||||
@@ -588,6 +591,10 @@
|
||||
<string name="mailbox_status_connected_title">Mailbox 运行中</string>
|
||||
<string name="mailbox_status_problem_title">Briar 连接到 Mailbox 时出现问题</string>
|
||||
<string name="mailbox_status_failure_title">已与信箱失去连接</string>
|
||||
<string name="mailbox_status_app_too_old_title">Briar 版本太旧</string>
|
||||
<string name="mailbox_status_app_too_old_message">更新 Briar 到最新版本并重试</string>
|
||||
<string name="mailbox_status_mailbox_too_old_title">Mailbox 版本太旧</string>
|
||||
<string name="mailbox_status_mailbox_too_old_message">将你的 Mailbox 应用更新到最新版本并重试</string>
|
||||
<string name="mailbox_status_check_button">请检查联网状况</string>
|
||||
<!--Example for string substitution: Last connection: 3min ago-->
|
||||
<string name="mailbox_status_connected_info">上次连接:%s</string>
|
||||
@@ -738,8 +745,9 @@
|
||||
<string name="hotspot_manual_site_address">地址 (URL)</string>
|
||||
<string name="hotspot_qr_site">你的手机正提供 Wi-Fi 热点。连接到这个热点的人可以通过扫描这个二维码下载 Briar。</string>
|
||||
<!--e.g. Download Briar 1.2.20-->
|
||||
<string name="website_download_title">下载 %s</string>
|
||||
<string name="website_download_intro">附近的某人和你分享了 %s</string>
|
||||
<string name="website_download_title_1">下载 Briar %s</string>
|
||||
<string name="website_download_intro_1">附近的某人和你分享了 Briar。</string>
|
||||
<string name="website_download_button">下载 Briar</string>
|
||||
<string name="website_download_outro">下载完成后,打开下载的文件并进行安装。 </string>
|
||||
<string name="website_troubleshooting_title">故障排除</string>
|
||||
<string name="website_troubleshooting_1">如果您无法下载该应用程序,请尝试使用不同的网络浏览器应用。</string>
|
||||
|
||||
@@ -31,7 +31,10 @@
|
||||
<string name="dnkm_xiaomi_button">Protect Briar</string>
|
||||
<string name="dnkm_xiaomi_help">If Briar is not locked to the recent apps list, it will be unable to run in the background.</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_old">1. Open the recent apps list (also called the app switcher)\n\n2. Swipe down on the image of Briar to show the padlock icon\n\n3. If the padlock is not locked, tap to lock it</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Open the recent apps list (also called the app switcher)\n\n2. Press and hold the image of Briar until the padlock button appears\n\n3. If the padlock is not locked, tap to lock it</string>
|
||||
<string name="dnkm_xiaomi_dialog_body_new">1. Open the recent apps list (also called the app switcher)\n\n2. If Briar has a small image of a padlock next to its name then you don\'t need to do anything\n\n3. If there\'s no padlock, press and hold the image of Briar until the padlock button appears, then tap it</string>
|
||||
<string name="dnkm_xiaomi_lock_apps_text">Please tap the button below to open the security settings. Tap \"Boost speed\", then tap \"Lock apps\", and make sure Briar is set to \"Locked\".</string>
|
||||
<string name="dnkm_xiaomi_lock_apps_help">If Briar is not set to \"Locked\" in the \"Lock apps\" screen, it will be unable to run in the background.</string>
|
||||
<string name="dnkm_warning_dozed_1">Briar was unable to run in the background</string>
|
||||
|
||||
<!-- Login -->
|
||||
<string name="enter_password">Password</string>
|
||||
@@ -245,8 +248,8 @@
|
||||
<string name="contact_added_toast">Contact added: %s</string>
|
||||
<string name="contact_already_exists">Contact %s already exists</string>
|
||||
<string name="qr_code_invalid">The QR code is invalid</string>
|
||||
<string name="qr_code_too_old">The QR code you have scanned comes from an older version of %s.\n\nPlease ask your contact to upgrade to the latest version and then try again.</string>
|
||||
<string name="qr_code_too_new">The QR code you have scanned comes from a newer version of %s.\n\nPlease upgrade to the latest version and then try again.</string>
|
||||
<string name="qr_code_too_old_1">The QR code you have scanned comes from an older version of Briar.\n\nPlease ask your contact to upgrade to the latest version and then try again.</string>
|
||||
<string name="qr_code_too_new_1">The QR code you have scanned comes from a newer version of Briar.\n\nPlease upgrade to the latest version and then try again.</string>
|
||||
<string name="camera_error">Camera error</string>
|
||||
<string name="connecting_to_device">Connecting to device\u2026</string>
|
||||
<string name="authenticating_with_device">Authenticating with device\u2026</string>
|
||||
@@ -810,8 +813,9 @@
|
||||
<string name="hotspot_qr_site">Your phone is providing a Wi-Fi hotspot. People who are connected to the hotspot can download Briar by scanning this QR code.</string>
|
||||
|
||||
<!-- e.g. Download Briar 1.2.20 -->
|
||||
<string name="website_download_title">Download %s</string>
|
||||
<string name="website_download_intro">Someone nearby shared %s with you.</string>
|
||||
<string name="website_download_title_1">Download Briar %s</string>
|
||||
<string name="website_download_intro_1">Someone nearby shared Briar with you.</string>
|
||||
<string name="website_download_button">Download Briar</string>
|
||||
<string name="website_download_outro">After the download is complete, open the downloaded file and install it.</string>
|
||||
<string name="website_troubleshooting_title">Troubleshooting</string>
|
||||
<string name="website_troubleshooting_1">If you cannot download the app, try it with a different web browser app.</string>
|
||||
|
||||
@@ -184,7 +184,7 @@ dependencyVerification {
|
||||
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
|
||||
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
|
||||
'org.bouncycastle:bcprov-jdk15on:1.65:bcprov-jdk15on-1.65.jar:e78f96eb59066c94c94fb2d6b5eb80f52feac6f5f9776898634f8addec6e2137',
|
||||
'org.briarproject:dont-kill-me-lib:0.2.2:dont-kill-me-lib-0.2.2.aar:5e95bf79abe1342fb15be6757ac23be165127f052b93055ef1a796e5b8d6ab8a',
|
||||
'org.briarproject:dont-kill-me-lib:0.2.5:dont-kill-me-lib-0.2.5.aar:55cd9d511b7016ab573905d64bc54e222e2633144d36389192b8b34485b31b9d',
|
||||
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
|
||||
'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a',
|
||||
'org.checkerframework:checker-qual:3.5.0:checker-qual-3.5.0.jar:729990b3f18a95606fc2573836b6958bcdb44cb52bfbd1b7aa9c339cff35a5a4',
|
||||
|
||||
@@ -45,6 +45,7 @@ dependencies {
|
||||
}
|
||||
|
||||
void jarFactory(Jar jarTask, jarArchitecture) {
|
||||
jarTask.dependsOn(jar)
|
||||
jarTask.doFirst {
|
||||
println 'Building ' + jarArchitecture + ' version has started'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user