Compare commits

..

4 Commits

Author SHA1 Message Date
goapunk
a51f0f803f add bt polling speedtest 2018-05-10 14:42:09 +02:00
akwizgran
8f9d7a70bf Pause between connection attempts. 2018-05-08 14:15:39 +01:00
akwizgran
3ea642c6c0 Don't poll again if last poll is still running. 2018-05-08 13:51:39 +01:00
akwizgran
da0a32c613 Poll contacts in series rather than parallel. 2018-05-08 13:51:31 +01:00
20 changed files with 338 additions and 114 deletions

View File

@@ -14,8 +14,8 @@ android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 26
versionCode 10002
versionName "1.0.2"
versionCode 10001
versionName "1.0.1"
consumerProguardFiles 'proguard-rules.txt'
}

View File

@@ -5,7 +5,7 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* A key pair consisting of a {@link PublicKey} and a {@link PrivateKey}.
* A key pair consisting of a {@link PublicKey} and a {@link PrivateKey).
*/
@Immutable
@NotNullByDefault

View File

@@ -7,12 +7,12 @@ package org.briarproject.bramble.api.system;
public interface Clock {
/**
* @see System#currentTimeMillis()
* @see {@link System#currentTimeMillis()}
*/
long currentTimeMillis();
/**
* @see Thread#sleep(long)
* @see {@link Thread#sleep(long)}
*/
void sleep(long milliseconds) throws InterruptedException;
}

View File

@@ -10,37 +10,37 @@ import java.security.GeneralSecurityException;
interface Signature {
/**
* @see java.security.Signature#initSign(java.security.PrivateKey)
* @see {@link java.security.Signature#initSign(java.security.PrivateKey)}
*/
void initSign(PrivateKey k) throws GeneralSecurityException;
/**
* @see java.security.Signature#initVerify(java.security.PublicKey)
* @see {@link java.security.Signature#initVerify(java.security.PublicKey)}
*/
void initVerify(PublicKey k) throws GeneralSecurityException;
/**
* @see java.security.Signature#update(byte)
* @see {@link java.security.Signature#update(byte)}
*/
void update(byte b) throws GeneralSecurityException;
/**
* @see java.security.Signature#update(byte[])
* @see {@link java.security.Signature#update(byte[])}
*/
void update(byte[] b) throws GeneralSecurityException;
/**
* @see java.security.Signature#update(byte[], int, int)
* @see {@link java.security.Signature#update(byte[], int, int)}
*/
void update(byte[] b, int off, int len) throws GeneralSecurityException;
/**
* @see java.security.Signature#sign()}
* @see {@link java.security.Signature#sign()}
*/
byte[] sign() throws GeneralSecurityException;
/**
* @see java.security.Signature#verify(byte[])
* @see {@link java.security.Signature#verify(byte[])}
*/
boolean verify(byte[] signature) throws GeneralSecurityException;
}

View File

@@ -34,8 +34,8 @@ import javax.annotation.Nullable;
* A low-level interface to the database (DatabaseComponent provides a
* high-level interface). Most operations take a transaction argument, which is
* obtained by calling {@link #startTransaction()}. Every transaction must be
* terminated by calling either {@link #abortTransaction(Object) abortTransaction(T)} or
* {@link #commitTransaction(Object) commitTransaction(T)}, even if an exception is thrown.
* terminated by calling either {@link #abortTransaction(T)} or
* {@link #commitTransaction(T)}, even if an exception is thrown.
*/
@NotNullByDefault
interface Database<T> {

View File

@@ -24,7 +24,9 @@ import org.briarproject.bramble.api.system.Scheduler;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
@@ -53,6 +55,7 @@ class Poller implements EventListener {
private final Clock clock;
private final Lock lock;
private final Map<TransportId, ScheduledPollTask> tasks; // Locking: lock
private final Set<TransportId> polling; // Locking: lock
@Inject
Poller(@IoExecutor Executor ioExecutor,
@@ -69,16 +72,19 @@ class Poller implements EventListener {
this.clock = clock;
lock = new ReentrantLock();
tasks = new HashMap<>();
polling = new HashSet<>();
}
@Override
public void eventOccurred(Event e) {
if (e instanceof ContactStatusChangedEvent) {
ContactStatusChangedEvent c = (ContactStatusChangedEvent) e;
/*
if (c.isActive()) {
// Connect to the newly activated contact
connectToContact(c.getContactId());
}
*/
} else if (e instanceof ConnectionClosedEvent) {
ConnectionClosedEvent c = (ConnectionClosedEvent) e;
// Reschedule polling, the polling interval may have decreased
@@ -215,20 +221,33 @@ class Poller implements EventListener {
@Override
@IoExecutor
public void run() {
TransportId t = plugin.getId();
boolean shouldPoll;
lock.lock();
try {
TransportId t = plugin.getId();
ScheduledPollTask scheduled = tasks.get(t);
if (scheduled != null && scheduled.task != this)
return; // Replaced by another task
tasks.remove(t);
// Don't poll again if last poll is still running
shouldPoll = polling.add(t);
} finally {
lock.unlock();
}
int delay = plugin.getPollingInterval();
if (randomiseNext) delay = (int) (delay * random.nextDouble());
schedule(plugin, delay, false);
poll(plugin);
if (shouldPoll) {
poll(plugin);
} else if (LOG.isLoggable(INFO)) {
LOG.info("Last poll for " + t + " is still running");
}
lock.lock();
try {
polling.remove(t);
} finally {
lock.unlock();
}
}
}
}

View File

@@ -26,9 +26,11 @@ import org.briarproject.bramble.util.StringUtils;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -53,6 +55,12 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
private static final Logger LOG =
Logger.getLogger(BluetoothPlugin.class.getName());
/**
* How many milliseconds to pause between connection attempts when
* polling, to avoid interfering with other Bluetooth or wifi connections.
*/
private static final int POLLING_PAUSE_MS = 3000;
final BluetoothConnectionLimiter connectionLimiter;
private final Executor ioExecutor;
@@ -253,27 +261,42 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
public void poll(Collection<ContactId> connected) {
if (!isRunning() || !shouldAllowContactConnections()) return;
backoff.increment();
// Try to connect to known devices in parallel
// Try to connect to known devices in a random order
Map<ContactId, TransportProperties> remote =
callback.getRemoteProperties();
for (Entry<ContactId, TransportProperties> e : remote.entrySet()) {
ContactId c = e.getKey();
if (connected.contains(c)) continue;
String address = e.getValue().get(PROP_ADDRESS);
if (StringUtils.isNullOrEmpty(address)) continue;
String uuid = e.getValue().get(PROP_UUID);
if (StringUtils.isNullOrEmpty(uuid)) continue;
ioExecutor.execute(() -> {
List<ContactId> keys = new ArrayList<>(remote.keySet());
Collections.shuffle(keys);
ioExecutor.execute(() -> {
boolean first = true;
for (ContactId c : keys) {
if (!isRunning() || !shouldAllowContactConnections()) return;
if (!connectionLimiter.canOpenContactConnection()) return;
if (connected.contains(c)) continue;
TransportProperties p = remote.get(c);
String address = p.get(PROP_ADDRESS);
if (StringUtils.isNullOrEmpty(address)) continue;
String uuid = p.get(PROP_UUID);
if (StringUtils.isNullOrEmpty(uuid)) continue;
// Pause between connection attempts
if (first) {
first = false;
} else {
try {
Thread.sleep(POLLING_PAUSE_MS);
} catch (InterruptedException ex) {
LOG.info("Interrupted while polling");
Thread.currentThread().interrupt();
return;
}
}
DuplexTransportConnection conn = connect(address, uuid);
if (conn != null) {
backoff.reset();
if (connectionLimiter.contactConnectionOpened(conn))
callback.outgoingConnectionCreated(c, conn);
}
});
}
}
});
}
@Nullable

View File

@@ -33,6 +33,10 @@ dependencies {
implementation 'com.jpardogo.materialtabstrip:library:1.1.0'
implementation 'com.github.bumptech.glide:glide:3.8.0'
implementation 'uk.co.samuelwall:material-tap-target-prompt:2.8.0'
implementation'fr.bmartel:jspeedtest:1.32.0'
implementation 'com.jjoe64:graphview:4.2.2'
annotationProcessor 'com.google.dagger:dagger-compiler:2.0.2'
@@ -238,8 +242,8 @@ android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 26
versionCode 10002
versionName "1.0.2"
versionCode 10001
versionName "1.0.1"
applicationId "org.briarproject.briar.android"
resValue "string", "app_package", "org.briarproject.briar.android"
resValue "string", "app_name", "Briar"

View File

@@ -4,17 +4,18 @@
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature android:name="android.hardware.bluetooth"/>
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<application
@@ -69,8 +70,8 @@
<activity
android:name="org.briarproject.briar.android.splash.SplashScreenActivity"
android:theme="@style/BriarTheme.NoActionBar"
android:label="@string/app_name">
android:label="@string/app_name"
android:theme="@style/BriarTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
@@ -84,15 +85,15 @@
<activity
android:name="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
android:theme="@style/BriarTheme.NoActionBar"
android:launchMode="singleTop">
android:launchMode="singleTop"
android:theme="@style/BriarTheme.NoActionBar">
</activity>
<activity
android:name="org.briarproject.briar.android.contact.ConversationActivity"
android:label="@string/app_name"
android:theme="@style/BriarTheme.NoActionBar"
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
android:theme="@style/BriarTheme.NoActionBar"
android:windowSoftInputMode="stateHidden|adjustResize">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
@@ -132,7 +133,7 @@
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/>
</activity>
<activity
<activity
android:name="org.briarproject.briar.android.privategroup.memberlist.GroupMemberListActivity"
android:label="@string/groups_member_list"
android:parentActivityName="org.briarproject.briar.android.privategroup.conversation.GroupActivity"
@@ -304,8 +305,8 @@
<activity
android:name="org.briarproject.briar.android.keyagreement.KeyAgreementActivity"
android:label="@string/add_contact_title"
android:theme="@style/BriarTheme.NoActionBar"
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity">
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
android:theme="@style/BriarTheme.NoActionBar">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.briarproject.briar.android.navdrawer.NavDrawerActivity"/>
@@ -362,6 +363,16 @@
/>
</activity>
<activity
android:name="org.briarproject.briar.android.test.PollingTestActivity"
android:label="Test polling"
android:parentActivityName="org.briarproject.briar.android.settings.SettingsActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.briarproject.briar.android.settings.SettingsActivity"
/>
</activity>
<activity
android:name="org.briarproject.briar.android.panic.PanicPreferencesActivity"
android:label="@string/panic_setting"

View File

@@ -70,6 +70,7 @@ import org.briarproject.briar.android.sharing.ShareForumFragment;
import org.briarproject.briar.android.sharing.ShareForumMessageFragment;
import org.briarproject.briar.android.sharing.SharingModule;
import org.briarproject.briar.android.splash.SplashScreenActivity;
import org.briarproject.briar.android.test.PollingTestActivity;
import org.briarproject.briar.android.test.TestDataActivity;
import dagger.Component;
@@ -150,6 +151,8 @@ public interface ActivityComponent {
void inject(TestDataActivity activity);
void inject(PollingTestActivity activity);
void inject(ChangePasswordActivity activity);
void inject(IntroductionActivity activity);

View File

@@ -89,9 +89,9 @@ abstract class PowerView extends ConstraintLayout {
public void setChecked(boolean checked) {
this.checked = checked;
if (checked) {
checkImage.setVisibility(VISIBLE);
checkImage.setImageResource(R.drawable.ic_check_white);
} else {
checkImage.setVisibility(INVISIBLE);
checkImage.setImageResource(R.drawable.contact_disconnected);
}
if (onCheckedChangedListener != null) {
onCheckedChangedListener.onCheckedChanged();

View File

@@ -0,0 +1,176 @@
package org.briarproject.briar.android.test;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.view.MenuItem;
import android.widget.Button;
import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.series.DataPoint;
import com.jjoe64.graphview.series.LineGraphSeries;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.plugin.BluetoothConstants;
import org.briarproject.bramble.api.plugin.event.TransportDisabledEvent;
import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity;
import org.briarproject.briar.api.test.TestDataCreator;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Logger;
import javax.inject.Inject;
import fr.bmartel.speedtest.SpeedTestReport;
import fr.bmartel.speedtest.SpeedTestSocket;
import fr.bmartel.speedtest.inter.ISpeedTestListener;
import fr.bmartel.speedtest.model.SpeedTestError;
public class PollingTestActivity extends BriarActivity {
private static final Logger LOG =
Logger.getLogger(PollingTestActivity.class.getName());
// Add one contact after each round up to:
private static int NUMBER_OF_CONTACTS = 10;
// Download x times per #contacts
private static int NUMBER_OF_DOWNLOADS = 1;
// File size to download. One of (5,10,50,100,500)MB.
private static int DOWNLOAD_SIZE = 10;
// Time to wait between each round in ms.
private static int PAUSE = 5000;
// Socket timeout in ms
private static int SO_TIMEOUT = 60000;
@Inject
TestDataCreator testDataCreator;
@Inject
AndroidExecutor executor;
@Inject
EventBus eventBus;
GraphView graphView;
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setHomeButtonEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
}
setContentView(R.layout.activity_test_polling);
Button button = findViewById(R.id.run_test_button);
button.setOnClickListener(v -> {
runTest();
});
graphView = findViewById(R.id.graph);
graphView.getGridLabelRenderer()
.setHorizontalAxisTitle("Number of contacts");
graphView.getGridLabelRenderer().setVerticalAxisTitle("MBit/s");
graphView.getViewport().setXAxisBoundsManual(true);
graphView.getViewport().setMinX(0);
graphView.getViewport().setMaxX(NUMBER_OF_CONTACTS);
}
private void runTest() {
executor.runOnBackgroundThread(() -> {
LineGraphSeries<DataPoint> series = new LineGraphSeries<>();
graphView.addSeries(series);
for (int i = 0; i < NUMBER_OF_CONTACTS; i++) {
if (i != 0) {
createContact();
// Wait to let the previous round of polling settle.
synchronized (this) {
try {
wait(PAUSE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// Reset BT polling.
eventBus.broadcast(new TransportDisabledEvent(
BluetoothConstants.ID));
eventBus.broadcast(
new TransportEnabledEvent(BluetoothConstants.ID));
LOG.info("\n###########\nRound " + i + " (Contacts)");
double y = run();
series.appendData(new DataPoint(i, y), false,
NUMBER_OF_CONTACTS);
}
});
}
private double run() {
SpeedTestReport reports[] = new SpeedTestReport[3];
double average = 0;
for (int i = 0; i < NUMBER_OF_DOWNLOADS; i++) {
final CountDownLatch cl = new CountDownLatch(1);
SpeedTestSocket speedTestSocket = new SpeedTestSocket();
speedTestSocket.setSocketTimeout(SO_TIMEOUT);
int finalI = i;
speedTestSocket.addSpeedTestListener(new ISpeedTestListener() {
@Override
public void onCompletion(SpeedTestReport report) {
LOG.info("[COMPLETED]: rate in bit/s : " +
report.getTransferRateBit() + " in " +
(report.getReportTime() -
report.getStartTime()) + "ms");
reports[finalI] = report;
cl.countDown();
}
@Override
public void onProgress(float percent,
SpeedTestReport report) {
/* LOG.info("[PROGRESS] rate in bit/s : " +
report.getTransferRateBit());
*/
}
@Override
public void onError(SpeedTestError speedTestError,
String errorMessage) {
LOG.info("Error: " + speedTestError.name() + " : " +
errorMessage);
}
});
LOG.info("Download " + (i + 1) + " of " + NUMBER_OF_DOWNLOADS);
speedTestSocket
.startDownload(
"http://ikoula.testdebit.info/" + DOWNLOAD_SIZE +
"M.iso");
try {
cl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
average += reports[i].getTransferRateBit().doubleValue() / 1000000;
}
return average / NUMBER_OF_DOWNLOADS;
}
private void createContact() {
testDataCreator.createTestData(1, 0, 0, 0, 0);
}
@Override
public void injectActivity(ActivityComponent component) {
component.inject(this);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
}
return false;
}
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Button
android:id="@+id/run_test_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Run test"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
/>
<com.jjoe64.graphview.GraphView
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/run_test_button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:id="@+id/graph" />
</android.support.constraint.ConstraintLayout>

View File

@@ -20,12 +20,10 @@
<ImageView
android:id="@+id/checkImage"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_margin="8dp"
android:src="@drawable/ic_check_white"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/contact_disconnected"
android:tint="?colorControlNormal"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="@+id/button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/button"
@@ -36,7 +34,9 @@
style="@style/BriarButton.Default"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toStartOf="@+id/helpButton"
app:layout_constraintStart_toEndOf="@+id/checkImage"
app:layout_constraintTop_toBottomOf="@+id/textView"
@@ -44,13 +44,11 @@
<ImageButton
android:id="@+id/helpButton"
style="@style/BriarButtonFlat.Positive"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_margin="8dp"
style="@style/BriarButton.Default"
android:layout_width="48dp"
android:layout_height="wrap_content"
android:contentDescription="@string/help"
android:src="@drawable/ic_help_outline_white"
android:tint="@color/briar_button_positive"
app:layout_constraintBottom_toBottomOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/button"/>

View File

@@ -31,11 +31,7 @@
<string name="dialog_title_lost_password">Passwort vergessen</string>
<string name="dialog_message_lost_password">Dein Briar-Konto ist auf deinem Gerät verschlüsselt und nicht in der Cloud gespeichert, deshalb kannst du dein Passwort nicht zurücksetzen. Willst du dein Konto löschen und neu beginnen?\n\nAchtung: Deine bestehenden Identitäten, Kontakte und Nachrichten gehen dann für immer verloren.</string>
<string name="startup_failed_notification_title">Briar konnte nicht gestartet werden</string>
<string name="startup_failed_notification_text">Für weitere Informationen, hier klicken.</string>
<string name="startup_failed_activity_title">Fehler beim Starten von Briar</string>
<string name="startup_failed_db_error">Aus irgendeinem Grund ist deine Briar-Datenbank irreparabel beschädigt. Dein Konto, deine Daten und alle deinen Kontakte sind verloren. Leider musst du Briar neu installieren oder ein neues Konto einrichten, indem du ,Ich habe mein Passwort vergessen\' auswählst, wenn du zur Eingabe deines Passworts aufgefordert wirst. </string>
<string name="startup_failed_data_too_old_error">Dein Konto wurde mit einer alten Version dieser App erstellt und kann mit dieser Version nicht geöffnet werden. Installiere entweder die alte Version oder richte ein neues Konto ein, indem du \"Ich habe mein Passwort vergessen\" auswählst, wenn du zur Eingabe deines Passworts aufgefordert wirst. </string>
<string name="startup_failed_data_too_new_error">Diese Version der App ist zu alt. Bitte führe eine Aktualisierung auf die neueste Version der App durch und versuch es dann noch mal.</string>
<string name="startup_failed_service_error">Briar konnte ein benötigtes Plugin nicht starten. Normalerweise kann das Problem durch eine Neuinstallation von Briar gelöst werden. Eine Neuinstallation führt jedoch zum Verlust deines Kontos und aller dazugehörigen Daten, da Briar deine Daten nicht auf zentralen Servern speichert.</string>
<plurals name="expiry_warning">
<item quantity="one">Dies ist eine Testversion von Briar. Dein Konto läuft in %d Tag ab und kann nicht verlängert werden.</item>
@@ -43,11 +39,6 @@
</plurals>
<string name="expiry_update">Das Ablaufdatum des Tests wurde verlängert. Dein Konto läuft nun in %d Tagen ab.</string>
<string name="expiry_date_reached">Diese Software ist abgelaufen.\nDanke dass du Briar getestet hast!</string>
<string name="download_briar">Lade bitte Version 1.0 herunter, um Briar weiterhin zu nutzen.</string>
<string name="create_new_account">Du wirst ein neues Konto erstellen müssen, wobei du jedoch wieder den selben Benutzernamen verwenden kannst.</string>
<string name="download_briar_button">Lade Briar 1.0 herunter</string>
<string name="startup_open_database">Datenbank wird entschlüsselt...</string>
<string name="startup_migrate_database">Datenbank wird aktualisiert...</string>
<!--Navigation Drawer-->
<string name="nav_drawer_open_description">Navigationsleiste öffnen</string>
<string name="nav_drawer_close_description">Navigationsleiste schliessen</string>
@@ -103,7 +94,6 @@
<string name="fix">Behoben</string>
<string name="help">Hilfe</string>
<!--Contacts and Private Conversations-->
<string name="no_contacts">Du hast noch keine Kontakte\n\nTippe auf das +-Symbol um einen Kontakt hinzuzufügen</string>
<string name="date_no_private_messages">Keine Nachrichten.</string>
<string name="message_hint">Nachricht eingeben</string>
<string name="delete_contact">Kontakt löschen</string>
@@ -122,7 +112,6 @@
<string name="contact_already_exists">Kontakt %s existiert bereits</string>
<string name="contact_exchange_failed">Kontaktaustausch fehlgeschlagen</string>
<string name="qr_code_invalid">Der QR-Code ist ungültig</string>
<string name="qr_code_unsupported">Der QR-Code, den du versuchst zu scannen, gehört zu einer alten Version von %s welche nicht mehr unterstützt wird.\n\nBitte versichert euch, dass bei euch beiden die neueste Version läuft und versucht es dann 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>
@@ -219,9 +208,7 @@
<string name="btn_reply">Antworten</string>
<string name="forum_leave">Forum verlassen</string>
<string name="dialog_title_leave_forum">Verlassen des Forums bestätigen</string>
<string name="dialog_message_leave_forum">Bist du sicher, dass du dieses Forum verlassen willst?\n\nKontakte, mit denen du dieses Forum geteilt hast, werden keine Updates mehr von diesem Forum bekommen.</string>
<string name="dialog_button_leave">Verlassen</string>
<string name="forum_left_toast">Forum wurde verlassen</string>
<!--Forum Sharing-->
<string name="forum_share_button">Forum teilen</string>
<string name="contacts_selected">Ausgewählte Kontakte</string>
@@ -232,9 +219,6 @@
<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">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>
<string name="shared_by_format">Geteilt durch %s</string>
<string name="forum_invitation_already_sharing">Bereits geteilt.</string>
<string name="forum_invitation_response_accepted_sent">Du hast die Forumseinladung von %s akzeptiert.</string>
@@ -252,14 +236,12 @@
<!--Blogs-->
<string name="read_more">weiterlesen</string>
<string name="blogs_write_blog_post">Blogbeitrag erstellen</string>
<string name="blogs_write_blog_post_body_hint">Gib deinen Blogbeitrag ein</string>
<string name="blogs_publish_blog_post">Veröffentlichen</string>
<string name="blogs_blog_post_created">Blogbeitrag erstellt</string>
<string name="blogs_blog_post_received">Neuen Blogbeitrag empfangen</string>
<string name="blogs_blog_post_scroll_to">Scrolle zu</string>
<string name="blogs_remove_blog">Blog entfernen</string>
<string name="blogs_remove_blog_ok">Aufheben</string>
<string name="blogs_blog_removed">Blog wurde entfernt</string>
<string name="blogs_reblog_comment_hint">Kommentar hinzufügen (optional)</string>
<string name="blogs_reblog_button">Rebloggen</string>
<!--Blog Sharing-->
@@ -274,8 +256,6 @@
<string name="blogs_sharing_invitation_received">%1$shat den Blog \"%2$s\" mit dir geteilt.</string>
<string name="blogs_sharing_invitation_sent">Du teilst den Blog \"%1$s\" mit %2$s.</string>
<string name="blogs_sharing_invitations_title">Blogeinladungen</string>
<string name="blogs_sharing_joined_toast">Blog abonniert</string>
<string name="blogs_sharing_declined_toast">Einladung abgelehnt</string>
<string name="sharing_status_blog">Jeder Abonnent eines Blogs kann diesen mit seinen Kontakten teilen. Du teilst diesen Blog mit den folgenden Kontakten. Möglicherweise gibt es Abonnenten die nicht sichtbar sind.</string>
<!--RSS Feeds-->
<string name="blogs_rss_feeds_import">RSS-Feed importieren</string>
@@ -376,6 +356,4 @@
<string name="permission_camera_denied_toast">Berechtigung für Kamera wurde nicht gewährt</string>
<string name="qr_code">QR-Code</string>
<!--Low Memory Notification-->
<string name="low_memory_shutdown_notification_title">Von Briar abgemeldet</string>
<string name="low_memory_shutdown_notification_text">Mangels Speicherplatz abgemeldet.</string>
</resources>

View File

@@ -134,7 +134,6 @@
<string name="introduction_onboarding_title">Présenter vos contacts</string>
<string name="introduction_onboarding_text">Vous pouvez présenter vos contacts mutuellement, afin quils naient pas à se rencontrer en personne pour se connecter les uns aux autres avec Briar.</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 dabord lui permettre de se terminer. Si vous ou vos contacts êtes rarement en ligne, cela peut prendre du temps.</string>
<string name="introduction_message_title">Présenter des contacts</string>
<string name="introduction_message_hint">Ajouter un message (facultatif)</string>
<string name="introduction_button">Faire les présentations</string>
@@ -146,7 +145,6 @@
<string name="introduction_request_exists_received">%1$s a demandé de vous présenter à %2$s, mais %2$s est déjà dans votre liste de contacts. Puisque %1$s pourrait ne pas le savoir, vous pouvez tout de même répondre :</string>
<string name="introduction_request_answered_received">%1$s a demandé de vous présenter à %2$s.</string>
<string name="introduction_response_accepted_sent">Vous avez accepté dêtre présenté à %1$s.</string>
<string name="introduction_response_accepted_sent_info">Avant que %1$s ne soit ajouté à vos contacts, ce contact doit aussi accepter la présentation. Cela peut prendre du temps. </string>
<string name="introduction_response_declined_sent">Vous avez refusé dêtre présenté à %1$s.</string>
<string name="introduction_response_accepted_received">%1$s a accepté dêtre présenté à %2$s.</string>
<string name="introduction_response_declined_received">%1$s a refusé dêtre présenté à %2$s.</string>

View File

@@ -1,9 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<!--Setup-->
<string name="setup_title">La benvenguda a Briar</string>
<string name="setup_next">Seguent</string>
<string name="setup_password_intro">Causissètz un senhal</string>
<string name="choose_nickname">Causir un escais-nom</string>
<string name="choose_password">Causir un senhal</string>
<string name="confirm_password">Confirmar lo senhal</string>
@@ -11,9 +8,6 @@
<string name="password_too_weak">Lo senhal es tròp feble</string>
<string name="passwords_do_not_match">Los senhals correspondon pas</string>
<string name="create_account_button">Crear un compte</string>
<string name="more_info">Mai dinformacions</string>
<string name="don_t_ask_again">Demandar pas mai</string>
<string name="setup_huawei_button">Projècte Briar</string>
<!--Login-->
<string name="enter_password">Picatz vòstre senhal:</string>
<string name="try_again">Senhal incorècte, tornatz ensajar</string>
@@ -24,14 +18,9 @@
Volètz suprimir vòstre compte e ne crear un nòu?\n
\nMèfi:vòstra identitat, vòstres contactes e messatges seràn perduts per totjorn.</string>
<string name="startup_failed_notification_title">Briar a pas pogut aviar</string>
<string name="startup_failed_notification_text">Tocatz per mai dinformacions.</string>
<string name="startup_failed_activity_title">Fracàs de laviada de Briar.</string>
<string name="startup_failed_service_error">Briar a pas pogut aviar un modul necessari. Tornar installar Briar pòt resolver aquò. Que aquò siá dich:perdretz vòstre compte e totas las donadas ligadas a aqueste. Briar utiliza pas de servidor centralizat per salvar sas donadas.</string>
<string name="expiry_date_reached">Vòstre logicial sacabèt.\nMercés daver ensajat!</string>
<string name="create_new_account">Vos caldrà crear un nòu compte, mas podètz emplegar lo meteis escais-nom.</string>
<string name="download_briar_button">Telecargar Briar 1.0</string>
<string name="startup_open_database">Deschirament de la basa de donadas…</string>
<string name="startup_migrate_database">Mesa a nivèl de la basa de donadas…</string>
<!--Navigation Drawer-->
<string name="nav_drawer_open_description">Dobrir lo panèl de navigacion</string>
<string name="nav_drawer_close_description">Tampar lo panèl de navigacion</string>
@@ -87,7 +76,6 @@ Volètz suprimir vòstre compte e ne crear un nòu?\n
<string name="help">Ajuda</string>
<!--Contacts and Private Conversations-->
<string name="date_no_private_messages">Cap messatge</string>
<string name="no_private_messages">Cap de messatge de mostrar</string>
<string name="message_hint">Picatz lo messatge</string>
<string name="delete_contact">Suprimir lo contacte</string>
<string name="dialog_title_delete_contact">Confirmatz la supression del contacte</string>
@@ -105,7 +93,6 @@ Volètz suprimir vòstre compte e ne crear un nòu?\n
<string name="contact_already_exists">Lo contacte %s existís ja</string>
<string name="contact_exchange_failed">Lescambi de contacte a fracassat</string>
<string name="qr_code_invalid">Lo QR còdi es invalid</string>
<string name="camera_error">Error de camèra</string>
<string name="connecting_to_device">Connexion a laparelh\u2026</string>
<string name="authenticating_with_device">Autentificacion amb laparelh\u2026</string>
<string name="connection_aborted_remote">Vòstre contacte a copat la connexion!Poiriá arribar que qualquun ensage dinterferir amb aquela</string>
@@ -201,7 +188,6 @@ Volètz suprimir vòstre compte e ne crear un nòu?\n
<string name="forum_leave">Quitar lo fòrum</string>
<string name="dialog_title_leave_forum">Confirmar la sortida del fòrum</string>
<string name="dialog_button_leave">Quitar</string>
<string name="forum_left_toast">Quitar lo forum</string>
<!--Forum Sharing-->
<string name="forum_share_button">Partejar lo fòrum</string>
<string name="contacts_selected">Contactes seleccionats</string>
@@ -340,10 +326,5 @@ Volètz suprimir vòstre compte e ne crear un nòu?\n
<!--Screen Filters & Tapjacking-->
<string name="screen_filter_title">Superposicion detectada</string>
<!--Permission Requests-->
<string name="permission_camera_title">Permission de la camèra</string>
<string name="permission_camera_request_body">Per numerizar lo còdi QR cal que Briar aja laccès a la camèra.</string>
<string name="permission_camera_denied_toast">La permission a la camèra es pas estada donada</string>
<string name="qr_code">Còdi QR</string>
<!--Low Memory Notification-->
<string name="low_memory_shutdown_notification_title">Desconnectat de Briar</string>
</resources>

View File

@@ -2,7 +2,7 @@
<resources>
<!--Setup-->
<string name="setup_title">Добро пожаловать в Briar</string>
<string name="setup_name_explanation">Ваш псевдоним будет показан рядом с любым публикуемым контентом. Его нельзя изменить после создания аккаунта.</string>
<string name="setup_name_explanation">Ваш ник будет показан рядом с любым контентом, который вы публикуете. Его нельзя изменить после создания аккаунта.</string>
<string name="setup_next">Вперед</string>
<string name="setup_password_intro">Придумайте пароль</string>
<string name="setup_password_explanation">Ваша учетная запись Briar хранится в зашифрованном виде только на устройстве. Если вы забудете свой пароль или удалите Briar, то не сможете восстановить свою учетную запись.\n\nПридумайте длинный пароль, который трудно угадать, например четыре случайных слова или десять случайных букв, цифр и символов.</string>
@@ -168,11 +168,11 @@
<item quantity="other">%d новых контактов добавлено.</item>
</plurals>
<!--Private Groups-->
<string name="groups_list_empty">Нет групп для отображения\n\nКоснитесь значка + для создания группы, или попросите ваши контакты поделиться с вами группами</string>
<string name="groups_list_empty">Нет групп для отображения\n\nTКоснитесь значка + для создания группы, или попросите ваши контакты поделиться с вами группами</string>
<string name="groups_created_by">Создано %s</string>
<plurals name="messages">
<item quantity="one">%d сообщение</item>
<item quantity="few">%d сообщения</item>
<item quantity="few">%d сообщений</item>
<item quantity="many">%d сообщений</item>
<item quantity="other">%d сообщений</item>
</plurals>
@@ -225,7 +225,7 @@
<string name="groups_reveal_visible_revealed_by_contact">Связь между контактами видна группе (раскрывается %s)</string>
<string name="groups_reveal_invisible">Связь между контактами не видна группе</string>
<!--Forums-->
<string name="no_forums">Нет форумов для отображения\n\nКоснитесь значка + для создания форума, или попросите ваши контакты поделиться с вами форумами</string>
<string name="no_forums">Нет форумов для отображения\n\nTКоснитесь значка + для создания форума, или попросите ваши контакты поделиться с вами форумами</string>
<string name="create_forum_title">Создать форум</string>
<string name="choose_forum_hint">Придумайте имя для вашего форума</string>
<string name="create_forum_button">Создать форум</string>
@@ -283,12 +283,12 @@
<string name="blogs_write_blog_post">Написать в блоге</string>
<string name="blogs_write_blog_post_body_hint">Напишите свой пост в блоге</string>
<string name="blogs_publish_blog_post">Опубликовать</string>
<string name="blogs_blog_post_created">Пост создан</string>
<string name="blogs_blog_post_received">Появился новый пост в блоге</string>
<string name="blogs_blog_post_created">Запись блога создана</string>
<string name="blogs_blog_post_received">Появилась новая запись блога</string>
<string name="blogs_blog_post_scroll_to">Перейти</string>
<string name="blogs_feed_empty_state">Нет постов для отображения\n\nПосты ваших контактов и блогов, на которые вы подписаны, появятся здесь\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>
@@ -318,7 +318,7 @@
<string name="blogs_rss_feeds_manage_author">Автор:</string>
<string name="blogs_rss_feeds_manage_updated">Последнее обновление:</string>
<string name="blogs_rss_remove_feed">Удалить RSS-канал</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_delete_error">Не удалось удалить RSS-канал!</string>
<string name="blogs_rss_feeds_manage_empty_state">Нет RSS-лент для отображения\n\nКоснитесь значка + для импорта ленты</string>
@@ -356,8 +356,8 @@
<string name="uninstall_setting_summary">Это потребует вашего подтверждения</string>
<!--Settings Notifications-->
<string name="notification_settings_title">Уведомления</string>
<string name="notify_private_messages_setting_title">Личные сообщения</string>
<string name="notify_private_messages_setting_summary">Показывать оповещения для личных сообщений</string>
<string name="notify_private_messages_setting_title">Приватные сообщения</string>
<string name="notify_private_messages_setting_summary">Показывать оповещения для приватных сообщений</string>
<string name="notify_private_messages_setting_summary_26">Настройка оповещений для личных сообщений</string>
<string name="notify_group_messages_setting_title">Групповые сообщения</string>
<string name="notify_group_messages_setting_summary">Показывать оповещения для групповых сообщений</string>

View File

@@ -131,4 +131,13 @@
android:targetPackage="@string/app_package"/>
</Preference>
<Preference
android:key="pref_key_speed_test"
android:title="Test polling impact on bandwith">
<intent
android:targetClass="org.briarproject.briar.android.test.PollingTestActivity"
android:targetPackage="@string/app_package"/>
</Preference>
</PreferenceScreen>

View File

@@ -32,7 +32,7 @@ public interface BlogManager {
int MINOR_VERSION = 0;
/**
* Adds the given {@link Blog}.
* Adds the given {@link Blog).}
*/
void addBlog(Blog b) throws DbException;