mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Compare commits
28 Commits
alpha-1.5.
...
beta-1.5.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f1a97f62d | ||
|
|
7a33d26533 | ||
|
|
f2c85f37be | ||
|
|
8e3fa872fd | ||
|
|
0d1e81ebdb | ||
|
|
bded4e7bc8 | ||
|
|
bf1a5cf218 | ||
|
|
dd7a638984 | ||
|
|
942222131e | ||
|
|
643757e407 | ||
|
|
7c530ad7a3 | ||
|
|
23b2dfa4a8 | ||
|
|
ce10e6770f | ||
|
|
b88dbee881 | ||
|
|
0ca21ad4c0 | ||
|
|
a14f62dcc3 | ||
|
|
f0c1ebcc1b | ||
|
|
4a4b04bec3 | ||
|
|
6f57ec8281 | ||
|
|
0eb0bbdc99 | ||
|
|
76344344d2 | ||
|
|
624f11a61f | ||
|
|
fbc32830bd | ||
|
|
145117a1dc | ||
|
|
6ed55bcd7d | ||
|
|
f8015272f4 | ||
|
|
462f57c966 | ||
|
|
8d20c5d8b8 |
@@ -11,10 +11,10 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 16
|
minSdkVersion 21
|
||||||
targetSdkVersion 31
|
targetSdkVersion 31
|
||||||
versionCode 10500
|
versionCode 10503
|
||||||
versionName "1.5.0"
|
versionName "1.5.3"
|
||||||
consumerProguardFiles 'proguard-rules.txt'
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
@@ -40,7 +40,7 @@ configurations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api 'org.briarproject:dont-kill-me-lib:0.2.6'
|
api 'org.briarproject:dont-kill-me-lib:0.2.7'
|
||||||
|
|
||||||
// In theory this dependency shouldn't be needed, but without it Android Studio's linter will
|
// In theory this dependency shouldn't be needed, but without it Android Studio's linter will
|
||||||
// complain about unresolved symbols for bramble-api test classes in bramble-android tests,
|
// complain about unresolved symbols for bramble-api test classes in bramble-android tests,
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
package org.briarproject.android.dontkillmelib.wakelock;
|
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import dagger.Module;
|
|
||||||
import dagger.Provides;
|
|
||||||
|
|
||||||
@Module
|
|
||||||
public class AndroidWakeLockModule {
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
AndroidWakeLockManager provideWakeLockManager(
|
|
||||||
AndroidWakeLockManagerImpl wakeLockManager) {
|
|
||||||
return wakeLockManager;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
package org.briarproject.bramble;
|
package org.briarproject.bramble;
|
||||||
|
|
||||||
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockModule;
|
|
||||||
import org.briarproject.bramble.battery.AndroidBatteryModule;
|
import org.briarproject.bramble.battery.AndroidBatteryModule;
|
||||||
import org.briarproject.bramble.io.DnsModule;
|
import org.briarproject.bramble.io.DnsModule;
|
||||||
import org.briarproject.bramble.network.AndroidNetworkModule;
|
import org.briarproject.bramble.network.AndroidNetworkModule;
|
||||||
|
import org.briarproject.bramble.plugin.tor.CircumventionModule;
|
||||||
import org.briarproject.bramble.reporting.ReportingModule;
|
import org.briarproject.bramble.reporting.ReportingModule;
|
||||||
import org.briarproject.bramble.socks.SocksModule;
|
import org.briarproject.bramble.socks.SocksModule;
|
||||||
import org.briarproject.bramble.system.AndroidSystemModule;
|
import org.briarproject.bramble.system.AndroidSystemModule;
|
||||||
import org.briarproject.bramble.system.AndroidTaskSchedulerModule;
|
import org.briarproject.bramble.system.AndroidTaskSchedulerModule;
|
||||||
|
import org.briarproject.bramble.system.AndroidWakeLockModule;
|
||||||
import org.briarproject.bramble.system.AndroidWakefulIoExecutorModule;
|
import org.briarproject.bramble.system.AndroidWakefulIoExecutorModule;
|
||||||
import org.briarproject.bramble.system.DefaultThreadFactoryModule;
|
import org.briarproject.bramble.system.DefaultThreadFactoryModule;
|
||||||
import org.briarproject.onionwrapper.CircumventionModule;
|
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import javax.annotation.Nullable;
|
|||||||
import javax.annotation.concurrent.GuardedBy;
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static org.briarproject.bramble.util.IoUtils.deleteFileOrDir;
|
import static org.briarproject.bramble.util.IoUtils.deleteFileOrDir;
|
||||||
@@ -105,15 +104,11 @@ class AndroidAccountManager extends AccountManagerImpl
|
|||||||
}
|
}
|
||||||
files.add(appContext.getFilesDir());
|
files.add(appContext.getFilesDir());
|
||||||
addIfNotNull(files, appContext.getExternalCacheDir());
|
addIfNotNull(files, appContext.getExternalCacheDir());
|
||||||
if (SDK_INT >= 19) {
|
for (File file : appContext.getExternalCacheDirs()) {
|
||||||
for (File file : appContext.getExternalCacheDirs()) {
|
addIfNotNull(files, file);
|
||||||
addIfNotNull(files, file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (SDK_INT >= 21) {
|
for (File file : appContext.getExternalMediaDirs()) {
|
||||||
for (File file : appContext.getExternalMediaDirs()) {
|
addIfNotNull(files, file);
|
||||||
addIfNotNull(files, file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Clear the cache directory but don't delete it
|
// Clear the cache directory but don't delete it
|
||||||
File cacheDir = appContext.getCacheDir();
|
File cacheDir = appContext.getCacheDir();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.plugin.bluetooth;
|
package org.briarproject.bramble.plugin.bluetooth;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
@@ -49,7 +50,6 @@ import static android.bluetooth.BluetoothAdapter.STATE_ON;
|
|||||||
import static android.bluetooth.BluetoothDevice.ACTION_FOUND;
|
import static android.bluetooth.BluetoothDevice.ACTION_FOUND;
|
||||||
import static android.bluetooth.BluetoothDevice.DEVICE_TYPE_LE;
|
import static android.bluetooth.BluetoothDevice.DEVICE_TYPE_LE;
|
||||||
import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
|
import static android.bluetooth.BluetoothDevice.EXTRA_DEVICE;
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static java.util.Collections.shuffle;
|
import static java.util.Collections.shuffle;
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
@@ -60,6 +60,7 @@ import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
|
|||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
class AndroidBluetoothPlugin extends
|
class AndroidBluetoothPlugin extends
|
||||||
AbstractBluetoothPlugin<BluetoothSocket, BluetoothServerSocket> {
|
AbstractBluetoothPlugin<BluetoothSocket, BluetoothServerSocket> {
|
||||||
|
|
||||||
@@ -253,7 +254,7 @@ class AndroidBluetoothPlugin extends
|
|||||||
} else if (ACTION_FOUND.equals(action)) {
|
} else if (ACTION_FOUND.equals(action)) {
|
||||||
BluetoothDevice d = i.getParcelableExtra(EXTRA_DEVICE);
|
BluetoothDevice d = i.getParcelableExtra(EXTRA_DEVICE);
|
||||||
// Ignore Bluetooth LE devices
|
// Ignore Bluetooth LE devices
|
||||||
if (SDK_INT < 18 || d.getType() != DEVICE_TYPE_LE) {
|
if (d.getType() != DEVICE_TYPE_LE) {
|
||||||
String address = d.getAddress();
|
String address = d.getAddress();
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Discovered " +
|
LOG.info("Discovered " +
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.briarproject.bramble.plugin.tcp;
|
package org.briarproject.bramble.plugin.tcp;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.LinkAddress;
|
import android.net.LinkAddress;
|
||||||
@@ -37,7 +36,6 @@ import javax.net.SocketFactory;
|
|||||||
import static android.content.Context.CONNECTIVITY_SERVICE;
|
import static android.content.Context.CONNECTIVITY_SERVICE;
|
||||||
import static android.content.Context.WIFI_SERVICE;
|
import static android.content.Context.WIFI_SERVICE;
|
||||||
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Collections.list;
|
import static java.util.Collections.list;
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
@@ -118,7 +116,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
// If there's no wifi IPv4 address, we might be a client on an
|
// If there's no wifi IPv4 address, we might be a client on an
|
||||||
// IPv6-only wifi network. We can only detect this on API 21+
|
// IPv6-only wifi network. We can only detect this on API 21+
|
||||||
if (wifi == null) {
|
if (wifi == null) {
|
||||||
return SDK_INT >= 21 ? getWifiClientIpv6Address() : null;
|
return getWifiClientIpv6Address();
|
||||||
}
|
}
|
||||||
// Use the wifi IPv4 address to determine which interface's IPv6
|
// Use the wifi IPv4 address to determine which interface's IPv6
|
||||||
// address we should return (if the interface has a suitable address)
|
// address we should return (if the interface has a suitable address)
|
||||||
@@ -172,7 +170,6 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
* Returns a link-local IPv6 address for the wifi client interface, or null
|
* Returns a link-local IPv6 address for the wifi client interface, or null
|
||||||
* if there's no such interface or it doesn't have a suitable address.
|
* if there's no such interface or it doesn't have a suitable address.
|
||||||
*/
|
*/
|
||||||
@TargetApi(21)
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private InetAddress getWifiClientIpv6Address() {
|
private InetAddress getWifiClientIpv6Address() {
|
||||||
// https://issuetracker.google.com/issues/175055271
|
// https://issuetracker.google.com/issues/175055271
|
||||||
@@ -234,7 +231,6 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
// On API 21 and later, a socket that is not created with the wifi
|
// On API 21 and later, a socket that is not created with the wifi
|
||||||
// network's socket factory may try to connect via another network
|
// network's socket factory may try to connect via another network
|
||||||
private SocketFactory getSocketFactory() {
|
private SocketFactory getSocketFactory() {
|
||||||
if (SDK_INT < 21) return SocketFactory.getDefault();
|
|
||||||
// https://issuetracker.google.com/issues/175055271
|
// https://issuetracker.google.com/issues/175055271
|
||||||
try {
|
try {
|
||||||
for (Network net : connectivityManager.getAllNetworks()) {
|
for (Network net : connectivityManager.getAllNetworks()) {
|
||||||
@@ -302,7 +298,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
Pair<InetAddress, Boolean> wifi = getWifiIpv4Address();
|
Pair<InetAddress, Boolean> wifi = getWifiIpv4Address();
|
||||||
// If there's no wifi IPv4 address, we might be a client on an
|
// If there's no wifi IPv4 address, we might be a client on an
|
||||||
// IPv6-only wifi network. We can only detect this on API 21+
|
// IPv6-only wifi network. We can only detect this on API 21+
|
||||||
if (wifi == null && SDK_INT >= 21) {
|
if (wifi == null) {
|
||||||
InetAddress ipv6 = getWifiClientIpv6Address();
|
InetAddress ipv6 = getWifiClientIpv6Address();
|
||||||
if (ipv6 != null) return new Pair<>(ipv6, false);
|
if (ipv6 != null) return new Pair<>(ipv6, false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ import org.briarproject.bramble.api.plugin.TorControlPort;
|
|||||||
import org.briarproject.bramble.api.plugin.TorDirectory;
|
import org.briarproject.bramble.api.plugin.TorDirectory;
|
||||||
import org.briarproject.bramble.api.plugin.TorSocksPort;
|
import org.briarproject.bramble.api.plugin.TorSocksPort;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
|
||||||
import org.briarproject.bramble.api.system.WakefulIoExecutor;
|
import org.briarproject.bramble.api.system.WakefulIoExecutor;
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.onionwrapper.AndroidTorWrapper;
|
import org.briarproject.onionwrapper.AndroidTorWrapper;
|
||||||
import org.briarproject.onionwrapper.CircumventionProvider;
|
import org.briarproject.onionwrapper.CircumventionProvider;
|
||||||
|
import org.briarproject.onionwrapper.LocationUtils;
|
||||||
import org.briarproject.onionwrapper.TorWrapper;
|
import org.briarproject.onionwrapper.TorWrapper;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
package org.briarproject.bramble.system;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.Application;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.telephony.TelephonyManager;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import static android.content.Context.TELEPHONY_SERVICE;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
|
||||||
class AndroidLocationUtils implements LocationUtils {
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(AndroidLocationUtils.class.getName());
|
|
||||||
|
|
||||||
private final Context appContext;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
AndroidLocationUtils(Application app) {
|
|
||||||
appContext = app.getApplicationContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This guesses the current country from the first of these sources that
|
|
||||||
* succeeds (also in order of likelihood of being correct):
|
|
||||||
*
|
|
||||||
* <ul>
|
|
||||||
* <li>Phone network. This works even when no SIM card is inserted, or a
|
|
||||||
* foreign SIM card is inserted.</li>
|
|
||||||
* <li>SIM card. This is only an heuristic and assumes the user is not
|
|
||||||
* roaming.</li>
|
|
||||||
* <li>User locale. This is an even worse heuristic.</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* Note: this is very similar to <a href="https://android.googlesource.com/platform/frameworks/base/+/cd92588%5E/location/java/android/location/CountryDetector.java">
|
|
||||||
* this API</a> except it seems that Google doesn't want us to use it for
|
|
||||||
* some reason - both that class and {@code Context.COUNTRY_CODE} are
|
|
||||||
* annotated {@code @hide}.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@SuppressLint("DefaultLocale")
|
|
||||||
public String getCurrentCountry() {
|
|
||||||
String countryCode = getCountryFromPhoneNetwork();
|
|
||||||
if (!TextUtils.isEmpty(countryCode)) return countryCode.toUpperCase();
|
|
||||||
LOG.info("Falling back to SIM card country");
|
|
||||||
countryCode = getCountryFromSimCard();
|
|
||||||
if (!TextUtils.isEmpty(countryCode)) return countryCode.toUpperCase();
|
|
||||||
LOG.info("Falling back to user-defined locale");
|
|
||||||
return Locale.getDefault().getCountry();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getCountryFromPhoneNetwork() {
|
|
||||||
Object o = appContext.getSystemService(TELEPHONY_SERVICE);
|
|
||||||
TelephonyManager tm = (TelephonyManager) o;
|
|
||||||
return tm == null ? "" : tm.getNetworkCountryIso();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getCountryFromSimCard() {
|
|
||||||
Object o = appContext.getSystemService(TELEPHONY_SERVICE);
|
|
||||||
TelephonyManager tm = (TelephonyManager) o;
|
|
||||||
return tm == null ? "" : tm.getSimCountryIso();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -31,8 +31,6 @@ import static android.provider.Settings.Secure.ANDROID_ID;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
|
class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
|
||||||
|
|
||||||
private static final int SEED_LENGTH = 32;
|
|
||||||
|
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -72,27 +70,6 @@ class AndroidSecureRandomProvider extends UnixSecureRandomProvider {
|
|||||||
// Silence strict mode
|
// Silence strict mode
|
||||||
StrictMode.ThreadPolicy tp = StrictMode.allowThreadDiskWrites();
|
StrictMode.ThreadPolicy tp = StrictMode.allowThreadDiskWrites();
|
||||||
super.writeSeed();
|
super.writeSeed();
|
||||||
if (SDK_INT <= 18) applyOpenSslFix();
|
|
||||||
StrictMode.setThreadPolicy(tp);
|
StrictMode.setThreadPolicy(tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Based on https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html
|
|
||||||
private void applyOpenSslFix() {
|
|
||||||
byte[] seed = new UnixSecureRandomSpi().engineGenerateSeed(
|
|
||||||
SEED_LENGTH);
|
|
||||||
try {
|
|
||||||
// Seed the OpenSSL PRNG
|
|
||||||
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
|
||||||
.getMethod("RAND_seed", byte[].class)
|
|
||||||
.invoke(null, (Object) seed);
|
|
||||||
// Mix the output of the Linux PRNG into the OpenSSL PRNG
|
|
||||||
int bytesRead = (Integer) Class.forName(
|
|
||||||
"org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
|
||||||
.getMethod("RAND_load_file", String.class, long.class)
|
|
||||||
.invoke(null, "/dev/urandom", 1024);
|
|
||||||
if (bytesRead != 1024) throw new IOException();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new SecurityException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package org.briarproject.bramble.system;
|
package org.briarproject.bramble.system;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.event.EventExecutor;
|
import org.briarproject.bramble.api.event.EventExecutor;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
|
||||||
import org.briarproject.bramble.api.system.ResourceProvider;
|
import org.briarproject.bramble.api.system.ResourceProvider;
|
||||||
import org.briarproject.bramble.api.system.SecureRandomProvider;
|
import org.briarproject.bramble.api.system.SecureRandomProvider;
|
||||||
|
import org.briarproject.onionwrapper.AndroidLocationUtilsFactory;
|
||||||
|
import org.briarproject.onionwrapper.LocationUtils;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.RejectedExecutionHandler;
|
import java.util.concurrent.RejectedExecutionHandler;
|
||||||
@@ -45,8 +48,9 @@ public class AndroidSystemModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
LocationUtils provideLocationUtils(AndroidLocationUtils locationUtils) {
|
@Singleton
|
||||||
return locationUtils;
|
LocationUtils provideLocationUtils(Application app) {
|
||||||
|
return AndroidLocationUtilsFactory.createAndroidLocationUtils(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package org.briarproject.bramble.system;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
|
||||||
|
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager;
|
||||||
|
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManagerFactory;
|
||||||
|
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class AndroidWakeLockModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
AndroidWakeLockManager provideWakeLockManager(Application app,
|
||||||
|
ScheduledExecutorService scheduledExecutorService) {
|
||||||
|
return AndroidWakeLockManagerFactory.createAndroidWakeLockManager(app,
|
||||||
|
scheduledExecutorService);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,14 +11,10 @@ import org.briarproject.bramble.api.Pair;
|
|||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Scanner;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@@ -29,7 +25,6 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
|||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static android.os.Process.myPid;
|
import static android.os.Process.myPid;
|
||||||
import static android.os.Process.myUid;
|
import static android.os.Process.myUid;
|
||||||
import static java.lang.Runtime.getRuntime;
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
import static org.briarproject.nullsafety.NullSafety.requireNonNull;
|
import static org.briarproject.nullsafety.NullSafety.requireNonNull;
|
||||||
|
|
||||||
@@ -43,14 +38,7 @@ public class AndroidUtils {
|
|||||||
private static final String STORED_LOGCAT = "dev-logcat";
|
private static final String STORED_LOGCAT = "dev-logcat";
|
||||||
|
|
||||||
public static Collection<String> getSupportedArchitectures() {
|
public static Collection<String> getSupportedArchitectures() {
|
||||||
List<String> abis = new ArrayList<>();
|
return asList(Build.SUPPORTED_ABIS);
|
||||||
if (SDK_INT >= 21) {
|
|
||||||
abis.addAll(asList(Build.SUPPORTED_ABIS));
|
|
||||||
} else {
|
|
||||||
abis.add(Build.CPU_ABI);
|
|
||||||
if (Build.CPU_ABI2 != null) abis.add(Build.CPU_ABI2);
|
|
||||||
}
|
|
||||||
return abis;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasBtConnectPermission(Context ctx) {
|
public static boolean hasBtConnectPermission(Context ctx) {
|
||||||
@@ -136,19 +124,6 @@ public class AndroidUtils {
|
|||||||
return new String[] {"image/jpeg", "image/png", "image/gif"};
|
return new String[] {"image/jpeg", "image/png", "image/gif"};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static String getSystemProperty(String propName) {
|
|
||||||
try {
|
|
||||||
Process p = getRuntime().exec("getprop " + propName);
|
|
||||||
Scanner s = new Scanner(p.getInputStream());
|
|
||||||
String line = s.nextLine();
|
|
||||||
s.close();
|
|
||||||
return line;
|
|
||||||
} catch (SecurityException | IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isUiThread() {
|
public static boolean isUiThread() {
|
||||||
return Looper.myLooper() == Looper.getMainLooper();
|
return Looper.myLooper() == Looper.getMainLooper();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,6 +87,10 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
|
|||||||
File potatoFile = new File(potatoDir, "file");
|
File potatoFile = new File(potatoDir, "file");
|
||||||
File filesDir = new File(testDir, "filesDir");
|
File filesDir = new File(testDir, "filesDir");
|
||||||
File externalCacheDir = new File(testDir, "externalCacheDir");
|
File externalCacheDir = new File(testDir, "externalCacheDir");
|
||||||
|
File externalCacheDir1 = new File(testDir, "externalCacheDir1");
|
||||||
|
File externalCacheDir2 = new File(testDir, "externalCacheDir2");
|
||||||
|
File externalMediaDir1 = new File(testDir, "externalMediaDir1");
|
||||||
|
File externalMediaDir2 = new File(testDir, "externalMediaDir2");
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(prefs).edit();
|
oneOf(prefs).edit();
|
||||||
@@ -109,6 +113,12 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(cacheDir));
|
will(returnValue(cacheDir));
|
||||||
oneOf(app).getExternalCacheDir();
|
oneOf(app).getExternalCacheDir();
|
||||||
will(returnValue(externalCacheDir));
|
will(returnValue(externalCacheDir));
|
||||||
|
oneOf(app).getExternalCacheDirs();
|
||||||
|
will(returnValue(
|
||||||
|
new File[] {externalCacheDir1, externalCacheDir2}));
|
||||||
|
oneOf(app).getExternalMediaDirs();
|
||||||
|
will(returnValue(
|
||||||
|
new File[] {externalMediaDir1, externalMediaDir2}));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertTrue(dbDir.mkdirs());
|
assertTrue(dbDir.mkdirs());
|
||||||
@@ -125,6 +135,10 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
|
|||||||
assertTrue(potatoFile.createNewFile());
|
assertTrue(potatoFile.createNewFile());
|
||||||
assertTrue(filesDir.mkdirs());
|
assertTrue(filesDir.mkdirs());
|
||||||
assertTrue(externalCacheDir.mkdirs());
|
assertTrue(externalCacheDir.mkdirs());
|
||||||
|
assertTrue(externalCacheDir1.mkdirs());
|
||||||
|
assertTrue(externalCacheDir2.mkdirs());
|
||||||
|
assertTrue(externalMediaDir1.mkdirs());
|
||||||
|
assertTrue(externalMediaDir2.mkdirs());
|
||||||
|
|
||||||
accountManager.deleteAccount();
|
accountManager.deleteAccount();
|
||||||
|
|
||||||
@@ -142,6 +156,10 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
|
|||||||
assertFalse(potatoFile.exists());
|
assertFalse(potatoFile.exists());
|
||||||
assertFalse(filesDir.exists());
|
assertFalse(filesDir.exists());
|
||||||
assertFalse(externalCacheDir.exists());
|
assertFalse(externalCacheDir.exists());
|
||||||
|
assertFalse(externalCacheDir1.exists());
|
||||||
|
assertFalse(externalCacheDir2.exists());
|
||||||
|
assertFalse(externalMediaDir1.exists());
|
||||||
|
assertFalse(externalMediaDir2.exists());
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ dependencyVerification {
|
|||||||
'cglib:cglib:3.2.8:cglib-3.2.8.jar:3f64de999ecc5595dc84ca8ff0879d8a34c8623f9ef3c517a53ed59023fcb9db',
|
'cglib:cglib:3.2.8:cglib-3.2.8.jar:3f64de999ecc5595dc84ca8ff0879d8a34c8623f9ef3c517a53ed59023fcb9db',
|
||||||
'com.google.code.findbugs:annotations:3.0.1:annotations-3.0.1.jar:6b47ff0a6de0ce17cbedc3abb0828ca5bce3009d53ea47b3723ff023c4742f79',
|
'com.google.code.findbugs:annotations:3.0.1:annotations-3.0.1.jar:6b47ff0a6de0ce17cbedc3abb0828ca5bce3009d53ea47b3723ff023c4742f79',
|
||||||
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
|
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
|
||||||
'com.google.dagger:dagger-compiler:2.43.2:dagger-compiler-2.43.2.jar:298c020ee6ed2f4cc651ebbfdb7f8de329b07c44b618d65be117846a850e2a03',
|
'com.google.dagger:dagger-compiler:2.45:dagger-compiler-2.45.jar:5617dfb994537dba5b41f3744a6dd13ec3cd99789c065e0d5c6fa9f21cf7ca25',
|
||||||
'com.google.dagger:dagger-producers:2.43.2:dagger-producers-2.43.2.jar:e7f5d9ffc85d48a49c8e22e02833d418f7ccad5d7512f529964db5127ab915ff',
|
'com.google.dagger:dagger-producers:2.45:dagger-producers-2.45.jar:a05abb4c3ccf6bb0f056bdcb5ef973898ecf172952ab5948a824aeea6c86ecaa',
|
||||||
'com.google.dagger:dagger-spi:2.43.2:dagger-spi-2.43.2.jar:3bae8d9dadeaaa5927da6f094389a560c12c05fec3d2711d2fa79292c7a7d7ad',
|
'com.google.dagger:dagger-spi:2.45:dagger-spi-2.45.jar:7cd6f0b09d88e64a9c97bc80e544ab8ac8fdee9301754413585a74cf64222b27',
|
||||||
'com.google.dagger:dagger:2.43.2:dagger-2.43.2.jar:c89681f7cbbf8c527bf4ac2748515d617fdb54a1d425c08d914fdc28192b5fe4',
|
'com.google.dagger:dagger:2.45:dagger-2.45.jar:f011cae7d2c0fb7ea17c34e05bc10e768b1081a5892ad019cf1fdb0e125c49c1',
|
||||||
'com.google.devtools.ksp:symbol-processing-api:1.7.0-1.0.6:symbol-processing-api-1.7.0-1.0.6.jar:adc29417be5ca9ff42118105fea4e36d9ef44987abfc41432309371a60198941',
|
'com.google.devtools.ksp:symbol-processing-api:1.7.0-1.0.6:symbol-processing-api-1.7.0-1.0.6.jar:adc29417be5ca9ff42118105fea4e36d9ef44987abfc41432309371a60198941',
|
||||||
'com.google.errorprone:error_prone_annotations:2.7.1:error_prone_annotations-2.7.1.jar:cd5257c08a246cf8628817ae71cb822be192ef91f6881ca4a3fcff4f1de1cff3',
|
'com.google.errorprone:error_prone_annotations:2.7.1:error_prone_annotations-2.7.1.jar:cd5257c08a246cf8628817ae71cb822be192ef91f6881ca4a3fcff4f1de1cff3',
|
||||||
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
|
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
|
||||||
@@ -17,6 +17,7 @@ dependencyVerification {
|
|||||||
'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava:listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99',
|
'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava:listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99',
|
||||||
'com.google.j2objc:j2objc-annotations:1.3:j2objc-annotations-1.3.jar:21af30c92267bd6122c0e0b4d20cccb6641a37eaf956c6540ec471d584e64a7b',
|
'com.google.j2objc:j2objc-annotations:1.3:j2objc-annotations-1.3.jar:21af30c92267bd6122c0e0b4d20cccb6641a37eaf956c6540ec471d584e64a7b',
|
||||||
'com.squareup:javapoet:1.13.0:javapoet-1.13.0.jar:4c7517e848a71b36d069d12bb3bf46a70fd4cda3105d822b0ed2e19c00b69291',
|
'com.squareup:javapoet:1.13.0:javapoet-1.13.0.jar:4c7517e848a71b36d069d12bb3bf46a70fd4cda3105d822b0ed2e19c00b69291',
|
||||||
|
'com.squareup:kotlinpoet:1.11.0:kotlinpoet-1.11.0.jar:2887ada1ca03dd83baa2758640d87e840d1907564db0ef88d2289c868a980492',
|
||||||
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
|
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
|
||||||
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||||
'junit:junit:4.13.2:junit-4.13.2.jar:8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3',
|
'junit:junit:4.13.2:junit-4.13.2.jar:8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3',
|
||||||
@@ -24,12 +25,12 @@ dependencyVerification {
|
|||||||
'net.jcip:jcip-annotations:1.0:jcip-annotations-1.0.jar:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0',
|
'net.jcip:jcip-annotations:1.0:jcip-annotations-1.0.jar:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0',
|
||||||
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
|
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
|
||||||
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
|
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
|
||||||
'org.briarproject:dont-kill-me-lib:0.2.6:dont-kill-me-lib-0.2.6.aar:8a4cc201143227c0865c2edfba035f71109bf02e1ab26444fa3e42d3c569960f',
|
'org.briarproject:dont-kill-me-lib:0.2.7:dont-kill-me-lib-0.2.7.aar:8a9540941fd927e1c127096a7a9b4aa61ce2f2965d2e24f849be92f9e57213c4',
|
||||||
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
|
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
|
||||||
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
|
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
|
||||||
'org.briarproject:obfs4proxy-android:0.0.14-tor2:obfs4proxy-android-0.0.14-tor2.jar:a0a93770d6760ce57d9dbd31cc7177687374e00c3361dac22ab75e3b6e0f289e',
|
'org.briarproject:obfs4proxy-android:0.0.14-tor2:obfs4proxy-android-0.0.14-tor2.jar:a0a93770d6760ce57d9dbd31cc7177687374e00c3361dac22ab75e3b6e0f289e',
|
||||||
'org.briarproject:onionwrapper-android:0.0.1:onionwrapper-android-0.0.1.aar:959115946586daa090f057645cf75992407a59025e221c3bf88d2aa930ef3919',
|
'org.briarproject:onionwrapper-android:0.0.2:onionwrapper-android-0.0.2.aar:d196f1fe5d8b750866ea09d80509716aae7645d39b2c85433994718dbebeb4d1',
|
||||||
'org.briarproject:onionwrapper-core:0.0.1:onionwrapper-core-0.0.1.jar:a1937506b00ee6620e909a500e5d004be81f94a6f7d7c898e1a9e841a8ae8a2a',
|
'org.briarproject:onionwrapper-core:0.0.2:onionwrapper-core-0.0.2.jar:7038e960c9e59803f0e2c19444dbb5214cd99e5a7463c0a01c45318e07a0eb80',
|
||||||
'org.briarproject:snowflake-android:2.5.1:snowflake-android-2.5.1.jar:88ec81c17b1b6fa884d06839dec0330e328b45c89f88c970a213ce91ca8eac87',
|
'org.briarproject:snowflake-android:2.5.1:snowflake-android-2.5.1.jar:88ec81c17b1b6fa884d06839dec0330e328b45c89f88c970a213ce91ca8eac87',
|
||||||
'org.briarproject:tor-android:0.4.7.13-2:tor-android-0.4.7.13-2.jar:453fd463b234a2104edd7f0d02d0649cbb5c5efbe47a76df3828f55a3f90f8b5',
|
'org.briarproject:tor-android:0.4.7.13-2:tor-android-0.4.7.13-2.jar:453fd463b234a2104edd7f0d02d0649cbb5c5efbe47a76df3828f55a3f90f8b5',
|
||||||
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
||||||
@@ -41,6 +42,7 @@ dependencyVerification {
|
|||||||
'org.jacoco:org.jacoco.ant:0.8.7:org.jacoco.ant-0.8.7.jar:97ca96a382c3f23a44d8eb4c4e6c3742a30cb8005774a76ced0fc4806ce49605',
|
'org.jacoco:org.jacoco.ant:0.8.7:org.jacoco.ant-0.8.7.jar:97ca96a382c3f23a44d8eb4c4e6c3742a30cb8005774a76ced0fc4806ce49605',
|
||||||
'org.jacoco:org.jacoco.core:0.8.7:org.jacoco.core-0.8.7.jar:ad7739b5fb5969aa1a8aead3d74ed54dc82ed012f1f10f336bd1b96e71c1a13c',
|
'org.jacoco:org.jacoco.core:0.8.7:org.jacoco.core-0.8.7.jar:ad7739b5fb5969aa1a8aead3d74ed54dc82ed012f1f10f336bd1b96e71c1a13c',
|
||||||
'org.jacoco:org.jacoco.report:0.8.7:org.jacoco.report-0.8.7.jar:cc89258623700a6c932592153cb528785876b6da183d5431f97efbba6f020e5b',
|
'org.jacoco:org.jacoco.report:0.8.7:org.jacoco.report-0.8.7.jar:cc89258623700a6c932592153cb528785876b6da183d5431f97efbba6f020e5b',
|
||||||
|
'org.jetbrains.kotlin:kotlin-reflect:1.6.10:kotlin-reflect-1.6.10.jar:3277ac102ae17aad10a55abec75ff5696c8d109790396434b496e75087854203',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-common:1.7.0:kotlin-stdlib-common-1.7.0.jar:59c6ff64fe9a6604afce03e8aaa75f83586c6030ac71fb0b34ee7cdefed3618f',
|
'org.jetbrains.kotlin:kotlin-stdlib-common:1.7.0:kotlin-stdlib-common-1.7.0.jar:59c6ff64fe9a6604afce03e8aaa75f83586c6030ac71fb0b34ee7cdefed3618f',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-common:1.8.0:kotlin-stdlib-common-1.8.0.jar:78ef93b59e603cc0fe51def9bd4c037b07cbace3b3b7806d1a490a42bc1f4cb2',
|
'org.jetbrains.kotlin:kotlin-stdlib-common:1.8.0:kotlin-stdlib-common-1.8.0.jar:78ef93b59e603cc0fe51def9bd4c037b07cbace3b3b7806d1a490a42bc1f4cb2',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.0:kotlin-stdlib-jdk7-1.7.0.jar:07e91be9b2ca20672d2bdb7e181b766e73453a2da13492b5ddaee8fa47aea239',
|
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.0:kotlin-stdlib-jdk7-1.7.0.jar:07e91be9b2ca20672d2bdb7e181b766e73453a2da13492b5ddaee8fa47aea239',
|
||||||
|
|||||||
@@ -54,6 +54,38 @@ public interface CryptoComponent {
|
|||||||
KeyPair ourKeyPair, byte[]... inputs)
|
KeyPair ourKeyPair, byte[]... inputs)
|
||||||
throws GeneralSecurityException;
|
throws GeneralSecurityException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derives a shared secret from two static and two ephemeral key pairs.
|
||||||
|
* <p>
|
||||||
|
* Do not use this method for new protocols. The shared secret can be
|
||||||
|
* re-derived using the ephemeral public keys and both static private
|
||||||
|
* keys, so keys derived from the shared secret should not be used if
|
||||||
|
* forward secrecy is required. Use {@link #deriveSharedSecret(String,
|
||||||
|
* PublicKey, PublicKey, KeyPair, KeyPair, boolean, byte[]...)} instead.
|
||||||
|
* <p>
|
||||||
|
* TODO: Remove this after a reasonable migration period (added 2023-03-10).
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* @param label A namespaced label indicating the purpose of this shared
|
||||||
|
* secret, to prevent it from being repurposed or colliding with a shared
|
||||||
|
* secret derived for another purpose
|
||||||
|
* @param theirStaticPublicKey The static public key of the remote party
|
||||||
|
* @param theirEphemeralPublicKey The ephemeral public key of the remote
|
||||||
|
* party
|
||||||
|
* @param ourStaticKeyPair The static key pair of the local party
|
||||||
|
* @param ourEphemeralKeyPair The ephemeral key pair of the local party
|
||||||
|
* @param alice True if the local party is Alice
|
||||||
|
* @param inputs Additional inputs that will be included in the
|
||||||
|
* derivation of the shared secret
|
||||||
|
* @return The shared secret
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
SecretKey deriveSharedSecretBadly(String label,
|
||||||
|
PublicKey theirStaticPublicKey, PublicKey theirEphemeralPublicKey,
|
||||||
|
KeyPair ourStaticKeyPair, KeyPair ourEphemeralKeyPair,
|
||||||
|
boolean alice, byte[]... inputs)
|
||||||
|
throws GeneralSecurityException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derives a shared secret from two static and two ephemeral key pairs.
|
* Derives a shared secret from two static and two ephemeral key pairs.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -32,8 +32,15 @@ public interface RecordReader {
|
|||||||
* 'accept' or 'ignore' predicates
|
* 'accept' or 'ignore' predicates
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
Record readRecord(Predicate<Record> accept, Predicate<Record> ignore)
|
Record readRecord(RecordPredicate accept, RecordPredicate ignore)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
void close() throws IOException;
|
void close() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface that reifies the generic interface {@code Predicate<Record>}
|
||||||
|
* for easier testing.
|
||||||
|
*/
|
||||||
|
interface RecordPredicate extends Predicate<Record> {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
package org.briarproject.bramble.api.system;
|
|
||||||
|
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
|
||||||
public interface LocationUtils {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the country the device is currently located in, or "" if it cannot
|
|
||||||
* be determined.
|
|
||||||
* <p>
|
|
||||||
* The country codes are formatted upper-case and as per <a href="
|
|
||||||
* https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-1 alpha 2</a>.
|
|
||||||
*/
|
|
||||||
String getCurrentCountry();
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,7 @@ dependencyVerification {
|
|||||||
'com.fasterxml.jackson.core:jackson-annotations:2.13.4:jackson-annotations-2.13.4.jar:ac5b27a634942391ca113850ee7db01df1499a240174021263501c05fc653b44',
|
'com.fasterxml.jackson.core:jackson-annotations:2.13.4:jackson-annotations-2.13.4.jar:ac5b27a634942391ca113850ee7db01df1499a240174021263501c05fc653b44',
|
||||||
'com.google.code.findbugs:annotations:3.0.1:annotations-3.0.1.jar:6b47ff0a6de0ce17cbedc3abb0828ca5bce3009d53ea47b3723ff023c4742f79',
|
'com.google.code.findbugs:annotations:3.0.1:annotations-3.0.1.jar:6b47ff0a6de0ce17cbedc3abb0828ca5bce3009d53ea47b3723ff023c4742f79',
|
||||||
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
|
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
|
||||||
'com.google.dagger:dagger:2.43.2:dagger-2.43.2.jar:c89681f7cbbf8c527bf4ac2748515d617fdb54a1d425c08d914fdc28192b5fe4',
|
'com.google.dagger:dagger:2.45:dagger-2.45.jar:f011cae7d2c0fb7ea17c34e05bc10e768b1081a5892ad019cf1fdb0e125c49c1',
|
||||||
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||||
'junit:junit:4.13.2:junit-4.13.2.jar:8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3',
|
'junit:junit:4.13.2:junit-4.13.2.jar:8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3',
|
||||||
'net.bytebuddy:byte-buddy:1.9.12:byte-buddy-1.9.12.jar:3688c3d434bebc3edc5516296a2ed0f47b65e451071b4afecad84f902f0efc11',
|
'net.bytebuddy:byte-buddy:1.9.12:byte-buddy-1.9.12.jar:3688c3d434bebc3edc5516296a2ed0f47b65e451071b4afecad84f902f0efc11',
|
||||||
@@ -12,8 +12,8 @@ dependencyVerification {
|
|||||||
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
|
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
|
||||||
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
|
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
|
||||||
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
|
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
|
||||||
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.20:animal-sniffer-ant-tasks-1.20.jar:bb7d2498144118311d968bb08ff6fae3fc535fb1cb9cca8b8e9ea65b189422ac',
|
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.22:animal-sniffer-ant-tasks-1.22.jar:3f6afeb3e09301d2d7179ed1db21e3ad8846c1e38415ad832a395138ae3f4218',
|
||||||
'org.codehaus.mojo:animal-sniffer:1.20:animal-sniffer-1.20.jar:80c422523c38db91260c6d78e5ee4b012862ab61cc55020c9e243dd7b5c62249',
|
'org.codehaus.mojo:animal-sniffer:1.22:animal-sniffer-1.22.jar:f18c11a25bdd8b520b9c6a28cbb6f33007c812ab0051b6be3f0778e660aa501c',
|
||||||
'org.hamcrest:hamcrest-core:2.1:hamcrest-core-2.1.jar:e09109e54a289d88506b9bfec987ddd199f4217c9464132668351b9a4f00bee9',
|
'org.hamcrest:hamcrest-core:2.1:hamcrest-core-2.1.jar:e09109e54a289d88506b9bfec987ddd199f4217c9464132668351b9a4f00bee9',
|
||||||
'org.hamcrest:hamcrest-library:2.1:hamcrest-library-2.1.jar:b7e2b6895b3b679f0e47b6380fda391b225e9b78505db9d8bdde8d3cc8d52a21',
|
'org.hamcrest:hamcrest-library:2.1:hamcrest-library-2.1.jar:b7e2b6895b3b679f0e47b6380fda391b225e9b78505db9d8bdde8d3cc8d52a21',
|
||||||
'org.hamcrest:hamcrest:2.1:hamcrest-2.1.jar:ba93b2e3a562322ba432f0a1b53addcc55cb188253319a020ed77f824e692050',
|
'org.hamcrest:hamcrest:2.1:hamcrest-2.1.jar:ba93b2e3a562322ba432f0a1b53addcc55cb188253319a020ed77f824e692050',
|
||||||
@@ -24,6 +24,6 @@ dependencyVerification {
|
|||||||
'org.jmock:jmock:2.12.0:jmock-2.12.0.jar:266d07314c0cd343c46ff8a55601272de8cf406807caf55e6f313295f83d10be',
|
'org.jmock:jmock:2.12.0:jmock-2.12.0.jar:266d07314c0cd343c46ff8a55601272de8cf406807caf55e6f313295f83d10be',
|
||||||
'org.objenesis:objenesis:3.0.1:objenesis-3.0.1.jar:7a8ff780b9ff48415d7c705f60030b0acaa616e7f823c98eede3b63508d4e984',
|
'org.objenesis:objenesis:3.0.1:objenesis-3.0.1.jar:7a8ff780b9ff48415d7c705f60030b0acaa616e7f823c98eede3b63508d4e984',
|
||||||
'org.ow2.asm:asm:7.1:asm-7.1.jar:4ab2fa2b6d2cc9ccb1eaa05ea329c407b47b13ed2915f62f8c4b8cc96258d4de',
|
'org.ow2.asm:asm:7.1:asm-7.1.jar:4ab2fa2b6d2cc9ccb1eaa05ea329c407b47b13ed2915f62f8c4b8cc96258d4de',
|
||||||
'org.ow2.asm:asm:9.1:asm-9.1.jar:cda4de455fab48ff0bcb7c48b4639447d4de859a7afc30a094a986f0936beba2',
|
'org.ow2.asm:asm:9.3:asm-9.3.jar:1263369b59e29c943918de11d6d6152e2ec6085ce63e5710516f8c67d368e4bc',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ dependencies {
|
|||||||
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
|
||||||
|
|
||||||
testImplementation 'org.hsqldb:hsqldb:2.3.5' // The last version that supports Java 1.6
|
testImplementation 'org.hsqldb:hsqldb:2.3.5' // The last version that supports Java 1.6
|
||||||
testImplementation 'net.jodah:concurrentunit:0.4.2'
|
testImplementation 'net.jodah:concurrentunit:0.4.6'
|
||||||
testImplementation "junit:junit:$junit_version"
|
testImplementation "junit:junit:$junit_version"
|
||||||
testImplementation "org.jmock:jmock:$jmock_version"
|
testImplementation "org.jmock:jmock:$jmock_version"
|
||||||
testImplementation "org.jmock:jmock-junit4:$jmock_version"
|
testImplementation "org.jmock:jmock-junit4:$jmock_version"
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.bramble.contact;
|
package org.briarproject.bramble.contact;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.Predicate;
|
|
||||||
import org.briarproject.bramble.api.client.ClientHelper;
|
import org.briarproject.bramble.api.client.ClientHelper;
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.contact.ContactExchangeManager;
|
import org.briarproject.bramble.api.contact.ContactExchangeManager;
|
||||||
@@ -24,6 +23,7 @@ import org.briarproject.bramble.api.properties.TransportProperties;
|
|||||||
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
import org.briarproject.bramble.api.properties.TransportPropertyManager;
|
||||||
import org.briarproject.bramble.api.record.Record;
|
import org.briarproject.bramble.api.record.Record;
|
||||||
import org.briarproject.bramble.api.record.RecordReader;
|
import org.briarproject.bramble.api.record.RecordReader;
|
||||||
|
import org.briarproject.bramble.api.record.RecordReader.RecordPredicate;
|
||||||
import org.briarproject.bramble.api.record.RecordReaderFactory;
|
import org.briarproject.bramble.api.record.RecordReaderFactory;
|
||||||
import org.briarproject.bramble.api.record.RecordWriter;
|
import org.briarproject.bramble.api.record.RecordWriter;
|
||||||
import org.briarproject.bramble.api.record.RecordWriterFactory;
|
import org.briarproject.bramble.api.record.RecordWriterFactory;
|
||||||
@@ -61,12 +61,12 @@ class ContactExchangeManagerImpl implements ContactExchangeManager {
|
|||||||
getLogger(ContactExchangeManagerImpl.class.getName());
|
getLogger(ContactExchangeManagerImpl.class.getName());
|
||||||
|
|
||||||
// Accept records with current protocol version, known record type
|
// Accept records with current protocol version, known record type
|
||||||
private static final Predicate<Record> ACCEPT = r ->
|
private static final RecordPredicate ACCEPT = r ->
|
||||||
r.getProtocolVersion() == PROTOCOL_VERSION &&
|
r.getProtocolVersion() == PROTOCOL_VERSION &&
|
||||||
isKnownRecordType(r.getRecordType());
|
isKnownRecordType(r.getRecordType());
|
||||||
|
|
||||||
// Ignore records with current protocol version, unknown record type
|
// Ignore records with current protocol version, unknown record type
|
||||||
private static final Predicate<Record> IGNORE = r ->
|
private static final RecordPredicate IGNORE = r ->
|
||||||
r.getProtocolVersion() == PROTOCOL_VERSION &&
|
r.getProtocolVersion() == PROTOCOL_VERSION &&
|
||||||
!isKnownRecordType(r.getRecordType());
|
!isKnownRecordType(r.getRecordType());
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,31 @@ import static org.briarproject.bramble.api.crypto.CryptoConstants.MAC_BYTES;
|
|||||||
interface HandshakeConstants {
|
interface HandshakeConstants {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current version of the handshake protocol.
|
* The current major version of the handshake protocol.
|
||||||
*/
|
*/
|
||||||
byte PROTOCOL_VERSION = 0;
|
byte PROTOCOL_MAJOR_VERSION = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Label for deriving the master key.
|
* The current minor version of the handshake protocol.
|
||||||
*/
|
*/
|
||||||
String MASTER_KEY_LABEL = "org.briarproject.bramble.handshake/MASTER_KEY";
|
byte PROTOCOL_MINOR_VERSION = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Label for deriving the master key when using the deprecated v0.0 key
|
||||||
|
* derivation method.
|
||||||
|
* <p>
|
||||||
|
* TODO: Remove this after a reasonable migration period (added 2023-03-10).
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
String MASTER_KEY_LABEL_0_0 =
|
||||||
|
"org.briarproject.bramble.handshake/MASTER_KEY";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Label for deriving the master key when using the v0.1 key derivation
|
||||||
|
* method.
|
||||||
|
*/
|
||||||
|
String MASTER_KEY_LABEL_0_1 =
|
||||||
|
"org.briarproject.bramble.handshake/MASTER_KEY_0_1";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Label for deriving Alice's proof of ownership from the master key.
|
* Label for deriving Alice's proof of ownership from the master key.
|
||||||
|
|||||||
@@ -13,11 +13,26 @@ interface HandshakeCrypto {
|
|||||||
KeyPair generateEphemeralKeyPair();
|
KeyPair generateEphemeralKeyPair();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derives the master key from the given static and ephemeral keys.
|
* Derives the master key from the given static and ephemeral keys using
|
||||||
|
* the deprecated v0.0 key derivation method.
|
||||||
|
* <p>
|
||||||
|
* TODO: Remove this after a reasonable migration period (added 2023-03-10).
|
||||||
*
|
*
|
||||||
* @param alice Whether the local peer is Alice
|
* @param alice Whether the local peer is Alice
|
||||||
*/
|
*/
|
||||||
SecretKey deriveMasterKey(PublicKey theirStaticPublicKey,
|
@Deprecated
|
||||||
|
SecretKey deriveMasterKey_0_0(PublicKey theirStaticPublicKey,
|
||||||
|
PublicKey theirEphemeralPublicKey, KeyPair ourStaticKeyPair,
|
||||||
|
KeyPair ourEphemeralKeyPair, boolean alice)
|
||||||
|
throws GeneralSecurityException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derives the master key from the given static and ephemeral keys using
|
||||||
|
* the v0.1 key derivation method.
|
||||||
|
*
|
||||||
|
* @param alice Whether the local peer is Alice
|
||||||
|
*/
|
||||||
|
SecretKey deriveMasterKey_0_1(PublicKey theirStaticPublicKey,
|
||||||
PublicKey theirEphemeralPublicKey, KeyPair ourStaticKeyPair,
|
PublicKey theirEphemeralPublicKey, KeyPair ourStaticKeyPair,
|
||||||
KeyPair ourEphemeralKeyPair, boolean alice)
|
KeyPair ourEphemeralKeyPair, boolean alice)
|
||||||
throws GeneralSecurityException;
|
throws GeneralSecurityException;
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
import static org.briarproject.bramble.contact.HandshakeConstants.ALICE_PROOF_LABEL;
|
import static org.briarproject.bramble.contact.HandshakeConstants.ALICE_PROOF_LABEL;
|
||||||
import static org.briarproject.bramble.contact.HandshakeConstants.BOB_PROOF_LABEL;
|
import static org.briarproject.bramble.contact.HandshakeConstants.BOB_PROOF_LABEL;
|
||||||
import static org.briarproject.bramble.contact.HandshakeConstants.MASTER_KEY_LABEL;
|
import static org.briarproject.bramble.contact.HandshakeConstants.MASTER_KEY_LABEL_0_0;
|
||||||
|
import static org.briarproject.bramble.contact.HandshakeConstants.MASTER_KEY_LABEL_0_1;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -32,7 +33,8 @@ class HandshakeCryptoImpl implements HandshakeCrypto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SecretKey deriveMasterKey(PublicKey theirStaticPublicKey,
|
@Deprecated
|
||||||
|
public SecretKey deriveMasterKey_0_0(PublicKey theirStaticPublicKey,
|
||||||
PublicKey theirEphemeralPublicKey, KeyPair ourStaticKeyPair,
|
PublicKey theirEphemeralPublicKey, KeyPair ourStaticKeyPair,
|
||||||
KeyPair ourEphemeralKeyPair, boolean alice) throws
|
KeyPair ourEphemeralKeyPair, boolean alice) throws
|
||||||
GeneralSecurityException {
|
GeneralSecurityException {
|
||||||
@@ -46,9 +48,29 @@ class HandshakeCryptoImpl implements HandshakeCrypto {
|
|||||||
alice ? ourEphemeral : theirEphemeral,
|
alice ? ourEphemeral : theirEphemeral,
|
||||||
alice ? theirEphemeral : ourEphemeral
|
alice ? theirEphemeral : ourEphemeral
|
||||||
};
|
};
|
||||||
return crypto.deriveSharedSecret(MASTER_KEY_LABEL, theirStaticPublicKey,
|
return crypto.deriveSharedSecretBadly(MASTER_KEY_LABEL_0_0,
|
||||||
theirEphemeralPublicKey, ourStaticKeyPair, ourEphemeralKeyPair,
|
theirStaticPublicKey, theirEphemeralPublicKey,
|
||||||
alice, inputs);
|
ourStaticKeyPair, ourEphemeralKeyPair, alice, inputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SecretKey deriveMasterKey_0_1(PublicKey theirStaticPublicKey,
|
||||||
|
PublicKey theirEphemeralPublicKey, KeyPair ourStaticKeyPair,
|
||||||
|
KeyPair ourEphemeralKeyPair, boolean alice) throws
|
||||||
|
GeneralSecurityException {
|
||||||
|
byte[] theirStatic = theirStaticPublicKey.getEncoded();
|
||||||
|
byte[] theirEphemeral = theirEphemeralPublicKey.getEncoded();
|
||||||
|
byte[] ourStatic = ourStaticKeyPair.getPublic().getEncoded();
|
||||||
|
byte[] ourEphemeral = ourEphemeralKeyPair.getPublic().getEncoded();
|
||||||
|
byte[][] inputs = {
|
||||||
|
alice ? ourStatic : theirStatic,
|
||||||
|
alice ? theirStatic : ourStatic,
|
||||||
|
alice ? ourEphemeral : theirEphemeral,
|
||||||
|
alice ? theirEphemeral : ourEphemeral
|
||||||
|
};
|
||||||
|
return crypto.deriveSharedSecret(MASTER_KEY_LABEL_0_1,
|
||||||
|
theirStaticPublicKey, theirEphemeralPublicKey,
|
||||||
|
ourStaticKeyPair, ourEphemeralKeyPair, alice, inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.briarproject.bramble.contact;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.Pair;
|
import org.briarproject.bramble.api.Pair;
|
||||||
import org.briarproject.bramble.api.Predicate;
|
|
||||||
import org.briarproject.bramble.api.contact.ContactManager;
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
import org.briarproject.bramble.api.contact.HandshakeManager;
|
import org.briarproject.bramble.api.contact.HandshakeManager;
|
||||||
import org.briarproject.bramble.api.contact.PendingContact;
|
import org.briarproject.bramble.api.contact.PendingContact;
|
||||||
@@ -12,12 +11,12 @@ import org.briarproject.bramble.api.crypto.KeyPair;
|
|||||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.crypto.TransportCrypto;
|
import org.briarproject.bramble.api.crypto.TransportCrypto;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.TransactionManager;
|
import org.briarproject.bramble.api.db.TransactionManager;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
import org.briarproject.bramble.api.record.Record;
|
import org.briarproject.bramble.api.record.Record;
|
||||||
import org.briarproject.bramble.api.record.RecordReader;
|
import org.briarproject.bramble.api.record.RecordReader;
|
||||||
|
import org.briarproject.bramble.api.record.RecordReader.RecordPredicate;
|
||||||
import org.briarproject.bramble.api.record.RecordReaderFactory;
|
import org.briarproject.bramble.api.record.RecordReaderFactory;
|
||||||
import org.briarproject.bramble.api.record.RecordWriter;
|
import org.briarproject.bramble.api.record.RecordWriter;
|
||||||
import org.briarproject.bramble.api.record.RecordWriterFactory;
|
import org.briarproject.bramble.api.record.RecordWriterFactory;
|
||||||
@@ -28,15 +27,20 @@ import java.io.EOFException;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_AGREEMENT_PUBLIC_KEY_BYTES;
|
import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_AGREEMENT_PUBLIC_KEY_BYTES;
|
||||||
import static org.briarproject.bramble.contact.HandshakeConstants.PROOF_BYTES;
|
import static org.briarproject.bramble.contact.HandshakeConstants.PROOF_BYTES;
|
||||||
import static org.briarproject.bramble.contact.HandshakeConstants.PROTOCOL_VERSION;
|
import static org.briarproject.bramble.contact.HandshakeConstants.PROTOCOL_MAJOR_VERSION;
|
||||||
import static org.briarproject.bramble.contact.HandshakeRecordTypes.EPHEMERAL_PUBLIC_KEY;
|
import static org.briarproject.bramble.contact.HandshakeConstants.PROTOCOL_MINOR_VERSION;
|
||||||
import static org.briarproject.bramble.contact.HandshakeRecordTypes.PROOF_OF_OWNERSHIP;
|
import static org.briarproject.bramble.contact.HandshakeRecordTypes.RECORD_TYPE_EPHEMERAL_PUBLIC_KEY;
|
||||||
|
import static org.briarproject.bramble.contact.HandshakeRecordTypes.RECORD_TYPE_MINOR_VERSION;
|
||||||
|
import static org.briarproject.bramble.contact.HandshakeRecordTypes.RECORD_TYPE_PROOF_OF_OWNERSHIP;
|
||||||
import static org.briarproject.bramble.util.ValidationUtils.checkLength;
|
import static org.briarproject.bramble.util.ValidationUtils.checkLength;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -44,12 +48,14 @@ import static org.briarproject.bramble.util.ValidationUtils.checkLength;
|
|||||||
class HandshakeManagerImpl implements HandshakeManager {
|
class HandshakeManagerImpl implements HandshakeManager {
|
||||||
|
|
||||||
// Ignore records with current protocol version, unknown record type
|
// Ignore records with current protocol version, unknown record type
|
||||||
private static final Predicate<Record> IGNORE = r ->
|
private static final RecordPredicate IGNORE = r ->
|
||||||
r.getProtocolVersion() == PROTOCOL_VERSION &&
|
r.getProtocolVersion() == PROTOCOL_MAJOR_VERSION &&
|
||||||
!isKnownRecordType(r.getRecordType());
|
!isKnownRecordType(r.getRecordType());
|
||||||
|
|
||||||
private static boolean isKnownRecordType(byte type) {
|
private static boolean isKnownRecordType(byte type) {
|
||||||
return type == EPHEMERAL_PUBLIC_KEY || type == PROOF_OF_OWNERSHIP;
|
return type == RECORD_TYPE_EPHEMERAL_PUBLIC_KEY ||
|
||||||
|
type == RECORD_TYPE_PROOF_OF_OWNERSHIP ||
|
||||||
|
type == RECORD_TYPE_MINOR_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final TransactionManager db;
|
private final TransactionManager db;
|
||||||
@@ -61,7 +67,7 @@ class HandshakeManagerImpl implements HandshakeManager {
|
|||||||
private final RecordWriterFactory recordWriterFactory;
|
private final RecordWriterFactory recordWriterFactory;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
HandshakeManagerImpl(DatabaseComponent db,
|
HandshakeManagerImpl(TransactionManager db,
|
||||||
IdentityManager identityManager,
|
IdentityManager identityManager,
|
||||||
ContactManager contactManager,
|
ContactManager contactManager,
|
||||||
TransportCrypto transportCrypto,
|
TransportCrypto transportCrypto,
|
||||||
@@ -95,19 +101,31 @@ class HandshakeManagerImpl implements HandshakeManager {
|
|||||||
.createRecordWriter(out.getOutputStream());
|
.createRecordWriter(out.getOutputStream());
|
||||||
KeyPair ourEphemeralKeyPair =
|
KeyPair ourEphemeralKeyPair =
|
||||||
handshakeCrypto.generateEphemeralKeyPair();
|
handshakeCrypto.generateEphemeralKeyPair();
|
||||||
PublicKey theirEphemeralPublicKey;
|
Pair<Byte, PublicKey> theirMinorVersionAndKey;
|
||||||
if (alice) {
|
if (alice) {
|
||||||
|
sendMinorVersion(recordWriter);
|
||||||
sendPublicKey(recordWriter, ourEphemeralKeyPair.getPublic());
|
sendPublicKey(recordWriter, ourEphemeralKeyPair.getPublic());
|
||||||
theirEphemeralPublicKey = receivePublicKey(recordReader);
|
theirMinorVersionAndKey = receiveMinorVersionAndKey(recordReader);
|
||||||
} else {
|
} else {
|
||||||
theirEphemeralPublicKey = receivePublicKey(recordReader);
|
theirMinorVersionAndKey = receiveMinorVersionAndKey(recordReader);
|
||||||
|
sendMinorVersion(recordWriter);
|
||||||
sendPublicKey(recordWriter, ourEphemeralKeyPair.getPublic());
|
sendPublicKey(recordWriter, ourEphemeralKeyPair.getPublic());
|
||||||
}
|
}
|
||||||
|
byte theirMinorVersion = theirMinorVersionAndKey.getFirst();
|
||||||
|
PublicKey theirEphemeralPublicKey = theirMinorVersionAndKey.getSecond();
|
||||||
SecretKey masterKey;
|
SecretKey masterKey;
|
||||||
try {
|
try {
|
||||||
masterKey = handshakeCrypto.deriveMasterKey(theirStaticPublicKey,
|
if (theirMinorVersion > 0) {
|
||||||
theirEphemeralPublicKey, ourStaticKeyPair,
|
masterKey = handshakeCrypto.deriveMasterKey_0_1(
|
||||||
ourEphemeralKeyPair, alice);
|
theirStaticPublicKey, theirEphemeralPublicKey,
|
||||||
|
ourStaticKeyPair, ourEphemeralKeyPair, alice);
|
||||||
|
} else {
|
||||||
|
// TODO: Remove this branch after a reasonable migration
|
||||||
|
// period (added 2023-03-10).
|
||||||
|
masterKey = handshakeCrypto.deriveMasterKey_0_0(
|
||||||
|
theirStaticPublicKey, theirEphemeralPublicKey,
|
||||||
|
ourStaticKeyPair, ourEphemeralKeyPair, alice);
|
||||||
|
}
|
||||||
} catch (GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
@@ -128,34 +146,91 @@ class HandshakeManagerImpl implements HandshakeManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void sendPublicKey(RecordWriter w, PublicKey k) throws IOException {
|
private void sendPublicKey(RecordWriter w, PublicKey k) throws IOException {
|
||||||
w.writeRecord(new Record(PROTOCOL_VERSION, EPHEMERAL_PUBLIC_KEY,
|
w.writeRecord(new Record(PROTOCOL_MAJOR_VERSION,
|
||||||
k.getEncoded()));
|
RECORD_TYPE_EPHEMERAL_PUBLIC_KEY, k.getEncoded()));
|
||||||
w.flush();
|
w.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
private PublicKey receivePublicKey(RecordReader r) throws IOException {
|
/**
|
||||||
byte[] key = readRecord(r, EPHEMERAL_PUBLIC_KEY).getPayload();
|
* Receives the remote peer's protocol minor version and ephemeral public
|
||||||
|
* key.
|
||||||
|
* <p>
|
||||||
|
* In version 0.1 of the protocol, each peer sends a minor version record
|
||||||
|
* followed by an ephemeral public key record.
|
||||||
|
* <p>
|
||||||
|
* In version 0.0 of the protocol, each peer sends an ephemeral public key
|
||||||
|
* record without a preceding minor version record.
|
||||||
|
* <p>
|
||||||
|
* Therefore the remote peer's minor version must be non-zero if a minor
|
||||||
|
* version record is received, and is assumed to be zero if no minor
|
||||||
|
* version record is received.
|
||||||
|
*/
|
||||||
|
private Pair<Byte, PublicKey> receiveMinorVersionAndKey(RecordReader r)
|
||||||
|
throws IOException {
|
||||||
|
byte theirMinorVersion;
|
||||||
|
PublicKey theirEphemeralPublicKey;
|
||||||
|
// The first record can be either a minor version record or an
|
||||||
|
// ephemeral public key record
|
||||||
|
Record first = readRecord(r, asList(RECORD_TYPE_MINOR_VERSION,
|
||||||
|
RECORD_TYPE_EPHEMERAL_PUBLIC_KEY));
|
||||||
|
if (first.getRecordType() == RECORD_TYPE_MINOR_VERSION) {
|
||||||
|
// The payload must be a single byte giving the remote peer's
|
||||||
|
// protocol minor version, which must be non-zero
|
||||||
|
byte[] payload = first.getPayload();
|
||||||
|
checkLength(payload, 1);
|
||||||
|
theirMinorVersion = payload[0];
|
||||||
|
if (theirMinorVersion == 0) throw new FormatException();
|
||||||
|
// The second record must be an ephemeral public key record
|
||||||
|
Record second = readRecord(r,
|
||||||
|
singletonList(RECORD_TYPE_EPHEMERAL_PUBLIC_KEY));
|
||||||
|
theirEphemeralPublicKey = parsePublicKey(second);
|
||||||
|
} else {
|
||||||
|
// The remote peer did not send a minor version record, so the
|
||||||
|
// remote peer's protocol minor version is assumed to be zero
|
||||||
|
// TODO: Remove this branch after a reasonable migration period
|
||||||
|
// (added 2023-03-10).
|
||||||
|
theirMinorVersion = 0;
|
||||||
|
theirEphemeralPublicKey = parsePublicKey(first);
|
||||||
|
}
|
||||||
|
return new Pair<>(theirMinorVersion, theirEphemeralPublicKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PublicKey parsePublicKey(Record rec) throws IOException {
|
||||||
|
if (rec.getRecordType() != RECORD_TYPE_EPHEMERAL_PUBLIC_KEY) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
byte[] key = rec.getPayload();
|
||||||
checkLength(key, 1, MAX_AGREEMENT_PUBLIC_KEY_BYTES);
|
checkLength(key, 1, MAX_AGREEMENT_PUBLIC_KEY_BYTES);
|
||||||
return new AgreementPublicKey(key);
|
return new AgreementPublicKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendProof(RecordWriter w, byte[] proof) throws IOException {
|
private void sendProof(RecordWriter w, byte[] proof) throws IOException {
|
||||||
w.writeRecord(new Record(PROTOCOL_VERSION, PROOF_OF_OWNERSHIP, proof));
|
w.writeRecord(new Record(PROTOCOL_MAJOR_VERSION,
|
||||||
|
RECORD_TYPE_PROOF_OF_OWNERSHIP, proof));
|
||||||
w.flush();
|
w.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] receiveProof(RecordReader r) throws IOException {
|
private byte[] receiveProof(RecordReader r) throws IOException {
|
||||||
byte[] proof = readRecord(r, PROOF_OF_OWNERSHIP).getPayload();
|
Record rec = readRecord(r,
|
||||||
|
singletonList(RECORD_TYPE_PROOF_OF_OWNERSHIP));
|
||||||
|
byte[] proof = rec.getPayload();
|
||||||
checkLength(proof, PROOF_BYTES, PROOF_BYTES);
|
checkLength(proof, PROOF_BYTES, PROOF_BYTES);
|
||||||
return proof;
|
return proof;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Record readRecord(RecordReader r, byte expectedType)
|
private void sendMinorVersion(RecordWriter w) throws IOException {
|
||||||
|
w.writeRecord(new Record(PROTOCOL_MAJOR_VERSION,
|
||||||
|
RECORD_TYPE_MINOR_VERSION,
|
||||||
|
new byte[] {PROTOCOL_MINOR_VERSION}));
|
||||||
|
w.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Record readRecord(RecordReader r, List<Byte> expectedTypes)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
// Accept records with current protocol version, expected type only
|
// Accept records with current protocol version, expected types only
|
||||||
Predicate<Record> accept = rec ->
|
RecordPredicate accept = rec ->
|
||||||
rec.getProtocolVersion() == PROTOCOL_VERSION &&
|
rec.getProtocolVersion() == PROTOCOL_MAJOR_VERSION &&
|
||||||
rec.getRecordType() == expectedType;
|
expectedTypes.contains(rec.getRecordType());
|
||||||
Record rec = r.readRecord(accept, IGNORE);
|
Record rec = r.readRecord(accept, IGNORE);
|
||||||
if (rec == null) throw new EOFException();
|
if (rec == null) throw new EOFException();
|
||||||
return rec;
|
return rec;
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ package org.briarproject.bramble.contact;
|
|||||||
*/
|
*/
|
||||||
interface HandshakeRecordTypes {
|
interface HandshakeRecordTypes {
|
||||||
|
|
||||||
byte EPHEMERAL_PUBLIC_KEY = 0;
|
byte RECORD_TYPE_EPHEMERAL_PUBLIC_KEY = 0;
|
||||||
|
|
||||||
byte PROOF_OF_OWNERSHIP = 1;
|
byte RECORD_TYPE_PROOF_OF_OWNERSHIP = 1;
|
||||||
|
|
||||||
|
byte RECORD_TYPE_MINOR_VERSION = 2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,7 +222,8 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SecretKey deriveSharedSecret(String label,
|
@Deprecated
|
||||||
|
public SecretKey deriveSharedSecretBadly(String label,
|
||||||
PublicKey theirStaticPublicKey, PublicKey theirEphemeralPublicKey,
|
PublicKey theirStaticPublicKey, PublicKey theirEphemeralPublicKey,
|
||||||
KeyPair ourStaticKeyPair, KeyPair ourEphemeralKeyPair,
|
KeyPair ourStaticKeyPair, KeyPair ourEphemeralKeyPair,
|
||||||
boolean alice, byte[]... inputs) throws GeneralSecurityException {
|
boolean alice, byte[]... inputs) throws GeneralSecurityException {
|
||||||
@@ -250,6 +251,35 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
return new SecretKey(hash);
|
return new SecretKey(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SecretKey deriveSharedSecret(String label,
|
||||||
|
PublicKey theirStaticPublicKey, PublicKey theirEphemeralPublicKey,
|
||||||
|
KeyPair ourStaticKeyPair, KeyPair ourEphemeralKeyPair,
|
||||||
|
boolean alice, byte[]... inputs) throws GeneralSecurityException {
|
||||||
|
PrivateKey ourStaticPrivateKey = ourStaticKeyPair.getPrivate();
|
||||||
|
PrivateKey ourEphemeralPrivateKey = ourEphemeralKeyPair.getPrivate();
|
||||||
|
byte[][] hashInputs = new byte[inputs.length + 3][];
|
||||||
|
// Alice ephemeral/Bob ephemeral
|
||||||
|
hashInputs[0] = performRawKeyAgreement(ourEphemeralPrivateKey,
|
||||||
|
theirEphemeralPublicKey);
|
||||||
|
// Alice static/Bob ephemeral, Bob static/Alice ephemeral
|
||||||
|
if (alice) {
|
||||||
|
hashInputs[1] = performRawKeyAgreement(ourStaticPrivateKey,
|
||||||
|
theirEphemeralPublicKey);
|
||||||
|
hashInputs[2] = performRawKeyAgreement(ourEphemeralPrivateKey,
|
||||||
|
theirStaticPublicKey);
|
||||||
|
} else {
|
||||||
|
hashInputs[1] = performRawKeyAgreement(ourEphemeralPrivateKey,
|
||||||
|
theirStaticPublicKey);
|
||||||
|
hashInputs[2] = performRawKeyAgreement(ourStaticPrivateKey,
|
||||||
|
theirEphemeralPublicKey);
|
||||||
|
}
|
||||||
|
arraycopy(inputs, 0, hashInputs, 3, inputs.length);
|
||||||
|
byte[] hash = hash(label, hashInputs);
|
||||||
|
if (hash.length != SecretKey.LENGTH) throw new IllegalStateException();
|
||||||
|
return new SecretKey(hash);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] sign(String label, byte[] toSign, PrivateKey privateKey)
|
public byte[] sign(String label, byte[] toSign, PrivateKey privateKey)
|
||||||
throws GeneralSecurityException {
|
throws GeneralSecurityException {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package org.briarproject.bramble.keyagreement;
|
package org.briarproject.bramble.keyagreement;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.Predicate;
|
|
||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
|
||||||
import org.briarproject.bramble.api.plugin.TransportId;
|
import org.briarproject.bramble.api.plugin.TransportId;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||||
import org.briarproject.bramble.api.record.Record;
|
import org.briarproject.bramble.api.record.Record;
|
||||||
import org.briarproject.bramble.api.record.RecordReader;
|
import org.briarproject.bramble.api.record.RecordReader;
|
||||||
|
import org.briarproject.bramble.api.record.RecordReader.RecordPredicate;
|
||||||
import org.briarproject.bramble.api.record.RecordReaderFactory;
|
import org.briarproject.bramble.api.record.RecordReaderFactory;
|
||||||
import org.briarproject.bramble.api.record.RecordWriter;
|
import org.briarproject.bramble.api.record.RecordWriter;
|
||||||
import org.briarproject.bramble.api.record.RecordWriterFactory;
|
import org.briarproject.bramble.api.record.RecordWriterFactory;
|
||||||
@@ -34,12 +34,12 @@ class KeyAgreementTransport {
|
|||||||
Logger.getLogger(KeyAgreementTransport.class.getName());
|
Logger.getLogger(KeyAgreementTransport.class.getName());
|
||||||
|
|
||||||
// Accept records with current protocol version, known record type
|
// Accept records with current protocol version, known record type
|
||||||
private static final Predicate<Record> ACCEPT = r ->
|
private static final RecordPredicate ACCEPT = r ->
|
||||||
r.getProtocolVersion() == PROTOCOL_VERSION &&
|
r.getProtocolVersion() == PROTOCOL_VERSION &&
|
||||||
isKnownRecordType(r.getRecordType());
|
isKnownRecordType(r.getRecordType());
|
||||||
|
|
||||||
// Ignore records with current protocol version, unknown record type
|
// Ignore records with current protocol version, unknown record type
|
||||||
private static final Predicate<Record> IGNORE = r ->
|
private static final RecordPredicate IGNORE = r ->
|
||||||
r.getProtocolVersion() == PROTOCOL_VERSION &&
|
r.getProtocolVersion() == PROTOCOL_VERSION &&
|
||||||
!isKnownRecordType(r.getRecordType());
|
!isKnownRecordType(r.getRecordType());
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.briarproject.bramble.plugin.tor;
|
||||||
|
|
||||||
|
import org.briarproject.onionwrapper.CircumventionProvider;
|
||||||
|
import org.briarproject.onionwrapper.CircumventionProviderFactory;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class CircumventionModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
CircumventionProvider provideCircumventionProvider() {
|
||||||
|
return CircumventionProviderFactory.createCircumventionProvider();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,11 +24,11 @@ import org.briarproject.bramble.api.rendezvous.KeyMaterialSource;
|
|||||||
import org.briarproject.bramble.api.rendezvous.RendezvousEndpoint;
|
import org.briarproject.bramble.api.rendezvous.RendezvousEndpoint;
|
||||||
import org.briarproject.bramble.api.settings.Settings;
|
import org.briarproject.bramble.api.settings.Settings;
|
||||||
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
|
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
|
||||||
import org.briarproject.nullsafety.InterfaceNotNullByDefault;
|
import org.briarproject.nullsafety.InterfaceNotNullByDefault;
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.onionwrapper.CircumventionProvider;
|
import org.briarproject.onionwrapper.CircumventionProvider;
|
||||||
import org.briarproject.onionwrapper.CircumventionProvider.BridgeType;
|
import org.briarproject.onionwrapper.CircumventionProvider.BridgeType;
|
||||||
|
import org.briarproject.onionwrapper.LocationUtils;
|
||||||
import org.briarproject.onionwrapper.TorWrapper;
|
import org.briarproject.onionwrapper.TorWrapper;
|
||||||
import org.briarproject.onionwrapper.TorWrapper.HiddenServiceProperties;
|
import org.briarproject.onionwrapper.TorWrapper.HiddenServiceProperties;
|
||||||
import org.briarproject.onionwrapper.TorWrapper.Observer;
|
import org.briarproject.onionwrapper.TorWrapper.Observer;
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ import org.briarproject.bramble.api.plugin.TransportId;
|
|||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
|
||||||
import org.briarproject.bramble.api.system.WakefulIoExecutor;
|
import org.briarproject.bramble.api.system.WakefulIoExecutor;
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.onionwrapper.CircumventionProvider;
|
import org.briarproject.onionwrapper.CircumventionProvider;
|
||||||
|
import org.briarproject.onionwrapper.LocationUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.bramble.record;
|
package org.briarproject.bramble.record;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.Predicate;
|
|
||||||
import org.briarproject.bramble.api.record.Record;
|
import org.briarproject.bramble.api.record.Record;
|
||||||
import org.briarproject.bramble.api.record.RecordReader;
|
import org.briarproject.bramble.api.record.RecordReader;
|
||||||
import org.briarproject.bramble.util.ByteUtils;
|
import org.briarproject.bramble.util.ByteUtils;
|
||||||
@@ -45,7 +44,7 @@ class RecordReaderImpl implements RecordReader {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Record readRecord(Predicate<Record> accept, Predicate<Record> ignore)
|
public Record readRecord(RecordPredicate accept, RecordPredicate ignore)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (eof()) return null;
|
if (eof()) return null;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package org.briarproject.bramble.sync;
|
package org.briarproject.bramble.sync;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.Predicate;
|
|
||||||
import org.briarproject.bramble.api.UniqueId;
|
import org.briarproject.bramble.api.UniqueId;
|
||||||
import org.briarproject.bramble.api.record.Record;
|
import org.briarproject.bramble.api.record.Record;
|
||||||
import org.briarproject.bramble.api.record.RecordReader;
|
import org.briarproject.bramble.api.record.RecordReader;
|
||||||
|
import org.briarproject.bramble.api.record.RecordReader.RecordPredicate;
|
||||||
import org.briarproject.bramble.api.sync.Ack;
|
import org.briarproject.bramble.api.sync.Ack;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
import org.briarproject.bramble.api.sync.MessageFactory;
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
@@ -41,12 +41,12 @@ import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
|
|||||||
class SyncRecordReaderImpl implements SyncRecordReader {
|
class SyncRecordReaderImpl implements SyncRecordReader {
|
||||||
|
|
||||||
// Accept records with current protocol version, known record type
|
// Accept records with current protocol version, known record type
|
||||||
private static final Predicate<Record> ACCEPT = r ->
|
private static final RecordPredicate ACCEPT = r ->
|
||||||
r.getProtocolVersion() == PROTOCOL_VERSION &&
|
r.getProtocolVersion() == PROTOCOL_VERSION &&
|
||||||
isKnownRecordType(r.getRecordType());
|
isKnownRecordType(r.getRecordType());
|
||||||
|
|
||||||
// Ignore records with current protocol version, unknown record type
|
// Ignore records with current protocol version, unknown record type
|
||||||
private static final Predicate<Record> IGNORE = r ->
|
private static final RecordPredicate IGNORE = r ->
|
||||||
r.getProtocolVersion() == PROTOCOL_VERSION &&
|
r.getProtocolVersion() == PROTOCOL_VERSION &&
|
||||||
!isKnownRecordType(r.getRecordType());
|
!isKnownRecordType(r.getRecordType());
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
package org.briarproject.onionwrapper;
|
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import dagger.Module;
|
|
||||||
import dagger.Provides;
|
|
||||||
|
|
||||||
@Module
|
|
||||||
public class CircumventionModule {
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
CircumventionProvider provideCircumventionProvider(
|
|
||||||
CircumventionProviderImpl provider) {
|
|
||||||
return provider;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,316 @@
|
|||||||
|
package org.briarproject.bramble.contact;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
|
import org.briarproject.bramble.api.contact.HandshakeManager.HandshakeResult;
|
||||||
|
import org.briarproject.bramble.api.contact.PendingContact;
|
||||||
|
import org.briarproject.bramble.api.crypto.KeyPair;
|
||||||
|
import org.briarproject.bramble.api.crypto.PrivateKey;
|
||||||
|
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
|
import org.briarproject.bramble.api.crypto.TransportCrypto;
|
||||||
|
import org.briarproject.bramble.api.db.Transaction;
|
||||||
|
import org.briarproject.bramble.api.db.TransactionManager;
|
||||||
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
|
import org.briarproject.bramble.api.record.Record;
|
||||||
|
import org.briarproject.bramble.api.record.RecordReader;
|
||||||
|
import org.briarproject.bramble.api.record.RecordReader.RecordPredicate;
|
||||||
|
import org.briarproject.bramble.api.record.RecordReaderFactory;
|
||||||
|
import org.briarproject.bramble.api.record.RecordWriter;
|
||||||
|
import org.briarproject.bramble.api.record.RecordWriterFactory;
|
||||||
|
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||||
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
|
import org.briarproject.bramble.test.DbExpectations;
|
||||||
|
import org.briarproject.bramble.test.PredicateMatcher;
|
||||||
|
import org.jmock.Expectations;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.contact.HandshakeConstants.PROOF_BYTES;
|
||||||
|
import static org.briarproject.bramble.contact.HandshakeConstants.PROTOCOL_MAJOR_VERSION;
|
||||||
|
import static org.briarproject.bramble.contact.HandshakeConstants.PROTOCOL_MINOR_VERSION;
|
||||||
|
import static org.briarproject.bramble.contact.HandshakeRecordTypes.RECORD_TYPE_EPHEMERAL_PUBLIC_KEY;
|
||||||
|
import static org.briarproject.bramble.contact.HandshakeRecordTypes.RECORD_TYPE_MINOR_VERSION;
|
||||||
|
import static org.briarproject.bramble.contact.HandshakeRecordTypes.RECORD_TYPE_PROOF_OF_OWNERSHIP;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getAgreementPrivateKey;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getPendingContact;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class HandshakeManagerImplTest extends BrambleMockTestCase {
|
||||||
|
|
||||||
|
private final TransactionManager db =
|
||||||
|
context.mock(TransactionManager.class);
|
||||||
|
private final IdentityManager identityManager =
|
||||||
|
context.mock(IdentityManager.class);
|
||||||
|
private final ContactManager contactManager =
|
||||||
|
context.mock(ContactManager.class);
|
||||||
|
private final TransportCrypto transportCrypto =
|
||||||
|
context.mock(TransportCrypto.class);
|
||||||
|
private final HandshakeCrypto handshakeCrypto =
|
||||||
|
context.mock(HandshakeCrypto.class);
|
||||||
|
private final RecordReaderFactory recordReaderFactory =
|
||||||
|
context.mock(RecordReaderFactory.class);
|
||||||
|
private final RecordWriterFactory recordWriterFactory =
|
||||||
|
context.mock(RecordWriterFactory.class);
|
||||||
|
private final RecordReader recordReader = context.mock(RecordReader.class);
|
||||||
|
private final RecordWriter recordWriter = context.mock(RecordWriter.class);
|
||||||
|
private final StreamWriter streamWriter = context.mock(StreamWriter.class);
|
||||||
|
|
||||||
|
private final PendingContact pendingContact = getPendingContact();
|
||||||
|
private final PublicKey theirStaticPublicKey =
|
||||||
|
pendingContact.getPublicKey();
|
||||||
|
private final PublicKey ourStaticPublicKey = getAgreementPublicKey();
|
||||||
|
private final PrivateKey ourStaticPrivateKey = getAgreementPrivateKey();
|
||||||
|
private final KeyPair ourStaticKeyPair =
|
||||||
|
new KeyPair(ourStaticPublicKey, ourStaticPrivateKey);
|
||||||
|
private final PublicKey theirEphemeralPublicKey = getAgreementPublicKey();
|
||||||
|
private final PublicKey ourEphemeralPublicKey = getAgreementPublicKey();
|
||||||
|
private final PrivateKey ourEphemeralPrivateKey = getAgreementPrivateKey();
|
||||||
|
private final KeyPair ourEphemeralKeyPair =
|
||||||
|
new KeyPair(ourEphemeralPublicKey, ourEphemeralPrivateKey);
|
||||||
|
private final SecretKey masterKey = getSecretKey();
|
||||||
|
private final byte[] ourProof = getRandomBytes(PROOF_BYTES);
|
||||||
|
private final byte[] theirProof = getRandomBytes(PROOF_BYTES);
|
||||||
|
|
||||||
|
private final InputStream in = new ByteArrayInputStream(new byte[0]);
|
||||||
|
private final OutputStream out = new ByteArrayOutputStream(0);
|
||||||
|
|
||||||
|
private final HandshakeManagerImpl handshakeManager =
|
||||||
|
new HandshakeManagerImpl(db, identityManager, contactManager,
|
||||||
|
transportCrypto, handshakeCrypto, recordReaderFactory,
|
||||||
|
recordWriterFactory);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHandshakeAsAliceWithPeerVersion_0_1() throws Exception {
|
||||||
|
testHandshakeWithPeerVersion_0_1(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHandshakeAsBobWithPeerVersion_0_1() throws Exception {
|
||||||
|
testHandshakeWithPeerVersion_0_1(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testHandshakeWithPeerVersion_0_1(boolean alice)
|
||||||
|
throws Exception {
|
||||||
|
expectPrepareForHandshake(alice);
|
||||||
|
expectSendMinorVersion();
|
||||||
|
expectSendKey();
|
||||||
|
// Remote peer sends minor version, so use new key derivation
|
||||||
|
expectReceiveMinorVersion();
|
||||||
|
expectReceiveKey();
|
||||||
|
expectDeriveMasterKey_0_1(alice);
|
||||||
|
expectDeriveProof(alice);
|
||||||
|
expectSendProof();
|
||||||
|
expectReceiveProof();
|
||||||
|
expectSendEof();
|
||||||
|
expectReceiveEof();
|
||||||
|
expectVerifyOwnership(alice, true);
|
||||||
|
|
||||||
|
HandshakeResult result = handshakeManager.handshake(
|
||||||
|
pendingContact.getId(), in, streamWriter);
|
||||||
|
|
||||||
|
assertArrayEquals(masterKey.getBytes(),
|
||||||
|
result.getMasterKey().getBytes());
|
||||||
|
assertEquals(alice, result.isAlice());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHandshakeAsAliceWithPeerVersion_0_0() throws Exception {
|
||||||
|
testHandshakeWithPeerVersion_0_0(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHandshakeAsBobWithPeerVersion_0_0() throws Exception {
|
||||||
|
testHandshakeWithPeerVersion_0_0(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testHandshakeWithPeerVersion_0_0(boolean alice)
|
||||||
|
throws Exception {
|
||||||
|
expectPrepareForHandshake(alice);
|
||||||
|
expectSendMinorVersion();
|
||||||
|
expectSendKey();
|
||||||
|
// Remote peer does not send minor version, so use old key derivation
|
||||||
|
expectReceiveKey();
|
||||||
|
expectDeriveMasterKey_0_0(alice);
|
||||||
|
expectDeriveProof(alice);
|
||||||
|
expectSendProof();
|
||||||
|
expectReceiveProof();
|
||||||
|
expectSendEof();
|
||||||
|
expectReceiveEof();
|
||||||
|
expectVerifyOwnership(alice, true);
|
||||||
|
|
||||||
|
HandshakeResult result = handshakeManager.handshake(
|
||||||
|
pendingContact.getId(), in, streamWriter);
|
||||||
|
|
||||||
|
assertArrayEquals(masterKey.getBytes(),
|
||||||
|
result.getMasterKey().getBytes());
|
||||||
|
assertEquals(alice, result.isAlice());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testProofOfOwnershipNotVerifiedAsAlice() throws Exception {
|
||||||
|
testProofOfOwnershipNotVerified(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testProofOfOwnershipNotVerifiedAsBob() throws Exception {
|
||||||
|
testProofOfOwnershipNotVerified(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testProofOfOwnershipNotVerified(boolean alice)
|
||||||
|
throws Exception {
|
||||||
|
expectPrepareForHandshake(alice);
|
||||||
|
expectSendMinorVersion();
|
||||||
|
expectSendKey();
|
||||||
|
expectReceiveMinorVersion();
|
||||||
|
expectReceiveKey();
|
||||||
|
expectDeriveMasterKey_0_1(alice);
|
||||||
|
expectDeriveProof(alice);
|
||||||
|
expectSendProof();
|
||||||
|
expectReceiveProof();
|
||||||
|
expectSendEof();
|
||||||
|
expectReceiveEof();
|
||||||
|
expectVerifyOwnership(alice, false);
|
||||||
|
|
||||||
|
handshakeManager.handshake(pendingContact.getId(), in, streamWriter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectPrepareForHandshake(boolean alice) throws Exception {
|
||||||
|
Transaction txn = new Transaction(null, true);
|
||||||
|
|
||||||
|
context.checking(new DbExpectations() {{
|
||||||
|
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||||
|
oneOf(contactManager).getPendingContact(txn,
|
||||||
|
pendingContact.getId());
|
||||||
|
will(returnValue(pendingContact));
|
||||||
|
oneOf(identityManager).getHandshakeKeys(txn);
|
||||||
|
will(returnValue(ourStaticKeyPair));
|
||||||
|
oneOf(transportCrypto).isAlice(theirStaticPublicKey,
|
||||||
|
ourStaticKeyPair);
|
||||||
|
will(returnValue(alice));
|
||||||
|
oneOf(recordReaderFactory).createRecordReader(in);
|
||||||
|
will(returnValue(recordReader));
|
||||||
|
oneOf(streamWriter).getOutputStream();
|
||||||
|
will(returnValue(out));
|
||||||
|
oneOf(recordWriterFactory).createRecordWriter(out);
|
||||||
|
will(returnValue(recordWriter));
|
||||||
|
oneOf(handshakeCrypto).generateEphemeralKeyPair();
|
||||||
|
will(returnValue(ourEphemeralKeyPair));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectSendMinorVersion() throws Exception {
|
||||||
|
expectWriteRecord(new Record(PROTOCOL_MAJOR_VERSION,
|
||||||
|
RECORD_TYPE_MINOR_VERSION,
|
||||||
|
new byte[] {PROTOCOL_MINOR_VERSION}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectReceiveMinorVersion() throws Exception {
|
||||||
|
expectReadRecord(new Record(PROTOCOL_MAJOR_VERSION,
|
||||||
|
RECORD_TYPE_MINOR_VERSION,
|
||||||
|
new byte[] {PROTOCOL_MINOR_VERSION}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectSendKey() throws Exception {
|
||||||
|
expectWriteRecord(new Record(PROTOCOL_MAJOR_VERSION,
|
||||||
|
RECORD_TYPE_EPHEMERAL_PUBLIC_KEY,
|
||||||
|
ourEphemeralPublicKey.getEncoded()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectReceiveKey() throws Exception {
|
||||||
|
expectReadRecord(new Record(PROTOCOL_MAJOR_VERSION,
|
||||||
|
RECORD_TYPE_EPHEMERAL_PUBLIC_KEY,
|
||||||
|
theirEphemeralPublicKey.getEncoded()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectDeriveMasterKey_0_1(boolean alice) throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(handshakeCrypto).deriveMasterKey_0_1(theirStaticPublicKey,
|
||||||
|
theirEphemeralPublicKey, ourStaticKeyPair,
|
||||||
|
ourEphemeralKeyPair, alice);
|
||||||
|
will(returnValue(masterKey));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectDeriveMasterKey_0_0(boolean alice) throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(handshakeCrypto).deriveMasterKey_0_0(theirStaticPublicKey,
|
||||||
|
theirEphemeralPublicKey, ourStaticKeyPair,
|
||||||
|
ourEphemeralKeyPair, alice);
|
||||||
|
will(returnValue(masterKey));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectDeriveProof(boolean alice) {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(handshakeCrypto).proveOwnership(masterKey, alice);
|
||||||
|
will(returnValue(ourProof));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectSendProof() throws Exception {
|
||||||
|
expectWriteRecord(new Record(PROTOCOL_MAJOR_VERSION,
|
||||||
|
RECORD_TYPE_PROOF_OF_OWNERSHIP, ourProof));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectReceiveProof() throws Exception {
|
||||||
|
expectReadRecord(new Record(PROTOCOL_MAJOR_VERSION,
|
||||||
|
RECORD_TYPE_PROOF_OF_OWNERSHIP, theirProof));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectSendEof() throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(streamWriter).sendEndOfStream();
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectReceiveEof() throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(recordReader).readRecord(with(any(RecordPredicate.class)),
|
||||||
|
with(any(RecordPredicate.class)));
|
||||||
|
will(returnValue(null));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectVerifyOwnership(boolean alice, boolean verified) {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(handshakeCrypto).verifyOwnership(masterKey, !alice,
|
||||||
|
theirProof);
|
||||||
|
will(returnValue(verified));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectWriteRecord(Record record) throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(recordWriter).writeRecord(with(new PredicateMatcher<>(
|
||||||
|
Record.class, r -> recordEquals(record, r))));
|
||||||
|
oneOf(recordWriter).flush();
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean recordEquals(Record expected, Record actual) {
|
||||||
|
return expected.getProtocolVersion() == actual.getProtocolVersion() &&
|
||||||
|
expected.getRecordType() == actual.getRecordType() &&
|
||||||
|
Arrays.equals(expected.getPayload(), actual.getPayload());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expectReadRecord(Record record) throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
// Test that the `accept` predicate passed to the reader would
|
||||||
|
// accept the expected record
|
||||||
|
oneOf(recordReader).readRecord(with(new PredicateMatcher<>(
|
||||||
|
RecordPredicate.class, rp -> rp.test(record))),
|
||||||
|
with(any(RecordPredicate.class)));
|
||||||
|
will(returnValue(record));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,6 +60,22 @@ public class KeyAgreementTest extends BrambleTestCase {
|
|||||||
assertArrayEquals(aShared.getBytes(), bShared.getBytes());
|
assertArrayEquals(aShared.getBytes(), bShared.getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDerivesStaticEphemeralSharedSecretBadly() throws Exception {
|
||||||
|
String label = getRandomString(123);
|
||||||
|
KeyPair aStatic = crypto.generateAgreementKeyPair();
|
||||||
|
KeyPair aEphemeral = crypto.generateAgreementKeyPair();
|
||||||
|
KeyPair bStatic = crypto.generateAgreementKeyPair();
|
||||||
|
KeyPair bEphemeral = crypto.generateAgreementKeyPair();
|
||||||
|
SecretKey aShared = crypto.deriveSharedSecretBadly(label,
|
||||||
|
bStatic.getPublic(), bEphemeral.getPublic(), aStatic,
|
||||||
|
aEphemeral, true, inputs);
|
||||||
|
SecretKey bShared = crypto.deriveSharedSecretBadly(label,
|
||||||
|
aStatic.getPublic(), aEphemeral.getPublic(), bStatic,
|
||||||
|
bEphemeral, false, inputs);
|
||||||
|
assertArrayEquals(aShared.getBytes(), bShared.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDerivesStaticEphemeralSharedSecret() throws Exception {
|
public void testDerivesStaticEphemeralSharedSecret() throws Exception {
|
||||||
String label = getRandomString(123);
|
String label = getRandomString(123);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.briarproject.bramble.keyagreement;
|
package org.briarproject.bramble.keyagreement;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.Predicate;
|
|
||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
|
||||||
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
|
||||||
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
|
||||||
@@ -8,11 +7,13 @@ import org.briarproject.bramble.api.plugin.TransportId;
|
|||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
||||||
import org.briarproject.bramble.api.record.Record;
|
import org.briarproject.bramble.api.record.Record;
|
||||||
import org.briarproject.bramble.api.record.RecordReader;
|
import org.briarproject.bramble.api.record.RecordReader;
|
||||||
|
import org.briarproject.bramble.api.record.RecordReader.RecordPredicate;
|
||||||
import org.briarproject.bramble.api.record.RecordReaderFactory;
|
import org.briarproject.bramble.api.record.RecordReaderFactory;
|
||||||
import org.briarproject.bramble.api.record.RecordWriter;
|
import org.briarproject.bramble.api.record.RecordWriter;
|
||||||
import org.briarproject.bramble.api.record.RecordWriterFactory;
|
import org.briarproject.bramble.api.record.RecordWriterFactory;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.briarproject.bramble.test.CaptureArgumentAction;
|
import org.briarproject.bramble.test.CaptureArgumentAction;
|
||||||
|
import org.briarproject.bramble.test.PredicateMatcher;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.jmock.imposters.ByteBuddyClassImposteriser;
|
import org.jmock.imposters.ByteBuddyClassImposteriser;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -21,8 +22,6 @@ import java.io.InputStream;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.keyagreement.RecordTypes.ABORT;
|
import static org.briarproject.bramble.api.keyagreement.RecordTypes.ABORT;
|
||||||
import static org.briarproject.bramble.api.keyagreement.RecordTypes.CONFIRM;
|
import static org.briarproject.bramble.api.keyagreement.RecordTypes.CONFIRM;
|
||||||
@@ -119,7 +118,7 @@ public class KeyAgreementTransportTest extends BrambleMockTestCase {
|
|||||||
public void testReceiveKeyThrowsExceptionIfAtEndOfStream()
|
public void testReceiveKeyThrowsExceptionIfAtEndOfStream()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
setup();
|
setup();
|
||||||
expectReadRecord(null);
|
expectReadEof();
|
||||||
|
|
||||||
kat.receiveKey();
|
kat.receiveKey();
|
||||||
}
|
}
|
||||||
@@ -148,7 +147,7 @@ public class KeyAgreementTransportTest extends BrambleMockTestCase {
|
|||||||
public void testReceiveConfirmThrowsExceptionIfAtEndOfStream()
|
public void testReceiveConfirmThrowsExceptionIfAtEndOfStream()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
setup();
|
setup();
|
||||||
expectReadRecord(null);
|
expectReadEof();
|
||||||
|
|
||||||
kat.receiveConfirm();
|
kat.receiveConfirm();
|
||||||
}
|
}
|
||||||
@@ -209,12 +208,22 @@ public class KeyAgreementTransportTest extends BrambleMockTestCase {
|
|||||||
assertArrayEquals(expectedPayload, actual.getPayload());
|
assertArrayEquals(expectedPayload, actual.getPayload());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void expectReadRecord(@Nullable Record record) throws Exception {
|
private void expectReadRecord(Record record) throws Exception {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
//noinspection unchecked
|
// Test that the `accept` predicate passed to the reader would
|
||||||
oneOf(recordReader).readRecord(with(any(Predicate.class)),
|
// accept the expected record
|
||||||
with(any(Predicate.class)));
|
oneOf(recordReader).readRecord(with(new PredicateMatcher<>(
|
||||||
|
RecordPredicate.class, rp -> rp.test(record))),
|
||||||
|
with(any(RecordPredicate.class)));
|
||||||
will(returnValue(record));
|
will(returnValue(record));
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void expectReadEof() throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(recordReader).readRecord(with(any(RecordPredicate.class)),
|
||||||
|
with(any(RecordPredicate.class)));
|
||||||
|
will(returnValue(null));
|
||||||
|
}});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package org.briarproject.bramble.record;
|
package org.briarproject.bramble.record;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.Predicate;
|
|
||||||
import org.briarproject.bramble.api.record.Record;
|
import org.briarproject.bramble.api.record.Record;
|
||||||
import org.briarproject.bramble.api.record.RecordReader;
|
import org.briarproject.bramble.api.record.RecordReader;
|
||||||
|
import org.briarproject.bramble.api.record.RecordReader.RecordPredicate;
|
||||||
import org.briarproject.bramble.test.BrambleTestCase;
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
import org.briarproject.bramble.util.ByteUtils;
|
import org.briarproject.bramble.util.ByteUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -128,12 +128,12 @@ public class RecordReaderImplTest extends BrambleTestCase {
|
|||||||
RecordReader reader = new RecordReaderImpl(in);
|
RecordReader reader = new RecordReaderImpl(in);
|
||||||
|
|
||||||
// Accept records with version 0, type 0 or 1
|
// Accept records with version 0, type 0 or 1
|
||||||
Predicate<Record> accept = r -> {
|
RecordPredicate accept = r -> {
|
||||||
byte version = r.getProtocolVersion(), type = r.getRecordType();
|
byte version = r.getProtocolVersion(), type = r.getRecordType();
|
||||||
return version == 0 && (type == 0 || type == 1);
|
return version == 0 && (type == 0 || type == 1);
|
||||||
};
|
};
|
||||||
// Ignore records with version 0, any other type
|
// Ignore records with version 0, any other type
|
||||||
Predicate<Record> ignore = r -> {
|
RecordPredicate ignore = r -> {
|
||||||
byte version = r.getProtocolVersion(), type = r.getRecordType();
|
byte version = r.getProtocolVersion(), type = r.getRecordType();
|
||||||
return version == 0 && !(type == 0 || type == 1);
|
return version == 0 && !(type == 0 || type == 1);
|
||||||
};
|
};
|
||||||
@@ -183,12 +183,12 @@ public class RecordReaderImplTest extends BrambleTestCase {
|
|||||||
RecordReader reader = new RecordReaderImpl(in);
|
RecordReader reader = new RecordReaderImpl(in);
|
||||||
|
|
||||||
// Accept records with version 0, type 0 or 1
|
// Accept records with version 0, type 0 or 1
|
||||||
Predicate<Record> accept = r -> {
|
RecordPredicate accept = r -> {
|
||||||
byte version = r.getProtocolVersion(), type = r.getRecordType();
|
byte version = r.getProtocolVersion(), type = r.getRecordType();
|
||||||
return version == 0 && (type == 0 || type == 1);
|
return version == 0 && (type == 0 || type == 1);
|
||||||
};
|
};
|
||||||
// Ignore records with version 0, any other type
|
// Ignore records with version 0, any other type
|
||||||
Predicate<Record> ignore = r -> {
|
RecordPredicate ignore = r -> {
|
||||||
byte version = r.getProtocolVersion(), type = r.getRecordType();
|
byte version = r.getProtocolVersion(), type = r.getRecordType();
|
||||||
return version == 0 && !(type == 0 || type == 1);
|
return version == 0 && !(type == 0 || type == 1);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package org.briarproject.bramble.sync;
|
package org.briarproject.bramble.sync;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.Predicate;
|
|
||||||
import org.briarproject.bramble.api.UniqueId;
|
import org.briarproject.bramble.api.UniqueId;
|
||||||
import org.briarproject.bramble.api.record.Record;
|
import org.briarproject.bramble.api.record.Record;
|
||||||
import org.briarproject.bramble.api.record.RecordReader;
|
import org.briarproject.bramble.api.record.RecordReader;
|
||||||
|
import org.briarproject.bramble.api.record.RecordReader.RecordPredicate;
|
||||||
import org.briarproject.bramble.api.sync.Ack;
|
import org.briarproject.bramble.api.sync.Ack;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
import org.briarproject.bramble.api.sync.Message;
|
||||||
@@ -24,8 +24,6 @@ import org.junit.Test;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
|
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
|
||||||
import static org.briarproject.bramble.api.sync.RecordTypes.ACK;
|
import static org.briarproject.bramble.api.sync.RecordTypes.ACK;
|
||||||
import static org.briarproject.bramble.api.sync.RecordTypes.MESSAGE;
|
import static org.briarproject.bramble.api.sync.RecordTypes.MESSAGE;
|
||||||
@@ -186,7 +184,7 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testEofReturnsTrueWhenAtEndOfStream() throws Exception {
|
public void testEofReturnsTrueWhenAtEndOfStream() throws Exception {
|
||||||
expectReadRecord(createAck());
|
expectReadRecord(createAck());
|
||||||
expectReadRecord(null);
|
expectReadEof();
|
||||||
|
|
||||||
SyncRecordReader reader =
|
SyncRecordReader reader =
|
||||||
new SyncRecordReaderImpl(messageFactory, recordReader);
|
new SyncRecordReaderImpl(messageFactory, recordReader);
|
||||||
@@ -212,15 +210,25 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
|
|||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void expectReadRecord(@Nullable Record record) throws Exception {
|
private void expectReadRecord(Record record) throws Exception {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
//noinspection unchecked
|
// Test that the `accept` predicate passed to the reader would
|
||||||
oneOf(recordReader).readRecord(with(any(Predicate.class)),
|
// accept the expected record
|
||||||
with(any(Predicate.class)));
|
oneOf(recordReader).readRecord(with(new PredicateMatcher<>(
|
||||||
|
RecordPredicate.class, rp -> rp.test(record))),
|
||||||
|
with(any(RecordPredicate.class)));
|
||||||
will(returnValue(record));
|
will(returnValue(record));
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void expectReadEof() throws Exception {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(recordReader).readRecord(with(any(RecordPredicate.class)),
|
||||||
|
with(any(RecordPredicate.class)));
|
||||||
|
will(returnValue(null));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
private Record createMessage(int payloadLength) {
|
private Record createMessage(int payloadLength) {
|
||||||
return new Record(PROTOCOL_VERSION, MESSAGE, new byte[payloadLength]);
|
return new Record(PROTOCOL_VERSION, MESSAGE, new byte[payloadLength]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,12 +234,12 @@ public abstract class BrambleIntegrationTest<C extends BrambleIntegrationTestCom
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void awaitPendingMessageDelivery(int num)
|
protected void awaitPendingMessageDelivery(int num)
|
||||||
throws TimeoutException {
|
throws TimeoutException, InterruptedException {
|
||||||
awaitPendingMessageDelivery(num, TIMEOUT);
|
awaitPendingMessageDelivery(num, TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void awaitPendingMessageDelivery(int num, long timeout)
|
protected void awaitPendingMessageDelivery(int num, long timeout)
|
||||||
throws TimeoutException {
|
throws TimeoutException, InterruptedException {
|
||||||
deliveryWaiter.await(timeout, num);
|
deliveryWaiter.await(timeout, num);
|
||||||
assertEquals("Messages delivered", num, deliveryCounter.getAndSet(0));
|
assertEquals("Messages delivered", num, deliveryCounter.getAndSet(0));
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ dependencyVerification {
|
|||||||
'com.fasterxml.jackson.core:jackson-databind:2.13.4:jackson-databind-2.13.4.jar:c9faff420d9e2c7e1e4711dbeebec2506a32c9942027211c5c293d8d87807eb6',
|
'com.fasterxml.jackson.core:jackson-databind:2.13.4:jackson-databind-2.13.4.jar:c9faff420d9e2c7e1e4711dbeebec2506a32c9942027211c5c293d8d87807eb6',
|
||||||
'com.google.code.findbugs:annotations:3.0.1:annotations-3.0.1.jar:6b47ff0a6de0ce17cbedc3abb0828ca5bce3009d53ea47b3723ff023c4742f79',
|
'com.google.code.findbugs:annotations:3.0.1:annotations-3.0.1.jar:6b47ff0a6de0ce17cbedc3abb0828ca5bce3009d53ea47b3723ff023c4742f79',
|
||||||
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
|
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
|
||||||
'com.google.dagger:dagger-compiler:2.43.2:dagger-compiler-2.43.2.jar:298c020ee6ed2f4cc651ebbfdb7f8de329b07c44b618d65be117846a850e2a03',
|
'com.google.dagger:dagger-compiler:2.45:dagger-compiler-2.45.jar:5617dfb994537dba5b41f3744a6dd13ec3cd99789c065e0d5c6fa9f21cf7ca25',
|
||||||
'com.google.dagger:dagger-producers:2.43.2:dagger-producers-2.43.2.jar:e7f5d9ffc85d48a49c8e22e02833d418f7ccad5d7512f529964db5127ab915ff',
|
'com.google.dagger:dagger-producers:2.45:dagger-producers-2.45.jar:a05abb4c3ccf6bb0f056bdcb5ef973898ecf172952ab5948a824aeea6c86ecaa',
|
||||||
'com.google.dagger:dagger-spi:2.43.2:dagger-spi-2.43.2.jar:3bae8d9dadeaaa5927da6f094389a560c12c05fec3d2711d2fa79292c7a7d7ad',
|
'com.google.dagger:dagger-spi:2.45:dagger-spi-2.45.jar:7cd6f0b09d88e64a9c97bc80e544ab8ac8fdee9301754413585a74cf64222b27',
|
||||||
'com.google.dagger:dagger:2.43.2:dagger-2.43.2.jar:c89681f7cbbf8c527bf4ac2748515d617fdb54a1d425c08d914fdc28192b5fe4',
|
'com.google.dagger:dagger:2.45:dagger-2.45.jar:f011cae7d2c0fb7ea17c34e05bc10e768b1081a5892ad019cf1fdb0e125c49c1',
|
||||||
'com.google.devtools.ksp:symbol-processing-api:1.7.0-1.0.6:symbol-processing-api-1.7.0-1.0.6.jar:adc29417be5ca9ff42118105fea4e36d9ef44987abfc41432309371a60198941',
|
'com.google.devtools.ksp:symbol-processing-api:1.7.0-1.0.6:symbol-processing-api-1.7.0-1.0.6.jar:adc29417be5ca9ff42118105fea4e36d9ef44987abfc41432309371a60198941',
|
||||||
'com.google.errorprone:error_prone_annotations:2.7.1:error_prone_annotations-2.7.1.jar:cd5257c08a246cf8628817ae71cb822be192ef91f6881ca4a3fcff4f1de1cff3',
|
'com.google.errorprone:error_prone_annotations:2.7.1:error_prone_annotations-2.7.1.jar:cd5257c08a246cf8628817ae71cb822be192ef91f6881ca4a3fcff4f1de1cff3',
|
||||||
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
|
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
|
||||||
@@ -19,42 +19,44 @@ dependencyVerification {
|
|||||||
'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava:listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99',
|
'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava:listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99',
|
||||||
'com.google.j2objc:j2objc-annotations:1.3:j2objc-annotations-1.3.jar:21af30c92267bd6122c0e0b4d20cccb6641a37eaf956c6540ec471d584e64a7b',
|
'com.google.j2objc:j2objc-annotations:1.3:j2objc-annotations-1.3.jar:21af30c92267bd6122c0e0b4d20cccb6641a37eaf956c6540ec471d584e64a7b',
|
||||||
'com.h2database:h2:1.4.192:h2-1.4.192.jar:225b22e9857235c46c93861410b60b8c81c10dc8985f4faf188985ba5445126c',
|
'com.h2database:h2:1.4.192:h2-1.4.192.jar:225b22e9857235c46c93861410b60b8c81c10dc8985f4faf188985ba5445126c',
|
||||||
'com.squareup.okhttp3:mockwebserver:4.9.3:mockwebserver-4.9.3.jar:9c8c581c29f22f877a35d11380462f75bb24bf1886204fe835ee695594a2784e',
|
'com.squareup.okhttp3:mockwebserver:4.10.0:mockwebserver-4.10.0.jar:af29da234e63159d6e0dea43bf8288eea97d71cdf1651a5ee2d6c0d0d4adbf8f',
|
||||||
'com.squareup.okhttp3:okhttp:3.12.13:okhttp-3.12.13.jar:508234e024ef7e270ab1a6d5b356f5b98e786511239ca986d684fd1e2cf7bc82',
|
'com.squareup.okhttp3:okhttp:4.10.0:okhttp-4.10.0.jar:7580f14fa1691206e37081ad3f92063b1603b328da0bb316f2fef02e0562e7ec',
|
||||||
'com.squareup.okhttp3:okhttp:4.9.3:okhttp-4.9.3.jar:93ecd6cba19d87dccfe566ec848d91aae799e3cf16c00709358ea69bd9227219',
|
'com.squareup.okio:okio-jvm:3.0.0:okio-jvm-3.0.0.jar:be64a0cc1f28ea9cd5c970dd7e7557af72c808d738c495b397bf897c9921e907',
|
||||||
'com.squareup.okio:okio:1.15.0:okio-1.15.0.jar:693fa319a7e8843300602b204023b7674f106ebcb577f2dd5807212b66118bd2',
|
|
||||||
'com.squareup.okio:okio:2.8.0:okio-jvm-2.8.0.jar:4496b06e73982fcdd8a5393f46e5df2ce2fa4465df5895454cac68a32f09bbc8',
|
|
||||||
'com.squareup:javapoet:1.13.0:javapoet-1.13.0.jar:4c7517e848a71b36d069d12bb3bf46a70fd4cda3105d822b0ed2e19c00b69291',
|
'com.squareup:javapoet:1.13.0:javapoet-1.13.0.jar:4c7517e848a71b36d069d12bb3bf46a70fd4cda3105d822b0ed2e19c00b69291',
|
||||||
|
'com.squareup:kotlinpoet:1.11.0:kotlinpoet-1.11.0.jar:2887ada1ca03dd83baa2758640d87e840d1907564db0ef88d2289c868a980492',
|
||||||
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||||
'junit:junit:4.13.2:junit-4.13.2.jar:8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3',
|
'junit:junit:4.13.2:junit-4.13.2.jar:8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3',
|
||||||
'net.bytebuddy:byte-buddy:1.9.12:byte-buddy-1.9.12.jar:3688c3d434bebc3edc5516296a2ed0f47b65e451071b4afecad84f902f0efc11',
|
'net.bytebuddy:byte-buddy:1.9.12:byte-buddy-1.9.12.jar:3688c3d434bebc3edc5516296a2ed0f47b65e451071b4afecad84f902f0efc11',
|
||||||
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
|
'net.i2p.crypto:eddsa:0.2.0:eddsa-0.2.0.jar:a7cb1b85c16e2f0730b9204106929a1d9aaae1df728adc7041a8b8b605692140',
|
||||||
'net.jcip:jcip-annotations:1.0:jcip-annotations-1.0.jar:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0',
|
'net.jcip:jcip-annotations:1.0:jcip-annotations-1.0.jar:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0',
|
||||||
'net.jodah:concurrentunit:0.4.2:concurrentunit-0.4.2.jar:5583078e1acf91734939e985bc9e7ee947b0e93a8eef679da6bb07bbeb47ced3',
|
'net.jodah:concurrentunit:0.4.6:concurrentunit-0.4.6.jar:760e6d4ab7801484de09da621b61141f3b2c2432949da9eb13f076e5d9a5e0a5',
|
||||||
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
|
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
|
||||||
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
|
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
|
||||||
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
|
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
|
||||||
'org.bouncycastle:bcprov-jdk15to18:1.71:bcprov-jdk15to18-1.71.jar:143aaa4a40edd5fc2a18db7900059f6c16f4d931b94b94b20f7e2238e6662886',
|
'org.bouncycastle:bcprov-jdk15to18:1.71:bcprov-jdk15to18-1.71.jar:143aaa4a40edd5fc2a18db7900059f6c16f4d931b94b94b20f7e2238e6662886',
|
||||||
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
|
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
|
||||||
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
|
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
|
||||||
'org.briarproject:onionwrapper-core:0.0.1:onionwrapper-core-0.0.1.jar:a1937506b00ee6620e909a500e5d004be81f94a6f7d7c898e1a9e841a8ae8a2a',
|
'org.briarproject:onionwrapper-core:0.0.2:onionwrapper-core-0.0.2.jar:7038e960c9e59803f0e2c19444dbb5214cd99e5a7463c0a01c45318e07a0eb80',
|
||||||
'org.briarproject:socks-socket:0.1:socks-socket-0.1.jar:e5898822d10f5390363c5dddb945891648c92cf93ba50709e07f0d173ec0eb4b',
|
'org.briarproject:socks-socket:0.1:socks-socket-0.1.jar:e5898822d10f5390363c5dddb945891648c92cf93ba50709e07f0d173ec0eb4b',
|
||||||
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
||||||
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
|
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
|
||||||
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
|
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
|
||||||
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.20:animal-sniffer-ant-tasks-1.20.jar:bb7d2498144118311d968bb08ff6fae3fc535fb1cb9cca8b8e9ea65b189422ac',
|
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.22:animal-sniffer-ant-tasks-1.22.jar:3f6afeb3e09301d2d7179ed1db21e3ad8846c1e38415ad832a395138ae3f4218',
|
||||||
'org.codehaus.mojo:animal-sniffer:1.20:animal-sniffer-1.20.jar:80c422523c38db91260c6d78e5ee4b012862ab61cc55020c9e243dd7b5c62249',
|
'org.codehaus.mojo:animal-sniffer:1.22:animal-sniffer-1.22.jar:f18c11a25bdd8b520b9c6a28cbb6f33007c812ab0051b6be3f0778e660aa501c',
|
||||||
'org.hamcrest:hamcrest-core:2.1:hamcrest-core-2.1.jar:e09109e54a289d88506b9bfec987ddd199f4217c9464132668351b9a4f00bee9',
|
'org.hamcrest:hamcrest-core:2.1:hamcrest-core-2.1.jar:e09109e54a289d88506b9bfec987ddd199f4217c9464132668351b9a4f00bee9',
|
||||||
'org.hamcrest:hamcrest-library:2.1:hamcrest-library-2.1.jar:b7e2b6895b3b679f0e47b6380fda391b225e9b78505db9d8bdde8d3cc8d52a21',
|
'org.hamcrest:hamcrest-library:2.1:hamcrest-library-2.1.jar:b7e2b6895b3b679f0e47b6380fda391b225e9b78505db9d8bdde8d3cc8d52a21',
|
||||||
'org.hamcrest:hamcrest:2.1:hamcrest-2.1.jar:ba93b2e3a562322ba432f0a1b53addcc55cb188253319a020ed77f824e692050',
|
'org.hamcrest:hamcrest:2.1:hamcrest-2.1.jar:ba93b2e3a562322ba432f0a1b53addcc55cb188253319a020ed77f824e692050',
|
||||||
'org.hsqldb:hsqldb:2.3.5:hsqldb-2.3.5.jar:6676a6977ac98997a80f827ddbd3fe8ca1e0853dad1492512135fd1a222ccfad',
|
'org.hsqldb:hsqldb:2.3.5:hsqldb-2.3.5.jar:6676a6977ac98997a80f827ddbd3fe8ca1e0853dad1492512135fd1a222ccfad',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-common:1.4.10:kotlin-stdlib-common-1.4.10.jar:4681f2d436a68c7523595d84ed5758e1382f9da0f67c91e6a848690d711274fe',
|
'org.jetbrains.kotlin:kotlin-reflect:1.6.10:kotlin-reflect-1.6.10.jar:3277ac102ae17aad10a55abec75ff5696c8d109790396434b496e75087854203',
|
||||||
|
'org.jetbrains.kotlin:kotlin-stdlib-common:1.6.20:kotlin-stdlib-common-1.6.20.jar:8da40a2520d30dcb1012176fe93d24e82d08a3e346c37e0343b0fb6f64f6be01',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-common:1.7.0:kotlin-stdlib-common-1.7.0.jar:59c6ff64fe9a6604afce03e8aaa75f83586c6030ac71fb0b34ee7cdefed3618f',
|
'org.jetbrains.kotlin:kotlin-stdlib-common:1.7.0:kotlin-stdlib-common-1.7.0.jar:59c6ff64fe9a6604afce03e8aaa75f83586c6030ac71fb0b34ee7cdefed3618f',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.10:kotlin-stdlib-jdk7-1.4.10.jar:f9566380c08722c780ce33ceee23e98ddf765ca98fabd3e2fabae7975c8d232b',
|
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.31:kotlin-stdlib-jdk7-1.5.31.jar:a25bf47353ce899d843cbddee516d621a73473e7fba97f8d0301e7b4aed7c15f',
|
||||||
|
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.10:kotlin-stdlib-jdk7-1.6.10.jar:2aedcdc6b69b33bdf5cc235bcea88e7cf6601146bb6bcdffdb312bbacd7be261',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.0:kotlin-stdlib-jdk7-1.7.0.jar:07e91be9b2ca20672d2bdb7e181b766e73453a2da13492b5ddaee8fa47aea239',
|
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.0:kotlin-stdlib-jdk7-1.7.0.jar:07e91be9b2ca20672d2bdb7e181b766e73453a2da13492b5ddaee8fa47aea239',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.10:kotlin-stdlib-jdk8-1.4.10.jar:39b7a9442d7a3865e0f4a732c56c1d5da0e11ffb3bb82a461d32deb0c0ca7673',
|
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.31:kotlin-stdlib-jdk8-1.5.31.jar:b548f7767aacf029d2417e47440742bd6d3ebede19b60386e23554ce5c4c5fdc',
|
||||||
|
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.10:kotlin-stdlib-jdk8-1.6.10.jar:1456d82d039ea30d8485b032901f52bbf07e7cdbe8bb1f8708ad32a8574c41ce',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.0:kotlin-stdlib-jdk8-1.7.0.jar:cf058e11db1dfc9944680c8c61b95ac689aaaa8a3eb30bced028100f038f030b',
|
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.0:kotlin-stdlib-jdk8-1.7.0.jar:cf058e11db1dfc9944680c8c61b95ac689aaaa8a3eb30bced028100f038f030b',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib:1.4.10:kotlin-stdlib-1.4.10.jar:01ecb09782c042b931c1839acf21a188340b295d05400afd6e3415d4475b8daa',
|
'org.jetbrains.kotlin:kotlin-stdlib:1.6.20:kotlin-stdlib-1.6.20.jar:eeb51c2b67b26233fd81d0bc4f8044ec849718890905763ceffd84a31e2cb799',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib:1.7.0:kotlin-stdlib-1.7.0.jar:aa88e9625577957f3249a46cb6e166ee09b369e600f7a11d148d16b0a6d87f05',
|
'org.jetbrains.kotlin:kotlin-stdlib:1.7.0:kotlin-stdlib-1.7.0.jar:aa88e9625577957f3249a46cb6e166ee09b369e600f7a11d148d16b0a6d87f05',
|
||||||
'org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.5.0:kotlinx-metadata-jvm-0.5.0.jar:ca063a96639b08b9eaa0de4d65e899480740a6efbe28ab9a8681a2ced03055a4',
|
'org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.5.0:kotlinx-metadata-jvm-0.5.0.jar:ca063a96639b08b9eaa0de4d65e899480740a6efbe28ab9a8681a2ced03055a4',
|
||||||
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
|
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
|
||||||
@@ -65,7 +67,7 @@ dependencyVerification {
|
|||||||
'org.jmock:jmock:2.12.0:jmock-2.12.0.jar:266d07314c0cd343c46ff8a55601272de8cf406807caf55e6f313295f83d10be',
|
'org.jmock:jmock:2.12.0:jmock-2.12.0.jar:266d07314c0cd343c46ff8a55601272de8cf406807caf55e6f313295f83d10be',
|
||||||
'org.objenesis:objenesis:3.0.1:objenesis-3.0.1.jar:7a8ff780b9ff48415d7c705f60030b0acaa616e7f823c98eede3b63508d4e984',
|
'org.objenesis:objenesis:3.0.1:objenesis-3.0.1.jar:7a8ff780b9ff48415d7c705f60030b0acaa616e7f823c98eede3b63508d4e984',
|
||||||
'org.ow2.asm:asm:7.1:asm-7.1.jar:4ab2fa2b6d2cc9ccb1eaa05ea329c407b47b13ed2915f62f8c4b8cc96258d4de',
|
'org.ow2.asm:asm:7.1:asm-7.1.jar:4ab2fa2b6d2cc9ccb1eaa05ea329c407b47b13ed2915f62f8c4b8cc96258d4de',
|
||||||
'org.ow2.asm:asm:9.1:asm-9.1.jar:cda4de455fab48ff0bcb7c48b4639447d4de859a7afc30a094a986f0936beba2',
|
'org.ow2.asm:asm:9.3:asm-9.3.jar:1263369b59e29c943918de11d6d6152e2ec6085ce63e5710516f8c67d368e4bc',
|
||||||
'org.whispersystems:curve25519-java:0.5.0:curve25519-java-0.5.0.jar:0aadd43cf01d11e9b58f867b3c4f25c3194e8b0623d1953d32dfbfbee009e38d',
|
'org.whispersystems:curve25519-java:0.5.0:curve25519-java-0.5.0.jar:0aadd43cf01d11e9b58f867b3c4f25c3194e8b0623d1953d32dfbfbee009e38d',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package org.briarproject.bramble;
|
|||||||
import org.briarproject.bramble.io.DnsModule;
|
import org.briarproject.bramble.io.DnsModule;
|
||||||
import org.briarproject.bramble.mailbox.ModularMailboxModule;
|
import org.briarproject.bramble.mailbox.ModularMailboxModule;
|
||||||
import org.briarproject.bramble.network.JavaNetworkModule;
|
import org.briarproject.bramble.network.JavaNetworkModule;
|
||||||
|
import org.briarproject.bramble.plugin.tor.CircumventionModule;
|
||||||
import org.briarproject.bramble.socks.SocksModule;
|
import org.briarproject.bramble.socks.SocksModule;
|
||||||
import org.briarproject.bramble.system.JavaSystemModule;
|
import org.briarproject.bramble.system.JavaSystemModule;
|
||||||
import org.briarproject.onionwrapper.CircumventionModule;
|
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import org.briarproject.bramble.api.plugin.TorControlPort;
|
|||||||
import org.briarproject.bramble.api.plugin.TorDirectory;
|
import org.briarproject.bramble.api.plugin.TorDirectory;
|
||||||
import org.briarproject.bramble.api.plugin.TorSocksPort;
|
import org.briarproject.bramble.api.plugin.TorSocksPort;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
|
||||||
import org.briarproject.bramble.api.system.WakefulIoExecutor;
|
import org.briarproject.bramble.api.system.WakefulIoExecutor;
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.onionwrapper.CircumventionProvider;
|
import org.briarproject.onionwrapper.CircumventionProvider;
|
||||||
|
import org.briarproject.onionwrapper.LocationUtils;
|
||||||
import org.briarproject.onionwrapper.TorWrapper;
|
import org.briarproject.onionwrapper.TorWrapper;
|
||||||
import org.briarproject.onionwrapper.UnixTorWrapper;
|
import org.briarproject.onionwrapper.UnixTorWrapper;
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import org.briarproject.bramble.api.plugin.TorControlPort;
|
|||||||
import org.briarproject.bramble.api.plugin.TorDirectory;
|
import org.briarproject.bramble.api.plugin.TorDirectory;
|
||||||
import org.briarproject.bramble.api.plugin.TorSocksPort;
|
import org.briarproject.bramble.api.plugin.TorSocksPort;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
|
||||||
import org.briarproject.bramble.api.system.WakefulIoExecutor;
|
import org.briarproject.bramble.api.system.WakefulIoExecutor;
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.onionwrapper.CircumventionProvider;
|
import org.briarproject.onionwrapper.CircumventionProvider;
|
||||||
|
import org.briarproject.onionwrapper.LocationUtils;
|
||||||
import org.briarproject.onionwrapper.TorWrapper;
|
import org.briarproject.onionwrapper.TorWrapper;
|
||||||
import org.briarproject.onionwrapper.WindowsTorWrapper;
|
import org.briarproject.onionwrapper.WindowsTorWrapper;
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public class DesktopSecureRandomModule {
|
|||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
SecureRandomProvider provideSecureRandomProvider() {
|
SecureRandomProvider provideSecureRandomProvider() {
|
||||||
if (isLinux() || isMac()) return new UnixSecureRandomProvider();
|
if (isLinux()) return new UnixSecureRandomProvider();
|
||||||
return () -> null; // Use system default
|
return () -> null; // Use system default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
package org.briarproject.bramble.system;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
|
||||||
class JavaLocationUtils implements LocationUtils {
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(JavaLocationUtils.class.getName());
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
JavaLocationUtils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCurrentCountry() {
|
|
||||||
LOG.info("Using user-defined locale");
|
|
||||||
return Locale.getDefault().getCountry();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
package org.briarproject.bramble.system;
|
package org.briarproject.bramble.system;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
|
||||||
import org.briarproject.bramble.api.system.ResourceProvider;
|
import org.briarproject.bramble.api.system.ResourceProvider;
|
||||||
|
import org.briarproject.onionwrapper.JavaLocationUtilsFactory;
|
||||||
|
import org.briarproject.onionwrapper.LocationUtils;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
@@ -13,8 +14,8 @@ public class JavaSystemModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
LocationUtils provideLocationUtils(JavaLocationUtils locationUtils) {
|
LocationUtils provideLocationUtils() {
|
||||||
return locationUtils;
|
return JavaLocationUtilsFactory.createJavaLocationUtils();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ dependencyVerification {
|
|||||||
'cglib:cglib:3.2.8:cglib-3.2.8.jar:3f64de999ecc5595dc84ca8ff0879d8a34c8623f9ef3c517a53ed59023fcb9db',
|
'cglib:cglib:3.2.8:cglib-3.2.8.jar:3f64de999ecc5595dc84ca8ff0879d8a34c8623f9ef3c517a53ed59023fcb9db',
|
||||||
'com.google.code.findbugs:annotations:3.0.1:annotations-3.0.1.jar:6b47ff0a6de0ce17cbedc3abb0828ca5bce3009d53ea47b3723ff023c4742f79',
|
'com.google.code.findbugs:annotations:3.0.1:annotations-3.0.1.jar:6b47ff0a6de0ce17cbedc3abb0828ca5bce3009d53ea47b3723ff023c4742f79',
|
||||||
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
|
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
|
||||||
'com.google.dagger:dagger-compiler:2.43.2:dagger-compiler-2.43.2.jar:298c020ee6ed2f4cc651ebbfdb7f8de329b07c44b618d65be117846a850e2a03',
|
'com.google.dagger:dagger-compiler:2.45:dagger-compiler-2.45.jar:5617dfb994537dba5b41f3744a6dd13ec3cd99789c065e0d5c6fa9f21cf7ca25',
|
||||||
'com.google.dagger:dagger-producers:2.43.2:dagger-producers-2.43.2.jar:e7f5d9ffc85d48a49c8e22e02833d418f7ccad5d7512f529964db5127ab915ff',
|
'com.google.dagger:dagger-producers:2.45:dagger-producers-2.45.jar:a05abb4c3ccf6bb0f056bdcb5ef973898ecf172952ab5948a824aeea6c86ecaa',
|
||||||
'com.google.dagger:dagger-spi:2.43.2:dagger-spi-2.43.2.jar:3bae8d9dadeaaa5927da6f094389a560c12c05fec3d2711d2fa79292c7a7d7ad',
|
'com.google.dagger:dagger-spi:2.45:dagger-spi-2.45.jar:7cd6f0b09d88e64a9c97bc80e544ab8ac8fdee9301754413585a74cf64222b27',
|
||||||
'com.google.dagger:dagger:2.43.2:dagger-2.43.2.jar:c89681f7cbbf8c527bf4ac2748515d617fdb54a1d425c08d914fdc28192b5fe4',
|
'com.google.dagger:dagger:2.45:dagger-2.45.jar:f011cae7d2c0fb7ea17c34e05bc10e768b1081a5892ad019cf1fdb0e125c49c1',
|
||||||
'com.google.devtools.ksp:symbol-processing-api:1.7.0-1.0.6:symbol-processing-api-1.7.0-1.0.6.jar:adc29417be5ca9ff42118105fea4e36d9ef44987abfc41432309371a60198941',
|
'com.google.devtools.ksp:symbol-processing-api:1.7.0-1.0.6:symbol-processing-api-1.7.0-1.0.6.jar:adc29417be5ca9ff42118105fea4e36d9ef44987abfc41432309371a60198941',
|
||||||
'com.google.errorprone:error_prone_annotations:2.7.1:error_prone_annotations-2.7.1.jar:cd5257c08a246cf8628817ae71cb822be192ef91f6881ca4a3fcff4f1de1cff3',
|
'com.google.errorprone:error_prone_annotations:2.7.1:error_prone_annotations-2.7.1.jar:cd5257c08a246cf8628817ae71cb822be192ef91f6881ca4a3fcff4f1de1cff3',
|
||||||
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
|
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
|
||||||
@@ -16,6 +16,7 @@ dependencyVerification {
|
|||||||
'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava:listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99',
|
'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava:listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99',
|
||||||
'com.google.j2objc:j2objc-annotations:1.3:j2objc-annotations-1.3.jar:21af30c92267bd6122c0e0b4d20cccb6641a37eaf956c6540ec471d584e64a7b',
|
'com.google.j2objc:j2objc-annotations:1.3:j2objc-annotations-1.3.jar:21af30c92267bd6122c0e0b4d20cccb6641a37eaf956c6540ec471d584e64a7b',
|
||||||
'com.squareup:javapoet:1.13.0:javapoet-1.13.0.jar:4c7517e848a71b36d069d12bb3bf46a70fd4cda3105d822b0ed2e19c00b69291',
|
'com.squareup:javapoet:1.13.0:javapoet-1.13.0.jar:4c7517e848a71b36d069d12bb3bf46a70fd4cda3105d822b0ed2e19c00b69291',
|
||||||
|
'com.squareup:kotlinpoet:1.11.0:kotlinpoet-1.11.0.jar:2887ada1ca03dd83baa2758640d87e840d1907564db0ef88d2289c868a980492',
|
||||||
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||||
'junit:junit:4.13.2:junit-4.13.2.jar:8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3',
|
'junit:junit:4.13.2:junit-4.13.2.jar:8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3',
|
||||||
'net.bytebuddy:byte-buddy:1.9.12:byte-buddy-1.9.12.jar:3688c3d434bebc3edc5516296a2ed0f47b65e451071b4afecad84f902f0efc11',
|
'net.bytebuddy:byte-buddy:1.9.12:byte-buddy-1.9.12.jar:3688c3d434bebc3edc5516296a2ed0f47b65e451071b4afecad84f902f0efc11',
|
||||||
@@ -26,13 +27,14 @@ dependencyVerification {
|
|||||||
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
|
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
|
||||||
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
|
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
|
||||||
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
|
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
|
||||||
'org.briarproject:onionwrapper-core:0.0.1:onionwrapper-core-0.0.1.jar:a1937506b00ee6620e909a500e5d004be81f94a6f7d7c898e1a9e841a8ae8a2a',
|
'org.briarproject:onionwrapper-core:0.0.2:onionwrapper-core-0.0.2.jar:7038e960c9e59803f0e2c19444dbb5214cd99e5a7463c0a01c45318e07a0eb80',
|
||||||
'org.briarproject:onionwrapper-java:0.0.1:onionwrapper-java-0.0.1.jar:102ccea934d02b13702fd28e890e27e342db8b669a4c84bb54a3783cb8926552',
|
'org.briarproject:onionwrapper-java:0.0.2:onionwrapper-java-0.0.2.jar:87a3f4082174dbbd32c4f5f062b46af1d3fedd8cfa1ec84f6ce6ccb6e3674fb6',
|
||||||
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
'org.checkerframework:checker-compat-qual:2.5.5:checker-compat-qual-2.5.5.jar:11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a',
|
||||||
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
|
'org.checkerframework:checker-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
|
||||||
'org.hamcrest:hamcrest-core:2.1:hamcrest-core-2.1.jar:e09109e54a289d88506b9bfec987ddd199f4217c9464132668351b9a4f00bee9',
|
'org.hamcrest:hamcrest-core:2.1:hamcrest-core-2.1.jar:e09109e54a289d88506b9bfec987ddd199f4217c9464132668351b9a4f00bee9',
|
||||||
'org.hamcrest:hamcrest-library:2.1:hamcrest-library-2.1.jar:b7e2b6895b3b679f0e47b6380fda391b225e9b78505db9d8bdde8d3cc8d52a21',
|
'org.hamcrest:hamcrest-library:2.1:hamcrest-library-2.1.jar:b7e2b6895b3b679f0e47b6380fda391b225e9b78505db9d8bdde8d3cc8d52a21',
|
||||||
'org.hamcrest:hamcrest:2.1:hamcrest-2.1.jar:ba93b2e3a562322ba432f0a1b53addcc55cb188253319a020ed77f824e692050',
|
'org.hamcrest:hamcrest:2.1:hamcrest-2.1.jar:ba93b2e3a562322ba432f0a1b53addcc55cb188253319a020ed77f824e692050',
|
||||||
|
'org.jetbrains.kotlin:kotlin-reflect:1.6.10:kotlin-reflect-1.6.10.jar:3277ac102ae17aad10a55abec75ff5696c8d109790396434b496e75087854203',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-common:1.7.0:kotlin-stdlib-common-1.7.0.jar:59c6ff64fe9a6604afce03e8aaa75f83586c6030ac71fb0b34ee7cdefed3618f',
|
'org.jetbrains.kotlin:kotlin-stdlib-common:1.7.0:kotlin-stdlib-common-1.7.0.jar:59c6ff64fe9a6604afce03e8aaa75f83586c6030ac71fb0b34ee7cdefed3618f',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.0:kotlin-stdlib-jdk7-1.7.0.jar:07e91be9b2ca20672d2bdb7e181b766e73453a2da13492b5ddaee8fa47aea239',
|
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.0:kotlin-stdlib-jdk7-1.7.0.jar:07e91be9b2ca20672d2bdb7e181b766e73453a2da13492b5ddaee8fa47aea239',
|
||||||
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.0:kotlin-stdlib-jdk8-1.7.0.jar:cf058e11db1dfc9944680c8c61b95ac689aaaa8a3eb30bced028100f038f030b',
|
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.0:kotlin-stdlib-jdk8-1.7.0.jar:cf058e11db1dfc9944680c8c61b95ac689aaaa8a3eb30bced028100f038f030b',
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 16
|
minSdkVersion 21
|
||||||
targetSdkVersion 31
|
targetSdkVersion 31
|
||||||
versionCode 10500
|
versionCode 10503
|
||||||
versionName "1.5.0"
|
versionName "1.5.3"
|
||||||
applicationId "org.briarproject.briar.android"
|
applicationId "org.briarproject.briar.android"
|
||||||
buildConfigField "String", "TorVersion", "\"$tor_version\""
|
buildConfigField "String", "TorVersion", "\"$tor_version\""
|
||||||
|
|
||||||
@@ -62,7 +62,6 @@ android {
|
|||||||
productFlavors {
|
productFlavors {
|
||||||
screenshot {
|
screenshot {
|
||||||
dimension "version"
|
dimension "version"
|
||||||
minSdkVersion 21
|
|
||||||
applicationIdSuffix ".screenshot" // = org.briarproject.briar.android.screenshot.debug
|
applicationIdSuffix ".screenshot" // = org.briarproject.briar.android.screenshot.debug
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-test.txt'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt', 'proguard-test.txt'
|
||||||
}
|
}
|
||||||
@@ -90,6 +89,7 @@ android {
|
|||||||
|
|
||||||
lintOptions {
|
lintOptions {
|
||||||
warning 'MissingTranslation'
|
warning 'MissingTranslation'
|
||||||
|
warning 'MissingDefaultResource'
|
||||||
warning 'ImpliedQuantity'
|
warning 'ImpliedQuantity'
|
||||||
warning 'ExtraTranslation'
|
warning 'ExtraTranslation'
|
||||||
// FIXME
|
// FIXME
|
||||||
@@ -108,24 +108,30 @@ dependencies {
|
|||||||
implementation project(':bramble-android')
|
implementation project(':bramble-android')
|
||||||
implementation project(':briar-core')
|
implementation project(':briar-core')
|
||||||
|
|
||||||
implementation 'androidx.fragment:fragment:1.3.4'
|
implementation 'androidx.fragment:fragment:1.5.5'
|
||||||
implementation 'androidx.preference:preference:1.1.1'
|
implementation 'androidx.preference:preference:1.2.0'
|
||||||
implementation 'androidx.exifinterface:exifinterface:1.3.3'
|
implementation 'androidx.exifinterface:exifinterface:1.3.6'
|
||||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
implementation 'androidx.lifecycle:lifecycle-livedata:2.5.1'
|
||||||
implementation 'com.google.android.material:material:1.3.0'
|
|
||||||
|
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||||
|
// check https://github.com/material-components/material-components-android/issues/3191
|
||||||
|
// before upgrading material library
|
||||||
|
implementation 'com.google.android.material:material:1.7.0'
|
||||||
implementation 'androidx.recyclerview:recyclerview-selection:1.1.0'
|
implementation 'androidx.recyclerview:recyclerview-selection:1.1.0'
|
||||||
|
|
||||||
|
// force kotlin standard lib to latest version to prevent jetifier issues
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
|
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
|
||||||
implementation "org.jsoup:jsoup:$jsoup_version"
|
implementation "org.jsoup:jsoup:$jsoup_version"
|
||||||
implementation 'info.guardianproject.panic:panic:1.0'
|
implementation 'info.guardianproject.panic:panic:1.0'
|
||||||
implementation 'de.hdodenhof:circleimageview:3.1.0'
|
implementation 'de.hdodenhof:circleimageview:3.1.0'
|
||||||
implementation 'com.google.zxing:core:3.3.3' // newer version need minSdk 24
|
implementation 'com.google.zxing:core:3.3.3' // newer version need minSdk 24
|
||||||
implementation 'uk.co.samuelwall:material-tap-target-prompt:3.3.0'
|
implementation 'uk.co.samuelwall:material-tap-target-prompt:3.3.2'
|
||||||
implementation 'com.vanniktech:emoji-google:0.7.0' // newer versions need minSdk 21
|
implementation 'com.vanniktech:emoji-google:0.9.0' // newer versions are more work to adapt
|
||||||
implementation 'com.github.kobakei:MaterialFabSpeedDial:1.2.1'
|
implementation 'com.github.kobakei:MaterialFabSpeedDial:1.2.1'
|
||||||
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
||||||
def glideVersion = '4.12.0'
|
def glideVersion = '4.14.2'
|
||||||
implementation("com.github.bumptech.glide:glide:$glideVersion") {
|
implementation("com.github.bumptech.glide:glide:$glideVersion") {
|
||||||
exclude group: 'com.android.support'
|
exclude group: 'com.android.support'
|
||||||
exclude module: 'disklrucache' // when there's no disk cache, we can't accidentally use it
|
exclude module: 'disklrucache' // when there's no disk cache, we can't accidentally use it
|
||||||
@@ -142,12 +148,12 @@ dependencies {
|
|||||||
|
|
||||||
def espressoVersion = '3.3.0'
|
def espressoVersion = '3.3.0'
|
||||||
testImplementation 'androidx.test:runner:1.4.0'
|
testImplementation 'androidx.test:runner:1.4.0'
|
||||||
testImplementation 'androidx.test.ext:junit:1.1.3'
|
testImplementation 'androidx.test.ext:junit:1.1.5'
|
||||||
testImplementation 'androidx.fragment:fragment-testing:1.4.0'
|
testImplementation 'androidx.fragment:fragment-testing:1.4.0'
|
||||||
testImplementation "androidx.arch.core:core-testing:2.1.0"
|
testImplementation "androidx.arch.core:core-testing:2.1.0"
|
||||||
testImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
|
testImplementation "androidx.test.espresso:espresso-core:3.5.0"
|
||||||
testImplementation 'org.robolectric:robolectric:4.4'
|
testImplementation 'org.robolectric:robolectric:4.8.2' // newer versions have SecureRandom issue
|
||||||
testImplementation 'org.mockito:mockito-core:3.9.0'
|
testImplementation 'org.mockito:mockito-core:5.1.1'
|
||||||
testImplementation "junit:junit:$junit_version"
|
testImplementation "junit:junit:$junit_version"
|
||||||
testImplementation "org.jmock:jmock:$jmock_version"
|
testImplementation "org.jmock:jmock:$jmock_version"
|
||||||
testImplementation "org.jmock:jmock-junit4:$jmock_version"
|
testImplementation "org.jmock:jmock-junit4:$jmock_version"
|
||||||
|
|||||||
@@ -99,11 +99,6 @@
|
|||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:label="@string/app_name" />
|
android:label="@string/app_name" />
|
||||||
|
|
||||||
<activity
|
|
||||||
android:name="org.briarproject.briar.android.splash.ExpiredOldAndroidActivity"
|
|
||||||
android:exported="false"
|
|
||||||
android:label="@string/app_name" />
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="org.briarproject.briar.android.login.StartupActivity"
|
android:name="org.briarproject.briar.android.login.StartupActivity"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import org.briarproject.bramble.api.plugin.PluginManager;
|
|||||||
import org.briarproject.bramble.api.settings.SettingsManager;
|
import org.briarproject.bramble.api.settings.SettingsManager;
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
import org.briarproject.bramble.api.system.Clock;
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
|
||||||
import org.briarproject.bramble.mailbox.ModularMailboxModule;
|
import org.briarproject.bramble.mailbox.ModularMailboxModule;
|
||||||
import org.briarproject.bramble.plugin.file.RemovableDriveModule;
|
import org.briarproject.bramble.plugin.file.RemovableDriveModule;
|
||||||
import org.briarproject.bramble.system.ClockModule;
|
import org.briarproject.bramble.system.ClockModule;
|
||||||
@@ -84,6 +83,7 @@ import org.briarproject.briar.api.privategroup.invitation.GroupInvitationFactory
|
|||||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
|
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
|
||||||
import org.briarproject.briar.api.test.TestDataCreator;
|
import org.briarproject.briar.api.test.TestDataCreator;
|
||||||
import org.briarproject.onionwrapper.CircumventionProvider;
|
import org.briarproject.onionwrapper.CircumventionProvider;
|
||||||
|
import org.briarproject.onionwrapper.LocationUtils;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
|||||||
@@ -294,10 +294,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
b.setOngoing(true);
|
b.setOngoing(true);
|
||||||
Intent i = new Intent(appContext, SplashScreenActivity.class);
|
Intent i = new Intent(appContext, SplashScreenActivity.class);
|
||||||
b.setContentIntent(getActivity(appContext, 0, i, getImmutableFlags(0)));
|
b.setContentIntent(getActivity(appContext, 0, i, getImmutableFlags(0)));
|
||||||
if (SDK_INT >= 21) {
|
b.setCategory(CATEGORY_SERVICE);
|
||||||
b.setCategory(CATEGORY_SERVICE);
|
b.setVisibility(VISIBILITY_SECRET);
|
||||||
b.setVisibility(VISIBILITY_SECRET);
|
|
||||||
}
|
|
||||||
b.setPriority(PRIORITY_MIN);
|
b.setPriority(PRIORITY_MIN);
|
||||||
return b.build();
|
return b.build();
|
||||||
}
|
}
|
||||||
@@ -773,8 +771,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
|
|||||||
i.setAction(ACTION_STOP_HOTSPOT);
|
i.setAction(ACTION_STOP_HOTSPOT);
|
||||||
PendingIntent actionIntent =
|
PendingIntent actionIntent =
|
||||||
getActivity(appContext, 0, i, getImmutableFlags(0));
|
getActivity(appContext, 0, i, getImmutableFlags(0));
|
||||||
int icon = SDK_INT >= 21 ? R.drawable.ic_portable_wifi_off : 0;
|
b.addAction(R.drawable.ic_portable_wifi_off, actionTitle, actionIntent);
|
||||||
b.addAction(icon, actionTitle, actionIntent);
|
|
||||||
notificationManager.notify(HOTSPOT_NOTIFICATION_ID, b.build());
|
notificationManager.notify(HOTSPOT_NOTIFICATION_ID, b.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ public class AppModule {
|
|||||||
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
public Collection<SimplexPluginFactory> getSimplexFactories() {
|
||||||
List<SimplexPluginFactory> simplex = new ArrayList<>();
|
List<SimplexPluginFactory> simplex = new ArrayList<>();
|
||||||
simplex.add(mailbox);
|
simplex.add(mailbox);
|
||||||
if (SDK_INT >= 19) simplex.add(drive);
|
simplex.add(drive);
|
||||||
return simplex;
|
return simplex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,16 +56,8 @@ public class Localizer {
|
|||||||
// Get Locale from BCP-47 tag
|
// Get Locale from BCP-47 tag
|
||||||
@Nullable
|
@Nullable
|
||||||
public static Locale getLocaleFromTag(String tag) {
|
public static Locale getLocaleFromTag(String tag) {
|
||||||
if (tag.equals("default"))
|
if (tag.equals("default")) return null;
|
||||||
return null;
|
return Locale.forLanguageTag(tag);
|
||||||
if (SDK_INT >= 21) {
|
|
||||||
return Locale.forLanguageTag(tag);
|
|
||||||
}
|
|
||||||
if (tag.contains("-")) {
|
|
||||||
String[] langArray = tag.split("-");
|
|
||||||
return new Locale(langArray[0], langArray[1]);
|
|
||||||
} else
|
|
||||||
return new Locale(tag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -94,12 +86,8 @@ public class Localizer {
|
|||||||
if (locale.equals(currentLocale))
|
if (locale.equals(currentLocale))
|
||||||
return context;
|
return context;
|
||||||
Locale.setDefault(locale);
|
Locale.setDefault(locale);
|
||||||
if (SDK_INT >= 17) {
|
conf.setLocale(locale);
|
||||||
conf.setLocale(locale);
|
context = context.createConfigurationContext(conf);
|
||||||
context = context.createConfigurationContext(conf);
|
|
||||||
} else
|
|
||||||
conf.locale = locale;
|
|
||||||
//noinspection deprecation
|
|
||||||
res.updateConfiguration(conf, res.getDisplayMetrics());
|
res.updateConfiguration(conf, res.getDisplayMetrics());
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package org.briarproject.briar.android;
|
|||||||
|
|
||||||
import org.briarproject.briar.BuildConfig;
|
import org.briarproject.briar.BuildConfig;
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static java.util.concurrent.TimeUnit.DAYS;
|
import static java.util.concurrent.TimeUnit.DAYS;
|
||||||
|
import static org.briarproject.briar.BuildConfig.BuildTimestamp;
|
||||||
|
|
||||||
public interface TestingConstants {
|
public interface TestingConstants {
|
||||||
|
|
||||||
@@ -20,15 +20,9 @@ public interface TestingConstants {
|
|||||||
*/
|
*/
|
||||||
boolean PREVENT_SCREENSHOTS = !IS_DEBUG_BUILD;
|
boolean PREVENT_SCREENSHOTS = !IS_DEBUG_BUILD;
|
||||||
|
|
||||||
boolean IS_OLD_ANDROID = SDK_INT <= 19;
|
|
||||||
long OLD_ANDROID_WARN_DATE = 1659225600_000L; // 2022-07-31
|
|
||||||
long OLD_ANDROID_EXPIRY_DATE = 1675123200_000L; // 2023-01-31
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debug builds expire after 90 days. Release builds running on Android 4
|
* Debug builds expire after 90 days.
|
||||||
* expire at a set date, otherwise they expire after 292 million years.
|
|
||||||
*/
|
*/
|
||||||
long EXPIRY_DATE = IS_DEBUG_BUILD ?
|
long EXPIRY_DATE = IS_DEBUG_BUILD ?
|
||||||
BuildConfig.BuildTimestamp + DAYS.toMillis(90)
|
BuildTimestamp + DAYS.toMillis(90) : Long.MAX_VALUE;
|
||||||
: (IS_OLD_ANDROID ? OLD_ANDROID_EXPIRY_DATE : Long.MAX_VALUE);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_KEYGU
|
|||||||
import static org.briarproject.briar.android.util.UiUtils.hasKeyguardLock;
|
import static org.briarproject.briar.android.util.UiUtils.hasKeyguardLock;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.hasUsableFingerprint;
|
import static org.briarproject.briar.android.util.UiUtils.hasUsableFingerprint;
|
||||||
|
|
||||||
@RequiresApi(21)
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
public class UnlockActivity extends BaseActivity {
|
public class UnlockActivity extends BaseActivity {
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ import org.briarproject.briar.android.sharing.ShareBlogFragment;
|
|||||||
import org.briarproject.briar.android.sharing.ShareForumActivity;
|
import org.briarproject.briar.android.sharing.ShareForumActivity;
|
||||||
import org.briarproject.briar.android.sharing.ShareForumFragment;
|
import org.briarproject.briar.android.sharing.ShareForumFragment;
|
||||||
import org.briarproject.briar.android.sharing.SharingModule;
|
import org.briarproject.briar.android.sharing.SharingModule;
|
||||||
import org.briarproject.briar.android.splash.ExpiredOldAndroidActivity;
|
|
||||||
import org.briarproject.briar.android.splash.SplashScreenActivity;
|
import org.briarproject.briar.android.splash.SplashScreenActivity;
|
||||||
import org.briarproject.briar.android.test.TestDataActivity;
|
import org.briarproject.briar.android.test.TestDataActivity;
|
||||||
|
|
||||||
@@ -184,8 +183,6 @@ public interface ActivityComponent {
|
|||||||
|
|
||||||
void inject(RemovableDriveActivity activity);
|
void inject(RemovableDriveActivity activity);
|
||||||
|
|
||||||
void inject(ExpiredOldAndroidActivity activity);
|
|
||||||
|
|
||||||
// Fragments
|
// Fragments
|
||||||
|
|
||||||
void inject(SetupFragment fragment);
|
void inject(SetupFragment fragment);
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import java.util.logging.Logger;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
@@ -105,7 +104,7 @@ public abstract class BriarActivity extends BaseActivity {
|
|||||||
LOG.info("Not signed in, launching StartupActivity");
|
LOG.info("Not signed in, launching StartupActivity");
|
||||||
Intent i = new Intent(this, StartupActivity.class);
|
Intent i = new Intent(this, StartupActivity.class);
|
||||||
startActivityForResult(i, REQUEST_PASSWORD);
|
startActivityForResult(i, REQUEST_PASSWORD);
|
||||||
} else if (SDK_INT >= 21 && lockManager.isLocked() && !isFinishing()) {
|
} else if (lockManager.isLocked() && !isFinishing()) {
|
||||||
// Also check that the activity isn't finishing already.
|
// Also check that the activity isn't finishing already.
|
||||||
// This is possible if we finished in onActivityResult().
|
// This is possible if we finished in onActivityResult().
|
||||||
// Launching another UnlockActivity would cause a loop.
|
// Launching another UnlockActivity would cause a loop.
|
||||||
@@ -135,8 +134,7 @@ public abstract class BriarActivity extends BaseActivity {
|
|||||||
* @param exitTransition used to move views out when starting a <b>new</b> activity.
|
* @param exitTransition used to move views out when starting a <b>new</b> activity.
|
||||||
* @param returnTransition used when window is closing, because the activity is finishing.
|
* @param returnTransition used when window is closing, because the activity is finishing.
|
||||||
*/
|
*/
|
||||||
@RequiresApi(api = 21)
|
protected void setSceneTransitionAnimation(
|
||||||
public void setSceneTransitionAnimation(
|
|
||||||
@Nullable Transition enterTransition,
|
@Nullable Transition enterTransition,
|
||||||
@Nullable Transition exitTransition,
|
@Nullable Transition exitTransition,
|
||||||
@Nullable Transition returnTransition) {
|
@Nullable Transition returnTransition) {
|
||||||
@@ -232,8 +230,7 @@ public abstract class BriarActivity extends BaseActivity {
|
|||||||
|
|
||||||
@Wakeful
|
@Wakeful
|
||||||
private void finishAndExit() {
|
private void finishAndExit() {
|
||||||
if (SDK_INT >= 21) finishAndRemoveTask();
|
finishAndRemoveTask();
|
||||||
else supportFinishAfterTransition();
|
|
||||||
LOG.info("Exiting");
|
LOG.info("Exiting");
|
||||||
BriarApplication app = (BriarApplication) getApplication();
|
BriarApplication app = (BriarApplication) getApplication();
|
||||||
if (!app.isInstrumentationTest()) System.exit(0);
|
if (!app.isInstrumentationTest()) System.exit(0);
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import androidx.annotation.UiThread;
|
|||||||
import androidx.core.view.ViewCompat;
|
import androidx.core.view.ViewCompat;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
|
||||||
@@ -134,12 +133,6 @@ class BlogPostViewHolder extends RecyclerView.ViewHolder {
|
|||||||
} else {
|
} else {
|
||||||
reblogger.setVisibility(GONE);
|
reblogger.setVisibility(GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply Android 4 padding fix after setting up author/reblogger views
|
|
||||||
if (SDK_INT < 21) {
|
|
||||||
reblogger.setPadding(padding, padding, padding, padding);
|
|
||||||
author.setPadding(padding, padding, padding, padding);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onBindComment(BlogCommentItem item, boolean authorClickable) {
|
private void onBindComment(BlogCommentItem item, boolean authorClickable) {
|
||||||
|
|||||||
@@ -27,11 +27,9 @@ import javax.annotation.Nullable;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
|
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
|
||||||
@@ -52,7 +50,6 @@ public class RssFeedImportFragment extends BaseFragment {
|
|||||||
private Button importButton;
|
private Button importButton;
|
||||||
private ProgressBar progressBar;
|
private ProgressBar progressBar;
|
||||||
|
|
||||||
@RequiresApi(19)
|
|
||||||
private final ActivityResultLauncher<String[]> docLauncher =
|
private final ActivityResultLauncher<String[]> docLauncher =
|
||||||
registerForActivityResult(new OpenDocumentAdvanced(),
|
registerForActivityResult(new OpenDocumentAdvanced(),
|
||||||
this::onFileChosen);
|
this::onFileChosen);
|
||||||
@@ -74,7 +71,7 @@ public class RssFeedImportFragment extends BaseFragment {
|
|||||||
@Nullable ViewGroup container,
|
@Nullable ViewGroup container,
|
||||||
@Nullable Bundle savedInstanceState) {
|
@Nullable Bundle savedInstanceState) {
|
||||||
requireActivity().setTitle(getString(R.string.blogs_rss_feeds_import));
|
requireActivity().setTitle(getString(R.string.blogs_rss_feeds_import));
|
||||||
if (SDK_INT >= 19) setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
View v = inflater.inflate(R.layout.fragment_rss_feed_import,
|
View v = inflater.inflate(R.layout.fragment_rss_feed_import,
|
||||||
container, false);
|
container, false);
|
||||||
|
|
||||||
@@ -117,15 +114,13 @@ public class RssFeedImportFragment extends BaseFragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
if (SDK_INT >= 19) {
|
inflater.inflate(R.menu.rss_feed_import_actions, menu);
|
||||||
inflater.inflate(R.menu.rss_feed_import_actions, menu);
|
|
||||||
}
|
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
if (item.getItemId() == R.id.action_import_file && SDK_INT >= 19) {
|
if (item.getItemId() == R.id.action_import_file) {
|
||||||
launchActivityToOpenFile(requireContext(), docLauncher,
|
launchActivityToOpenFile(requireContext(), docLauncher,
|
||||||
contentLauncher, "*/*");
|
contentLauncher, "*/*");
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener
|
|||||||
import org.briarproject.briar.android.introduction.IntroductionActivity;
|
import org.briarproject.briar.android.introduction.IntroductionActivity;
|
||||||
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
|
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
|
||||||
import org.briarproject.briar.android.removabledrive.RemovableDriveActivity;
|
import org.briarproject.briar.android.removabledrive.RemovableDriveActivity;
|
||||||
import org.briarproject.briar.android.util.ActivityLaunchers.GetImageAdvanced;
|
|
||||||
import org.briarproject.briar.android.util.ActivityLaunchers.GetMultipleImagesAdvanced;
|
import org.briarproject.briar.android.util.ActivityLaunchers.GetMultipleImagesAdvanced;
|
||||||
import org.briarproject.briar.android.util.ActivityLaunchers.OpenMultipleImageDocumentsAdvanced;
|
import org.briarproject.briar.android.util.ActivityLaunchers.OpenMultipleImageDocumentsAdvanced;
|
||||||
import org.briarproject.briar.android.util.BriarSnackbarBuilder;
|
import org.briarproject.briar.android.util.BriarSnackbarBuilder;
|
||||||
@@ -122,13 +121,11 @@ import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
|
|||||||
import de.hdodenhof.circleimageview.CircleImageView;
|
import de.hdodenhof.circleimageview.CircleImageView;
|
||||||
import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt;
|
import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt;
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static android.view.Gravity.RIGHT;
|
import static android.view.Gravity.RIGHT;
|
||||||
import static android.widget.Toast.LENGTH_SHORT;
|
import static android.widget.Toast.LENGTH_SHORT;
|
||||||
import static androidx.core.app.ActivityOptionsCompat.makeSceneTransitionAnimation;
|
import static androidx.core.app.ActivityOptionsCompat.makeSceneTransitionAnimation;
|
||||||
import static androidx.lifecycle.Lifecycle.State.STARTED;
|
import static androidx.lifecycle.Lifecycle.State.STARTED;
|
||||||
import static androidx.recyclerview.widget.SortedList.INVALID_POSITION;
|
import static androidx.recyclerview.widget.SortedList.INVALID_POSITION;
|
||||||
import static java.util.Collections.singletonList;
|
|
||||||
import static java.util.Collections.sort;
|
import static java.util.Collections.sort;
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
@@ -200,18 +197,13 @@ public class ConversationActivity extends BriarActivity
|
|||||||
requireNonNull(name);
|
requireNonNull(name);
|
||||||
loadMessages();
|
loadMessages();
|
||||||
};
|
};
|
||||||
@Nullable
|
|
||||||
private final ActivityResultLauncher<String[]> docLauncher = SDK_INT >= 19 ?
|
private final ActivityResultLauncher<String[]> docLauncher =
|
||||||
registerForActivityResult(new OpenMultipleImageDocumentsAdvanced(),
|
registerForActivityResult(new OpenMultipleImageDocumentsAdvanced(),
|
||||||
this::onImagesChosen) :
|
this::onImagesChosen);
|
||||||
null;
|
|
||||||
private final ActivityResultLauncher<String> contentLauncher =
|
private final ActivityResultLauncher<String> contentLauncher =
|
||||||
SDK_INT >= 18 ?
|
registerForActivityResult(new GetMultipleImagesAdvanced(),
|
||||||
registerForActivityResult(new GetMultipleImagesAdvanced(),
|
this::onImagesChosen);
|
||||||
this::onImagesChosen) :
|
|
||||||
registerForActivityResult(new GetImageAdvanced(), uri -> {
|
|
||||||
if (uri != null) onImagesChosen(singletonList(uri));
|
|
||||||
});
|
|
||||||
|
|
||||||
private AttachmentRetriever attachmentRetriever;
|
private AttachmentRetriever attachmentRetriever;
|
||||||
private ConversationViewModel viewModel;
|
private ConversationViewModel viewModel;
|
||||||
@@ -242,13 +234,11 @@ public class ConversationActivity extends BriarActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle state) {
|
public void onCreate(@Nullable Bundle state) {
|
||||||
if (SDK_INT >= 21) {
|
// Spurious lint warning - using END causes a crash
|
||||||
// Spurious lint warning - using END causes a crash
|
@SuppressLint("RtlHardcoded")
|
||||||
@SuppressLint("RtlHardcoded")
|
Transition slide = new Slide(RIGHT);
|
||||||
Transition slide = new Slide(RIGHT);
|
slide.setDuration(TRANSITION_DURATION_MS);
|
||||||
slide.setDuration(TRANSITION_DURATION_MS);
|
setSceneTransitionAnimation(slide, null, slide);
|
||||||
setSceneTransitionAnimation(slide, null, slide);
|
|
||||||
}
|
|
||||||
super.onCreate(state);
|
super.onCreate(state);
|
||||||
|
|
||||||
Intent i = getIntent();
|
Intent i = getIntent();
|
||||||
@@ -389,10 +379,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
this::showIntroductionOnboarding);
|
this::showIntroductionOnboarding);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Transfer Data feature only supported on API 19+
|
|
||||||
if (SDK_INT >= 19) {
|
|
||||||
menu.findItem(R.id.action_transfer_data).setVisible(true);
|
|
||||||
}
|
|
||||||
// enable alias and bluetooth action once available
|
// enable alias and bluetooth action once available
|
||||||
observeOnce(viewModel.getContactItem(), this, contact -> {
|
observeOnce(viewModel.getContactItem(), this, contact -> {
|
||||||
menu.findItem(R.id.action_set_alias).setEnabled(true);
|
menu.findItem(R.id.action_set_alias).setEnabled(true);
|
||||||
@@ -434,11 +420,9 @@ public class ConversationActivity extends BriarActivity
|
|||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
return true;
|
return true;
|
||||||
} else if (itemId == R.id.action_transfer_data) {
|
} else if (itemId == R.id.action_transfer_data) {
|
||||||
if (SDK_INT >= 19) {
|
Intent intent = new Intent(this, RemovableDriveActivity.class);
|
||||||
Intent intent = new Intent(this, RemovableDriveActivity.class);
|
intent.putExtra(CONTACT_ID, contactId.getInt());
|
||||||
intent.putExtra(CONTACT_ID, contactId.getInt());
|
startActivity(intent);
|
||||||
startActivity(intent);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
} else if (itemId == R.id.action_delete_all_messages) {
|
} else if (itemId == R.id.action_delete_all_messages) {
|
||||||
askToDeleteAllMessages();
|
askToDeleteAllMessages();
|
||||||
@@ -955,14 +939,10 @@ public class ConversationActivity extends BriarActivity
|
|||||||
|
|
||||||
private void showImageOnboarding(Boolean show) {
|
private void showImageOnboarding(Boolean show) {
|
||||||
if (!show) return;
|
if (!show) return;
|
||||||
if (SDK_INT >= 21) {
|
// show onboarding only after the enter transition has ended
|
||||||
// show onboarding only after the enter transition has ended
|
// otherwise the tap target animation won't play
|
||||||
// otherwise the tap target animation won't play
|
textInputView.postDelayed(this::showImageOnboarding,
|
||||||
textInputView.postDelayed(this::showImageOnboarding,
|
TRANSITION_DURATION_MS + ONBOARDING_DELAY_MS);
|
||||||
TRANSITION_DURATION_MS + ONBOARDING_DELAY_MS);
|
|
||||||
} else {
|
|
||||||
showImageOnboarding();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showImageOnboarding() {
|
private void showImageOnboarding() {
|
||||||
@@ -973,14 +953,10 @@ public class ConversationActivity extends BriarActivity
|
|||||||
|
|
||||||
private void showIntroductionOnboarding(@Nullable Boolean show) {
|
private void showIntroductionOnboarding(@Nullable Boolean show) {
|
||||||
if (show == null || !show) return;
|
if (show == null || !show) return;
|
||||||
if (SDK_INT >= 21) {
|
// show onboarding only after the enter transition has ended
|
||||||
// show onboarding only after the enter transition has ended
|
// otherwise the tap target animation won't play
|
||||||
// otherwise the tap target animation won't play
|
textInputView.postDelayed(this::showIntroductionOnboarding,
|
||||||
textInputView.postDelayed(this::showIntroductionOnboarding,
|
TRANSITION_DURATION_MS + ONBOARDING_DELAY_MS);
|
||||||
TRANSITION_DURATION_MS + ONBOARDING_DELAY_MS);
|
|
||||||
} else {
|
|
||||||
showIntroductionOnboarding();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showIntroductionOnboarding() {
|
private void showIntroductionOnboarding() {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import org.briarproject.briar.android.util.BriarSnackbarBuilder;
|
|||||||
import org.briarproject.briar.android.view.PullDownLayout;
|
import org.briarproject.briar.android.view.PullDownLayout;
|
||||||
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -41,13 +42,11 @@ import androidx.viewpager2.adapter.FragmentStateAdapter;
|
|||||||
import androidx.viewpager2.widget.ViewPager2;
|
import androidx.viewpager2.widget.ViewPager2;
|
||||||
|
|
||||||
import static android.graphics.Color.TRANSPARENT;
|
import static android.graphics.Color.TRANSPARENT;
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
|
import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
|
||||||
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
|
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
|
||||||
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
|
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
|
|
||||||
import static com.google.android.material.snackbar.Snackbar.LENGTH_LONG;
|
import static com.google.android.material.snackbar.Snackbar.LENGTH_LONG;
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.formatDateAbsolute;
|
import static org.briarproject.briar.android.util.UiUtils.formatDateAbsolute;
|
||||||
@@ -77,11 +76,9 @@ public class ImageActivity extends BriarActivity
|
|||||||
private List<AttachmentItem> attachments;
|
private List<AttachmentItem> attachments;
|
||||||
private MessageId conversationMessageId;
|
private MessageId conversationMessageId;
|
||||||
|
|
||||||
@Nullable
|
private final ActivityResultLauncher<String> launcher =
|
||||||
private final ActivityResultLauncher<String> launcher = SDK_INT >= 19 ?
|
|
||||||
registerForActivityResult(new CreateDocumentAdvanced(),
|
registerForActivityResult(new CreateDocumentAdvanced(),
|
||||||
this::onImageUriSelected) :
|
this::onImageUriSelected);
|
||||||
null;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void injectActivity(ActivityComponent component) {
|
public void injectActivity(ActivityComponent component) {
|
||||||
@@ -97,10 +94,8 @@ public class ImageActivity extends BriarActivity
|
|||||||
// Transitions
|
// Transitions
|
||||||
if (state == null) supportPostponeEnterTransition();
|
if (state == null) supportPostponeEnterTransition();
|
||||||
Window window = getWindow();
|
Window window = getWindow();
|
||||||
if (SDK_INT >= 21) {
|
Transition transition = new Fade();
|
||||||
Transition transition = new Fade();
|
setSceneTransitionAnimation(transition, null, transition);
|
||||||
setSceneTransitionAnimation(transition, null, transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Intent Extras
|
// Intent Extras
|
||||||
Intent i = getIntent();
|
Intent i = getIntent();
|
||||||
@@ -124,12 +119,7 @@ public class ImageActivity extends BriarActivity
|
|||||||
layout.getViewTreeObserver().addOnGlobalLayoutListener(this);
|
layout.getViewTreeObserver().addOnGlobalLayoutListener(this);
|
||||||
|
|
||||||
// Status Bar
|
// Status Bar
|
||||||
if (SDK_INT >= 21) {
|
window.setStatusBarColor(TRANSPARENT);
|
||||||
window.setStatusBarColor(TRANSPARENT);
|
|
||||||
} else if (SDK_INT >= 19) {
|
|
||||||
// we can't make the status bar transparent, but translucent
|
|
||||||
window.addFlags(FLAG_TRANSLUCENT_STATUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Toolbar
|
// Toolbar
|
||||||
appBarLayout = findViewById(R.id.appBarLayout);
|
appBarLayout = findViewById(R.id.appBarLayout);
|
||||||
@@ -257,16 +247,12 @@ public class ImageActivity extends BriarActivity
|
|||||||
|
|
||||||
private void showSaveImageDialog() {
|
private void showSaveImageDialog() {
|
||||||
OnClickListener okListener = (dialog, which) -> {
|
OnClickListener okListener = (dialog, which) -> {
|
||||||
if (SDK_INT >= 19) {
|
String name = viewModel.getFileName() + "." +
|
||||||
String name = viewModel.getFileName() + "." +
|
getVisibleAttachment().getExtension();
|
||||||
getVisibleAttachment().getExtension();
|
try {
|
||||||
try {
|
launcher.launch(name);
|
||||||
requireNonNull(launcher).launch(name);
|
} catch (ActivityNotFoundException e) {
|
||||||
} catch (ActivityNotFoundException e) {
|
viewModel.onSaveImageError();
|
||||||
viewModel.onSaveImageError();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
viewModel.saveImage(getVisibleAttachment());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Builder builder = new Builder(this, R.style.BriarDialogTheme);
|
Builder builder = new Builder(this, R.style.BriarDialogTheme);
|
||||||
@@ -295,7 +281,7 @@ public class ImageActivity extends BriarActivity
|
|||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
AttachmentItem getVisibleAttachment() {
|
private AttachmentItem getVisibleAttachment() {
|
||||||
return attachments.get(viewPager.getCurrentItem());
|
return attachments.get(viewPager.getCurrentItem());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,6 +293,7 @@ public class ImageActivity extends BriarActivity
|
|||||||
super(ImageActivity.this);
|
super(ImageActivity.this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public Fragment createFragment(int position) {
|
public Fragment createFragment(int position) {
|
||||||
Fragment f = ImageFragment.newInstance(
|
Fragment f = ImageFragment.newInstance(
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import androidx.fragment.app.Fragment;
|
|||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static android.widget.ImageView.ScaleType.FIT_START;
|
import static android.widget.ImageView.ScaleType.FIT_START;
|
||||||
import static com.bumptech.glide.load.engine.DiskCacheStrategy.NONE;
|
import static com.bumptech.glide.load.engine.DiskCacheStrategy.NONE;
|
||||||
import static org.briarproject.briar.android.attachment.AttachmentItem.State.AVAILABLE;
|
import static org.briarproject.briar.android.attachment.AttachmentItem.State.AVAILABLE;
|
||||||
@@ -150,7 +149,7 @@ public class ImageFragment extends Fragment
|
|||||||
public boolean onResourceReady(Drawable resource, Object model,
|
public boolean onResourceReady(Drawable resource, Object model,
|
||||||
Target<Drawable> target, DataSource dataSource,
|
Target<Drawable> target, DataSource dataSource,
|
||||||
boolean isFirstResource) {
|
boolean isFirstResource) {
|
||||||
if (SDK_INT >= 21 && !(resource instanceof Animatable)) {
|
if (!(resource instanceof Animatable)) {
|
||||||
// set transition name only when not animatable,
|
// set transition name only when not animatable,
|
||||||
// because the animation won't start otherwise
|
// because the animation won't start otherwise
|
||||||
photoView.setTransitionName(
|
photoView.setTransitionName(
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import androidx.annotation.DrawableRes;
|
|||||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager.LayoutParams;
|
import androidx.recyclerview.widget.StaggeredGridLayoutManager.LayoutParams;
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static android.widget.ImageView.ScaleType.CENTER_CROP;
|
import static android.widget.ImageView.ScaleType.CENTER_CROP;
|
||||||
import static android.widget.ImageView.ScaleType.FIT_CENTER;
|
import static android.widget.ImageView.ScaleType.FIT_CENTER;
|
||||||
import static com.bumptech.glide.load.engine.DiskCacheStrategy.NONE;
|
import static com.bumptech.glide.load.engine.DiskCacheStrategy.NONE;
|
||||||
@@ -58,10 +57,8 @@ class ImageViewHolder extends ViewHolder {
|
|||||||
loadImage(attachment, r);
|
loadImage(attachment, r);
|
||||||
imageView.setScaleType(CENTER_CROP);
|
imageView.setScaleType(CENTER_CROP);
|
||||||
}
|
}
|
||||||
if (SDK_INT >= 21) {
|
imageView.setTransitionName(
|
||||||
imageView.setTransitionName(
|
attachment.getTransitionName(conversationItemId));
|
||||||
attachment.getTransitionName(conversationItemId));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setImageViewDimensions(AttachmentItem a, boolean single,
|
private void setImageViewDimensions(AttachmentItem a, boolean single,
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
package org.briarproject.briar.android.forum;
|
package org.briarproject.briar.android.forum;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
|
||||||
import org.briarproject.briar.api.identity.AuthorInfo;
|
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
|
||||||
import org.briarproject.briar.android.threaded.ThreadItem;
|
import org.briarproject.briar.android.threaded.ThreadItem;
|
||||||
import org.briarproject.briar.api.forum.ForumPostHeader;
|
import org.briarproject.briar.api.forum.ForumPostHeader;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.briarproject.briar.android.hotspot;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ResolveInfo;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@@ -17,8 +16,6 @@ import org.briarproject.briar.android.util.ActivityLaunchers.CreateDocumentAdvan
|
|||||||
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
@@ -29,14 +26,11 @@ import androidx.lifecycle.ViewModelProvider;
|
|||||||
import static android.content.Intent.ACTION_SEND;
|
import static android.content.Intent.ACTION_SEND;
|
||||||
import static android.content.Intent.EXTRA_STREAM;
|
import static android.content.Intent.EXTRA_STREAM;
|
||||||
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
|
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
|
||||||
import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static android.view.View.INVISIBLE;
|
import static android.view.View.INVISIBLE;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
import static androidx.transition.TransitionManager.beginDelayedTransition;
|
import static androidx.transition.TransitionManager.beginDelayedTransition;
|
||||||
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
||||||
import static org.briarproject.briar.android.hotspot.HotspotViewModel.getApkFileName;
|
import static org.briarproject.briar.android.hotspot.HotspotViewModel.getApkFileName;
|
||||||
import static org.briarproject.nullsafety.NullSafety.requireNonNull;
|
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -48,11 +42,9 @@ public class FallbackFragment extends BaseFragment {
|
|||||||
ViewModelProvider.Factory viewModelFactory;
|
ViewModelProvider.Factory viewModelFactory;
|
||||||
|
|
||||||
private HotspotViewModel viewModel;
|
private HotspotViewModel viewModel;
|
||||||
@Nullable
|
private final ActivityResultLauncher<String> launcher =
|
||||||
private final ActivityResultLauncher<String> launcher = SDK_INT >= 19 ?
|
|
||||||
registerForActivityResult(new CreateDocumentAdvanced(),
|
registerForActivityResult(new CreateDocumentAdvanced(),
|
||||||
this::onDocumentCreated) :
|
this::onDocumentCreated);
|
||||||
null;
|
|
||||||
private Button fallbackButton;
|
private Button fallbackButton;
|
||||||
private ProgressBar progressBar;
|
private ProgressBar progressBar;
|
||||||
|
|
||||||
@@ -89,12 +81,7 @@ public class FallbackFragment extends BaseFragment {
|
|||||||
beginDelayedTransition((ViewGroup) v);
|
beginDelayedTransition((ViewGroup) v);
|
||||||
fallbackButton.setVisibility(INVISIBLE);
|
fallbackButton.setVisibility(INVISIBLE);
|
||||||
progressBar.setVisibility(VISIBLE);
|
progressBar.setVisibility(VISIBLE);
|
||||||
|
launcher.launch(getApkFileName());
|
||||||
if (SDK_INT >= 19) {
|
|
||||||
requireNonNull(launcher).launch(getApkFileName());
|
|
||||||
} else {
|
|
||||||
viewModel.exportApk();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
viewModel.getSavedApkToUri().observeEvent(this, this::shareUri);
|
viewModel.getSavedApkToUri().observeEvent(this, this::shareUri);
|
||||||
}
|
}
|
||||||
@@ -110,23 +97,11 @@ public class FallbackFragment extends BaseFragment {
|
|||||||
progressBar.setVisibility(INVISIBLE);
|
progressBar.setVisibility(INVISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void shareUri(Uri uri) {
|
private void shareUri(Uri uri) {
|
||||||
Intent i = new Intent(ACTION_SEND);
|
Intent i = new Intent(ACTION_SEND);
|
||||||
i.putExtra(EXTRA_STREAM, uri);
|
i.putExtra(EXTRA_STREAM, uri);
|
||||||
i.setType("*/*"); // gives us all sharing options
|
i.setType("*/*"); // gives us all sharing options
|
||||||
i.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
|
i.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
Context ctx = requireContext();
|
|
||||||
if (SDK_INT <= 19) {
|
|
||||||
// Workaround for Android bug:
|
|
||||||
// ctx.grantUriPermission also needed for Android 4
|
|
||||||
List<ResolveInfo> resInfoList = ctx.getPackageManager()
|
|
||||||
.queryIntentActivities(i, MATCH_DEFAULT_ONLY);
|
|
||||||
for (ResolveInfo resolveInfo : resInfoList) {
|
|
||||||
String packageName = resolveInfo.activityInfo.packageName;
|
|
||||||
ctx.grantUriPermission(packageName, uri,
|
|
||||||
FLAG_GRANT_READ_URI_PERMISSION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
startActivity(Intent.createChooser(i, null));
|
startActivity(Intent.createChooser(i, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import org.briarproject.nullsafety.NotNullByDefault;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
@@ -38,9 +37,6 @@ import androidx.annotation.UiThread;
|
|||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static android.os.Environment.DIRECTORY_DOWNLOADS;
|
|
||||||
import static android.os.Environment.getExternalStoragePublicDirectory;
|
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
@@ -168,7 +164,6 @@ class HotspotViewModel extends DbViewModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
void exportApk(Uri uri) {
|
void exportApk(Uri uri) {
|
||||||
if (SDK_INT < 19) throw new IllegalStateException();
|
|
||||||
try {
|
try {
|
||||||
OutputStream out = getApplication().getContentResolver()
|
OutputStream out = getApplication().getContentResolver()
|
||||||
.openOutputStream(uri, "wt");
|
.openOutputStream(uri, "wt");
|
||||||
@@ -178,20 +173,6 @@ class HotspotViewModel extends DbViewModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void exportApk() {
|
|
||||||
if (SDK_INT >= 19) throw new IllegalStateException();
|
|
||||||
File path = getExternalStoragePublicDirectory(DIRECTORY_DOWNLOADS);
|
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
path.mkdirs();
|
|
||||||
File file = new File(path, getApkFileName());
|
|
||||||
try {
|
|
||||||
OutputStream out = new FileOutputStream(file);
|
|
||||||
writeApk(out, Uri.fromFile(file));
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
handleException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static String getApkFileName() {
|
static String getApkFileName() {
|
||||||
return "briar" + (DEBUG ? "-debug-" : "-") + VERSION_NAME + ".apk";
|
return "briar" + (DEBUG ? "-debug-" : "-") + VERSION_NAME + ".apk";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ import android.os.Bundle;
|
|||||||
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
|
|
||||||
public class ExitActivity extends Activity {
|
public class ExitActivity extends Activity {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
@@ -15,8 +13,7 @@ public class ExitActivity extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle state) {
|
public void onCreate(Bundle state) {
|
||||||
super.onCreate(state);
|
super.onCreate(state);
|
||||||
if (SDK_INT >= 21) finishAndRemoveTask();
|
finishAndRemoveTask();
|
||||||
else finish();
|
|
||||||
LOG.info("Exiting");
|
LOG.info("Exiting");
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,15 +75,12 @@ import static org.briarproject.bramble.api.plugin.Plugin.State.ENABLING;
|
|||||||
import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING;
|
import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING;
|
||||||
import static org.briarproject.briar.android.BriarService.EXTRA_STARTUP_FAILED;
|
import static org.briarproject.briar.android.BriarService.EXTRA_STARTUP_FAILED;
|
||||||
import static org.briarproject.briar.android.BriarService.EXTRA_START_RESULT;
|
import static org.briarproject.briar.android.BriarService.EXTRA_START_RESULT;
|
||||||
import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE;
|
|
||||||
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
|
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
|
||||||
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PASSWORD;
|
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_PASSWORD;
|
||||||
import static org.briarproject.briar.android.navdrawer.IntentRouter.handleExternalIntent;
|
import static org.briarproject.briar.android.navdrawer.IntentRouter.handleExternalIntent;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.formatDateFull;
|
|
||||||
import static org.briarproject.briar.android.util.UiUtils.getDaysUntilExpiry;
|
import static org.briarproject.briar.android.util.UiUtils.getDaysUntilExpiry;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.observeOnce;
|
import static org.briarproject.briar.android.util.UiUtils.observeOnce;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.resolveColorAttribute;
|
import static org.briarproject.briar.android.util.UiUtils.resolveColorAttribute;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.shouldWarnOldAndroidExpiry;
|
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
@@ -140,11 +137,9 @@ public class NavDrawerActivity extends BriarActivity implements
|
|||||||
setContentView(R.layout.activity_nav_drawer);
|
setContentView(R.layout.activity_nav_drawer);
|
||||||
|
|
||||||
BriarApplication app = (BriarApplication) getApplication();
|
BriarApplication app = (BriarApplication) getApplication();
|
||||||
if (!app.isInstrumentationTest()) {
|
if (IS_DEBUG_BUILD && !app.isInstrumentationTest()) {
|
||||||
if (IS_DEBUG_BUILD || shouldWarnOldAndroidExpiry()) {
|
navDrawerViewModel.showExpiryWarning()
|
||||||
navDrawerViewModel.showExpiryWarning()
|
.observe(this, this::showExpiryWarning);
|
||||||
.observe(this, this::showExpiryWarning);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
navDrawerViewModel.shouldAskForDozeWhitelisting().observe(this, ask -> {
|
navDrawerViewModel.shouldAskForDozeWhitelisting().observe(this, ask -> {
|
||||||
if (ask) showDozeDialog(R.string.dnkm_doze_intro);
|
if (ask) showDozeDialog(R.string.dnkm_doze_intro);
|
||||||
@@ -212,7 +207,7 @@ public class NavDrawerActivity extends BriarActivity implements
|
|||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
lockManager.checkIfLockable();
|
lockManager.checkIfLockable();
|
||||||
if (IS_DEBUG_BUILD || shouldWarnOldAndroidExpiry()) {
|
if (IS_DEBUG_BUILD) {
|
||||||
navDrawerViewModel.checkExpiryWarning();
|
navDrawerViewModel.checkExpiryWarning();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -384,23 +379,14 @@ public class NavDrawerActivity extends BriarActivity implements
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String text;
|
|
||||||
if (IS_DEBUG_BUILD) {
|
|
||||||
text = getResources().getQuantityString(
|
|
||||||
R.plurals.expiry_warning, (int) daysUntilExpiry,
|
|
||||||
(int) daysUntilExpiry);
|
|
||||||
} else {
|
|
||||||
text = getResources().getQuantityString(
|
|
||||||
R.plurals.old_android_expiry_warning, (int) daysUntilExpiry,
|
|
||||||
formatDateFull(this, EXPIRY_DATE),
|
|
||||||
(int) daysUntilExpiry);
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewGroup expiryWarning = findViewById(R.id.expiryWarning);
|
ViewGroup expiryWarning = findViewById(R.id.expiryWarning);
|
||||||
if (show) {
|
if (show) {
|
||||||
// show expiry warning text
|
// show expiry warning text
|
||||||
TextView expiryWarningText =
|
TextView expiryWarningText =
|
||||||
expiryWarning.findViewById(R.id.expiryWarningText);
|
expiryWarning.findViewById(R.id.expiryWarningText);
|
||||||
|
String text = getResources().getQuantityString(
|
||||||
|
R.plurals.expiry_warning, (int) daysUntilExpiry,
|
||||||
|
(int) daysUntilExpiry);
|
||||||
expiryWarningText.setText(text);
|
expiryWarningText.setText(text);
|
||||||
// make close button functional
|
// make close button functional
|
||||||
ImageView expiryWarningClose =
|
ImageView expiryWarningClose =
|
||||||
@@ -432,7 +418,7 @@ public class NavDrawerActivity extends BriarActivity implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View getView(int position, View convertView,
|
public View getView(int position, @Nullable View convertView,
|
||||||
ViewGroup parent) {
|
ViewGroup parent) {
|
||||||
View view;
|
View view;
|
||||||
if (convertView != null) {
|
if (convertView != null) {
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import info.guardianproject.panic.Panic;
|
|||||||
import info.guardianproject.panic.PanicResponder;
|
import info.guardianproject.panic.PanicResponder;
|
||||||
import info.guardianproject.trustedintents.TrustedIntents;
|
import info.guardianproject.trustedintents.TrustedIntents;
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.briar.android.panic.PanicPreferencesFragment.KEY_LOCK;
|
import static org.briarproject.briar.android.panic.PanicPreferencesFragment.KEY_LOCK;
|
||||||
import static org.briarproject.briar.android.panic.PanicPreferencesFragment.KEY_PURGE;
|
import static org.briarproject.briar.android.panic.PanicPreferencesFragment.KEY_PURGE;
|
||||||
@@ -73,12 +72,7 @@ public class PanicResponderActivity extends BriarActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finishAndRemoveTask();
|
||||||
if (SDK_INT >= 21) {
|
|
||||||
finishAndRemoveTask();
|
|
||||||
} else {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
@@ -31,7 +30,6 @@ import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
|||||||
import static org.briarproject.briar.android.util.UiUtils.hideViewOnSmallScreen;
|
import static org.briarproject.briar.android.util.UiUtils.hideViewOnSmallScreen;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.launchActivityToOpenFile;
|
import static org.briarproject.briar.android.util.UiUtils.launchActivityToOpenFile;
|
||||||
|
|
||||||
@RequiresApi(19)
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
public class ReceiveFragment extends Fragment {
|
public class ReceiveFragment extends Fragment {
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
@@ -29,7 +28,6 @@ import static java.util.Objects.requireNonNull;
|
|||||||
import static org.briarproject.briar.android.conversation.ConversationActivity.CONTACT_ID;
|
import static org.briarproject.briar.android.conversation.ConversationActivity.CONTACT_ID;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.showFragment;
|
import static org.briarproject.briar.android.util.UiUtils.showFragment;
|
||||||
|
|
||||||
@RequiresApi(19)
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
public class RemovableDriveActivity extends BriarActivity {
|
public class RemovableDriveActivity extends BriarActivity {
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
@@ -38,7 +37,6 @@ import static org.briarproject.bramble.util.LogUtils.logException;
|
|||||||
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.hideViewOnSmallScreen;
|
import static org.briarproject.briar.android.util.UiUtils.hideViewOnSmallScreen;
|
||||||
|
|
||||||
@RequiresApi(19)
|
|
||||||
@MethodsNotNullByDefault
|
@MethodsNotNullByDefault
|
||||||
@ParametersNotNullByDefault
|
@ParametersNotNullByDefault
|
||||||
public class SendFragment extends Fragment {
|
public class SendFragment extends Fragment {
|
||||||
|
|||||||
@@ -220,10 +220,10 @@ class BriarReportCollector {
|
|||||||
method.setAccessible(true);
|
method.setAccessible(true);
|
||||||
mobileEnabled = (Boolean) requireNonNull(method.invoke(cm));
|
mobileEnabled = (Boolean) requireNonNull(method.invoke(cm));
|
||||||
} catch (ClassNotFoundException
|
} catch (ClassNotFoundException
|
||||||
| NoSuchMethodException
|
| NoSuchMethodException
|
||||||
| IllegalArgumentException
|
| IllegalArgumentException
|
||||||
| InvocationTargetException
|
| InvocationTargetException
|
||||||
| IllegalAccessException e) {
|
| IllegalAccessException e) {
|
||||||
connectivityInfo
|
connectivityInfo
|
||||||
.add("MobileDataReflectionException", e.toString());
|
.add("MobileDataReflectionException", e.toString());
|
||||||
}
|
}
|
||||||
@@ -300,15 +300,12 @@ class BriarReportCollector {
|
|||||||
scanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE;
|
scanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE;
|
||||||
connectivityInfo.add("BluetoothDiscoverable", btDiscoverable);
|
connectivityInfo.add("BluetoothDiscoverable", btDiscoverable);
|
||||||
|
|
||||||
if (SDK_INT >= 21) {
|
// Is Bluetooth LE scanning and advertising supported?
|
||||||
// Is Bluetooth LE scanning and advertising supported?
|
boolean btLeScan = bt.getBluetoothLeScanner() != null;
|
||||||
boolean btLeScan = bt.getBluetoothLeScanner() != null;
|
connectivityInfo.add("BluetoothLeScanningSupported", btLeScan);
|
||||||
connectivityInfo.add("BluetoothLeScanningSupported", btLeScan);
|
boolean btLeAdvertise = bt.getBluetoothLeAdvertiser() != null;
|
||||||
boolean btLeAdvertise =
|
connectivityInfo.add("BluetoothLeAdvertisingSupported",
|
||||||
bt.getBluetoothLeAdvertiser() != null;
|
btLeAdvertise);
|
||||||
connectivityInfo.add("BluetoothLeAdvertisingSupported",
|
|
||||||
btLeAdvertise);
|
|
||||||
}
|
|
||||||
|
|
||||||
Pair<String, String> p = getBluetoothAddressAndMethod(ctx, bt);
|
Pair<String, String> p = getBluetoothAddressAndMethod(ctx, bt);
|
||||||
String address = p.getFirst();
|
String address = p.getFirst();
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
|||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
import static androidx.core.view.ViewCompat.LAYOUT_DIRECTION_LTR;
|
import static androidx.core.view.ViewCompat.LAYOUT_DIRECTION_LTR;
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
import static java.util.logging.Level.INFO;
|
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.briar.android.BriarApplication.ENTRY_ACTIVITY;
|
import static org.briarproject.briar.android.BriarApplication.ENTRY_ACTIVITY;
|
||||||
import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.SIGN_OUT_URI;
|
import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.SIGN_OUT_URI;
|
||||||
@@ -75,12 +74,6 @@ public class DisplayFragment extends PreferenceFragmentCompat {
|
|||||||
Locale locale = Localizer.getLocaleFromTag(tag);
|
Locale locale = Localizer.getLocaleFromTag(tag);
|
||||||
if (locale == null)
|
if (locale == null)
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
// Exclude RTL locales on API < 17, they won't be laid out correctly
|
|
||||||
if (SDK_INT < 17 && !isLeftToRight(locale)) {
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Skipping RTL locale " + tag);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String nativeName = locale.getDisplayName(locale);
|
String nativeName = locale.getDisplayName(locale);
|
||||||
// Fallback to English if the name is unknown in both native and
|
// Fallback to English if the name is unknown in both native and
|
||||||
// current locale.
|
// current locale.
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import androidx.preference.ListPreference;
|
|||||||
import androidx.preference.PreferenceFragmentCompat;
|
import androidx.preference.PreferenceFragmentCompat;
|
||||||
import androidx.preference.SwitchPreferenceCompat;
|
import androidx.preference.SwitchPreferenceCompat;
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
||||||
import static org.briarproject.briar.android.settings.SettingsActivity.enableAndPersist;
|
import static org.briarproject.briar.android.settings.SettingsActivity.enableAndPersist;
|
||||||
@@ -71,17 +70,12 @@ public class SecurityFragment extends PreferenceFragmentCompat {
|
|||||||
@Override
|
@Override
|
||||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
if (SDK_INT < 21) {
|
// timeout depends on screenLock and gets disabled automatically
|
||||||
screenLock.setVisible(false);
|
LifecycleOwner lifecycleOwner = getViewLifecycleOwner();
|
||||||
screenLockTimeout.setVisible(false);
|
viewModel.getScreenLockTimeout().observe(lifecycleOwner, value -> {
|
||||||
} else {
|
screenLockTimeout.setValue(value);
|
||||||
// timeout depends on screenLock and gets disabled automatically
|
enableAndPersist(screenLockTimeout);
|
||||||
LifecycleOwner lifecycleOwner = getViewLifecycleOwner();
|
});
|
||||||
viewModel.getScreenLockTimeout().observe(lifecycleOwner, value -> {
|
|
||||||
screenLockTimeout.setValue(value);
|
|
||||||
enableAndPersist(screenLockTimeout);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -92,7 +86,6 @@ public class SecurityFragment extends PreferenceFragmentCompat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkScreenLock() {
|
private void checkScreenLock() {
|
||||||
if (SDK_INT < 21) return;
|
|
||||||
LifecycleOwner lifecycleOwner = getViewLifecycleOwner();
|
LifecycleOwner lifecycleOwner = getViewLifecycleOwner();
|
||||||
viewModel.getScreenLockEnabled().removeObservers(lifecycleOwner);
|
viewModel.getScreenLockEnabled().removeObservers(lifecycleOwner);
|
||||||
if (hasScreenLock(requireActivity())) {
|
if (hasScreenLock(requireActivity())) {
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package org.briarproject.briar.android.settings;
|
package org.briarproject.briar.android.settings;
|
||||||
|
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.mailbox.MailboxActivity;
|
import org.briarproject.briar.android.mailbox.MailboxActivity;
|
||||||
@@ -24,7 +26,9 @@ import androidx.preference.Preference;
|
|||||||
import androidx.preference.PreferenceFragmentCompat;
|
import androidx.preference.PreferenceFragmentCompat;
|
||||||
import androidx.preference.PreferenceGroup;
|
import androidx.preference.PreferenceGroup;
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.content.Intent.ACTION_SEND;
|
||||||
|
import static android.content.Intent.EXTRA_TEXT;
|
||||||
|
import static android.widget.Toast.LENGTH_LONG;
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
|
||||||
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
|
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
|
||||||
@@ -38,22 +42,23 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||||||
public static final String SETTINGS_NAMESPACE = "android-ui";
|
public static final String SETTINGS_NAMESPACE = "android-ui";
|
||||||
|
|
||||||
private static final String PREF_KEY_AVATAR = "pref_key_avatar";
|
private static final String PREF_KEY_AVATAR = "pref_key_avatar";
|
||||||
|
private static final String PREF_KEY_SHARE_LINK = "pref_key_share_app_link";
|
||||||
private static final String PREF_KEY_FEEDBACK = "pref_key_send_feedback";
|
private static final String PREF_KEY_FEEDBACK = "pref_key_send_feedback";
|
||||||
private static final String PREF_KEY_DEV = "pref_key_dev";
|
private static final String PREF_KEY_DEV = "pref_key_dev";
|
||||||
private static final String PREF_KEY_EXPLODE = "pref_key_explode";
|
private static final String PREF_KEY_EXPLODE = "pref_key_explode";
|
||||||
private static final String PREF_KEY_MAILBOX = "pref_key_mailbox";
|
private static final String PREF_KEY_MAILBOX = "pref_key_mailbox";
|
||||||
|
|
||||||
|
private static final String DOWNLOAD_URL = "https://briarproject.org/download/";
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ViewModelProvider.Factory viewModelFactory;
|
ViewModelProvider.Factory viewModelFactory;
|
||||||
|
|
||||||
private SettingsViewModel viewModel;
|
private SettingsViewModel viewModel;
|
||||||
private AvatarPreference prefAvatar;
|
private AvatarPreference prefAvatar;
|
||||||
|
|
||||||
@Nullable
|
private final ActivityResultLauncher<String[]> docLauncher =
|
||||||
private final ActivityResultLauncher<String[]> docLauncher = SDK_INT >= 19 ?
|
|
||||||
registerForActivityResult(new OpenImageDocumentAdvanced(),
|
registerForActivityResult(new OpenImageDocumentAdvanced(),
|
||||||
this::onImageSelected) :
|
this::onImageSelected);
|
||||||
null;
|
|
||||||
private final ActivityResultLauncher<String> contentLauncher =
|
private final ActivityResultLauncher<String> contentLauncher =
|
||||||
registerForActivityResult(new GetImageAdvanced(),
|
registerForActivityResult(new GetImageAdvanced(),
|
||||||
this::onImageSelected);
|
this::onImageSelected);
|
||||||
@@ -89,6 +94,21 @@ public class SettingsFragment extends PreferenceFragmentCompat {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Preference prefShareLink =
|
||||||
|
requireNonNull(findPreference(PREF_KEY_SHARE_LINK));
|
||||||
|
prefShareLink.setOnPreferenceClickListener(preference -> {
|
||||||
|
String text = getString(R.string.share_app_link_text, DOWNLOAD_URL);
|
||||||
|
Intent sendIntent = new Intent(ACTION_SEND);
|
||||||
|
sendIntent.putExtra(EXTRA_TEXT, text);
|
||||||
|
sendIntent.setType("text/plain");
|
||||||
|
try {
|
||||||
|
startActivity(Intent.createChooser(sendIntent, null));
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
Toast.makeText(requireContext(),
|
||||||
|
R.string.error_start_activity, LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
Preference prefFeedback =
|
Preference prefFeedback =
|
||||||
requireNonNull(findPreference(PREF_KEY_FEEDBACK));
|
requireNonNull(findPreference(PREF_KEY_FEEDBACK));
|
||||||
prefFeedback.setOnPreferenceClickListener(preference -> {
|
prefFeedback.setOnPreferenceClickListener(preference -> {
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import org.briarproject.bramble.api.settings.Settings;
|
|||||||
import org.briarproject.bramble.api.settings.SettingsManager;
|
import org.briarproject.bramble.api.settings.SettingsManager;
|
||||||
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
|
import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
|
||||||
import org.briarproject.bramble.api.system.AndroidExecutor;
|
import org.briarproject.bramble.api.system.AndroidExecutor;
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.briar.android.attachment.UnsupportedMimeTypeException;
|
import org.briarproject.briar.android.attachment.UnsupportedMimeTypeException;
|
||||||
import org.briarproject.briar.android.attachment.media.ImageCompressor;
|
import org.briarproject.briar.android.attachment.media.ImageCompressor;
|
||||||
@@ -34,6 +33,7 @@ import org.briarproject.briar.api.identity.AuthorManager;
|
|||||||
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.onionwrapper.CircumventionProvider;
|
import org.briarproject.onionwrapper.CircumventionProvider;
|
||||||
|
import org.briarproject.onionwrapper.LocationUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package org.briarproject.briar.android.settings;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.system.LocationUtils;
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.onionwrapper.CircumventionProvider;
|
import org.briarproject.onionwrapper.CircumventionProvider;
|
||||||
|
import org.briarproject.onionwrapper.LocationUtils;
|
||||||
|
|
||||||
import androidx.preference.ListPreference;
|
import androidx.preference.ListPreference;
|
||||||
import androidx.preference.Preference.SummaryProvider;
|
import androidx.preference.Preference.SummaryProvider;
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
package org.briarproject.briar.android.splash;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager;
|
|
||||||
import org.briarproject.briar.R;
|
|
||||||
import org.briarproject.briar.android.activity.ActivityComponent;
|
|
||||||
import org.briarproject.briar.android.activity.BaseActivity;
|
|
||||||
import org.briarproject.briar.android.controller.BriarController;
|
|
||||||
import org.briarproject.briar.android.logout.ExitActivity;
|
|
||||||
import org.briarproject.nullsafety.MethodsNotNullByDefault;
|
|
||||||
import org.briarproject.nullsafety.ParametersNotNullByDefault;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
|
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
|
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
|
|
||||||
|
|
||||||
@MethodsNotNullByDefault
|
|
||||||
@ParametersNotNullByDefault
|
|
||||||
public class ExpiredOldAndroidActivity extends BaseActivity {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
BriarController briarController;
|
|
||||||
@Inject
|
|
||||||
AndroidWakeLockManager wakeLockManager;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@Nullable Bundle state) {
|
|
||||||
super.onCreate(state);
|
|
||||||
|
|
||||||
setContentView(R.layout.activity_expired_old_android);
|
|
||||||
findViewById(R.id.delete_account_button).setOnClickListener(v -> {
|
|
||||||
// Hold a wake lock to ensure we exit before the device goes to sleep
|
|
||||||
wakeLockManager.runWakefully(() -> {
|
|
||||||
// we're not signed in, just go ahead and delete
|
|
||||||
briarController.deleteAccount();
|
|
||||||
// remove from recent apps
|
|
||||||
Intent i = new Intent(this, ExitActivity.class);
|
|
||||||
i.addFlags(FLAG_ACTIVITY_NEW_TASK
|
|
||||||
| FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
|
|
||||||
| FLAG_ACTIVITY_NO_ANIMATION
|
|
||||||
| FLAG_ACTIVITY_CLEAR_TASK);
|
|
||||||
startActivity(i);
|
|
||||||
}, "DeleteAccount");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void injectActivity(ActivityComponent component) {
|
|
||||||
component.inject(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static androidx.preference.PreferenceManager.setDefaultValues;
|
import static androidx.preference.PreferenceManager.setDefaultValues;
|
||||||
import static java.lang.System.currentTimeMillis;
|
import static java.lang.System.currentTimeMillis;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
@@ -50,12 +49,8 @@ public class SplashScreenActivity extends BaseActivity {
|
|||||||
public void onCreate(@Nullable Bundle state) {
|
public void onCreate(@Nullable Bundle state) {
|
||||||
super.onCreate(state);
|
super.onCreate(state);
|
||||||
|
|
||||||
if (SDK_INT >= 21) {
|
getWindow().setExitTransition(new Fade());
|
||||||
getWindow().setExitTransition(new Fade());
|
|
||||||
}
|
|
||||||
|
|
||||||
setPreferencesDefaults();
|
setPreferencesDefaults();
|
||||||
|
|
||||||
setContentView(R.layout.splash);
|
setContentView(R.layout.splash);
|
||||||
|
|
||||||
if (accountManager.hasDatabaseKey()) {
|
if (accountManager.hasDatabaseKey()) {
|
||||||
@@ -65,14 +60,9 @@ public class SplashScreenActivity extends BaseActivity {
|
|||||||
int duration =
|
int duration =
|
||||||
getResources().getInteger(R.integer.splashScreenDuration);
|
getResources().getInteger(R.integer.splashScreenDuration);
|
||||||
new Handler().postDelayed(() -> {
|
new Handler().postDelayed(() -> {
|
||||||
if (currentTimeMillis() >= EXPIRY_DATE) {
|
if (IS_DEBUG_BUILD && currentTimeMillis() >= EXPIRY_DATE) {
|
||||||
if (IS_DEBUG_BUILD) {
|
LOG.info("Expired");
|
||||||
LOG.info("Expired: debug build");
|
startNextActivity(ExpiredActivity.class);
|
||||||
startNextActivity(ExpiredActivity.class);
|
|
||||||
} else {
|
|
||||||
LOG.info("Expired: running on old Android");
|
|
||||||
startNextActivity(ExpiredOldAndroidActivity.class);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
startNextActivity(ENTRY_ACTIVITY);
|
startNextActivity(ENTRY_ACTIVITY);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,9 +24,10 @@ public class TestDataActivity extends BriarActivity {
|
|||||||
@Inject
|
@Inject
|
||||||
TestDataCreator testDataCreator;
|
TestDataCreator testDataCreator;
|
||||||
|
|
||||||
private TextView contactsTextView, forumsTextView;
|
private TextView contactsTextView, forumsTextView, privateGroupsTextView;
|
||||||
private SeekBar contactsSeekBar, messagesSeekBar, avatarsSeekBar,
|
private SeekBar contactsSeekBar, messagesSeekBar, avatarsSeekBar,
|
||||||
blogPostsSeekBar, forumsSeekBar, forumPostsSeekBar;
|
blogPostsSeekBar, forumsSeekBar, forumPostsSeekBar,
|
||||||
|
privateGroupsSeekBar, privateGroupPostsSeekBar;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle bundle) {
|
public void onCreate(Bundle bundle) {
|
||||||
@@ -46,28 +47,26 @@ public class TestDataActivity extends BriarActivity {
|
|||||||
forumsTextView = findViewById(R.id.TextViewForumsSb);
|
forumsTextView = findViewById(R.id.TextViewForumsSb);
|
||||||
TextView forumPostsTextView =
|
TextView forumPostsTextView =
|
||||||
findViewById(R.id.TextViewForumMessagesSb);
|
findViewById(R.id.TextViewForumMessagesSb);
|
||||||
|
privateGroupsTextView = findViewById(R.id.TextViewPrivateGroupsSb);
|
||||||
|
TextView privateGroupPostsTextView =
|
||||||
|
findViewById(R.id.TextViewPrivateGroupMessagesSb);
|
||||||
contactsSeekBar = findViewById(R.id.seekBarContacts);
|
contactsSeekBar = findViewById(R.id.seekBarContacts);
|
||||||
messagesSeekBar = findViewById(R.id.seekBarMessages);
|
messagesSeekBar = findViewById(R.id.seekBarMessages);
|
||||||
avatarsSeekBar = findViewById(R.id.seekBarAvatars);
|
avatarsSeekBar = findViewById(R.id.seekBarAvatars);
|
||||||
blogPostsSeekBar = findViewById(R.id.seekBarBlogPosts);
|
blogPostsSeekBar = findViewById(R.id.seekBarBlogPosts);
|
||||||
forumsSeekBar = findViewById(R.id.seekBarForums);
|
forumsSeekBar = findViewById(R.id.seekBarForums);
|
||||||
forumPostsSeekBar = findViewById(R.id.seekBarForumMessages);
|
forumPostsSeekBar = findViewById(R.id.seekBarForumMessages);
|
||||||
|
privateGroupsSeekBar = findViewById(R.id.seekBarPrivateGroups);
|
||||||
|
privateGroupPostsSeekBar =
|
||||||
|
findViewById(R.id.seekBarPrivateGroupMessages);
|
||||||
|
|
||||||
contactsSeekBar
|
contactsSeekBar.setOnSeekBarChangeListener(
|
||||||
.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
|
new AbstractOnSeekBarChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onProgressChanged(SeekBar seekBar,
|
public void onProgressChanged(SeekBar seekBar, int progress,
|
||||||
int progress, boolean fromUser) {
|
boolean fromUser) {
|
||||||
contactsTextView.setText(String.valueOf(progress + 1));
|
contactsTextView.setText(String.valueOf(progress + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
messagesSeekBar.setOnSeekBarChangeListener(
|
messagesSeekBar.setOnSeekBarChangeListener(
|
||||||
@@ -76,35 +75,39 @@ public class TestDataActivity extends BriarActivity {
|
|||||||
new OnSeekBarChangeUpdateProgress(avatarsTextView));
|
new OnSeekBarChangeUpdateProgress(avatarsTextView));
|
||||||
blogPostsSeekBar.setOnSeekBarChangeListener(
|
blogPostsSeekBar.setOnSeekBarChangeListener(
|
||||||
new OnSeekBarChangeUpdateProgress(blogPostsTextView));
|
new OnSeekBarChangeUpdateProgress(blogPostsTextView));
|
||||||
forumsSeekBar
|
forumsSeekBar.setOnSeekBarChangeListener(
|
||||||
.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
|
new AbstractOnSeekBarChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onProgressChanged(SeekBar seekBar,
|
public void onProgressChanged(SeekBar seekBar, int progress,
|
||||||
int progress, boolean fromUser) {
|
boolean fromUser) {
|
||||||
forumsTextView.setText(String.valueOf(progress));
|
forumsTextView.setText(String.valueOf(progress));
|
||||||
forumPostsSeekBar.setEnabled(progress > 0);
|
forumPostsSeekBar.setEnabled(progress > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
forumPostsSeekBar.setOnSeekBarChangeListener(
|
forumPostsSeekBar.setOnSeekBarChangeListener(
|
||||||
new OnSeekBarChangeUpdateProgress(forumPostsTextView));
|
new OnSeekBarChangeUpdateProgress(forumPostsTextView));
|
||||||
|
privateGroupsSeekBar.setOnSeekBarChangeListener(
|
||||||
findViewById(R.id.buttonZeroValues).setOnClickListener(
|
new AbstractOnSeekBarChangeListener() {
|
||||||
v -> {
|
@Override
|
||||||
contactsSeekBar.setProgress(0);
|
public void onProgressChanged(SeekBar seekBar, int progress,
|
||||||
messagesSeekBar.setProgress(0);
|
boolean fromUser) {
|
||||||
avatarsSeekBar.setProgress(0);
|
privateGroupsTextView.setText(String.valueOf(progress));
|
||||||
blogPostsSeekBar.setProgress(0);
|
privateGroupPostsSeekBar.setEnabled(progress > 0);
|
||||||
forumsSeekBar.setProgress(0);
|
}
|
||||||
forumPostsSeekBar.setProgress(0);
|
|
||||||
});
|
});
|
||||||
|
privateGroupPostsSeekBar.setOnSeekBarChangeListener(
|
||||||
|
new OnSeekBarChangeUpdateProgress(privateGroupPostsTextView));
|
||||||
|
|
||||||
|
findViewById(R.id.buttonZeroValues).setOnClickListener(v -> {
|
||||||
|
contactsSeekBar.setProgress(0);
|
||||||
|
messagesSeekBar.setProgress(0);
|
||||||
|
avatarsSeekBar.setProgress(0);
|
||||||
|
blogPostsSeekBar.setProgress(0);
|
||||||
|
forumsSeekBar.setProgress(0);
|
||||||
|
forumPostsSeekBar.setProgress(0);
|
||||||
|
privateGroupsSeekBar.setProgress(0);
|
||||||
|
privateGroupPostsSeekBar.setProgress(0);
|
||||||
|
});
|
||||||
|
|
||||||
findViewById(R.id.buttonCreateTestData).setOnClickListener(
|
findViewById(R.id.buttonCreateTestData).setOnClickListener(
|
||||||
v -> createTestData());
|
v -> createTestData());
|
||||||
@@ -114,7 +117,9 @@ public class TestDataActivity extends BriarActivity {
|
|||||||
testDataCreator.createTestData(contactsSeekBar.getProgress() + 1,
|
testDataCreator.createTestData(contactsSeekBar.getProgress() + 1,
|
||||||
messagesSeekBar.getProgress(), avatarsSeekBar.getProgress(),
|
messagesSeekBar.getProgress(), avatarsSeekBar.getProgress(),
|
||||||
blogPostsSeekBar.getProgress(), forumsSeekBar.getProgress(),
|
blogPostsSeekBar.getProgress(), forumsSeekBar.getProgress(),
|
||||||
forumPostsSeekBar.getProgress());
|
forumPostsSeekBar.getProgress(),
|
||||||
|
privateGroupsSeekBar.getProgress(),
|
||||||
|
privateGroupPostsSeekBar.getProgress());
|
||||||
Intent intent = new Intent(this, ENTRY_ACTIVITY);
|
Intent intent = new Intent(this, ENTRY_ACTIVITY);
|
||||||
intent.addFlags(FLAG_ACTIVITY_CLEAR_TOP);
|
intent.addFlags(FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
@@ -136,7 +141,7 @@ public class TestDataActivity extends BriarActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class OnSeekBarChangeUpdateProgress
|
private static class OnSeekBarChangeUpdateProgress
|
||||||
implements OnSeekBarChangeListener {
|
extends AbstractOnSeekBarChangeListener {
|
||||||
private final TextView textView;
|
private final TextView textView;
|
||||||
|
|
||||||
private OnSeekBarChangeUpdateProgress(TextView textView) {
|
private OnSeekBarChangeUpdateProgress(TextView textView) {
|
||||||
@@ -148,7 +153,10 @@ public class TestDataActivity extends BriarActivity {
|
|||||||
boolean fromUser) {
|
boolean fromUser) {
|
||||||
textView.setText(String.valueOf(progress));
|
textView.setText(String.valueOf(progress));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private abstract static class AbstractOnSeekBarChangeListener
|
||||||
|
implements OnSeekBarChangeListener {
|
||||||
@Override
|
@Override
|
||||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||||
}
|
}
|
||||||
@@ -157,5 +165,4 @@ public class TestDataActivity extends BriarActivity {
|
|||||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import androidx.activity.result.contract.ActivityResultContracts.OpenDocument;
|
|||||||
import androidx.activity.result.contract.ActivityResultContracts.OpenMultipleDocuments;
|
import androidx.activity.result.contract.ActivityResultContracts.OpenMultipleDocuments;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
|
|
||||||
import static android.app.Activity.RESULT_CANCELED;
|
import static android.app.Activity.RESULT_CANCELED;
|
||||||
import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE;
|
import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE;
|
||||||
@@ -26,7 +25,6 @@ import static org.briarproject.bramble.util.AndroidUtils.getSupportedImageConten
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class ActivityLaunchers {
|
public class ActivityLaunchers {
|
||||||
|
|
||||||
@RequiresApi(19)
|
|
||||||
public static class CreateDocumentAdvanced extends CreateDocument {
|
public static class CreateDocumentAdvanced extends CreateDocument {
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
@@ -48,7 +46,6 @@ public class ActivityLaunchers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(19)
|
|
||||||
public static class OpenDocumentAdvanced extends OpenDocument {
|
public static class OpenDocumentAdvanced extends OpenDocument {
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
@@ -69,13 +66,11 @@ public class ActivityLaunchers {
|
|||||||
putShowAdvancedExtra(i);
|
putShowAdvancedExtra(i);
|
||||||
i.setType("image/*");
|
i.setType("image/*");
|
||||||
i.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
|
i.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
if (SDK_INT >= 19)
|
i.putExtra(EXTRA_MIME_TYPES, getSupportedImageContentTypes());
|
||||||
i.putExtra(EXTRA_MIME_TYPES, getSupportedImageContentTypes());
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(18)
|
|
||||||
public static class GetMultipleImagesAdvanced extends GetMultipleContents {
|
public static class GetMultipleImagesAdvanced extends GetMultipleContents {
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
@@ -84,13 +79,11 @@ public class ActivityLaunchers {
|
|||||||
putShowAdvancedExtra(i);
|
putShowAdvancedExtra(i);
|
||||||
i.setType("image/*");
|
i.setType("image/*");
|
||||||
i.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
|
i.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
if (SDK_INT >= 19)
|
i.putExtra(EXTRA_MIME_TYPES, getSupportedImageContentTypes());
|
||||||
i.putExtra(EXTRA_MIME_TYPES, getSupportedImageContentTypes());
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(19)
|
|
||||||
public static class OpenImageDocumentAdvanced extends OpenDocument {
|
public static class OpenImageDocumentAdvanced extends OpenDocument {
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
@@ -99,13 +92,11 @@ public class ActivityLaunchers {
|
|||||||
putShowAdvancedExtra(i);
|
putShowAdvancedExtra(i);
|
||||||
i.setType("image/*");
|
i.setType("image/*");
|
||||||
i.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
|
i.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
if (SDK_INT >= 19)
|
i.putExtra(EXTRA_MIME_TYPES, getSupportedImageContentTypes());
|
||||||
i.putExtra(EXTRA_MIME_TYPES, getSupportedImageContentTypes());
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(19)
|
|
||||||
public static class OpenMultipleImageDocumentsAdvanced
|
public static class OpenMultipleImageDocumentsAdvanced
|
||||||
extends OpenMultipleDocuments {
|
extends OpenMultipleDocuments {
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -115,8 +106,7 @@ public class ActivityLaunchers {
|
|||||||
putShowAdvancedExtra(i);
|
putShowAdvancedExtra(i);
|
||||||
i.setType("image/*");
|
i.setType("image/*");
|
||||||
i.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
|
i.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
if (SDK_INT >= 19)
|
i.putExtra(EXTRA_MIME_TYPES, getSupportedImageContentTypes());
|
||||||
i.putExtra(EXTRA_MIME_TYPES, getSupportedImageContentTypes());
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import androidx.annotation.ColorRes;
|
|||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static androidx.core.app.NotificationCompat.VISIBILITY_PRIVATE;
|
import static androidx.core.app.NotificationCompat.VISIBILITY_PRIVATE;
|
||||||
|
|
||||||
public class BriarNotificationBuilder extends NotificationCompat.Builder {
|
public class BriarNotificationBuilder extends NotificationCompat.Builder {
|
||||||
@@ -24,7 +23,7 @@ public class BriarNotificationBuilder extends NotificationCompat.Builder {
|
|||||||
|
|
||||||
setLights(ContextCompat.getColor(context, R.color.briar_lime_400),
|
setLights(ContextCompat.getColor(context, R.color.briar_lime_400),
|
||||||
750, 500);
|
750, 500);
|
||||||
if (SDK_INT >= 21) setVisibility(VISIBILITY_PRIVATE);
|
setVisibility(VISIBILITY_PRIVATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BriarNotificationBuilder setColorRes(@ColorRes int res) {
|
public BriarNotificationBuilder setColorRes(@ColorRes int res) {
|
||||||
@@ -33,7 +32,7 @@ public class BriarNotificationBuilder extends NotificationCompat.Builder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public BriarNotificationBuilder setNotificationCategory(String category) {
|
public BriarNotificationBuilder setNotificationCategory(String category) {
|
||||||
if (SDK_INT >= 21) setCategory(category);
|
setCategory(category);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import android.view.View;
|
|||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
import com.google.android.material.snackbar.Snackbar.Callback;
|
|
||||||
|
|
||||||
import org.briarproject.briar.R;
|
import org.briarproject.briar.R;
|
||||||
import org.briarproject.nullsafety.NotNullByDefault;
|
import org.briarproject.nullsafety.NotNullByDefault;
|
||||||
@@ -13,11 +12,7 @@ import androidx.annotation.ColorRes;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
import static android.view.View.INVISIBLE;
|
|
||||||
import static android.view.View.VISIBLE;
|
|
||||||
import static androidx.core.content.ContextCompat.getColor;
|
import static androidx.core.content.ContextCompat.getColor;
|
||||||
import static com.google.android.material.snackbar.Snackbar.LENGTH_INDEFINITE;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class BriarSnackbarBuilder {
|
public class BriarSnackbarBuilder {
|
||||||
@@ -37,24 +32,6 @@ public class BriarSnackbarBuilder {
|
|||||||
R.color.briar_button_text_positive));
|
R.color.briar_button_text_positive));
|
||||||
s.setAction(actionResId, onClickListener);
|
s.setAction(actionResId, onClickListener);
|
||||||
}
|
}
|
||||||
// Workaround for https://issuetracker.google.com/issues/64285517
|
|
||||||
if (duration == LENGTH_INDEFINITE && SDK_INT < 21) {
|
|
||||||
// Hide snackbar while it's opening to make bouncing less noticeable
|
|
||||||
s.getView().setVisibility(INVISIBLE);
|
|
||||||
s.addCallback(new Callback() {
|
|
||||||
@Override
|
|
||||||
public void onShown(Snackbar snackbar) {
|
|
||||||
snackbar.getView().setVisibility(VISIBLE);
|
|
||||||
// Request layout again in case snackbar is in wrong place
|
|
||||||
snackbar.getView().requestLayout();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDismissed(Snackbar snackbar, int event) {
|
|
||||||
snackbar.getView().setVisibility(INVISIBLE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ import androidx.annotation.ColorInt;
|
|||||||
import androidx.annotation.ColorRes;
|
import androidx.annotation.ColorRes;
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
@@ -108,8 +107,6 @@ import static java.util.logging.Level.WARNING;
|
|||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE;
|
import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE;
|
||||||
import static org.briarproject.briar.android.TestingConstants.IS_OLD_ANDROID;
|
|
||||||
import static org.briarproject.briar.android.TestingConstants.OLD_ANDROID_WARN_DATE;
|
|
||||||
import static org.briarproject.briar.android.reporting.CrashReportActivity.EXTRA_APP_LOGCAT;
|
import static org.briarproject.briar.android.reporting.CrashReportActivity.EXTRA_APP_LOGCAT;
|
||||||
import static org.briarproject.briar.android.reporting.CrashReportActivity.EXTRA_APP_START_TIME;
|
import static org.briarproject.briar.android.reporting.CrashReportActivity.EXTRA_APP_START_TIME;
|
||||||
import static org.briarproject.briar.android.reporting.CrashReportActivity.EXTRA_INITIAL_COMMENT;
|
import static org.briarproject.briar.android.reporting.CrashReportActivity.EXTRA_INITIAL_COMMENT;
|
||||||
@@ -244,11 +241,6 @@ public class UiUtils {
|
|||||||
return (EXPIRY_DATE - now) / DAYS.toMillis(1);
|
return (EXPIRY_DATE - now) / DAYS.toMillis(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean shouldWarnOldAndroidExpiry() {
|
|
||||||
return IS_OLD_ANDROID &&
|
|
||||||
System.currentTimeMillis() >= OLD_ANDROID_WARN_DATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SpannableStringBuilder getTeaser(Context ctx, Spanned text) {
|
public static SpannableStringBuilder getTeaser(Context ctx, Spanned text) {
|
||||||
if (text.length() < TEASER_LENGTH)
|
if (text.length() < TEASER_LENGTH)
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
@@ -376,7 +368,6 @@ public class UiUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasKeyguardLock(Context ctx) {
|
public static boolean hasKeyguardLock(Context ctx) {
|
||||||
if (SDK_INT < 21) return false;
|
|
||||||
KeyguardManager keyguardManager =
|
KeyguardManager keyguardManager =
|
||||||
(KeyguardManager) ctx.getSystemService(KEYGUARD_SERVICE);
|
(KeyguardManager) ctx.getSystemService(KEYGUARD_SERVICE);
|
||||||
if (keyguardManager == null) return false;
|
if (keyguardManager == null) return false;
|
||||||
@@ -438,7 +429,6 @@ public class UiUtils {
|
|||||||
keyEvent.getKeyCode() == KEYCODE_ENTER;
|
keyEvent.getKeyCode() == KEYCODE_ENTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(api = 21)
|
|
||||||
public static void excludeSystemUi(Transition transition) {
|
public static void excludeSystemUi(Transition transition) {
|
||||||
transition.excludeTarget(android.R.id.statusBarBackground, true);
|
transition.excludeTarget(android.R.id.statusBarBackground, true);
|
||||||
transition.excludeTarget(android.R.id.navigationBarBackground, true);
|
transition.excludeTarget(android.R.id.navigationBarBackground, true);
|
||||||
@@ -480,7 +470,6 @@ public class UiUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isRtl(Context ctx) {
|
public static boolean isRtl(Context ctx) {
|
||||||
if (SDK_INT < 17) return false;
|
|
||||||
return ctx.getResources().getConfiguration().getLayoutDirection() ==
|
return ctx.getResources().getConfiguration().getLayoutDirection() ==
|
||||||
LAYOUT_DIRECTION_RTL;
|
LAYOUT_DIRECTION_RTL;
|
||||||
}
|
}
|
||||||
@@ -507,7 +496,7 @@ public class UiUtils {
|
|||||||
view.setVisibility(small ? GONE : VISIBLE);
|
view.setVisibility(small ? GONE : VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isSmallScreenRelativeToFontSize(Context ctx) {
|
private static boolean isSmallScreenRelativeToFontSize(Context ctx) {
|
||||||
Configuration config = ctx.getResources().getConfiguration();
|
Configuration config = ctx.getResources().getConfiguration();
|
||||||
if (config.fontScale == 0f) return true;
|
if (config.fontScale == 0f) return true;
|
||||||
return config.screenHeightDp / config.fontScale < 600;
|
return config.screenHeightDp / config.fontScale < 600;
|
||||||
@@ -546,7 +535,7 @@ public class UiUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void launchActivityToOpenFile(Context ctx,
|
public static void launchActivityToOpenFile(Context ctx,
|
||||||
@Nullable ActivityResultLauncher<String[]> docLauncher,
|
ActivityResultLauncher<String[]> docLauncher,
|
||||||
ActivityResultLauncher<String> contentLauncher,
|
ActivityResultLauncher<String> contentLauncher,
|
||||||
String contentType) {
|
String contentType) {
|
||||||
// Try GET_CONTENT, fall back to OPEN_DOCUMENT if available
|
// Try GET_CONTENT, fall back to OPEN_DOCUMENT if available
|
||||||
@@ -556,13 +545,11 @@ public class UiUtils {
|
|||||||
} catch (ActivityNotFoundException e) {
|
} catch (ActivityNotFoundException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
if (docLauncher != null) {
|
try {
|
||||||
try {
|
docLauncher.launch(new String[] {contentType});
|
||||||
docLauncher.launch(new String[] {contentType});
|
return;
|
||||||
return;
|
} catch (ActivityNotFoundException e) {
|
||||||
} catch (ActivityNotFoundException e) {
|
logException(LOG, WARNING, e);
|
||||||
logException(LOG, WARNING, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Toast.makeText(ctx, R.string.error_start_activity, LENGTH_LONG).show();
|
Toast.makeText(ctx, R.string.error_start_activity, LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.briarproject.briar.android.widget;
|
package org.briarproject.briar.android.widget;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
@@ -27,7 +26,6 @@ public class TouchInterceptingLinearLayout extends LinearLayout {
|
|||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(21)
|
|
||||||
public TouchInterceptingLinearLayout(Context context, AttributeSet attrs,
|
public TouchInterceptingLinearLayout(Context context, AttributeSet attrs,
|
||||||
int defStyleAttr, int defStyleRes) {
|
int defStyleAttr, int defStyleRes) {
|
||||||
super(context, attrs, defStyleAttr, defStyleRes);
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?android:attr/textColorPrimary"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M21,12L14,5V9C7,10 4,15 3,20C5.5,16.5 9,14.9 14,14.9V19L21,12Z" />
|
||||||
|
</vector>
|
||||||
@@ -191,6 +191,66 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/textViewForumMessages" />
|
app:layout_constraintTop_toBottomOf="@+id/textViewForumMessages" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textViewPrivateGroups"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="@dimen/margin_medium"
|
||||||
|
android:text="Number of private groups"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/seekBarForumMessages" />
|
||||||
|
|
||||||
|
<SeekBar
|
||||||
|
android:id="@+id/seekBarPrivateGroups"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:max="50"
|
||||||
|
android:paddingTop="5dp"
|
||||||
|
android:progress="5"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/TextViewPrivateGroupsSb"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/textViewPrivateGroups" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/TextViewPrivateGroupsSb"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ems="2"
|
||||||
|
android:text="5"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/seekBarPrivateGroups"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/textViewPrivateGroups" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textViewPrivateGroupMessages"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="@dimen/margin_medium"
|
||||||
|
android:text="Number of private group messages"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/seekBarPrivateGroups" />
|
||||||
|
|
||||||
|
<SeekBar
|
||||||
|
android:id="@+id/seekBarPrivateGroupMessages"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:max="50"
|
||||||
|
android:paddingTop="5dp"
|
||||||
|
android:progress="20"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/TextViewPrivateGroupMessagesSb"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/textViewPrivateGroupMessages" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/TextViewPrivateGroupMessagesSb"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ems="2"
|
||||||
|
android:text="20"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/seekBarPrivateGroupMessages"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/textViewPrivateGroupMessages" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/buttonZeroValues"
|
android:id="@+id/buttonZeroValues"
|
||||||
style="@style/BriarButton"
|
style="@style/BriarButton"
|
||||||
@@ -201,7 +261,7 @@
|
|||||||
android:text="Zero values"
|
android:text="Zero values"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/seekBarForumMessages"
|
app:layout_constraintTop_toBottomOf="@+id/seekBarPrivateGroupMessages"
|
||||||
app:layout_constraintVertical_bias="1.0" />
|
app:layout_constraintVertical_bias="1.0" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -52,10 +52,10 @@
|
|||||||
android:layout_height="24dp"
|
android:layout_height="24dp"
|
||||||
android:layout_margin="@dimen/margin_medium"
|
android:layout_margin="@dimen/margin_medium"
|
||||||
android:contentDescription="@string/help"
|
android:contentDescription="@string/help"
|
||||||
android:tint="@color/briar_button_text_positive"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/button"
|
app:layout_constraintBottom_toBottomOf="@+id/button"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="@+id/button"
|
app:layout_constraintTop_toTopOf="@+id/button"
|
||||||
app:srcCompat="@drawable/ic_help_outline_white" />
|
app:srcCompat="@drawable/ic_help_outline_white"
|
||||||
|
app:tint="@color/briar_button_text_positive" />
|
||||||
|
|
||||||
</merge>
|
</merge>
|
||||||
@@ -35,7 +35,6 @@
|
|||||||
<item
|
<item
|
||||||
android:id="@+id/action_transfer_data"
|
android:id="@+id/action_transfer_data"
|
||||||
android:title="@string/removable_drive_menu_title"
|
android:title="@string/removable_drive_menu_title"
|
||||||
android:visible="false"
|
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
</menu>
|
</menu>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
<string name="dnkm_xiaomi_help">Ако 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_old">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_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>
|
<string name="dnkm_warning_dozed_1">Briar не може да работи във фонов режим</string>
|
||||||
<!--Login-->
|
<!--Login-->
|
||||||
<string name="enter_password">Парола</string>
|
<string name="enter_password">Парола</string>
|
||||||
@@ -47,10 +49,6 @@
|
|||||||
<item quantity="one">Това е тестова версия на Briar. Вашият акаунт ще бъде изтече след %d ден и не може да бъде подновена.</item>
|
<item quantity="one">Това е тестова версия на Briar. Вашият акаунт ще бъде изтече след %d ден и не може да бъде подновена.</item>
|
||||||
<item quantity="other">Това е изпитателно издание на Briar. Валидността на профила ще изтече след %d дена и не може да бъде подновена.</item>
|
<item quantity="other">Това е изпитателно издание на Briar. Валидността на профила ще изтече след %d дена и не може да бъде подновена.</item>
|
||||||
</plurals>
|
</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>
|
|
||||||
</plurals>
|
|
||||||
<string name="expiry_date_reached">Софтуерът е с изтекъл срок.\nБлагодарим за изпитването!</string>
|
<string name="expiry_date_reached">Софтуерът е с изтекъл срок.\nБлагодарим за изпитването!</string>
|
||||||
<string name="download_briar">За да продължите да използвате Briar изтеглете последното издание.</string>
|
<string name="download_briar">За да продължите да използвате Briar изтеглете последното издание.</string>
|
||||||
<string name="create_new_account">Ще трябва да създадете нов профил, но ще можете да използвате същия прякор.</string>
|
<string name="create_new_account">Ще трябва да създадете нов профил, но ще можете да използвате същия прякор.</string>
|
||||||
|
|||||||
@@ -49,10 +49,6 @@
|
|||||||
<item quantity="one">Aquesta és una versió de prova de Briar. El vostre compte expira en %d dia i no es pot renovar.</item>
|
<item quantity="one">Aquesta és una versió de prova de Briar. El vostre compte expira en %d dia i no es pot renovar.</item>
|
||||||
<item quantity="other">Aquesta és una versió de prova de Briar. El vostre compte caducarà en %d dies i no es podrà renovar.</item>
|
<item quantity="other">Aquesta és una versió de prova de Briar. El vostre compte caducarà en %d dies i no es podrà renovar.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="old_android_expiry_warning">
|
|
||||||
<item quantity="one">L\'Android 4 ja no és compatible. El Briar deixarà de funcionar a %s (d\'aquí a %d dia). Instal·leu el Briar en un dispositiu més nou i creeu un compte nou.</item>
|
|
||||||
<item quantity="other">L\'Android 4 ja no és compatible. El Briar deixarà de funcionar a %s (d\'aquí a %d dies). Instal·leu el Briar en un dispositiu més nou i creeu un compte nou.</item>
|
|
||||||
</plurals>
|
|
||||||
<string name="expiry_date_reached">Aquesta versió de Briar ha caducat.\nGràcies per haver-lo provat!</string>
|
<string name="expiry_date_reached">Aquesta versió de Briar ha caducat.\nGràcies per haver-lo provat!</string>
|
||||||
<string name="download_briar">Per continuar utilitzant Briar, baixeu la darrera versió.</string>
|
<string name="download_briar">Per continuar utilitzant Briar, baixeu la darrera versió.</string>
|
||||||
<string name="create_new_account">Haureu de crear un compte nou, però podeu utilitzar el mateix sobrenom.</string>
|
<string name="create_new_account">Haureu de crear un compte nou, però podeu utilitzar el mateix sobrenom.</string>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
<string name="dialog_title_lost_password">Passwort vergessen</string>
|
<string name="dialog_title_lost_password">Passwort vergessen</string>
|
||||||
<string name="dialog_message_lost_password">Dein Briar-Konto ist verschlüsselt auf deinem Gerät und nicht in der Cloud gespeichert, deshalb kannst du dein Passwort nicht zurücksetzen. Willst du dein Konto löschen und neu beginnen?\n\nAchtung: Deine bestehenden Identitäten, Kontakte und Nachrichten gehen dann für immer verloren.</string>
|
<string name="dialog_message_lost_password">Dein Briar-Konto ist verschlüsselt auf deinem Gerät 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_activity_title">Fehler beim Starten von Briar</string>
|
<string name="startup_failed_activity_title">Fehler beim Starten von Briar</string>
|
||||||
<string name="startup_failed_clock_error">Briar konnte nicht gestartet werden, weil die Uhr deines Geräts falsch eingestellt ist.\n\Bitte stelle die Uhr deines Geräts auf die richtige Zeit ein und versuche es erneut.</string>
|
<string name="startup_failed_clock_error">Briar konnte nicht gestartet werden, weil die Uhr deines Geräts falsch eingestellt ist.\n\nBitte stelle die Uhr deines Geräts auf die richtige Zeit ein und versuche es erneut.</string>
|
||||||
<string name="startup_failed_db_error">Briar konnte die Datenbank mit deinem Konto, deinen Kontakten und deinen Nachrichten nicht öffnen.\n\nBitte aktualisiere auf die neueste Version der App und versuche es erneut, oder richte ein neues Konto ein, indem du bei der Passwortabfrage \"Ich habe mein Passwort vergessen\" wählst.</string>
|
<string name="startup_failed_db_error">Briar konnte die Datenbank mit deinem Konto, deinen Kontakten und deinen Nachrichten nicht öffnen.\n\nBitte aktualisiere auf die neueste Version der App und versuche es erneut, oder richte ein neues Konto ein, indem du bei der Passwortabfrage \"Ich habe mein Passwort vergessen\" wählst.</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.\n\nDu musst entweder die alte Version neu installieren oder ein neues Konto einrichten, indem du bei der Passwortabfrage \"Ich habe mein Passwort vergessen\" wählst.</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.\n\nDu musst entweder die alte Version neu installieren oder ein neues Konto einrichten, indem du bei der Passwortabfrage \"Ich habe mein Passwort vergessen\" wählst.</string>
|
||||||
<string name="startup_failed_data_too_new_error">Dein Konto wurde mit einer neueren Version dieser App erstellt und kann mit dieser Version nicht geöffnet werden.\n\nBitte aktualisiere auf die neueste Version und versuche es erneut.</string>
|
<string name="startup_failed_data_too_new_error">Dein Konto wurde mit einer neueren Version dieser App erstellt und kann mit dieser Version nicht geöffnet werden.\n\nBitte aktualisiere auf die neueste Version und versuche es erneut.</string>
|
||||||
@@ -49,10 +49,6 @@
|
|||||||
<item quantity="one">Dies ist eine Testversion von Briar. Dein Konto läuft in %d Tag ab und kann nicht verlängert werden.</item>
|
<item quantity="one">Dies ist eine Testversion von Briar. Dein Konto läuft in %d Tag ab und kann nicht verlängert werden.</item>
|
||||||
<item quantity="other">Dies ist eine Testversion von Briar. Dein Konto läuft in %d Tagen ab und kann nicht verlängert werden.</item>
|
<item quantity="other">Dies ist eine Testversion von Briar. Dein Konto läuft in %d Tagen ab und kann nicht verlängert werden.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="old_android_expiry_warning">
|
|
||||||
<item quantity="one">Android 4 wird nicht mehr unterstützt. Briar wird nicht mehr auf %s funktionieren (in %d Tag). Bitte installiere es auf einem neueren Gerät und erstelle ein neues Konto.</item>
|
|
||||||
<item quantity="other">Android 4 wird nicht mehr unterstützt. Briar wird nicht mehr auf %s funktionieren (in %dTagen). Bitte installiere es auf einem neueren Gerät und erstelle ein neues Konto.</item>
|
|
||||||
</plurals>
|
|
||||||
<string name="expiry_date_reached">Diese Software ist abgelaufen.\nDanke, dass du Briar getestet hast!</string>
|
<string name="expiry_date_reached">Diese Software ist abgelaufen.\nDanke, dass du Briar getestet hast!</string>
|
||||||
<string name="download_briar">Bitte lade die aktuelle Version von Briar herunter, um es weiter zu benutzen.</string>
|
<string name="download_briar">Bitte lade die aktuelle Version von Briar herunter, um es weiter zu benutzen.</string>
|
||||||
<string name="create_new_account">Du wirst ein neues Konto erstellen müssen, wobei du jedoch wieder denselben Spitznamen verwenden kannst.</string>
|
<string name="create_new_account">Du wirst ein neues Konto erstellen müssen, wobei du jedoch wieder denselben Spitznamen verwenden kannst.</string>
|
||||||
|
|||||||
@@ -50,11 +50,6 @@
|
|||||||
<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="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>
|
<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>
|
||||||
<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>
|
<string name="expiry_date_reached">Este programa ha caducado.\n¡Gracias por probarlo!</string>
|
||||||
<string name="download_briar">Para continuar usando Briar, por favor descarga la versión mas reciente.</string>
|
<string name="download_briar">Para continuar usando Briar, por favor descarga la versión mas reciente.</string>
|
||||||
<string name="create_new_account">Necesitarás crear una nueva cuenta, pero puedes usar el mismo nombre de usuario.</string>
|
<string name="create_new_account">Necesitarás crear una nueva cuenta, pero puedes usar el mismo nombre de usuario.</string>
|
||||||
|
|||||||
@@ -53,10 +53,6 @@
|
|||||||
<item quantity="one">این یک نسخه آزمایشی از Briar (برایر) می باشد. حساب کاربری شما در %d روز آینده به پایان می رسد و امکان تمدید آن وجود نخواهد داشت.</item>
|
<item quantity="one">این یک نسخه آزمایشی از Briar (برایر) می باشد. حساب کاربری شما در %d روز آینده به پایان می رسد و امکان تمدید آن وجود نخواهد داشت.</item>
|
||||||
<item quantity="other">این یک نسخه آزمایشی از Briar (برایر) می باشد. حساب کاربری شما در %d روز آینده به پایان می رسد و امکان تمدید آن وجود نخواهد داشت.</item>
|
<item quantity="other">این یک نسخه آزمایشی از Briar (برایر) می باشد. حساب کاربری شما در %d روز آینده به پایان می رسد و امکان تمدید آن وجود نخواهد داشت.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="old_android_expiry_warning">
|
|
||||||
<item quantity="one">اندروید 4 دیگر پشتیبانی نمیشود. Briar (در عرض %d روز) کار بر روی %s را متوقف خواهد کرد. لطفا Briar را در دستگاه جدیدتر نصب کنید و یک حساب کاربری جدید ایجاد کنید.</item>
|
|
||||||
<item quantity="other">اندروید 4 دیگر پشتیبانی نمیشود. Briar (در عرض %d روز) کار بر روی %s را متوقف خواهد کرد. لطفا Briar را در دستگاه جدیدتر نصب کنید و یک حساب کاربری جدید ایجاد کنید.</item>
|
|
||||||
</plurals>
|
|
||||||
<string name="expiry_date_reached">این نرم افزار منقضی شده است.
|
<string name="expiry_date_reached">این نرم افزار منقضی شده است.
|
||||||
|
|
||||||
بابت تست از شما سپاسگزاریم.</string>
|
بابت تست از شما سپاسگزاریم.</string>
|
||||||
@@ -700,7 +696,7 @@
|
|||||||
<string name="mailbox_error_wizard_info2">لطفا هنگامی که به دستگاه دسترسی دارید به این صفحه بازگردید.</string>
|
<string name="mailbox_error_wizard_info2">لطفا هنگامی که به دستگاه دسترسی دارید به این صفحه بازگردید.</string>
|
||||||
<string name="mailbox_error_wizard_info3">لطفا با استفاده از دکمه زیر، پیوند Mailbox خود را لغو کنید.\n\nپس از لغو پیوند Mailbox قدیمی، میتوانید هر زمان که خواستید یک Mailbox جدید راهاندازی کنید.</string>
|
<string name="mailbox_error_wizard_info3">لطفا با استفاده از دکمه زیر، پیوند Mailbox خود را لغو کنید.\n\nپس از لغو پیوند Mailbox قدیمی، میتوانید هر زمان که خواستید یک Mailbox جدید راهاندازی کنید.</string>
|
||||||
<!--About-->
|
<!--About-->
|
||||||
<string name="about_title">دربارهی Psiphon</string>
|
<string name="about_title">دربارهی Briar</string>
|
||||||
<string name="briar_version">نسخه Briar: %s</string>
|
<string name="briar_version">نسخه Briar: %s</string>
|
||||||
<string name="tor_version">نسخه Tor: %s</string>
|
<string name="tor_version">نسخه Tor: %s</string>
|
||||||
<string name="links">لینک ها</string>
|
<string name="links">لینک ها</string>
|
||||||
|
|||||||
@@ -46,11 +46,6 @@
|
|||||||
<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="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>
|
<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>
|
||||||
<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>
|
<string name="expiry_date_reached">Ce logiciel est arrivé à expiration.\nMerci de l’avoir testé !</string>
|
||||||
<string name="download_briar">Pour continuer à utiliser Briar, veuillez télécharger la dernière version.</string>
|
<string name="download_briar">Pour continuer à utiliser Briar, veuillez télécharger la dernière version.</string>
|
||||||
<string name="create_new_account">Vous devrez créer un nouveau compte, mais vous pouvez utiliser le même pseudonyme.</string>
|
<string name="create_new_account">Vous devrez créer un nouveau compte, mais vous pouvez utiliser le même pseudonyme.</string>
|
||||||
|
|||||||
@@ -45,10 +45,6 @@
|
|||||||
<item quantity="one">Þetta er prufuútgáfa af Briar. Notandaaðgangurinn þinn mun renna út eftir %d dag og er ekki hægt að endurnýja hann.</item>
|
<item quantity="one">Þetta er prufuútgáfa af Briar. Notandaaðgangurinn þinn mun renna út eftir %d dag og er ekki hægt að endurnýja hann.</item>
|
||||||
<item quantity="other">Þetta er prufuútgáfa af Briar. Notandaaðgangurinn þinn mun renna út eftir %d daga og er ekki hægt að endurnýja hann.</item>
|
<item quantity="other">Þetta er prufuútgáfa af Briar. Notandaaðgangurinn þinn mun renna út eftir %d daga og er ekki hægt að endurnýja hann.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="old_android_expiry_warning">
|
|
||||||
<item quantity="one">Android 4 er ekki lengur stutt. Briar mun hætta að virka á %s (eftir %d dag). Settu Briar upp á nýrra tæki og útbúðu nýjan aðgang.</item>
|
|
||||||
<item quantity="other">Android 4 er ekki lengur stutt. Briar mun hætta að virka á %s (eftir %d daga). Settu Briar upp á nýrra tæki og útbúðu nýjan aðgang.</item>
|
|
||||||
</plurals>
|
|
||||||
<string name="expiry_date_reached">Þessi hugbúnaður er úreltur.\nTakk fyrir að hafa tekið þátt í prófunum!</string>
|
<string name="expiry_date_reached">Þessi hugbúnaður er úreltur.\nTakk fyrir að hafa tekið þátt í prófunum!</string>
|
||||||
<string name="download_briar">Til að halda áfram að nota Briar, ættirðu að sækja nýjustu útgáfuna.</string>
|
<string name="download_briar">Til að halda áfram að nota Briar, ættirðu að sækja nýjustu útgáfuna.</string>
|
||||||
<string name="create_new_account">Þú þarft að búa til nýjan notandaaðgang, en þú getur notað áfram sama stuttnefni.</string>
|
<string name="create_new_account">Þú þarft að búa til nýjan notandaaðgang, en þú getur notað áfram sama stuttnefni.</string>
|
||||||
|
|||||||
@@ -49,10 +49,6 @@
|
|||||||
<item quantity="one">ესაა საცდელი ვერსიის Briar. თქვენს ანგარიშს %d დღეში გაუვა ვადა და ვეღარ გახანგრძლივდება.</item>
|
<item quantity="one">ესაა საცდელი ვერსიის Briar. თქვენს ანგარიშს %d დღეში გაუვა ვადა და ვეღარ გახანგრძლივდება.</item>
|
||||||
<item quantity="other">ეს არის Briar-ის საცდელი ვერსია, რომლის ვადა %d დღეში ამოიწურება და მისი განახლება შეუძლებელია.</item>
|
<item quantity="other">ეს არის Briar-ის საცდელი ვერსია, რომლის ვადა %d დღეში ამოიწურება და მისი განახლება შეუძლებელია.</item>
|
||||||
</plurals>
|
</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>
|
|
||||||
</plurals>
|
|
||||||
<string name="expiry_date_reached">პროგრამული უზრუნველყოფის ვადა ამოიწურა.\nგმადლობთ ტესტირებისთვის!</string>
|
<string name="expiry_date_reached">პროგრამული უზრუნველყოფის ვადა ამოიწურა.\nგმადლობთ ტესტირებისთვის!</string>
|
||||||
<string name="download_briar">თუ გსურთ, კვლავ გამოიყენოთ Briar, ჩამოტვირთეთ ბოლო გამოშვება.</string>
|
<string name="download_briar">თუ გსურთ, კვლავ გამოიყენოთ Briar, ჩამოტვირთეთ ბოლო გამოშვება.</string>
|
||||||
<string name="create_new_account">დაგჭირდებათ ახალი ანგარიშის შექმნა, თუმცა იმავე მეტსახელის გამოყენება შეგეძლებათ.</string>
|
<string name="create_new_account">დაგჭირდებათ ახალი ანგარიშის შექმნა, თუმცა იმავე მეტსახელის გამოყენება შეგეძლებათ.</string>
|
||||||
|
|||||||
@@ -47,12 +47,6 @@
|
|||||||
<item quantity="many">Tai yra bandomoji Briar versija. Jūsų paskyros galiojimas pasibaigs po %d dienų ir negalės būti pratęstas.</item>
|
<item quantity="many">Tai yra bandomoji Briar versija. Jūsų paskyros galiojimas pasibaigs po %d dienų ir negalės būti pratęstas.</item>
|
||||||
<item quantity="other">Tai yra bandomoji Briar versija. Jūsų paskyros galiojimas pasibaigs po %d dienos ir negalės būti pratęstas.</item>
|
<item quantity="other">Tai yra bandomoji Briar versija. Jūsų paskyros galiojimas pasibaigs po %d dienos ir negalės būti pratęstas.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="old_android_expiry_warning">
|
|
||||||
<item quantity="one">„Android“ 4 yra daugiau nebepalaikoma. Briar nustos veikti ties %s (po %d dienos). Įsidiekite Briar naujesniame įrenginyje ir susikurkite naują paskyrą.</item>
|
|
||||||
<item quantity="few">„Android“ 4 yra daugiau nebepalaikoma. Briar nustos veikti ties %s (po %d dienų). Įsidiekite Briar naujesniame įrenginyje ir susikurkite naują paskyrą.</item>
|
|
||||||
<item quantity="many">„Android“ 4 yra daugiau nebepalaikoma. Briar nustos veikti ties %s (po %d dienų). Įsidiekite Briar naujesniame įrenginyje ir susikurkite naują paskyrą.</item>
|
|
||||||
<item quantity="other">„Android“ 4 yra daugiau nebepalaikoma. Briar nustos veikti ties %s (po %d dienos). Įsidiekite Briar naujesniame įrenginyje ir susikurkite naują paskyrą.</item>
|
|
||||||
</plurals>
|
|
||||||
<string name="expiry_date_reached">Programinės įrangos galiojimas pasibaigė.\nDėkojame, kad išbandėte!</string>
|
<string name="expiry_date_reached">Programinės įrangos galiojimas pasibaigė.\nDėkojame, kad išbandėte!</string>
|
||||||
<string name="download_briar">Norėdami ir toliau naudotis Briar, atsisiųskite naujausią programos laidą.</string>
|
<string name="download_briar">Norėdami ir toliau naudotis Briar, atsisiųskite naujausią programos laidą.</string>
|
||||||
<string name="create_new_account">Jūs turėsite susikurti paskyrą, tačiau galėsite naudoti tą patį slapyvardį.</string>
|
<string name="create_new_account">Jūs turėsite susikurti paskyrą, tačiau galėsite naudoti tą patį slapyvardį.</string>
|
||||||
@@ -780,6 +774,7 @@
|
|||||||
<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>
|
<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-->
|
<!--e.g. Download Briar 1.2.20-->
|
||||||
<string name="website_download_title_1">Atsisiųsti Briar %s</string>
|
<string name="website_download_title_1">Atsisiųsti Briar %s</string>
|
||||||
|
<string name="website_download_intro_1">Kažkas iš šalia esančių pradėjo bendrinti su jumis Briar.</string>
|
||||||
<string name="website_download_button">Atsisiųsti Briar</string>
|
<string name="website_download_button">Atsisiųsti Briar</string>
|
||||||
<string name="website_download_outro">Kai atsisiuntimas pasibaigs, atverkite atsisiųstą failą ir jį įdiekite.</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_title">Nesklandumų šalinimas</string>
|
||||||
|
|||||||
@@ -44,9 +44,6 @@
|
|||||||
<plurals name="expiry_warning">
|
<plurals name="expiry_warning">
|
||||||
<item quantity="other">ဤအရာသည် Briar ၏ စမ်းသပ်ဆဲဗားရှင်းဖြစ်ပါသည်။ သင့်အကောင့်သည် %d ရက်ကြာလျှင် သက်တမ်းကုန်ဆုံးမည်ဖြစ်ပြီး သက်တမ်းတိုး၍မရနိုင်ပါ။</item>
|
<item quantity="other">ဤအရာသည် Briar ၏ စမ်းသပ်ဆဲဗားရှင်းဖြစ်ပါသည်။ သင့်အကောင့်သည် %d ရက်ကြာလျှင် သက်တမ်းကုန်ဆုံးမည်ဖြစ်ပြီး သက်တမ်းတိုး၍မရနိုင်ပါ။</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="old_android_expiry_warning">
|
|
||||||
<item quantity="other">အန်းဒရိုက် ၄ ကို မပံ့ပိုးတော့ပါ။ Briar သည် %s(ရက်%dတွင်) အလုပ် မလုပ်တော့ပါ။ ကျေးဇူးပြု၍ Briar ကို စက်ပစ္စည်းအသစ်တွင် ထည့်သွင်းပြီး အကောင့်အသစ်တစ်ခု ဖန်တီးပါ။</item>
|
|
||||||
</plurals>
|
|
||||||
<string name="expiry_date_reached">ဤဆော့ဖ်ဝဲသည် သက်တမ်းကုန်သွားပါပြီ။ \nစမ်းသပ်အသုံးပြုခြင်းအတွက် ကျေးဇူးတင်ပါသည်။</string>
|
<string name="expiry_date_reached">ဤဆော့ဖ်ဝဲသည် သက်တမ်းကုန်သွားပါပြီ။ \nစမ်းသပ်အသုံးပြုခြင်းအတွက် ကျေးဇူးတင်ပါသည်။</string>
|
||||||
<string name="download_briar">Briar ကို ဆက်လက်အသုံးပြုရန် နောက်ဆုံးထွက်ထားသည်ကို ဒေါင်းလုဒ်လုပ်ပါ။</string>
|
<string name="download_briar">Briar ကို ဆက်လက်အသုံးပြုရန် နောက်ဆုံးထွက်ထားသည်ကို ဒေါင်းလုဒ်လုပ်ပါ။</string>
|
||||||
<string name="create_new_account">အကောင့်အသစ်ဖွင့်ရန် လိုအပ်သော်လည်း သုံးလက်စနာမည်ပြောင်ကို ဆက်သုံးနိုင်ပါသည်။</string>
|
<string name="create_new_account">အကောင့်အသစ်ဖွင့်ရန် လိုအပ်သော်လည်း သုံးလက်စနာမည်ပြောင်ကို ဆက်သုံးနိုင်ပါသည်။</string>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user