Compare commits

...

77 Commits

Author SHA1 Message Date
akwizgran
35d035b19f Remove observer when load completes or is cancelled. 2025-05-02 15:03:20 +01:00
akwizgran
9ecac899fb Reset bound message ID when view is recycled. 2025-05-02 14:35:46 +01:00
akwizgran
16104b84b2 Load private group text lazily too, what the heck. 2025-05-02 14:35:46 +01:00
akwizgran
1542be20db Load forum post text lazily. 2025-05-02 14:35:41 +01:00
akwizgran
070a0181d9 Merge branch 'remove-forum-without-opening' into 'master'
Allow forums to be removed without opening them

See merge request briar/briar!1841
2025-05-01 08:24:38 +00:00
akwizgran
d83ae3a3b4 Use long click to open menu, clean up some cruft. 2025-04-30 15:25:14 +01:00
akwizgran
143f04bf1b Merge branch 'mark-db-clean-after-compacting' into 'master'
Mark DB as clean after compacting, keep foreground service until shutdown completes

See merge request briar/briar!1842
2025-04-30 10:30:48 +00:00
akwizgran
138fa6f39d Allow forums to be removed without opening them. 2025-04-29 10:17:40 +01:00
akwizgran
8e1371acf0 Keep foreground service until lifecycle shutdown completes.
This ensures our background threads keep running.
2025-04-29 10:17:09 +01:00
akwizgran
29f0b9d3c0 Mark DB as clean after compacting.
This ensures we compact the DB at the next startup if we didn't finish
compacting it at shutdown.
2025-04-29 10:17:09 +01:00
akwizgran
eb45ccfe9e Merge branch 'fix-problem-from-recent-fix-for-annotations-processor' into 'master'
Fix problem in AS after 8962fefd

See merge request briar/briar!1840
2025-04-29 08:49:15 +00:00
Sebastian Kürten
e98b5a9882 Fix problem in AS after 8962fefd
Commit 8962fefd introduced a problem while loading the project into
Android Studio. Apparently the fix from that commit did not handly
updated types of the more recent Gradle API. This update should fix it.
2025-04-03 08:30:16 +02:00
akwizgran
1a603d52da Bump version numbers for 1.5.14 release. 2025-02-13 12:46:50 +00:00
Torsten Grote
1e74b213e3 Merge branch 'upgrade-tor-lyrebird-onionwrapper' into 'master'
Tor 0.4.8.14, Lyrebird 0.5.0-3, Onionwrapper 0.1.3

See merge request briar/briar!1839
2025-02-13 12:44:07 +00:00
akwizgran
292808dbfc Merge branch 'fix-gradle-warnings' into 'master'
Remove warning concerning annotation processor sources

See merge request briar/briar!1838
2025-02-13 12:32:36 +00:00
akwizgran
a3f1ce6d87 Tor 0.4.8.14, Lyrebird 0.5.0-3, Onionwrapper 0.1.3. 2025-02-13 12:25:50 +00:00
Sebastian Kürten
8962fefd14 Remove warning concerning annotation processor sources
When running Gradle with --warning-mode all, we currently get this
warning:

> Configure project :bramble-core
The CompileOptions.annotationProcessorGeneratedSourcesDirectory property has
been deprecated. This is scheduled to be removed in Gradle 8.0.
Please use the generatedSourceOutputDirectory property instead. See
 https://docs.gradle.org/7.3.3/dsl/org.gradle.api.tasks.compile.CompileOptions.html#org.gradle.api.tasks.compile.CompileOptions:annotationProcessorGeneratedSourcesDirectory
for more details.
        at
dagger_aws623iifvykitf9kogs8i23w$_run_closure2$_closure4.doCall(/home/z/gitlab/briar/briar/dagger.gradle:9)
2025-02-12 10:08:14 +01:00
Torsten Grote
7034524fa1 Merge branch 'use-java-17-for-ci' into 'master'
Use Java 17 for CI

See merge request briar/briar!1837
2025-02-05 18:04:15 +00:00
akwizgran
a6153c91ed Use Java 17 for CI. 2025-01-02 18:00:14 +00:00
Torsten Grote
dd0175f4aa Merge branch 'remove-reflection-from-tests' into 'master'
Remove reflection from tests that's not allowed by Java 17

See merge request briar/briar!1835
2025-01-02 15:34:53 +00:00
akwizgran
7c6e351a37 Remove reflection from tests that's not allowed by Java 17. 2025-01-02 14:45:21 +00:00
Torsten Grote
05c3e9bf40 Merge branch 'tor-0.4.8.13-lyrebird' into 'master'
Upgrade to Tor 0.4.8.13, Lyrebird 0.5.0, onionwrapper 0.1.2

See merge request briar/briar!1833
2025-01-02 12:50:58 +00:00
akwizgran
68d26bf25e Upgrade to Tor 0.4.8.13, Lyrebird 0.5.0, onionwrapper 0.1.2. 2025-01-02 12:41:43 +00:00
Torsten Grote
daa03b1d73 Merge branch 'remove-another-flaky-ui-test' into 'master'
Remove another intermittently failing UI test and some dead code

See merge request briar/briar!1834
2025-01-02 11:42:43 +00:00
akwizgran
1e71361700 Update translations, add Bengali. 2025-01-02 11:32:44 +00:00
akwizgran
a89a0cbaa3 Remove another intermittently failing UI test and some dead code.
These tests have been failing intermittently since the UI refactoring and Material Design update last year. They don't seem to provide much value so I'm removing them rather than spending time to work out why they're no longer reliable.
2025-01-01 17:47:39 +00:00
Torsten Grote
1dbb8aa512 Merge branch 'target-34' into 'master'
Target SDK 34

Closes #2464

See merge request briar/briar!1832
2024-11-04 11:57:09 +00:00
akwizgran
e8ed0b4703 Use two foreground service types. 2024-11-04 11:41:13 +00:00
akwizgran
c76a76318c Use app context to unregister receiver. 2024-11-04 11:36:20 +00:00
akwizgran
5a34e2c0ab Small code cleanup. 2024-11-04 11:36:03 +00:00
Torsten Grote
ad5349c8a7 Target SDK 34 2024-10-31 17:22:42 -03:00
Torsten Grote
863db40f8e Specify foregroundServiceType for BriarService in Manifest 2024-10-31 17:08:20 -03:00
Torsten Grote
4f8ac5f734 Use helper function of registerReceiver() that doesn't export receiver 2024-10-31 17:07:49 -03:00
akwizgran
6e4052fa87 Bump version numbers for 1.5.13 release. 2024-08-07 12:20:20 +01:00
akwizgran
23ac592f27 Update translations. 2024-08-05 14:51:50 +01:00
akwizgran
4a1a09c855 Merge branch '2466-outline-button-fix' into 'master'
Fix outline buttons to not have green background

Closes #2466

See merge request briar/briar!1830
2024-07-25 10:09:18 +00:00
Torsten Grote
2dd0be879e Fix outline buttons to not have green background 2024-07-24 14:51:56 -03:00
akwizgran
d369b9d150 Merge branch 'monochrome-icon' into 'master'
Add monochrome (themable) icon

See merge request briar/briar!1829
2024-07-22 13:33:55 +00:00
Torsten Grote
4cc7619838 Add monochrome icon 2024-07-20 15:16:49 -03:00
akwizgran
2af1e5c421 Bump version numbers for 1.5.12 release. 2024-07-03 16:32:32 +01:00
akwizgran
3d60ec5e97 Actually add Cuban Spanish translation this time. 2024-07-03 16:32:32 +01:00
Torsten Grote
48e7ffde92 Merge branch 'remove-failing-ui-test' into 'master'
Remove UI test that has been failing since recent UI changes

See merge request briar/briar!1828
2024-07-01 13:13:59 +00:00
akwizgran
a8b561afb2 Update translations, add Spanish (Cuba). 2024-06-29 11:25:11 +01:00
akwizgran
69db146a03 Remove UI test that has been failing since recent UI changes.
This test has been failing intermittently since the changes to the
account creation UI were merged, and failing more often since the
Material Design 3 changes were merged. There's no obvious reason why
the changes should have affected this test. Since the UI tests don't
provide much value I'm removing it rather than spending time to find
out the cause and make it reliable again.
2024-06-28 17:52:48 +01:00
akwizgran
e5f49674ce Update translations. 2024-06-15 15:18:09 +01:00
Torsten Grote
27b8a8a105 Merge branch 'onionwrapper-0.1.1' into 'master'
Upgrade onionwrapper to 0.1.1

See merge request briar/briar!1827
2024-06-10 18:46:24 +00:00
akwizgran
bfbbdd897f Upgrade onionwrapper to 0.1.1. 2024-06-10 18:29:22 +01:00
akwizgran
f6f5570ac6 Merge branch 'md3' into 'master'
Migrate app to Material Design 3

Closes #2460

See merge request briar/briar!1825
2024-06-10 16:55:38 +00:00
Torsten Grote
07ab0146dd Use proper MD3 theme color definitions for step bubbles 2024-06-10 10:56:08 -03:00
Torsten Grote
5bba0daa89 Use new colors for step bubbles when adding contacts remotely 2024-06-10 10:12:56 -03:00
Torsten Grote
dcaf873117 Adapt MD3 error color 2024-06-10 09:35:47 -03:00
Torsten Grote
19d9e823a8 use default snackbar colors until specified otherwise 2024-06-10 09:28:50 -03:00
Torsten Grote
10a24c5966 Apply MD3 changes for set password screen to change password screen as well 2024-06-03 13:50:09 -03:00
Torsten Grote
642ac3fbe0 Don't allow MIUI to mess with our theme 2024-06-03 12:42:33 -03:00
Torsten Grote
675e984eaa Second round of MD3 review feedback 2024-06-03 12:39:06 -03:00
Torsten Grote
03196b65ab Use MD3 switches 2024-05-27 13:52:17 -03:00
Torsten Grote
d5f920e9b9 Address issues of first design review
less round buttons, fixed outline buttons, fixed dialogs
2024-05-27 13:24:28 -03:00
akwizgran
6f937eb929 Update translations. 2024-05-27 10:31:04 +01:00
Torsten Grote
e8ee0f4b44 Migrate app to Material Design 3
without dynamic colors, trying to look as before
2024-05-24 10:59:26 -03:00
akwizgran
ab223da18c Merge branch '2131-follow-system-theme' into 'master'
Change default theme to 'follow system' instead of 'light'

Closes #2131

See merge request briar/briar!1824
2024-05-24 13:39:11 +00:00
akwizgran
ccd191b692 Merge branch '2459-login-screen-redesign' into 'master'
Redesign login screen and setup wizard

Closes #2459

See merge request briar/briar!1823
2024-05-24 13:22:08 +00:00
Torsten Grote
fd7088389f Remove removal of system default theme on API < 27
This doesn't seem to be necessary anymore. The app falls back to light theme in this case.
2024-05-14 15:52:53 -03:00
Torsten Grote
424e022388 Default theme to follow system instead of light
Also remove deprecated Auto option
2024-05-10 17:35:05 -03:00
Torsten Grote
16385ecafe Add textual representations to password strength meter 2024-05-10 14:58:00 -03:00
Torsten Grote
7d95eb4de6 Don't mess with IME actions when doze isn't needed
Doing this was causing the keyboard action button to cycle between password and password confirmation field. Now it creates the account (if the passwords match).
2024-05-10 14:55:57 -03:00
Torsten Grote
0724bb89b2 Redesign doze screen of setup wizard 2024-05-10 14:55:57 -03:00
Torsten Grote
f1662d7311 Redesign password screen of setup wizard 2024-05-10 14:55:56 -03:00
Torsten Grote
8980cc07d2 Redesign nickname screen of setup wizard 2024-05-10 14:55:56 -03:00
Torsten Grote
04e14cfa29 Redesign login screen 2024-05-10 14:55:56 -03:00
Torsten Grote
8fa0866243 Merge branch 'update-translations' into 'master'
Update translations, upgrade dont-kill-me-lib

See merge request briar/briar!1822
2024-04-24 15:09:30 +00:00
akwizgran
a406eb5651 Update translations, upgrade dont-kill-me-lib. 2024-04-24 14:56:34 +01:00
akwizgran
8a8c6256a5 Bump version numbers for 1.5.11 release. 2024-04-16 11:09:43 +01:00
akwizgran
c076a8e2cd Update translations, add Portuguese (Portugal). 2024-04-16 11:08:58 +01:00
Torsten Grote
c0234ebe13 Merge branch '2446-illegal-state-exception-hotspot-activity' into 'master'
Move initialisation of condition manager so it's only called once

Closes #2446

See merge request briar/briar!1821
2024-03-28 13:29:05 +00:00
akwizgran
b15d316946 Move initialisation of condition manager so it's only called once. 2024-03-27 18:10:51 +00:00
Torsten Grote
e40c0caf97 Merge branch '2420-bluetooth-permission-still-needed' into 'master'
Assume that obsolete Bluetooth permission will be needed forever

Closes #2420

See merge request briar/briar!1820
2024-03-18 17:24:45 +00:00
akwizgran
f3af1d90d1 Assume that obsolete Bluetooth permission will be needed forever. 2024-03-18 17:15:20 +00:00
187 changed files with 4541 additions and 1231 deletions

View File

@@ -7,6 +7,7 @@ stages:
variables:
GIT_SUBMODULE_STRATEGY: recursive
JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
workflow:
# when to create a CI pipeline

View File

@@ -3,8 +3,8 @@ apply plugin: 'witness'
apply from: 'witness.gradle'
android {
compileSdkVersion 33
buildToolsVersion '33.0.0'
compileSdkVersion 34
buildToolsVersion '34.0.0'
packagingOptions {
doNotStrip '**/*.so'
@@ -13,8 +13,8 @@ android {
defaultConfig {
minSdkVersion 21
targetSdkVersion 33
versionCode 10510
versionName "1.5.10"
versionCode 10514
versionName "1.5.14"
consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -40,7 +40,7 @@ configurations {
}
dependencies {
api 'org.briarproject:dont-kill-me-lib:0.2.7'
api 'org.briarproject:dont-kill-me-lib:0.2.8'
// 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,
@@ -54,8 +54,7 @@ dependencies {
implementation "org.briarproject:onionwrapper-android:$onionwrapper_version"
tor "org.briarproject:tor-android:$tor_version"
tor "org.briarproject:obfs4proxy-android:$obfs4proxy_version"
tor "org.briarproject:snowflake-android:$snowflake_version"
tor "org.briarproject:lyrebird-android:$lyrebird_version"
annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"

View File

@@ -8,10 +8,8 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- The BLUETOOTH permission was supposed to be removed in API 31 but is still needed on some Xiaomi/Redmi/POCO devices running API 31 and Nubia devices running API 32 -->
<uses-permission
android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="32" />
<!-- The BLUETOOTH permission was supposed to be removed in API 31 but is still needed on some Xiaomi/Redmi/POCO devices running API 31 and Nubia devices running API 32/33 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission
android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />

View File

@@ -30,6 +30,7 @@ import static android.os.PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED;
import static android.os.PowerManager.ACTION_POWER_SAVE_MODE_CHANGED;
import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.AndroidUtils.registerReceiver;
class AndroidBatteryManager implements BatteryManager, Service {
@@ -52,7 +53,7 @@ class AndroidBatteryManager implements BatteryManager, Service {
public boolean isCharging() {
// Get the sticky intent for ACTION_BATTERY_CHANGED
IntentFilter filter = new IntentFilter(ACTION_BATTERY_CHANGED);
Intent i = appContext.registerReceiver(null, filter);
Intent i = registerReceiver(appContext, null, filter);
if (i == null) return false;
int status = i.getIntExtra(EXTRA_PLUGGED, 0);
return status != 0;
@@ -71,7 +72,7 @@ class AndroidBatteryManager implements BatteryManager, Service {
filter.addAction(ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED);
filter.addAction(ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED);
}
appContext.registerReceiver(batteryReceiver, filter);
registerReceiver(appContext, batteryReceiver, filter);
}
@Override

View File

@@ -55,6 +55,7 @@ import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.AndroidUtils.registerReceiver;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.nullsafety.NullSafety.requireNonNull;
@@ -103,7 +104,7 @@ class AndroidNetworkManager implements NetworkManager, Service {
filter.addAction(WIFI_AP_STATE_CHANGED_ACTION);
filter.addAction(WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
if (SDK_INT >= 23) filter.addAction(ACTION_DEVICE_IDLE_MODE_CHANGED);
app.registerReceiver(networkStateReceiver, filter);
registerReceiver(app, networkStateReceiver, filter);
}
@Override

View File

@@ -56,6 +56,7 @@ import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.AndroidUtils.hasBtConnectPermission;
import static org.briarproject.bramble.util.AndroidUtils.registerReceiver;
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
@MethodsNotNullByDefault
@@ -112,7 +113,7 @@ class AndroidBluetoothPlugin extends
filter.addAction(ACTION_STATE_CHANGED);
filter.addAction(ACTION_SCAN_MODE_CHANGED);
receiver = new BluetoothStateReceiver();
app.registerReceiver(receiver, filter);
registerReceiver(app, receiver, filter);
}
@Override
@@ -237,7 +238,7 @@ class AndroidBluetoothPlugin extends
filter.addAction(ACTION_DISCOVERY_STARTED);
filter.addAction(ACTION_DISCOVERY_FINISHED);
filter.addAction(ACTION_FOUND);
app.registerReceiver(receiver, filter);
registerReceiver(app, receiver, filter);
try {
if (adapter.startDiscovery()) {
long now = clock.currentTimeMillis();

View File

@@ -2,7 +2,10 @@ package org.briarproject.bramble.util;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Looper;
import android.provider.Settings;
@@ -21,6 +24,7 @@ import javax.annotation.Nullable;
import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.content.Context.MODE_PRIVATE;
import static android.content.Context.RECEIVER_NOT_EXPORTED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.Process.myPid;
@@ -141,4 +145,20 @@ public class AndroidUtils {
}
return flags;
}
/**
* Could be replaced to a similar call in ContextCompat once we
* use and upgrade to version 1.9.0 or higher of the AndroidX Core library.
*/
@Nullable
@SuppressLint("UnspecifiedRegisterReceiverFlag") // we specify where needed
public static Intent registerReceiver(Context ctx,
@Nullable BroadcastReceiver receiver, IntentFilter filter) {
if (SDK_INT >= 33) {
return ctx.registerReceiver(receiver, filter,
RECEIVER_NOT_EXPORTED);
} else {
return ctx.registerReceiver(receiver, filter);
}
}
}

View File

@@ -4,18 +4,16 @@ dependencyVerification {
'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:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.dagger:dagger-compiler:2.45:dagger-compiler-2.45.jar:5617dfb994537dba5b41f3744a6dd13ec3cd99789c065e0d5c6fa9f21cf7ca25',
'com.google.dagger:dagger-producers:2.45:dagger-producers-2.45.jar:a05abb4c3ccf6bb0f056bdcb5ef973898ecf172952ab5948a824aeea6c86ecaa',
'com.google.dagger:dagger-spi:2.45:dagger-spi-2.45.jar:7cd6f0b09d88e64a9c97bc80e544ab8ac8fdee9301754413585a74cf64222b27',
'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.errorprone:error_prone_annotations:2.7.1:error_prone_annotations-2.7.1.jar:cd5257c08a246cf8628817ae71cb822be192ef91f6881ca4a3fcff4f1de1cff3',
'com.google.dagger:dagger-compiler:2.51.1:dagger-compiler-2.51.1.jar:14cf2def1c4c8cd3b977840e297b463191d537cd1c8330992ca5c0b341a641ad',
'com.google.dagger:dagger-spi:2.51.1:dagger-spi-2.51.1.jar:deb52030b92b27c5dcd76b2c0747f1cf105b60939f6073b43eb06cfe7c9ba601',
'com.google.dagger:dagger:2.51.1:dagger-2.51.1.jar:c3891a4c4a4e48682888ca321eaf8497004b286e1d9a2936867373219f7dd86d',
'com.google.devtools.ksp:symbol-processing-api:1.9.20-1.0.14:symbol-processing-api-1.9.20-1.0.14.jar:d0339396f40dc9eb3b3f7bc86257f93869ee23448fa31ec4a1de900c6b7ae6d7',
'com.google.errorprone:error_prone_annotations:2.23.0:error_prone_annotations-2.23.0.jar:ec6f39f068b6ff9ac323c68e28b9299f8c0a80ca512dccb1d4a70f40ac3ec054',
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
'com.google.guava:failureaccess:1.0.1:failureaccess-1.0.1.jar:a171ee4c734dd2da837e4b16be9df4661afab72a41adaf31eb84dfdaf936ca26',
'com.google.guava:guava:31.0.1-jre:guava-31.0.1-jre.jar:d5be94d65e87bd219fb3193ad1517baa55a3b88fc91d21cf735826ab5af087b9',
'com.google.guava:failureaccess:1.0.2:failureaccess-1.0.2.jar:8a8f81cf9b359e3f6dfa691a1e776985c061ef2f223c9b2c80753e1b458e8064',
'com.google.guava:guava:33.0.0-jre:guava-33.0.0-jre.jar:f4d85c3e4d411694337cb873abea09b242b664bb013320be6105327c45991537',
'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.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',
@@ -25,16 +23,15 @@ dependencyVerification {
'net.jcip:jcip-annotations:1.0:jcip-annotations-1.0.jar:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0',
'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.briarproject:dont-kill-me-lib:0.2.7:dont-kill-me-lib-0.2.7.aar:8a9540941fd927e1c127096a7a9b4aa61ce2f2965d2e24f849be92f9e57213c4',
'org.briarproject:dont-kill-me-lib:0.2.8:dont-kill-me-lib-0.2.8.aar:e21173e480ee3f2364c142cc14db8dc6447be91bde9e62e4985c485ea0af9126',
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
'org.briarproject:lyrebird-android:0.5.0-3:lyrebird-android-0.5.0-3.jar:67e21cbbfda0b17ab9e0741ada170c606ddda4e9548a70c421aa83b907ebb714',
'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:onionwrapper-android:0.1.0:onionwrapper-android-0.1.0.aar:d761854dac454616b3e0ca099b2cd17060365ce4316afe495cc7ae86b6c81d15',
'org.briarproject:onionwrapper-core:0.1.0:onionwrapper-core-0.1.0.jar:3e6631771b891c959403f6145de034c6f9816e7d067808d534f954eef9a1ca35',
'org.briarproject:snowflake-android:2.9.1:snowflake-android-2.9.1.jar:8d6195637edbe3717d205c2e524e9d3cb742b90fc67b10565d16262af134e489',
'org.briarproject:tor-android:0.4.8.9-1:tor-android-0.4.8.9-1.jar:8fbaaf0cb1663abd12852b7fc51a804534b7e7d865b4dec3fc4e9ec0e79f3ad5',
'org.briarproject:onionwrapper-android:0.1.3:onionwrapper-android-0.1.3.aar:15231f0b2ad44df8eb1dd362a989ba3f88ebdc9b02a9128daa72a8da83651bf0',
'org.briarproject:onionwrapper-core:0.1.3:onionwrapper-core-0.1.3.jar:32d08c9d81a9591e08d7e64e3569334fee21f503b00514006f2e6cbbd409d0df',
'org.briarproject:tor-android:0.4.8.14:tor-android-0.4.8.14.jar:fc7c4f5007a98132ba84534a873f101951d2d554d5da5f2031b85c277f8617a6',
'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.41.0:checker-qual-3.41.0.jar:2f9f245bf68e4259d610894f2406dc1f6363dc639302bd566e8272e4f4541172',
'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:2.1:hamcrest-2.1.jar:ba93b2e3a562322ba432f0a1b53addcc55cb188253319a020ed77f824e692050',
@@ -43,14 +40,12 @@ dependencyVerification {
'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.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.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.8.0:kotlin-stdlib-jdk7-1.8.0.jar:4c889d1d9803f5f2eb6c1592a6b7e62369ac7660c9eee15aba16fec059163666',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.0:kotlin-stdlib-jdk8-1.7.0.jar:cf058e11db1dfc9944680c8c61b95ac689aaaa8a3eb30bced028100f038f030b',
'org.jetbrains.kotlin:kotlin-stdlib:1.7.0:kotlin-stdlib-1.7.0.jar:aa88e9625577957f3249a46cb6e166ee09b369e600f7a11d148d16b0a6d87f05',
'org.jetbrains.kotlin:kotlin-stdlib:1.8.0:kotlin-stdlib-1.8.0.jar:c77bef8774640b9fb9d6e217459ff220dae59878beb7d2e4b430506feffc654e',
'org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.5.0:kotlinx-metadata-jvm-0.5.0.jar:ca063a96639b08b9eaa0de4d65e899480740a6efbe28ab9a8681a2ced03055a4',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.9.10:kotlin-stdlib-common-1.9.10.jar:cde3341ba18a2ba262b0b7cf6c55b20c90e8d434e42c9a13e6a3f770db965a88',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0:kotlin-stdlib-jdk7-1.9.0.jar:b7979a7aac94055f0d9f1fd3b47ce5ffe1cb6032a842ba9fbe7186f085289178',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.10:kotlin-stdlib-jdk7-1.9.10.jar:ac6361bf9ad1ed382c2103d9712c47cdec166232b4903ed596e8876b0681c9b7',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0:kotlin-stdlib-jdk8-1.9.0.jar:a59fa24fdf1ffb594baecdbf0fd10010f977cea10236d487fe3464977a7377fa',
'org.jetbrains.kotlin:kotlin-stdlib:1.9.10:kotlin-stdlib-1.9.10.jar:55e989c512b80907799f854309f3bc7782c5b3d13932442d0379d5c472711504',
'org.jetbrains.kotlin:kotlin-stdlib:1.9.20:kotlin-stdlib-1.9.20.jar:28a35bcdff46d864f80f346a617e486284b208d17378c41900dfb1de95a90e6c',
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
'org.jmock:jmock-imposters:2.12.0:jmock-imposters-2.12.0.jar:3b836269745a137c9b2347e8d7c2104845b126ef04f012d6bfd94f1a7dea7b09',
'org.jmock:jmock-junit4:2.12.0:jmock-junit4-2.12.0.jar:3233062fc889637c151a24f1ee086bad04321ab7d8264fef279daff0fa27205b',

View File

@@ -4,7 +4,7 @@ dependencyVerification {
'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:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.dagger:dagger:2.45:dagger-2.45.jar:f011cae7d2c0fb7ea17c34e05bc10e768b1081a5892ad019cf1fdb0e125c49c1',
'com.google.dagger:dagger:2.51.1:dagger-2.51.1.jar:c3891a4c4a4e48682888ca321eaf8497004b286e1d9a2936867373219f7dd86d',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'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',

View File

@@ -89,11 +89,17 @@ class H2Database extends JdbcDatabase {
try {
c = createConnection();
closeAllConnections();
setDirty(c, false);
LOG.info("Compacting DB");
s = c.createStatement();
s.execute("SHUTDOWN COMPACT");
LOG.info("Finished compacting DB");
s.close();
c.close();
// Reopen the DB to mark it as clean after compacting
c = createConnection();
setDirty(c, false);
LOG.info("Marked DB as clean");
c.close();
} catch (SQLException e) {
tryToClose(s, LOG, WARNING);
tryToClose(c, LOG, WARNING);
@@ -126,6 +132,7 @@ class H2Database extends JdbcDatabase {
closeAllConnections();
s = c.createStatement();
s.execute("SHUTDOWN COMPACT");
LOG.info("Finished compacting DB");
s.close();
c.close();
} catch (SQLException e) {

View File

@@ -388,7 +388,6 @@ abstract class AbstractBluetoothPlugin<S, SS> implements BluetoothPlugin,
}
// Validate the UUID
try {
//noinspection ResultOfMethodCallIgnored
UUID.fromString(uuid);
} catch (IllegalArgumentException e) {
if (LOG.isLoggable(WARNING)) LOG.warning("Invalid UUID " + uuid);

View File

@@ -0,0 +1,45 @@
package org.briarproject.bramble.crypto;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.SecureRandomSpi;
import static java.util.Arrays.fill;
/**
* A fake SecureRandom implementation for testing, which returns all zeroes.
*/
public class NeitherSecureNorRandom extends SecureRandom {
private static final Provider PROVIDER =
new NeitherSecureNorRandomProvider();
public NeitherSecureNorRandom() {
super(new NeitherSecureNorRandomSpi(), PROVIDER);
}
private static class NeitherSecureNorRandomSpi extends SecureRandomSpi {
@Override
protected byte[] engineGenerateSeed(int length) {
return new byte[length];
}
@Override
protected void engineNextBytes(byte[] b) {
fill(b, (byte) 0);
}
@Override
protected void engineSetSeed(byte[] seed) {
// Thank you for your input
}
}
private static class NeitherSecureNorRandomProvider extends Provider {
private NeitherSecureNorRandomProvider() {
super("NeitherSecureNorRandom", 1.0, "Only for testing");
}
}
}

View File

@@ -1,34 +0,0 @@
package org.briarproject.bramble.crypto;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.Blake2bDigest;
import org.bouncycastle.crypto.engines.Salsa20Engine;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.briarproject.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe
@NotNullByDefault
class PseudoRandom {
private final Salsa20Engine cipher = new Salsa20Engine();
PseudoRandom(byte[] seed) {
// Hash the seed to produce a 32-byte key
byte[] key = new byte[32];
Digest digest = new Blake2bDigest(256);
digest.update(seed, 0, seed.length);
digest.doFinal(key, 0);
// Initialise the stream cipher with an all-zero nonce
byte[] nonce = new byte[8];
cipher.init(true, new ParametersWithIV(new KeyParameter(key), nonce));
}
byte[] nextBytes(int length) {
byte[] in = new byte[length], out = new byte[length];
cipher.processBytes(in, 0, length, out, 0);
return out;
}
}

View File

@@ -1,46 +0,0 @@
package org.briarproject.bramble.crypto;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.SecureRandomSpi;
class PseudoSecureRandom extends SecureRandom {
private static final Provider PROVIDER = new PseudoSecureRandomProvider();
PseudoSecureRandom(byte[] seed) {
super(new PseudoSecureRandomSpi(seed), PROVIDER);
}
private static class PseudoSecureRandomSpi extends SecureRandomSpi {
private final PseudoRandom pseudoRandom;
private PseudoSecureRandomSpi(byte[] seed) {
pseudoRandom = new PseudoRandom(seed);
}
@Override
protected byte[] engineGenerateSeed(int length) {
return pseudoRandom.nextBytes(length);
}
@Override
protected void engineNextBytes(byte[] b) {
byte[] random = pseudoRandom.nextBytes(b.length);
System.arraycopy(random, 0, b, 0, b.length);
}
@Override
protected void engineSetSeed(byte[] seed) {
// Thank you for your input
}
}
private static class PseudoSecureRandomProvider extends Provider {
private PseudoSecureRandomProvider() {
super("PseudoSecureRandom", 1.0, "Only for testing");
}
}
}

View File

@@ -15,9 +15,10 @@ import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.CaptureArgumentAction;
import org.briarproject.bramble.test.PredicateMatcher;
import org.jmock.Expectations;
import org.jmock.imposters.ByteBuddyClassImposteriser;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.atomic.AtomicReference;
@@ -51,17 +52,12 @@ public class KeyAgreementTransportTest extends BrambleMockTestCase {
private final KeyAgreementConnection keyAgreementConnection =
new KeyAgreementConnection(duplexTransportConnection, transportId);
private final InputStream inputStream;
private final OutputStream outputStream;
private final InputStream inputStream =
new ByteArrayInputStream(new byte[0]);
private final OutputStream outputStream = new ByteArrayOutputStream();
private KeyAgreementTransport kat;
public KeyAgreementTransportTest() {
context.setImposteriser(ByteBuddyClassImposteriser.INSTANCE);
inputStream = context.mock(InputStream.class);
outputStream = context.mock(OutputStream.class);
}
@Test
public void testSendKey() throws Exception {
byte[] key = getRandomBytes(123);

View File

@@ -21,11 +21,11 @@ import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.properties.TransportPropertyManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.TaskScheduler;
import org.briarproject.bramble.crypto.NeitherSecureNorRandom;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.ImmediateExecutor;
import org.briarproject.bramble.test.RunAction;
import org.jmock.Expectations;
import org.jmock.imposters.ByteBuddyClassImposteriser;
import org.junit.Test;
import java.security.SecureRandom;
@@ -55,7 +55,6 @@ public class PollerImplTest extends BrambleMockTestCase {
context.mock(TransportPropertyManager.class);
private final Clock clock = context.mock(Clock.class);
private final Cancellable cancellable = context.mock(Cancellable.class);
private final SecureRandom random;
private final Executor ioExecutor = new ImmediateExecutor();
private final TransportId transportId = getTransportId();
@@ -67,8 +66,8 @@ public class PollerImplTest extends BrambleMockTestCase {
private final PollerImpl poller;
public PollerImplTest() {
context.setImposteriser(ByteBuddyClassImposteriser.INSTANCE);
random = context.mock(SecureRandom.class);
// Use a fake SecureRandom that returns all zeroes
SecureRandom random = new NeitherSecureNorRandom();
Executor wakefulIoExecutor = new ImmediateExecutor();
poller = new PollerImpl(ioExecutor, wakefulIoExecutor, scheduler,
connectionManager, connectionRegistry, pluginManager,
@@ -352,12 +351,10 @@ public class PollerImplTest extends BrambleMockTestCase {
// Running the polling task schedules the next polling task
oneOf(plugin).getPollingInterval();
will(returnValue(pollingInterval));
oneOf(random).nextDouble();
will(returnValue(0.5));
oneOf(clock).currentTimeMillis();
will(returnValue(now));
oneOf(scheduler).schedule(with(any(Runnable.class)),
with(ioExecutor), with((long) (pollingInterval * 0.5)),
with(ioExecutor), with(0L),
with(MILLISECONDS));
will(returnValue(cancellable));
// Get the transport properties and connected contacts
@@ -396,12 +393,10 @@ public class PollerImplTest extends BrambleMockTestCase {
// Running the polling task schedules the next polling task
oneOf(plugin).getPollingInterval();
will(returnValue(pollingInterval));
oneOf(random).nextDouble();
will(returnValue(0.5));
oneOf(clock).currentTimeMillis();
will(returnValue(now));
oneOf(scheduler).schedule(with(any(Runnable.class)),
with(ioExecutor), with((long) (pollingInterval * 0.5)),
with(ioExecutor), with(0L),
with(MILLISECONDS));
will(returnValue(cancellable));
// Get the transport properties and connected contacts

View File

@@ -6,22 +6,20 @@ dependencyVerification {
'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:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.dagger:dagger-compiler:2.45:dagger-compiler-2.45.jar:5617dfb994537dba5b41f3744a6dd13ec3cd99789c065e0d5c6fa9f21cf7ca25',
'com.google.dagger:dagger-producers:2.45:dagger-producers-2.45.jar:a05abb4c3ccf6bb0f056bdcb5ef973898ecf172952ab5948a824aeea6c86ecaa',
'com.google.dagger:dagger-spi:2.45:dagger-spi-2.45.jar:7cd6f0b09d88e64a9c97bc80e544ab8ac8fdee9301754413585a74cf64222b27',
'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.errorprone:error_prone_annotations:2.7.1:error_prone_annotations-2.7.1.jar:cd5257c08a246cf8628817ae71cb822be192ef91f6881ca4a3fcff4f1de1cff3',
'com.google.dagger:dagger-compiler:2.51.1:dagger-compiler-2.51.1.jar:14cf2def1c4c8cd3b977840e297b463191d537cd1c8330992ca5c0b341a641ad',
'com.google.dagger:dagger-spi:2.51.1:dagger-spi-2.51.1.jar:deb52030b92b27c5dcd76b2c0747f1cf105b60939f6073b43eb06cfe7c9ba601',
'com.google.dagger:dagger:2.51.1:dagger-2.51.1.jar:c3891a4c4a4e48682888ca321eaf8497004b286e1d9a2936867373219f7dd86d',
'com.google.devtools.ksp:symbol-processing-api:1.9.20-1.0.14:symbol-processing-api-1.9.20-1.0.14.jar:d0339396f40dc9eb3b3f7bc86257f93869ee23448fa31ec4a1de900c6b7ae6d7',
'com.google.errorprone:error_prone_annotations:2.23.0:error_prone_annotations-2.23.0.jar:ec6f39f068b6ff9ac323c68e28b9299f8c0a80ca512dccb1d4a70f40ac3ec054',
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
'com.google.guava:failureaccess:1.0.1:failureaccess-1.0.1.jar:a171ee4c734dd2da837e4b16be9df4661afab72a41adaf31eb84dfdaf936ca26',
'com.google.guava:guava:31.0.1-jre:guava-31.0.1-jre.jar:d5be94d65e87bd219fb3193ad1517baa55a3b88fc91d21cf735826ab5af087b9',
'com.google.guava:failureaccess:1.0.2:failureaccess-1.0.2.jar:8a8f81cf9b359e3f6dfa691a1e776985c061ef2f223c9b2c80753e1b458e8064',
'com.google.guava:guava:33.0.0-jre:guava-33.0.0-jre.jar:f4d85c3e4d411694337cb873abea09b242b664bb013320be6105327c45991537',
'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.h2database:h2:1.4.192:h2-1.4.192.jar:225b22e9857235c46c93861410b60b8c81c10dc8985f4faf188985ba5445126c',
'com.squareup.okhttp3:mockwebserver:4.10.0:mockwebserver-4.10.0.jar:af29da234e63159d6e0dea43bf8288eea97d71cdf1651a5ee2d6c0d0d4adbf8f',
'com.squareup.okhttp3:okhttp:4.10.0:okhttp-4.10.0.jar:7580f14fa1691206e37081ad3f92063b1603b328da0bb316f2fef02e0562e7ec',
'com.squareup.okio:okio-jvm:3.0.0:okio-jvm-3.0.0.jar:be64a0cc1f28ea9cd5c970dd7e7557af72c808d738c495b397bf897c9921e907',
'com.squareup.okhttp3:okhttp:4.12.0:okhttp-4.12.0.jar:b1050081b14bb7a3a7e55a4d3ef01b5dcfabc453b4573a4fc019767191d5f4e0',
'com.squareup.okio:okio-jvm:3.6.0:okio-jvm-3.6.0.jar:67543f0736fc422ae927ed0e504b98bc5e269fda0d3500579337cb713da28412',
'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',
@@ -36,10 +34,10 @@ dependencyVerification {
'org.bouncycastle:bcprov-jdk15to18:1.71:bcprov-jdk15to18-1.71.jar:143aaa4a40edd5fc2a18db7900059f6c16f4d931b94b94b20f7e2238e6662886',
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
'org.briarproject:onionwrapper-core:0.1.0:onionwrapper-core-0.1.0.jar:3e6631771b891c959403f6145de034c6f9816e7d067808d534f954eef9a1ca35',
'org.briarproject:onionwrapper-core:0.1.3:onionwrapper-core-0.1.3.jar:32d08c9d81a9591e08d7e64e3569334fee21f503b00514006f2e6cbbd409d0df',
'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-qual:3.12.0:checker-qual-3.12.0.jar:ff10785ac2a357ec5de9c293cb982a2cbb605c0309ea4cc1cb9b9bc6dbe7f3cb',
'org.checkerframework:checker-qual:3.41.0:checker-qual-3.41.0.jar:2f9f245bf68e4259d610894f2406dc1f6363dc639302bd566e8272e4f4541172',
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
'org.codehaus.mojo:animal-sniffer-ant-tasks:1.22:animal-sniffer-ant-tasks-1.22.jar:3f6afeb3e09301d2d7179ed1db21e3ad8846c1e38415ad832a395138ae3f4218',
'org.codehaus.mojo:animal-sniffer:1.22:animal-sniffer-1.22.jar:f18c11a25bdd8b520b9c6a28cbb6f33007c812ab0051b6be3f0778e660aa501c',
@@ -48,17 +46,13 @@ dependencyVerification {
'org.hamcrest:hamcrest:2.1:hamcrest-2.1.jar:ba93b2e3a562322ba432f0a1b53addcc55cb188253319a020ed77f824e692050',
'org.hsqldb:hsqldb:2.3.5:hsqldb-2.3.5.jar:6676a6977ac98997a80f827ddbd3fe8ca1e0853dad1492512135fd1a222ccfad',
'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-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-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: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.kotlinx:kotlinx-metadata-jvm:0.5.0:kotlinx-metadata-jvm-0.5.0.jar:ca063a96639b08b9eaa0de4d65e899480740a6efbe28ab9a8681a2ced03055a4',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.9.10:kotlin-stdlib-common-1.9.10.jar:cde3341ba18a2ba262b0b7cf6c55b20c90e8d434e42c9a13e6a3f770db965a88',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0:kotlin-stdlib-jdk7-1.9.0.jar:b7979a7aac94055f0d9f1fd3b47ce5ffe1cb6032a842ba9fbe7186f085289178',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.10:kotlin-stdlib-jdk7-1.9.10.jar:ac6361bf9ad1ed382c2103d9712c47cdec166232b4903ed596e8876b0681c9b7',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0:kotlin-stdlib-jdk8-1.9.0.jar:a59fa24fdf1ffb594baecdbf0fd10010f977cea10236d487fe3464977a7377fa',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.10:kotlin-stdlib-jdk8-1.9.10.jar:a4c74d94d64ce1abe53760fe0389dd941f6fc558d0dab35e47c085a11ec80f28',
'org.jetbrains.kotlin:kotlin-stdlib:1.9.10:kotlin-stdlib-1.9.10.jar:55e989c512b80907799f854309f3bc7782c5b3d13932442d0379d5c472711504',
'org.jetbrains.kotlin:kotlin-stdlib:1.9.20:kotlin-stdlib-1.9.20.jar:28a35bcdff46d864f80f346a617e486284b208d17378c41900dfb1de95a90e6c',
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
'org.jmock:jmock-imposters:2.12.0:jmock-imposters-2.12.0.jar:3b836269745a137c9b2347e8d7c2104845b126ef04f012d6bfd94f1a7dea7b09',
'org.jmock:jmock-junit4:2.12.0:jmock-junit4-2.12.0.jar:3233062fc889637c151a24f1ee086bad04321ab7d8264fef279daff0fa27205b',

View File

@@ -3,18 +3,16 @@ dependencyVerification {
'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:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.dagger:dagger-compiler:2.45:dagger-compiler-2.45.jar:5617dfb994537dba5b41f3744a6dd13ec3cd99789c065e0d5c6fa9f21cf7ca25',
'com.google.dagger:dagger-producers:2.45:dagger-producers-2.45.jar:a05abb4c3ccf6bb0f056bdcb5ef973898ecf172952ab5948a824aeea6c86ecaa',
'com.google.dagger:dagger-spi:2.45:dagger-spi-2.45.jar:7cd6f0b09d88e64a9c97bc80e544ab8ac8fdee9301754413585a74cf64222b27',
'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.errorprone:error_prone_annotations:2.7.1:error_prone_annotations-2.7.1.jar:cd5257c08a246cf8628817ae71cb822be192ef91f6881ca4a3fcff4f1de1cff3',
'com.google.dagger:dagger-compiler:2.51.1:dagger-compiler-2.51.1.jar:14cf2def1c4c8cd3b977840e297b463191d537cd1c8330992ca5c0b341a641ad',
'com.google.dagger:dagger-spi:2.51.1:dagger-spi-2.51.1.jar:deb52030b92b27c5dcd76b2c0747f1cf105b60939f6073b43eb06cfe7c9ba601',
'com.google.dagger:dagger:2.51.1:dagger-2.51.1.jar:c3891a4c4a4e48682888ca321eaf8497004b286e1d9a2936867373219f7dd86d',
'com.google.devtools.ksp:symbol-processing-api:1.9.20-1.0.14:symbol-processing-api-1.9.20-1.0.14.jar:d0339396f40dc9eb3b3f7bc86257f93869ee23448fa31ec4a1de900c6b7ae6d7',
'com.google.errorprone:error_prone_annotations:2.23.0:error_prone_annotations-2.23.0.jar:ec6f39f068b6ff9ac323c68e28b9299f8c0a80ca512dccb1d4a70f40ac3ec054',
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e',
'com.google.guava:failureaccess:1.0.1:failureaccess-1.0.1.jar:a171ee4c734dd2da837e4b16be9df4661afab72a41adaf31eb84dfdaf936ca26',
'com.google.guava:guava:31.0.1-jre:guava-31.0.1-jre.jar:d5be94d65e87bd219fb3193ad1517baa55a3b88fc91d21cf735826ab5af087b9',
'com.google.guava:failureaccess:1.0.2:failureaccess-1.0.2.jar:8a8f81cf9b359e3f6dfa691a1e776985c061ef2f223c9b2c80753e1b458e8064',
'com.google.guava:guava:33.0.0-jre:guava-33.0.0-jre.jar:f4d85c3e4d411694337cb873abea09b242b664bb013320be6105327c45991537',
'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.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',
@@ -27,19 +25,17 @@ dependencyVerification {
'org.apache-extras.beanshell:bsh:2.0b6:bsh-2.0b6.jar:a17955976070c0573235ee662f2794a78082758b61accffce8d3f8aedcd91047',
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
'org.briarproject:onionwrapper-core:0.1.0:onionwrapper-core-0.1.0.jar:3e6631771b891c959403f6145de034c6f9816e7d067808d534f954eef9a1ca35',
'org.briarproject:onionwrapper-java:0.1.0:onionwrapper-java-0.1.0.jar:c1a961c73f06d28e2a63c301d4e747398745bfc9709ade4ae3ba8818c6849fe0',
'org.briarproject:onionwrapper-core:0.1.3:onionwrapper-core-0.1.3.jar:32d08c9d81a9591e08d7e64e3569334fee21f503b00514006f2e6cbbd409d0df',
'org.briarproject:onionwrapper-java:0.1.3:onionwrapper-java-0.1.3.jar:a6bc535e8ea55e567c932f23123eabd10ad53251d3a1e5648960b177e7ab209b',
'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.41.0:checker-qual-3.41.0.jar:2f9f245bf68e4259d610894f2406dc1f6363dc639302bd566e8272e4f4541172',
'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: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-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: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.kotlin:kotlin-stdlib-jdk7:1.9.0:kotlin-stdlib-jdk7-1.9.0.jar:b7979a7aac94055f0d9f1fd3b47ce5ffe1cb6032a842ba9fbe7186f085289178',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0:kotlin-stdlib-jdk8-1.9.0.jar:a59fa24fdf1ffb594baecdbf0fd10010f977cea10236d487fe3464977a7377fa',
'org.jetbrains.kotlin:kotlin-stdlib:1.9.20:kotlin-stdlib-1.9.20.jar:28a35bcdff46d864f80f346a617e486284b208d17378c41900dfb1de95a90e6c',
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
'org.jmock:jmock-imposters:2.12.0:jmock-imposters-2.12.0.jar:3b836269745a137c9b2347e8d7c2104845b126ef04f012d6bfd94f1a7dea7b09',
'org.jmock:jmock-junit4:2.12.0:jmock-junit4-2.12.0.jar:3233062fc889637c151a24f1ee086bad04321ab7d8264fef279daff0fa27205b',

View File

@@ -1,6 +1,6 @@
[main]
host = https://www.transifex.com
lang_map = pt_BR: pt-rBR, nb_NO: nb, zh-Hans: zh-rCN, zh-Hant: zh-rTW
lang_map = es_CU: es-rCU, pt_BR: pt-rBR, pt_PT: pt-rPT, nb_NO: nb, zh-Hans: zh-rCN, zh-Hant: zh-rTW
[o:otf:p:briar:r:google-play-full-description]
file_filter = fastlane/metadata/android/<lang>/full_description.txt

View File

@@ -16,8 +16,8 @@ def getStdout = { command, defaultValue ->
}
android {
compileSdkVersion 33
buildToolsVersion '33.0.0'
compileSdk 34
buildToolsVersion '34.0.0'
packagingOptions {
doNotStrip '**/*.so'
@@ -25,9 +25,9 @@ android {
defaultConfig {
minSdkVersion 21
targetSdkVersion 33
versionCode 10510
versionName "1.5.10"
targetSdkVersion 34
versionCode 10514
versionName "1.5.14"
applicationId "org.briarproject.briar.android"
buildConfigField "String", "TorVersion", "\"$tor_version\""
@@ -108,16 +108,15 @@ dependencies {
implementation project(':bramble-android')
implementation project(':briar-core')
implementation 'androidx.fragment:fragment:1.5.5'
implementation 'androidx.preference:preference:1.2.0'
implementation 'androidx.exifinterface:exifinterface:1.3.6'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
implementation 'androidx.lifecycle:lifecycle-livedata:2.5.1'
// newer versions of the libraries below require compileSdk 34
implementation 'androidx.fragment:fragment:1.6.2'
implementation 'androidx.preference:preference:1.2.1'
implementation 'androidx.exifinterface:exifinterface:1.3.7'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
implementation 'androidx.lifecycle:lifecycle-livedata:2.6.2'
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 'com.google.android.material:material:1.9.0'
implementation 'androidx.recyclerview:recyclerview-selection:1.1.0'
// force kotlin standard lib to latest version to prevent jetifier issues
@@ -131,7 +130,7 @@ dependencies {
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.chrisbanes:PhotoView:2.3.0'
def glideVersion = '4.14.2'
def glideVersion = '4.16.0'
implementation("com.github.bumptech.glide:glide:$glideVersion") {
exclude group: 'com.android.support'
exclude module: 'disklrucache' // when there's no disk cache, we can't accidentally use it

View File

@@ -39,6 +39,8 @@
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission-sdk-23 android:name="android.permission.USE_BIOMETRIC" />
<uses-permission-sdk-23 android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission-sdk-23 android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
<uses-permission-sdk-23 android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission
android:name="android.permission.HIDE_OVERLAY_WINDOWS"
@@ -68,7 +70,8 @@
<service
android:name="org.briarproject.briar.android.BriarService"
android:exported="false">
android:exported="false"
android:foregroundServiceType="connectedDevice|dataSync">
<intent-filter>
<action android:name="org.briarproject.briar.android.BriarService" />
</intent-filter>
@@ -109,12 +112,12 @@
<activity
android:name="org.briarproject.briar.android.login.StartupActivity"
android:exported="false"
android:label="@string/app_name" />
android:theme="@style/BriarTheme.NoActionBar" />
<activity
android:name="org.briarproject.briar.android.account.SetupActivity"
android:exported="false"
android:label="@string/setup_title" />
android:theme="@style/BriarTheme.NoActionBar" />
<activity
android:name="org.briarproject.briar.android.splash.SplashScreenActivity"

View File

@@ -27,7 +27,7 @@ class BriarAccountManager extends AndroidAccountManager {
super.deleteAccount();
Localizer.reinitialize();
UiUtils.setTheme(appContext,
appContext.getString(R.string.pref_theme_light_value));
appContext.getString(R.string.pref_theme_system_value));
}
}
}

View File

@@ -33,6 +33,7 @@ import static java.util.logging.Level.FINE;
import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
import static org.briarproject.briar.android.settings.DisplayFragment.PREF_THEME;
public class BriarApplicationImpl extends Application
implements BriarApplication {
@@ -109,11 +110,11 @@ public class BriarApplicationImpl extends Application
}
private void setTheme(Context ctx, SharedPreferences prefs) {
String theme = prefs.getString("pref_key_theme", null);
String theme = prefs.getString(PREF_THEME, null);
if (theme == null) {
// set default value
theme = getString(R.string.pref_theme_light_value);
prefs.edit().putString("pref_key_theme", theme).apply();
theme = getString(R.string.pref_theme_system_value);
prefs.edit().putString(PREF_THEME, theme).apply();
}
// set theme
UiUtils.setTheme(ctx, theme);

View File

@@ -22,6 +22,7 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.AndroidUtils;
import org.briarproject.briar.R;
import org.briarproject.briar.android.logout.HideUiActivity;
import org.briarproject.briar.api.android.AndroidNotificationManager;
@@ -174,7 +175,8 @@ public class BriarService extends Service {
filter.addAction(ACTION_SHUTDOWN);
filter.addAction("android.intent.action.QUICKBOOT_POWEROFF");
filter.addAction("com.htc.intent.action.QUICKBOOT_POWEROFF");
registerReceiver(receiver, filter);
AndroidUtils.registerReceiver(getApplicationContext(), receiver,
filter);
}, "LifecycleStartup");
}
@@ -215,17 +217,14 @@ public class BriarService extends Service {
@Override
public void onDestroy() {
// Hold a wake lock during shutdown
wakeLockManager.runWakefully(() -> {
super.onDestroy();
LOG.info("Destroyed");
stopForeground(true);
if (receiver != null) unregisterReceiver(receiver);
// Stop the services in a background thread
wakeLockManager.executeWakefully(() -> {
if (started) lifecycleManager.stopServices();
}, "LifecycleShutdown");
}, "LifecycleShutdown");
super.onDestroy();
LOG.info("Destroyed");
// Stop the lifecycle, if not already stopped
shutdown(false);
stopForeground(true);
if (receiver != null) {
getApplicationContext().unregisterReceiver(receiver);
}
}
@Override
@@ -295,8 +294,8 @@ public class BriarService extends Service {
private void shutdownFromBackground() {
// Hold a wake lock during shutdown
wakeLockManager.runWakefully(() -> {
// Stop the service
stopSelf();
// Begin lifecycle shutdown
shutdown(true);
// Hide the UI
hideUi();
// Wait for shutdown to complete, then exit
@@ -331,8 +330,18 @@ public class BriarService extends Service {
/**
* Starts the shutdown process.
*/
public void shutdown() {
stopSelf(); // This will call onDestroy()
public void shutdown(boolean stopAndroidService) {
// Hold a wake lock during shutdown
wakeLockManager.runWakefully(() -> {
// Stop the lifecycle services in a background thread,
// then stop this Android service if needed
wakeLockManager.executeWakefully(() -> {
if (started) lifecycleManager.stopServices();
if (stopAndroidService) {
androidExecutor.runOnUiThread(() -> stopSelf());
}
}, "LifecycleShutdown");
}, "LifecycleShutdown");
}
public class BriarBinder extends Binder {

View File

@@ -21,6 +21,7 @@ import static android.os.PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED;
import static android.os.PowerManager.ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.AndroidUtils.registerReceiver;
class DozeWatchdogImpl implements DozeWatchdog, Service {
@@ -48,7 +49,7 @@ class DozeWatchdogImpl implements DozeWatchdog, Service {
filter.addAction(ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED);
filter.addAction(ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED);
}
appContext.registerReceiver(receiver, filter);
registerReceiver(appContext, receiver, filter);
}
@Override

View File

@@ -49,6 +49,7 @@ import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.GET_SIGNATURES;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.AndroidUtils.registerReceiver;
import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault
@@ -207,7 +208,7 @@ class ScreenFilterMonitorImpl implements ScreenFilterMonitor, Service {
filter.addAction(ACTION_PACKAGE_REPLACED);
filter.addDataScheme("package");
receiver = new PackageBroadcastReceiver();
app.registerReceiver(receiver, filter);
registerReceiver(app, receiver, filter);
cachedApps = null;
});
}

View File

@@ -18,7 +18,9 @@ import javax.annotation.Nullable;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.util.StringUtils.toUtf8;
import static org.briarproject.briar.android.util.UiUtils.hideViewOnSmallScreen;
import static org.briarproject.briar.android.util.UiUtils.setError;
import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
@@ -38,19 +40,27 @@ public class AuthorNameFragment extends SetupFragment {
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
requireActivity().setTitle(getString(R.string.setup_title));
View v = inflater.inflate(R.layout.fragment_setup_author_name,
container, false);
authorNameWrapper = v.findViewById(R.id.nickname_entry_wrapper);
authorNameInput = v.findViewById(R.id.nickname_entry);
Button infoButton = v.findViewById(R.id.info_button);
nextButton = v.findViewById(R.id.next);
authorNameInput.addTextChangedListener(this);
infoButton.setOnClickListener(view ->
showOnboardingDialog(requireContext(), getHelpText()));
nextButton.setOnClickListener(this);
return v;
}
@Override
public void onStart() {
super.onStart();
hideViewOnSmallScreen(requireView().findViewById(R.id.logo));
}
@Override
public String getUniqueTag() {
return TAG;

View File

@@ -23,6 +23,7 @@ import static android.view.View.VISIBLE;
import static android.widget.Toast.LENGTH_LONG;
import static org.briarproject.android.dontkillmelib.DozeUtils.getDozeWhitelistingIntent;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING;
import static org.briarproject.briar.android.util.UiUtils.hideViewOnSmallScreen;
import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog;
@MethodsNotNullByDefault
@@ -79,6 +80,12 @@ public class DozeFragment extends SetupFragment
return v;
}
@Override
public void onStart() {
super.onStart();
hideViewOnSmallScreen(requireView().findViewById(R.id.logo));
}
@Override
public String getUniqueTag() {
return TAG;

View File

@@ -28,10 +28,12 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Build.VERSION.SDK_INT;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
import static androidx.core.content.ContextCompat.checkSelfPermission;
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK;
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.STRONG;
import static org.briarproject.briar.android.util.UiUtils.hideViewOnSmallScreen;
import static org.briarproject.briar.android.util.UiUtils.setError;
import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
@@ -57,7 +59,6 @@ public class SetPasswordFragment extends SetupFragment {
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
requireActivity().setTitle(getString(R.string.setup_password_intro));
View v = inflater.inflate(R.layout.fragment_setup_password, container,
false);
@@ -67,17 +68,18 @@ public class SetPasswordFragment extends SetupFragment {
passwordConfirmationWrapper =
v.findViewById(R.id.password_confirm_wrapper);
passwordConfirmation = v.findViewById(R.id.password_confirm);
Button infoButton = v.findViewById(R.id.info_button);
nextButton = v.findViewById(R.id.next);
ProgressBar progressBar = v.findViewById(R.id.progress);
passwordEntry.addTextChangedListener(this);
passwordConfirmation.addTextChangedListener(this);
infoButton.setOnClickListener(view ->
showOnboardingDialog(requireContext(), getHelpText()));
nextButton.setOnClickListener(this);
if (!viewModel.needToShowDozeFragment()) {
nextButton.setText(R.string.create_account_button);
int options = passwordConfirmation.getImeOptions();
passwordConfirmation.setImeOptions(options | IME_ACTION_DONE);
}
viewModel.getIsCreatingAccount()
@@ -94,6 +96,12 @@ public class SetPasswordFragment extends SetupFragment {
return v;
}
@Override
public void onStart() {
super.onStart();
hideViewOnSmallScreen(requireView().findViewById(R.id.logo));
}
@Override
public String getUniqueTag() {
return TAG;
@@ -110,17 +118,27 @@ public class SetPasswordFragment extends SetupFragment {
String password2 = passwordConfirmation.getText().toString();
boolean passwordsMatch = password1.equals(password2);
strengthMeter
.setVisibility(password1.length() > 0 ? VISIBLE : INVISIBLE);
strengthMeter.setVisibility(!password1.isEmpty() ? VISIBLE : INVISIBLE);
float strength = viewModel.estimatePasswordStrength(password1);
strengthMeter.setStrength(strength);
boolean strongEnough = strength >= QUITE_WEAK;
if (!password1.isEmpty()) {
if (strength >= STRONG) {
passwordEntryWrapper.setHelperText(
getString(R.string.password_strong));
} else if (strength >= QUITE_WEAK) {
passwordEntryWrapper.setHelperText(
getString(R.string.password_quite_strong));
} else {
passwordEntryWrapper.setHelperTextEnabled(false);
}
}
setError(passwordEntryWrapper, getString(R.string.password_too_weak),
password1.length() > 0 && !strongEnough);
!password1.isEmpty() && !strongEnough);
setError(passwordConfirmationWrapper,
getString(R.string.passwords_do_not_match),
password2.length() > 0 && !passwordsMatch);
!password2.isEmpty() && !passwordsMatch);
boolean enabled = passwordsMatch && strongEnough;
nextButton.setEnabled(enabled);

View File

@@ -1,5 +1,6 @@
package org.briarproject.briar.android.account;
import android.annotation.SuppressLint;
import android.app.KeyguardManager;
import android.content.ActivityNotFoundException;
import android.content.Intent;
@@ -113,6 +114,7 @@ public class UnlockActivity extends BaseActivity {
}
@Override
@SuppressLint("MissingSuperCall")
public void onBackPressed() {
moveTaskToBack(true);
}

View File

@@ -7,6 +7,8 @@ import android.view.Window;
import android.widget.CheckBox;
import android.widget.Toast;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.briarproject.android.dontkillmelib.wakelock.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.Wakeful;
import org.briarproject.briar.R;
@@ -177,8 +179,8 @@ public abstract class BriarActivity extends BaseActivity {
}
protected void showDozeDialog(@StringRes int message) {
AlertDialog.Builder b =
new AlertDialog.Builder(this, R.style.BriarDialogTheme);
MaterialAlertDialogBuilder b =
new MaterialAlertDialogBuilder(this, R.style.BriarDialogTheme);
b.setMessage(message);
b.setView(R.layout.checkbox);
b.setPositiveButton(R.string.fix,

View File

@@ -10,6 +10,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
@@ -27,7 +29,6 @@ import javax.inject.Inject;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView.LayoutManager;
@@ -220,8 +221,8 @@ public class BlogFragment extends BaseFragment
}
private void showDeleteDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext(),
R.style.BriarDialogTheme);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(
requireContext(), R.style.BriarDialogTheme);
builder.setTitle(getString(R.string.blogs_remove_blog));
builder.setMessage(
getString(R.string.blogs_remove_blog_dialog_message));

View File

@@ -4,6 +4,8 @@ import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.BaseActivity;
@@ -13,7 +15,6 @@ import org.briarproject.nullsafety.ParametersNotNullByDefault;
import javax.inject.Inject;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import androidx.lifecycle.ViewModelProvider;
@@ -51,8 +52,8 @@ public class RssFeedDeleteFeedDialogFragment extends DialogFragment {
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
GroupId groupId = new GroupId(
requireNonNull(requireArguments().getByteArray(GROUP_ID)));
AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity(),
R.style.BriarDialogTheme);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(
requireActivity(), R.style.BriarDialogTheme);
builder.setTitle(getString(R.string.blogs_rss_remove_feed));
builder.setMessage(
getString(R.string.blogs_rss_remove_feed_dialog_message));

View File

@@ -4,6 +4,8 @@ import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.BaseActivity;
import org.briarproject.nullsafety.MethodsNotNullByDefault;
@@ -12,7 +14,6 @@ import org.briarproject.nullsafety.ParametersNotNullByDefault;
import javax.inject.Inject;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import androidx.lifecycle.ViewModelProvider;
@@ -47,8 +48,8 @@ public class RssFeedImportFailedDialogFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
AlertDialog.Builder builder =
new AlertDialog.Builder(requireActivity(),
MaterialAlertDialogBuilder builder =
new MaterialAlertDialogBuilder(requireActivity(),
R.style.BriarDialogTheme);
builder.setMessage(R.string.blogs_rss_feeds_import_error);
builder.setNegativeButton(R.string.cancel, null);

View File

@@ -88,6 +88,7 @@ import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED;
import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE;
import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING;
import static org.briarproject.bramble.util.AndroidUtils.registerReceiver;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.StringUtils.ISO_8859_1;
import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactPermissionManager.areEssentialPermissionsGranted;
@@ -208,7 +209,7 @@ class AddNearbyContactViewModel extends AndroidViewModel
qrCodeDecoder = new QrCodeDecoder(androidExecutor, ioExecutor, this);
eventBus.addListener(this);
IntentFilter filter = new IntentFilter(ACTION_SCAN_MODE_CHANGED);
getApplication().registerReceiver(bluetoothReceiver, filter);
registerReceiver(getApplication(), bluetoothReceiver, filter);
}
@Override

View File

@@ -55,6 +55,7 @@ public class NicknameFragment extends BaseFragment {
private TextInputLayout contactNameLayout;
private TextInputEditText contactNameInput;
private BriarButton addButton;
@Override
public String getUniqueTag() {
@@ -91,7 +92,7 @@ public class NicknameFragment extends BaseFragment {
contactNameLayout = v.findViewById(R.id.contactNameLayout);
contactNameInput = v.findViewById(R.id.contactNameInput);
BriarButton addButton = v.findViewById(R.id.addButton);
addButton = v.findViewById(R.id.addButton);
addButton.setOnClickListener(view -> onAddButtonClicked());
return v;
@@ -112,7 +113,7 @@ public class NicknameFragment extends BaseFragment {
@Nullable
private String getNicknameOrNull() {
Editable text = contactNameInput.getText();
if (text == null || text.toString().trim().length() == 0) {
if (text == null || text.toString().trim().isEmpty()) {
contactNameLayout.setError(getString(R.string.nickname_missing));
contactNameInput.requestFocus();
return null;
@@ -129,7 +130,10 @@ public class NicknameFragment extends BaseFragment {
private void onAddButtonClicked() {
String name = getNicknameOrNull();
if (name == null) return; // invalid nickname
if (name == null) { // invalid nickname
addButton.reset();
return;
}
LifecycleOwner owner = getViewLifecycleOwner();
viewModel.getAddContactResult().observe(owner, result -> {

View File

@@ -4,6 +4,7 @@ import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.view.MenuItem;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.snackbar.Snackbar;
import org.briarproject.bramble.api.contact.PendingContactId;
@@ -21,7 +22,6 @@ import javax.annotation.Nullable;
import javax.inject.Inject;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
@@ -110,7 +110,7 @@ public class PendingContactListActivity extends BriarActivity
// show warning dialog
OnClickListener removeListener = (dialog, which) ->
removePendingContact(item.getPendingContact().getId());
AlertDialog.Builder builder = new AlertDialog.Builder(
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(
PendingContactListActivity.this, R.style.BriarDialogTheme);
builder.setTitle(
getString(R.string.dialog_title_remove_pending_contact));

View File

@@ -147,7 +147,7 @@ public class BriarControllerImpl implements BriarController {
service.waitForStartup();
// Shut down the service and wait for it to shut down
LOG.info("Shutting down service");
service.shutdown();
service.shutdown(true);
service.waitForShutdown();
} catch (InterruptedException e) {
LOG.warning("Interrupted while waiting for service");

View File

@@ -19,6 +19,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.snackbar.Snackbar;
import org.briarproject.bramble.api.FeatureFlags;
@@ -101,7 +102,6 @@ import javax.inject.Inject;
import androidx.activity.result.ActivityResultLauncher;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.ActionMenuView;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
@@ -812,8 +812,8 @@ public class ConversationActivity extends BriarActivity
}
private void askToDeleteAllMessages() {
AlertDialog.Builder builder =
new AlertDialog.Builder(this, R.style.BriarDialogTheme);
MaterialAlertDialogBuilder builder =
new MaterialAlertDialogBuilder(this, R.style.BriarDialogTheme);
builder.setTitle(getString(R.string.dialog_title_delete_all_messages));
builder.setMessage(
getString(R.string.dialog_message_delete_all_messages));
@@ -892,8 +892,8 @@ public class ConversationActivity extends BriarActivity
}
String msg = join(fails, "\n\n");
// show dialog
AlertDialog.Builder builder =
new AlertDialog.Builder(this, R.style.BriarDialogTheme);
MaterialAlertDialogBuilder builder =
new MaterialAlertDialogBuilder(this, R.style.BriarDialogTheme);
builder.setTitle(
getString(R.string.dialog_title_not_all_messages_deleted));
builder.setMessage(msg);
@@ -904,8 +904,8 @@ public class ConversationActivity extends BriarActivity
private void askToRemoveContact() {
DialogInterface.OnClickListener okListener =
(dialog, which) -> removeContact();
AlertDialog.Builder builder =
new AlertDialog.Builder(ConversationActivity.this,
MaterialAlertDialogBuilder builder =
new MaterialAlertDialogBuilder(ConversationActivity.this,
R.style.BriarDialogTheme);
builder.setTitle(getString(R.string.dialog_title_delete_contact));
builder.setMessage(

View File

@@ -7,6 +7,8 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.sharing.ForumSharingStatusActivity;
@@ -20,7 +22,6 @@ import org.briarproject.nullsafety.ParametersNotNullByDefault;
import javax.annotation.Nullable;
import javax.inject.Inject;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.lifecycle.ViewModelProvider;
@@ -53,7 +54,7 @@ public class ForumActivity extends
@Override
protected ThreadItemAdapter<ForumPostItem> createAdapter() {
return new ThreadItemAdapter<>(this);
return new ThreadItemAdapter<>(this, this);
}
@Override
@@ -128,7 +129,7 @@ public class ForumActivity extends
private void showUnsubscribeDialog() {
OnClickListener okListener = (dialog, which) -> viewModel.deleteForum();
AlertDialog.Builder builder = new AlertDialog.Builder(this,
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this,
R.style.BriarDialogTheme);
builder.setTitle(getString(R.string.dialog_title_leave_forum));
builder.setMessage(getString(R.string.dialog_message_leave_forum));

View File

@@ -13,15 +13,18 @@ import androidx.recyclerview.widget.ListAdapter;
@NotNullByDefault
class ForumListAdapter extends ListAdapter<ForumListItem, ForumViewHolder> {
ForumListAdapter() {
private final ForumListViewModel viewModel;
ForumListAdapter(ForumListViewModel viewModel) {
super(new ForumListCallback());
this.viewModel = viewModel;
}
@Override
public ForumViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.list_item_forum, parent, false);
return new ForumViewHolder(v);
return new ForumViewHolder(v, viewModel);
}
@Override

View File

@@ -40,7 +40,7 @@ public class ForumListFragment extends BaseFragment implements
private ForumListViewModel viewModel;
private BriarRecyclerView list;
private Snackbar snackbar;
private final ForumListAdapter adapter = new ForumListAdapter();
private ForumListAdapter adapter;
@Inject
ViewModelProvider.Factory viewModelFactory;
@@ -54,6 +54,7 @@ public class ForumListFragment extends BaseFragment implements
component.inject(this);
viewModel = new ViewModelProvider(this, viewModelFactory)
.get(ForumListViewModel.class);
adapter = new ForumListAdapter(viewModel);
}
@Nullable

View File

@@ -1,6 +1,7 @@
package org.briarproject.briar.android.forum;
import android.app.Application;
import android.widget.Toast;
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
import org.briarproject.bramble.api.db.DatabaseExecutor;
@@ -15,6 +16,7 @@ import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.event.GroupAddedEvent;
import org.briarproject.bramble.api.sync.event.GroupRemovedEvent;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.briar.R;
import org.briarproject.briar.android.viewmodel.DbViewModel;
import org.briarproject.briar.android.viewmodel.LiveResult;
import org.briarproject.briar.api.android.AndroidNotificationManager;
@@ -40,6 +42,7 @@ import androidx.annotation.UiThread;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import static android.widget.Toast.LENGTH_SHORT;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.now;
@@ -180,4 +183,17 @@ class ForumListViewModel extends DbViewModel implements EventListener {
return numInvitations;
}
void deleteForum(GroupId groupId) {
runOnDbThread(() -> {
try {
Forum f = forumManager.getForum(groupId);
forumManager.removeForum(f);
androidExecutor.runOnUiThread(() -> Toast
.makeText(getApplication(), R.string.forum_left_toast,
LENGTH_SHORT).show());
} catch (DbException e) {
handleException(e);
}
});
}
}

View File

@@ -6,10 +6,10 @@ import org.briarproject.briar.api.forum.ForumPostHeader;
import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe
class ForumPostItem extends ThreadItem {
public class ForumPostItem extends ThreadItem {
ForumPostItem(ForumPostHeader h, String text) {
super(h.getId(), h.getParentId(), text, h.getTimestamp(), h.getAuthor(),
ForumPostItem(ForumPostHeader h) {
super(h.getId(), h.getParentId(), h.getTimestamp(), h.getAuthor(),
h.getAuthorInfo(), h.isRead());
}

View File

@@ -4,6 +4,7 @@ import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.PopupMenu;
import android.widget.TextView;
import org.briarproject.briar.R;
@@ -20,6 +21,7 @@ import static org.briarproject.briar.android.activity.BriarActivity.GROUP_NAME;
class ForumViewHolder extends RecyclerView.ViewHolder {
private final ForumListViewModel viewModel;
private final Context ctx;
private final ViewGroup layout;
private final TextAvatarView avatar;
@@ -27,8 +29,9 @@ class ForumViewHolder extends RecyclerView.ViewHolder {
private final TextView postCount;
private final TextView date;
ForumViewHolder(View v) {
ForumViewHolder(View v, ForumListViewModel viewModel) {
super(v);
this.viewModel = viewModel;
ctx = v.getContext();
layout = (ViewGroup) v;
avatar = v.findViewById(R.id.avatarView);
@@ -64,6 +67,21 @@ class ForumViewHolder extends RecyclerView.ViewHolder {
date.setVisibility(VISIBLE);
}
// Open popup menu on long click
layout.setOnLongClickListener(v -> {
PopupMenu pm = new PopupMenu(ctx, v);
pm.getMenuInflater().inflate(R.menu.forum_list_item_actions,
pm.getMenu());
pm.setOnMenuItemClickListener(it -> {
if (it.getItemId() == R.id.action_forum_delete) {
viewModel.deleteForum(item.getForum().getId());
}
return true;
});
pm.show();
return true;
});
// Open Forum on Click
layout.setOnClickListener(v -> {
Intent i = new Intent(ctx, ForumActivity.class);

View File

@@ -91,9 +91,7 @@ class ForumViewModel extends ThreadListViewModel<ForumPostItem> {
ForumPostReceivedEvent f = (ForumPostReceivedEvent) e;
if (f.getGroupId().equals(groupId)) {
LOG.info("Forum post received, adding...");
ForumPostItem item =
new ForumPostItem(f.getHeader(), f.getText());
addItem(item, false);
addItem(new ForumPostItem(f.getHeader()), false);
}
} else if (e instanceof ForumInvitationResponseReceivedEvent) {
ForumInvitationResponseReceivedEvent f =
@@ -139,22 +137,14 @@ class ForumViewModel extends ThreadListViewModel<ForumPostItem> {
List<ForumPostHeader> headers =
forumManager.getPostHeaders(txn, groupId);
logDuration(LOG, "Loading headers", start);
start = now();
List<ForumPostItem> items = new ArrayList<>();
for (ForumPostHeader header : headers) {
items.add(loadItem(txn, header));
items.add(new ForumPostItem(header));
}
logDuration(LOG, "Loading bodies and creating items", start);
return items;
}, this::setItems);
}
private ForumPostItem loadItem(Transaction txn, ForumPostHeader header)
throws DbException {
String text = forumManager.getPostText(txn, header.getId());
return new ForumPostItem(header, text);
}
@Override
public void createAndStoreMessage(String text,
@Nullable MessageId parentId) {
@@ -175,21 +165,17 @@ class ForumViewModel extends ThreadListViewModel<ForumPostItem> {
@Nullable MessageId parentId, LocalAuthor author) {
cryptoExecutor.execute(() -> {
LOG.info("Creating forum post...");
ForumPost msg = forumManager.createLocalPost(groupId, text,
timestamp, parentId, author);
storePost(msg, text);
storePost(forumManager.createLocalPost(groupId, text,
timestamp, parentId, author));
});
}
private void storePost(ForumPost msg, String text) {
private void storePost(ForumPost msg) {
runOnDbThread(false, txn -> {
long start = now();
ForumPostHeader header = forumManager.addLocalPost(txn, msg);
logDuration(LOG, "Storing forum post", start);
txn.attach(() -> {
ForumPostItem item = new ForumPostItem(header, text);
addItem(item, true);
});
txn.attach(() -> addItem(new ForumPostItem(header), true));
}, this::handleException);
}
@@ -229,4 +215,9 @@ class ForumViewModel extends ThreadListViewModel<ForumPostItem> {
});
}
@Override
protected String getMessageText(Transaction txn, MessageId m)
throws DbException {
return forumManager.getPostText(txn, m);
}
}

View File

@@ -13,6 +13,8 @@ import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.BaseActivity;
import org.briarproject.briar.api.android.ScreenFilterMonitor;
@@ -27,7 +29,6 @@ import java.util.Collection;
import javax.annotation.Nullable;
import javax.inject.Inject;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import static android.os.Build.VERSION.SDK_INT;
@@ -75,8 +76,8 @@ public class ScreenFilterDialogFragment extends DialogFragment {
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
Activity activity = getActivity();
if (activity == null) throw new IllegalStateException();
AlertDialog.Builder builder = new AlertDialog.Builder(activity,
R.style.BriarDialogThemeNoFilter);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(
activity, R.style.BriarDialogThemeNoFilter);
builder.setTitle(R.string.screen_filter_title);
Bundle args = getArguments();
if (args == null) throw new IllegalStateException();

View File

@@ -6,12 +6,13 @@ import android.content.Intent;
import android.net.wifi.WifiManager;
import android.widget.Toast;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.briarproject.briar.R;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AlertDialog;
import androidx.core.util.Consumer;
import androidx.fragment.app.FragmentActivity;
@@ -73,7 +74,8 @@ abstract class AbstractConditionManager {
void showRationale(Context ctx, @StringRes int title,
@StringRes int body, Runnable onContinueClicked,
Runnable onDismiss) {
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
MaterialAlertDialogBuilder builder =
new MaterialAlertDialogBuilder(ctx);
builder.setTitle(title);
builder.setMessage(body);
builder.setNeutralButton(R.string.continue_button,

View File

@@ -61,6 +61,7 @@ public class HotspotIntroFragment extends Fragment {
getAndroidComponent(activity).inject(this);
viewModel = new ViewModelProvider(activity, viewModelFactory)
.get(HotspotViewModel.class);
conditionManager.init(requireActivity());
}
@Override
@@ -76,8 +77,6 @@ public class HotspotIntroFragment extends Fragment {
startButton.setOnClickListener(this::onButtonClick);
conditionManager.init(requireActivity());
return v;
}

View File

@@ -32,6 +32,7 @@ import static android.widget.Toast.LENGTH_LONG;
import static org.briarproject.bramble.api.crypto.DecryptionResult.KEY_STRENGTHENER_ERROR;
import static org.briarproject.bramble.api.crypto.DecryptionResult.SUCCESS;
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK;
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.STRONG;
import static org.briarproject.briar.android.login.LoginUtils.createKeyStrengthenerErrorDialog;
import static org.briarproject.briar.android.util.UiUtils.hideSoftKeyboard;
import static org.briarproject.briar.android.util.UiUtils.setError;
@@ -123,12 +124,25 @@ public class ChangePasswordActivity extends BriarActivity
boolean passwordsMatch = firstPassword.equals(secondPassword);
float strength = viewModel.estimatePasswordStrength(firstPassword);
strengthMeter.setStrength(strength);
if (!firstPassword.isEmpty()) {
if (strength >= STRONG) {
newPasswordEntryWrapper.setHelperText(
getString(R.string.password_strong));
} else if (strength >= QUITE_WEAK) {
newPasswordEntryWrapper.setHelperText(
getString(R.string.password_quite_strong));
} else {
newPasswordEntryWrapper.setHelperTextEnabled(false);
}
}
setError(newPasswordEntryWrapper,
getString(R.string.password_too_weak),
firstPassword.length() > 0 && strength < QUITE_WEAK);
!firstPassword.isEmpty() && strength < QUITE_WEAK);
setError(newPasswordConfirmationWrapper,
getString(R.string.passwords_do_not_match),
secondPassword.length() > 0 && !passwordsMatch);
!secondPassword.isEmpty() && !passwordsMatch);
changePasswordButton.setEnabled(
!currentPassword.getText().toString().isEmpty() &&
passwordsMatch && strength >= QUITE_WEAK);

View File

@@ -2,6 +2,8 @@ package org.briarproject.briar.android.login;
import android.content.Context;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.briarproject.briar.R;
import org.briarproject.nullsafety.NotNullByDefault;
@@ -13,8 +15,8 @@ import static org.briarproject.briar.android.util.UiUtils.getDialogIcon;
class LoginUtils {
static AlertDialog createKeyStrengthenerErrorDialog(Context ctx) {
AlertDialog.Builder builder =
new AlertDialog.Builder(ctx, R.style.BriarDialogTheme);
MaterialAlertDialogBuilder builder =
new MaterialAlertDialogBuilder(ctx, R.style.BriarDialogTheme);
builder.setIcon(getDialogIcon(ctx, R.drawable.alerts_and_states_error));
builder.setTitle(R.string.dialog_title_cannot_check_password);
builder.setMessage(R.string.dialog_message_cannot_check_password);

View File

@@ -9,6 +9,7 @@ import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ProgressBar;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputEditText;
import com.google.android.material.textfield.TextInputLayout;
@@ -40,6 +41,7 @@ import static org.briarproject.bramble.api.crypto.DecryptionResult.SUCCESS;
import static org.briarproject.briar.android.login.LoginUtils.createKeyStrengthenerErrorDialog;
import static org.briarproject.briar.android.util.UiUtils.enterPressed;
import static org.briarproject.briar.android.util.UiUtils.hideSoftKeyboard;
import static org.briarproject.briar.android.util.UiUtils.hideViewOnSmallScreen;
import static org.briarproject.briar.android.util.UiUtils.setError;
import static org.briarproject.briar.android.util.UiUtils.showSoftKeyboard;
@@ -100,6 +102,12 @@ public class PasswordFragment extends BaseFragment implements TextWatcher {
return v;
}
@Override
public void onStart() {
super.onStart();
hideViewOnSmallScreen(requireView().findViewById(R.id.logo));
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
@@ -147,9 +155,11 @@ public class PasswordFragment extends BaseFragment implements TextWatcher {
}
private void onForgottenPasswordClick() {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext(),
R.style.BriarDialogTheme);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(
requireContext(), R.style.BriarDialogTheme);
builder.setTitle(R.string.dialog_title_lost_password);
builder.setBackgroundInsetStart(25);
builder.setBackgroundInsetEnd(25);
builder.setMessage(R.string.dialog_message_lost_password);
builder.setPositiveButton(R.string.cancel, null);
builder.setNegativeButton(R.string.delete,

View File

@@ -1,5 +1,6 @@
package org.briarproject.briar.android.login;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
@@ -74,6 +75,7 @@ public class StartupActivity extends BaseActivity implements
}
@Override
@SuppressLint("MissingSuperCall")
public void onBackPressed() {
// Move task and activity to the background instead of showing another
// password prompt.

View File

@@ -11,6 +11,7 @@ import android.widget.RadioGroup;
import android.widget.ScrollView;
import com.google.android.material.animation.ArgbEvaluatorCompat;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.briarproject.briar.R;
import org.briarproject.briar.android.view.BriarButton;
@@ -24,7 +25,6 @@ import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModelProvider;
@@ -148,8 +148,8 @@ public class ErrorWizardFragment extends Fragment {
}
private void onUnlinkButtonClicked(View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext(),
R.style.BriarDialogTheme);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(
requireContext(), R.style.BriarDialogTheme);
builder.setTitle(R.string.mailbox_status_unlink_dialog_title);
builder.setMessage(R.string.mailbox_status_unlink_dialog_question);
builder.setPositiveButton(R.string.cancel,

View File

@@ -5,6 +5,8 @@ import android.view.MenuItem;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
import org.briarproject.bramble.api.mailbox.MailboxPairingState.ConnectionError;
import org.briarproject.bramble.api.mailbox.MailboxPairingState.InvalidQrCode;
@@ -31,7 +33,6 @@ import org.briarproject.nullsafety.ParametersNotNullByDefault;
import javax.inject.Inject;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProvider;
@@ -249,8 +250,8 @@ public class MailboxActivity extends BriarActivity {
if (tellUserToWipeMailbox) {
showFragment(getSupportFragmentManager(), new BlankFragment(),
BlankFragment.TAG);
AlertDialog.Builder builder =
new AlertDialog.Builder(this, R.style.BriarDialogTheme);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(
this, R.style.BriarDialogTheme);
builder.setTitle(R.string.mailbox_status_unlink_no_wipe_title);
builder.setMessage(R.string.mailbox_status_unlink_no_wipe_message);
builder.setNeutralButton(R.string.got_it,

View File

@@ -13,6 +13,8 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.briarproject.bramble.api.mailbox.MailboxStatus;
import org.briarproject.briar.R;
import org.briarproject.briar.android.view.BriarButton;
@@ -214,8 +216,8 @@ public class MailboxStatusFragment extends Fragment {
}
private void onUnlinkButtonClicked(boolean showWarning) {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext(),
R.style.BriarDialogTheme);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(
requireContext(), R.style.BriarDialogTheme);
builder.setTitle(R.string.mailbox_status_unlink_dialog_title);
String msg = getString(R.string.mailbox_status_unlink_dialog_question);
if (showWarning) {

View File

@@ -48,6 +48,7 @@ import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.plugin.Plugin.PREF_PLUGIN_ENABLE;
import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING;
import static org.briarproject.bramble.util.AndroidUtils.registerReceiver;
import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.now;
@@ -96,7 +97,7 @@ public class PluginViewModel extends DbViewModel implements EventListener {
this.eventBus = eventBus;
eventBus.addListener(this);
receiver = new BluetoothStateReceiver();
app.registerReceiver(receiver, new IntentFilter(ACTION_STATE_CHANGED));
registerReceiver(app, receiver, new IntentFilter(ACTION_STATE_CHANGED));
networkStatus.setValue(networkManager.getNetworkStatus());
torPluginState.setValue(getTransportState(TorConstants.ID));
wifiPluginState.setValue(getTransportState(LanTcpConstants.ID));

View File

@@ -10,6 +10,8 @@ import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.briarproject.briar.R;
import java.util.ArrayList;
@@ -17,7 +19,6 @@ import java.util.logging.Logger;
import javax.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.ListPreference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.SwitchPreferenceCompat;
@@ -201,8 +202,8 @@ public class PanicPreferencesFragment extends PreferenceFragmentCompat
getActivity().finish();
};
AlertDialog.Builder builder = new AlertDialog.Builder(getContext(),
R.style.BriarDialogTheme);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(
requireContext(), R.style.BriarDialogTheme);
builder.setTitle(getString(R.string.dialog_title_connect_panic_app));
CharSequence app = getString(R.string.unknown_app);

View File

@@ -6,6 +6,8 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.privategroup.creation.GroupInviteActivity;
@@ -13,14 +15,12 @@ import org.briarproject.briar.android.privategroup.memberlist.GroupMemberListAct
import org.briarproject.briar.android.privategroup.reveal.RevealContactsActivity;
import org.briarproject.briar.android.threaded.ThreadListActivity;
import org.briarproject.briar.android.threaded.ThreadListViewModel;
import org.briarproject.briar.android.widget.LinkDialogFragment;
import org.briarproject.nullsafety.MethodsNotNullByDefault;
import org.briarproject.nullsafety.ParametersNotNullByDefault;
import javax.annotation.Nullable;
import javax.inject.Inject;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.lifecycle.ViewModelProvider;
@@ -55,7 +55,7 @@ public class GroupActivity extends
@Override
protected GroupMessageAdapter createAdapter() {
return new GroupMessageAdapter(this);
return new GroupMessageAdapter(this, this);
}
@Override
@@ -159,12 +159,6 @@ public class GroupActivity extends
if (isDissolved != null && !isDissolved) super.onReplyClick(item);
}
@Override
public void onLinkClick(String url){
LinkDialogFragment f = LinkDialogFragment.newInstance(url);
f.show(getSupportFragmentManager(), f.getUniqueTag());
}
private void setGroupEnabled(boolean enabled) {
sendController.setReady(enabled);
list.getRecyclerView().setAlpha(enabled ? 1f : 0.5f);
@@ -178,8 +172,8 @@ public class GroupActivity extends
}
private void showLeaveGroupDialog() {
AlertDialog.Builder builder =
new AlertDialog.Builder(this, R.style.BriarDialogTheme);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(
this, R.style.BriarDialogTheme);
builder.setTitle(getString(R.string.groups_leave_dialog_title));
builder.setMessage(getString(R.string.groups_leave_dialog_message));
builder.setNegativeButton(R.string.dialog_button_leave,
@@ -189,8 +183,8 @@ public class GroupActivity extends
}
private void showDissolveGroupDialog() {
AlertDialog.Builder builder =
new AlertDialog.Builder(this, R.style.BriarDialogTheme);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(
this, R.style.BriarDialogTheme);
builder.setTitle(getString(R.string.groups_dissolve_dialog_title));
builder.setMessage(getString(R.string.groups_dissolve_dialog_message));
builder.setNegativeButton(R.string.groups_dissolve_button,
@@ -206,8 +200,8 @@ public class GroupActivity extends
}
private void onGroupDissolved() {
AlertDialog.Builder builder =
new AlertDialog.Builder(this, R.style.BriarDialogTheme);
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(
this, R.style.BriarDialogTheme);
builder.setTitle(getString(R.string.groups_dissolved_dialog_title));
builder.setMessage(getString(R.string.groups_dissolved_dialog_message));
builder.setNeutralButton(R.string.ok, null);

View File

@@ -11,16 +11,19 @@ import org.briarproject.briar.android.threaded.ThreadPostViewHolder;
import org.briarproject.nullsafety.NotNullByDefault;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
import androidx.lifecycle.LifecycleOwner;
@UiThread
@NotNullByDefault
class GroupMessageAdapter extends ThreadItemAdapter<GroupMessageItem> {
public class GroupMessageAdapter extends ThreadItemAdapter<GroupMessageItem> {
private boolean isCreator = false;
GroupMessageAdapter(ThreadItemListener<GroupMessageItem> listener) {
super(listener);
GroupMessageAdapter(LifecycleOwner lifecycleOwner,
ThreadItemListener<GroupMessageItem> listener) {
super(lifecycleOwner, listener);
}
@LayoutRes
@@ -30,6 +33,7 @@ class GroupMessageAdapter extends ThreadItemAdapter<GroupMessageItem> {
return item.getLayout();
}
@NonNull
@Override
public BaseThreadItemViewHolder<GroupMessageItem> onCreateViewHolder(
ViewGroup parent, int type) {

View File

@@ -1,14 +1,10 @@
package org.briarproject.briar.android.privategroup.conversation;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.briar.api.identity.AuthorInfo;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.R;
import org.briarproject.briar.android.threaded.ThreadItem;
import org.briarproject.briar.api.privategroup.GroupMessageHeader;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
import androidx.annotation.LayoutRes;
@@ -16,20 +12,14 @@ import androidx.annotation.UiThread;
@UiThread
@NotThreadSafe
class GroupMessageItem extends ThreadItem {
public class GroupMessageItem extends ThreadItem {
private final GroupId groupId;
private GroupMessageItem(MessageId messageId, GroupId groupId,
@Nullable MessageId parentId, String text, long timestamp,
Author author, AuthorInfo authorInfo, boolean isRead) {
super(messageId, parentId, text, timestamp, author, authorInfo, isRead);
this.groupId = groupId;
}
GroupMessageItem(GroupMessageHeader h, String text) {
this(h.getId(), h.getGroupId(), h.getParentId(), text, h.getTimestamp(),
h.getAuthor(), h.getAuthorInfo(), h.isRead());
GroupMessageItem(GroupMessageHeader h) {
super(h.getId(), h.getParentId(), h.getTimestamp(), h.getAuthor(),
h.getAuthorInfo(), h.isRead());
this.groupId = h.getGroupId();
}
public GroupId getGroupId() {

View File

@@ -99,7 +99,7 @@ class GroupViewModel extends ThreadListViewModel<GroupMessageItem> {
// only act on non-local messages in this group
if (!g.isLocal() && g.getGroupId().equals(groupId)) {
LOG.info("Group message received, adding...");
GroupMessageItem item = buildItem(g.getHeader(), g.getText());
GroupMessageItem item = buildItem(g.getHeader());
addItem(item, false);
// In case the join message comes from the creator,
// we need to reload the sharing contacts
@@ -167,33 +167,19 @@ class GroupViewModel extends ThreadListViewModel<GroupMessageItem> {
List<GroupMessageHeader> headers =
privateGroupManager.getHeaders(txn, groupId);
logDuration(LOG, "Loading headers", start);
start = now();
List<GroupMessageItem> items = new ArrayList<>();
for (GroupMessageHeader header : headers) {
items.add(loadItem(txn, header));
items.add(buildItem(header));
}
logDuration(LOG, "Loading bodies and creating items", start);
return items;
}, this::setItems);
}
private GroupMessageItem loadItem(Transaction txn,
GroupMessageHeader header) throws DbException {
String text;
private GroupMessageItem buildItem(GroupMessageHeader header) {
if (header instanceof JoinMessageHeader) {
// will be looked up later
text = "";
} else {
text = privateGroupManager.getMessageText(txn, header.getId());
return new JoinMessageItem((JoinMessageHeader) header);
}
return buildItem(header, text);
}
private GroupMessageItem buildItem(GroupMessageHeader header, String text) {
if (header instanceof JoinMessageHeader) {
return new JoinMessageItem((JoinMessageHeader) header, text);
}
return new GroupMessageItem(header, text);
return new GroupMessageItem(header);
}
@Override
@@ -221,19 +207,17 @@ class GroupViewModel extends ThreadListViewModel<GroupMessageItem> {
LOG.info("Creating group message...");
GroupMessage msg = groupMessageFactory.createGroupMessage(groupId,
timestamp, parentId, author, text, previousMsgId);
storePost(msg, text);
storePost(msg);
});
}
private void storePost(GroupMessage msg, String text) {
private void storePost(GroupMessage msg) {
runOnDbThread(false, txn -> {
long start = now();
GroupMessageHeader header =
privateGroupManager.addLocalMessage(txn, msg);
logDuration(LOG, "Storing group message", start);
txn.attach(() ->
addItem(buildItem(header, text), true)
);
txn.attach(() -> addItem(buildItem(header), true));
}, this::handleException);
}
@@ -284,4 +268,9 @@ class GroupViewModel extends ThreadListViewModel<GroupMessageItem> {
return isDissolved;
}
@Override
protected String getMessageText(Transaction txn, MessageId m)
throws DbException {
return privateGroupManager.getMessageText(txn, m);
}
}

View File

@@ -14,8 +14,8 @@ class JoinMessageItem extends GroupMessageItem {
private final boolean isInitial;
JoinMessageItem(JoinMessageHeader h, String text) {
super(h, text);
JoinMessageItem(JoinMessageHeader h) {
super(h);
isInitial = h.isInitial();
}

View File

@@ -9,6 +9,7 @@ import org.briarproject.briar.android.threaded.ThreadItemAdapter.ThreadItemListe
import org.briarproject.nullsafety.NotNullByDefault;
import androidx.annotation.UiThread;
import androidx.lifecycle.LifecycleOwner;
import static org.briarproject.briar.api.identity.AuthorInfo.Status.OURSELVES;
@@ -25,10 +26,8 @@ class JoinMessageItemViewHolder
}
@Override
public void bind(GroupMessageItem item,
protected void setText(GroupMessageItem item, LifecycleOwner lifecycleOwner,
ThreadItemListener<GroupMessageItem> listener) {
super.bind(item, listener);
if (isCreator) bindForCreator((JoinMessageItem) item);
else bind((JoinMessageItem) item);
}

View File

@@ -9,6 +9,8 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.sync.GroupId;
@@ -26,7 +28,6 @@ import javax.annotation.Nullable;
import javax.inject.Inject;
import androidx.annotation.LayoutRes;
import androidx.appcompat.app.AlertDialog;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
@@ -105,7 +106,8 @@ public class RevealContactsActivity extends ContactSelectorActivity
}
private void showOnboardingDialog() {
new AlertDialog.Builder(this, R.style.OnboardingDialogTheme)
new MaterialAlertDialogBuilder(this,
R.style.OnboardingDialogTheme)
.setMessage(getString(R.string.groups_reveal_dialog_message))
.setNeutralButton(R.string.got_it,
(dialog, which) -> dialog.cancel())

View File

@@ -1,5 +1,6 @@
package org.briarproject.briar.android.reporting;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
@@ -87,6 +88,7 @@ public class CrashReportActivity extends BaseActivity
}
@Override
@SuppressLint("MissingSuperCall")
public void onBackPressed() {
exit();
}

View File

@@ -10,6 +10,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.BaseActivity;
@@ -20,7 +21,6 @@ import org.briarproject.nullsafety.ParametersNotNullByDefault;
import javax.inject.Inject;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModelProvider;
@@ -86,7 +86,7 @@ public class ConfirmAvatarDialogFragment extends DialogFragment {
);
int theme = R.style.BriarDialogTheme;
return new AlertDialog.Builder(activity, theme)
return new MaterialAlertDialogBuilder(activity, theme)
.setView(view)
.setTitle(R.string.dialog_confirm_profile_picture_title)
.setNegativeButton(R.string.cancel, null)

View File

@@ -1,21 +1,19 @@
package org.briarproject.briar.android.settings;
import android.app.AlertDialog;
import android.content.Intent;
import android.os.Bundle;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.briarproject.briar.R;
import org.briarproject.briar.android.Localizer;
import org.briarproject.briar.android.util.UiUtils;
import org.briarproject.nullsafety.NotNullByDefault;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.logging.Logger;
import androidx.core.text.TextUtilsCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
@@ -24,10 +22,7 @@ import androidx.preference.PreferenceFragmentCompat;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.core.view.ViewCompat.LAYOUT_DIRECTION_LTR;
import static java.util.Objects.requireNonNull;
import static java.util.logging.Logger.getLogger;
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.settings.SettingsActivity.EXTRA_THEME_CHANGE;
@@ -36,10 +31,7 @@ import static org.briarproject.briar.android.settings.SettingsActivity.EXTRA_THE
public class DisplayFragment extends PreferenceFragmentCompat {
public static final String PREF_LANGUAGE = "pref_key_language";
private static final String PREF_THEME = "pref_key_theme";
private static final Logger LOG =
getLogger(DisplayFragment.class.getName());
public static final String PREF_THEME = "pref_key_theme";
@Override
public void onCreatePreferences(Bundle bundle, String s) {
@@ -50,7 +42,6 @@ public class DisplayFragment extends PreferenceFragmentCompat {
language.setOnPreferenceChangeListener(this::onLanguageChanged);
ListPreference theme = requireNonNull(findPreference(PREF_THEME));
setThemeEntries(theme);
theme.setOnPreferenceChangeListener(this::onThemeChanged);
}
@@ -91,30 +82,6 @@ public class DisplayFragment extends PreferenceFragmentCompat {
language.setEntryValues(entryValues.toArray(new CharSequence[0]));
}
private boolean isLeftToRight(Locale locale) {
// TextUtilsCompat returns the wrong direction for Hebrew on some phones
String language = locale.getLanguage();
if (language.equals("iw") || language.equals("he")) return false;
int direction = TextUtilsCompat.getLayoutDirectionFromLocale(locale);
return direction == LAYOUT_DIRECTION_LTR;
}
private void setThemeEntries(ListPreference theme) {
if (SDK_INT < 27) {
// remove System Default Theme option from preference entries
// as it is not functional on this API anyway
List<CharSequence> entries =
new ArrayList<>(Arrays.asList(theme.getEntries()));
entries.remove(getString(R.string.pref_theme_system));
theme.setEntries(entries.toArray(new CharSequence[0]));
// also remove corresponding value
List<CharSequence> values =
new ArrayList<>(Arrays.asList(theme.getEntryValues()));
values.remove(getString(R.string.pref_theme_system_value));
theme.setEntryValues(values.toArray(new CharSequence[0]));
}
}
private boolean onThemeChanged(Preference preference, Object newValue) {
// activate new theme
FragmentActivity activity = requireActivity();
@@ -135,8 +102,8 @@ public class DisplayFragment extends PreferenceFragmentCompat {
private boolean onLanguageChanged(Preference preference, Object newValue) {
ListPreference language = (ListPreference) preference;
if (!language.getValue().equals(newValue)) {
AlertDialog.Builder builder =
new AlertDialog.Builder(getActivity());
MaterialAlertDialogBuilder builder =
new MaterialAlertDialogBuilder(requireContext());
builder.setTitle(R.string.pref_language_title);
builder.setMessage(R.string.pref_language_changed);
builder.setPositiveButton(R.string.sign_out_button, (d, i) -> {

View File

@@ -4,35 +4,46 @@ import android.animation.Animator;
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.text.util.Linkify;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.widget.TextView;
import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.R;
import org.briarproject.briar.android.threaded.ThreadItemAdapter.ThreadItemListener;
import org.briarproject.briar.android.view.AuthorView;
import org.briarproject.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
import androidx.annotation.CallSuper;
import androidx.annotation.UiThread;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import androidx.recyclerview.widget.RecyclerView;
import static android.text.util.Linkify.WEB_URLS;
import static android.text.util.Linkify.addLinks;
import static androidx.core.content.ContextCompat.getColor;
import static org.briarproject.bramble.util.StringUtils.trim;
import static org.briarproject.briar.android.util.UiUtils.makeLinksClickable;
import static org.briarproject.nullsafety.NullSafety.requireNonNull;
@UiThread
@NotNullByDefault
public abstract class BaseThreadItemViewHolder<I extends ThreadItem>
extends RecyclerView.ViewHolder {
extends RecyclerView.ViewHolder implements Observer<String> {
private final static int ANIMATION_DURATION = 5000;
protected final TextView textView;
private final ViewGroup layout;
private final AuthorView author;
@Nullable
private ThreadItemListener<I> listener = null;
@Nullable
private LiveData<String> textLiveData = null;
public BaseThreadItemViewHolder(View v) {
super(v);
@@ -43,10 +54,9 @@ public abstract class BaseThreadItemViewHolder<I extends ThreadItem>
}
@CallSuper
public void bind(I item, ThreadItemListener<I> listener) {
textView.setText(StringUtils.trim(item.getText()));
Linkify.addLinks(textView, Linkify.WEB_URLS);
makeLinksClickable(textView, listener::onLinkClick);
public void bind(I item, LifecycleOwner lifecycleOwner,
ThreadItemListener<I> listener) {
setText(item, lifecycleOwner, listener);
author.setAuthor(item.getAuthor(), item.getAuthorInfo());
author.setDate(item.getTimestamp());
@@ -61,6 +71,20 @@ public abstract class BaseThreadItemViewHolder<I extends ThreadItem>
}
}
protected void setText(I item, LifecycleOwner lifecycleOwner,
ThreadItemListener<I> listener) {
// Clear any existing text while we asynchronously load the new text
textView.setText(null);
// Remember the listener so we can use it to create links later
this.listener = listener;
// If the view has been re-bound and we're already asynchronously
// loading text for another item, stop observing it
if (textLiveData != null) textLiveData.removeObserver(this);
// Asynchronously load the text for this item and observe the result
textLiveData = listener.loadItemText(item.getId());
textLiveData.observe(lifecycleOwner, this);
}
private void animateFadeOut() {
setIsRecyclable(false);
ValueAnimator anim = new ValueAnimator();
@@ -73,6 +97,7 @@ public abstract class BaseThreadItemViewHolder<I extends ThreadItem>
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
layout.setBackgroundResource(
@@ -80,9 +105,11 @@ public abstract class BaseThreadItemViewHolder<I extends ThreadItem>
layout.setActivated(false);
setIsRecyclable(true);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
@@ -97,4 +124,24 @@ public abstract class BaseThreadItemViewHolder<I extends ThreadItem>
return textView.getContext();
}
void onViewRecycled() {
textView.setText(null);
if (textLiveData != null) {
textLiveData.removeObserver(this);
textLiveData = null;
listener = null;
}
}
@Override
public void onChanged(String s) {
if (textLiveData != null) {
textLiveData.removeObserver(this);
textLiveData = null;
textView.setText(trim(s));
addLinks(textView, WEB_URLS);
makeLinksClickable(textView, requireNonNull(listener)::onLinkClick);
listener = null;
}
}
}

View File

@@ -19,7 +19,6 @@ public abstract class ThreadItem implements MessageNode {
private final MessageId messageId;
@Nullable
private final MessageId parentId;
private final String text;
private final long timestamp;
private final Author author;
private final AuthorInfo authorInfo;
@@ -27,11 +26,10 @@ public abstract class ThreadItem implements MessageNode {
private boolean isRead, highlighted;
public ThreadItem(MessageId messageId, @Nullable MessageId parentId,
String text, long timestamp, Author author, AuthorInfo authorInfo,
long timestamp, Author author, AuthorInfo authorInfo,
boolean isRead) {
this.messageId = messageId;
this.parentId = parentId;
this.text = text;
this.timestamp = timestamp;
this.author = author;
this.authorInfo = authorInfo;
@@ -39,10 +37,6 @@ public abstract class ThreadItem implements MessageNode {
this.highlighted = false;
}
public String getText() {
return text;
}
public int getLevel() {
return level;
}

View File

@@ -13,6 +13,8 @@ import javax.annotation.Nullable;
import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.ListAdapter;
@@ -27,9 +29,11 @@ public class ThreadItemAdapter<I extends ThreadItem>
static final int UNDEFINED = -1;
private final LifecycleOwner lifecycleOwner;
private final ThreadItemListener<I> listener;
public ThreadItemAdapter(ThreadItemListener<I> listener) {
public ThreadItemAdapter(LifecycleOwner lifecycleOwner,
ThreadItemListener<I> listener) {
super(new DiffUtil.ItemCallback<I>() {
@Override
public boolean areItemsTheSame(I a, I b) {
@@ -42,6 +46,7 @@ public class ThreadItemAdapter<I extends ThreadItem>
a.isRead() == b.isRead();
}
});
this.lifecycleOwner = lifecycleOwner;
this.listener = listener;
}
@@ -58,7 +63,7 @@ public class ThreadItemAdapter<I extends ThreadItem>
public void onBindViewHolder(@NonNull BaseThreadItemViewHolder<I> ui,
int position) {
I item = getItem(position);
ui.bind(item, listener);
ui.bind(item, lifecycleOwner, listener);
}
int findItemPosition(MessageId id) {
@@ -135,9 +140,19 @@ public class ThreadItemAdapter<I extends ThreadItem>
return getItem(position);
}
@Override
public void onViewRecycled(BaseThreadItemViewHolder<I> viewHolder) {
super.onViewRecycled(viewHolder);
viewHolder.onViewRecycled();
}
public interface ThreadItemListener<I> {
void onReplyClick(I item);
void onLinkClick(String url);
LiveData<String> loadItemText(MessageId m);
}
}

View File

@@ -85,6 +85,9 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
scrollListener = new ThreadScrollListener<>(adapter, viewModel,
upButton, downButton);
list.getRecyclerView().addOnScrollListener(scrollListener);
// This is a tradeoff between memory consumption for cached views
// and the cost of loading message text from the database
list.getRecyclerView().setItemViewCacheSize(20);
upButton.setOnClickListener(v -> {
int position = adapter.getVisibleUnreadPosTop(layoutManager);
@@ -257,4 +260,8 @@ public abstract class ThreadListActivity<I extends ThreadItem, A extends ThreadI
protected abstract int getMaxTextLength();
@Override
public LiveData<String> loadItemText(MessageId m) {
return getViewModel().loadMessageText(m);
}
}

View File

@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.crypto.CryptoExecutor;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.NoSuchGroupException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus;
@@ -260,4 +261,14 @@ public abstract class ThreadListViewModel<I extends ThreadItem>
return scrollToItem.getAndSet(null);
}
public LiveData<String> loadMessageText(MessageId m) {
MutableLiveData<String> textLiveData = new MutableLiveData<>();
runOnDbThread(true, txn ->
textLiveData.postValue(getMessageText(txn, m)),
this::handleException);
return textLiveData;
}
protected abstract String getMessageText(Transaction txn, MessageId m)
throws DbException;
}

View File

@@ -10,6 +10,7 @@ import org.briarproject.nullsafety.NotNullByDefault;
import java.util.Locale;
import androidx.annotation.UiThread;
import androidx.lifecycle.LifecycleOwner;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
@@ -40,8 +41,9 @@ public class ThreadPostViewHolder<I extends ThreadItem>
}
@Override
public void bind(I item, ThreadItemListener<I> listener) {
super.bind(item, listener);
public void bind(I item, LifecycleOwner lifecycleOwner,
ThreadItemListener<I> listener) {
super.bind(item, lifecycleOwner, listener);
for (int i = 0; i < lvls.length; i++) {
lvls[i].setVisibility(i < item.getLevel() ? VISIBLE : GONE);

View File

@@ -18,7 +18,8 @@ import static androidx.core.content.ContextCompat.getColor;
public class BriarSnackbarBuilder {
@ColorRes
private int backgroundResId = R.color.briar_primary;
@Nullable
private Integer backgroundResId = null;
@StringRes
private int actionResId;
@Nullable
@@ -26,7 +27,11 @@ public class BriarSnackbarBuilder {
public Snackbar make(View view, CharSequence text, int duration) {
Snackbar s = Snackbar.make(view, text, duration);
s.getView().setBackgroundResource(backgroundResId);
if (backgroundResId != null) {
s.setBackgroundTint(getColor(view.getContext(), backgroundResId));
s.setTextColor(
getColor(view.getContext(), R.color.md_theme_onSecondary));
}
if (onClickListener != null) {
s.setActionTextColor(getColor(view.getContext(),
R.color.briar_button_text_positive));

View File

@@ -6,6 +6,8 @@ import android.content.Intent;
import android.location.LocationManager;
import android.net.Uri;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.briarproject.briar.R;
import org.briarproject.nullsafety.MethodsNotNullByDefault;
import org.briarproject.nullsafety.ParametersNotNullByDefault;
@@ -16,7 +18,6 @@ import androidx.activity.result.ActivityResultLauncher;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
import static android.Manifest.permission.BLUETOOTH_ADVERTISE;
@@ -108,8 +109,8 @@ public class PermissionUtils {
}
public static void showLocationDialog(Context ctx, boolean forBluetooth) {
AlertDialog.Builder builder =
new AlertDialog.Builder(ctx, R.style.BriarDialogTheme);
MaterialAlertDialogBuilder builder =
new MaterialAlertDialogBuilder(ctx, R.style.BriarDialogTheme);
builder.setTitle(R.string.permission_location_setting_title);
if (forBluetooth) {
builder.setMessage(R.string.permission_location_setting_body);
@@ -136,8 +137,8 @@ public class PermissionUtils {
public static void showDenialDialog(FragmentActivity ctx,
@StringRes int title, @StringRes int body, Runnable onDenied) {
AlertDialog.Builder builder =
new AlertDialog.Builder(ctx, R.style.BriarDialogTheme);
MaterialAlertDialogBuilder builder =
new MaterialAlertDialogBuilder(ctx, R.style.BriarDialogTheme);
builder.setTitle(title);
builder.setMessage(body);
builder.setPositiveButton(R.string.ok, getGoToSettingsListener(ctx));
@@ -148,8 +149,8 @@ public class PermissionUtils {
public static void showRationale(FragmentActivity ctx, @StringRes int title,
@StringRes int body, @Nullable Runnable onOk) {
AlertDialog.Builder builder =
new AlertDialog.Builder(ctx, R.style.BriarDialogTheme);
MaterialAlertDialogBuilder builder =
new MaterialAlertDialogBuilder(ctx, R.style.BriarDialogTheme);
builder.setTitle(title);
builder.setMessage(body);
builder.setNeutralButton(R.string.continue_button, (dialog, which) -> {

View File

@@ -28,6 +28,7 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputLayout;
import org.briarproject.bramble.api.contact.Contact;
@@ -52,7 +53,6 @@ import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.core.hardware.fingerprint.FingerprintManagerCompat;
import androidx.core.text.HtmlCompat;
@@ -92,7 +92,6 @@ import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN;
import static android.view.inputmethod.EditorInfo.IME_NULL;
import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
import static android.widget.Toast.LENGTH_LONG;
import static androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_AUTO_TIME;
import static androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;
import static androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO;
import static androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES;
@@ -323,7 +322,7 @@ public class UiUtils {
}
public static void showOnboardingDialog(Context ctx, String text) {
new AlertDialog.Builder(ctx, R.style.OnboardingDialogTheme)
new MaterialAlertDialogBuilder(ctx, R.style.OnboardingDialogTheme)
.setMessage(text)
.setNeutralButton(R.string.got_it,
(dialog, which) -> dialog.cancel())
@@ -349,12 +348,7 @@ public class UiUtils {
} else if (theme
.equals(ctx.getString(R.string.pref_theme_dark_value))) {
setDefaultNightMode(MODE_NIGHT_YES);
} else if (theme
.equals(ctx.getString(R.string.pref_theme_auto_value))) {
// TODO remove AUTO-setting as it is deprecated
setDefaultNightMode(MODE_NIGHT_AUTO_TIME);
} else if (theme
.equals(ctx.getString(R.string.pref_theme_system_value))) {
} else {
setDefaultNightMode(MODE_NIGHT_FOLLOW_SYSTEM);
}
}
@@ -404,8 +398,8 @@ public class UiUtils {
public static void startDevReportActivity(Context ctx,
Class<? extends FragmentActivity> activity, @Nullable Throwable t,
@Nullable Long appStartTime, @Nullable byte[] logKey, @Nullable
String initialComment) {
@Nullable Long appStartTime, @Nullable byte[] logKey,
@Nullable String initialComment) {
// Collect memory stats from the current process, not the crash
// reporter process
ActivityManager am =

View File

@@ -8,12 +8,13 @@ import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import com.google.android.material.button.MaterialButton;
import org.briarproject.briar.R;
import org.briarproject.nullsafety.NotNullByDefault;
import androidx.annotation.Nullable;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.AppCompatButton;
import static android.content.Context.LAYOUT_INFLATER_SERVICE;
import static androidx.transition.TransitionManager.beginDelayedTransition;
@@ -47,8 +48,7 @@ public class BriarButton extends FrameLayout {
attributes.recycle();
ContextThemeWrapper wrapper = new ContextThemeWrapper(context, style);
button = isInEditMode() ? new AppCompatButton(context) :
new AppCompatButton(wrapper, null, style);
button = new MaterialButton(wrapper, null, style);
button.setText(text);
addView(button);
progressBar = findViewById(R.id.briar_button_progress_bar);

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:color="@color/briar_button_text_disabled"
android:state_enabled="false"/>
<item
android:color="#ffffffff"/>
</selector>

View File

@@ -1,7 +0,0 @@
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item
android:id="@android:id/mask"
android:drawable="@drawable/button_outline_mask" />
<item android:drawable="@drawable/button_outline_background" />
</ripple>

View File

@@ -1,19 +0,0 @@
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="4dp"
android:insetTop="6dp"
android:insetRight="4dp"
android:insetBottom="6dp">
<shape
android:shape="rectangle">
<corners android:radius="2dp" />
<solid android:color="@android:color/transparent" />
<stroke
android:width="1dp"
android:color="@color/briar_button_outline" />
<padding
android:bottom="4dp"
android:left="8dp"
android:right="8dp"
android:top="4dp" />
</shape>
</inset>

View File

@@ -1,19 +0,0 @@
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="4dp"
android:insetTop="6dp"
android:insetRight="4dp"
android:insetBottom="6dp">
<shape
android:shape="rectangle">
<corners android:radius="2dp" />
<solid android:color="@android:color/white" />
<stroke
android:width="1dp"
android:color="@android:color/white" />
<padding
android:bottom="4dp"
android:left="8dp"
android:right="8dp"
android:top="4dp" />
</shape>
</inset>

View File

@@ -7,7 +7,7 @@
android:radius="32dp"/>
<solid
android:color="@color/briar_lime_600"/>
android:color="?colorTertiaryContainer"/>
</shape>

View File

@@ -7,7 +7,7 @@
android:radius="32dp"/>
<solid
android:color="@color/briar_accent"/>
android:color="?colorTertiary"/>
</shape>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:radius="32dp"/>
<solid
android:color="?colorSurfaceDim"/>
</shape>

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="6dp"
android:left="4dp"
android:right="4dp"
android:top="6dp">
<shape android:shape="rectangle">
<corners android:radius="2dp" />
<solid android:color="@android:color/transparent" />
<stroke
android:width="1dp"
android:color="@color/briar_button_outline" />
</shape>
</item>
</layer-list>

View File

@@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
tools:context=".android.login.ChangePasswordActivity">
<androidx.constraintlayout.widget.ConstraintLayout
@@ -64,15 +65,27 @@
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
<org.briarproject.briar.android.login.StrengthMeter
android:id="@+id/strength_meter"
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_marginTop="8dp"
android:visibility="invisible"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/new_password_entry_wrapper"
tools:visibility="visible" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/new_password_confirm_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:errorEnabled="true"
app:hintEnabled="false"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/new_password_entry_wrapper"
app:layout_constraintTop_toBottomOf="@id/strength_meter"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
@@ -86,15 +99,6 @@
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
<org.briarproject.briar.android.login.StrengthMeter
android:id="@+id/strength_meter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/new_password_confirm_wrapper" />
<Button
android:id="@+id/change_password"
style="@style/BriarButton"
@@ -103,16 +107,20 @@
android:layout_marginTop="@dimen/margin_medium"
android:enabled="false"
android:text="@string/change_password"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/strength_meter"
app:layout_constraintTop_toBottomOf="@id/new_password_confirm_wrapper"
app:layout_constraintVertical_bias="1.0"
tools:enabled="true" />
<ProgressBar
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progress_wheel"
style="@style/CircularProgress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="@+id/change_password"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/change_password" />

View File

@@ -12,7 +12,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
style="@style/BriarToolbar"
android:layout_width="match_parent"
@@ -40,7 +40,7 @@
</LinearLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.MaterialToolbar>
</com.google.android.material.appbar.AppBarLayout>

View File

@@ -35,8 +35,9 @@
android:text="@string/create_forum_button"
tools:enabled="true" />
<ProgressBar
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/createForumProgressBar"
style="@style/CircularProgress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"

View File

@@ -18,7 +18,7 @@
android:layout_height="wrap_content"
android:background="@color/msg_status_bubble_background">
<androidx.appcompat.widget.Toolbar
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
style="@style/BriarToolbar"
android:layout_width="match_parent"
@@ -50,7 +50,7 @@
</LinearLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.MaterialToolbar>
</com.google.android.material.appbar.AppBarLayout>

View File

@@ -5,9 +5,9 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progressBar"
style="?android:progressBarStyleLarge"
style="@style/CircularProgress.Large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"

View File

@@ -19,9 +19,9 @@
</org.briarproject.briar.android.view.LargeTextInputView>
<ProgressBar
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleLarge"
style="@style/CircularProgress.Large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"

View File

@@ -6,12 +6,14 @@
<!-- Button gets added programmatically so we can pass on the styles -->
<ProgressBar
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/briar_button_progress_bar"
style="@style/CircularProgress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="invisible"
tools:progress="50"
tools:visibility="visible" />
</merge>

View File

@@ -15,9 +15,9 @@
tools:listitem="@layout/list_item_contact"
tools:visibility="visible" />
<ProgressBar
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleLarge"
style="@style/CircularProgress.Large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"

View File

@@ -21,6 +21,7 @@
android:id="@+id/aliasEditLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:errorEnabled="true"
app:hintEnabled="false">
@@ -28,7 +29,6 @@
android:id="@+id/aliasEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:hint="@string/set_contact_alias_hint"
android:imeOptions="flagNoPersonalizedLearning"
android:inputType="text|textCapWords"
@@ -41,7 +41,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_xxlarge"
android:layout_marginLeft="@dimen/margin_xxlarge"
android:layout_marginBottom="8dp"
android:gravity="end"
android:orientation="horizontal">

View File

@@ -19,9 +19,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ProgressBar
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleLarge"
style="@style/CircularProgress.Large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />

View File

@@ -34,7 +34,6 @@
android:text="@string/connect_via_bluetooth_intro"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/introImageView" />

View File

@@ -17,12 +17,12 @@
app:layout_constraintVertical_chainStyle="packed"
app:srcCompat="@drawable/il_bluetooth_connect" />
<ProgressBar
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:indeterminate="true"
app:indicatorColor="@color/briar_accent"
app:layout_constraintBottom_toTopOf="@+id/textView"
app:layout_constraintEnd_toEndOf="@+id/introImageView"
app:layout_constraintStart_toStartOf="@+id/introImageView"

View File

@@ -18,8 +18,7 @@
app:fab_fabDrawable="@drawable/ic_action_add"
app:fab_fabRippleColor="@android:color/transparent"
app:fab_menu="@menu/contact_list_actions"
app:fab_miniFabTextBackground="@color/briar_accent"
app:fab_miniFabTextColor="@android:color/white"
app:fab_miniFabTextBackground="?attr/colorPrimary"
app:layout_anchorGravity="bottom|right|end"
app:layout_behavior="org.briarproject.briar.android.view.SnackbarAwareBehavior" />

View File

@@ -5,7 +5,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
style="@style/BriarToolbar"
android:layout_width="match_parent"
@@ -40,7 +40,7 @@
app:tint="?attr/colorControlNormal"
tools:ignore="ContentDescription" />
<androidx.appcompat.widget.SwitchCompat
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/switchDisappearingMessages"
android:layout_width="0dp"
android:layout_height="wrap_content"
@@ -50,6 +50,7 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageViewBomb"
tools:checked="true"
tools:enabled="true" />
<Button

Some files were not shown because too many files have changed in this diff Show More