Compare commits

..

97 Commits

Author SHA1 Message Date
Sebastian Kürten
8f5c6f76ad Replace a statment lambda with method reference 2021-01-14 12:23:27 +01:00
Sebastian Kürten
927b52a6b6 ConversationSettingsFragment: improve threading logic 2021-01-14 12:21:38 +01:00
Sebastian Kürten
a77d90355b ConversationSettingsActivity: add null-related annotations 2021-01-14 12:17:35 +01:00
Sebastian Kürten
787348042e Use SwitchCompat instead of Switch 2021-01-14 12:12:42 +01:00
Sebastian Kürten
8d2640f459 ConversationSettingsFragemten: use lambdas in two places 2021-01-14 12:06:10 +01:00
Sebastian Kürten
6eb803596c ConversationSettingsFragemten: improve field section 2021-01-14 12:03:59 +01:00
Sebastian Kürten
fd544b2c28 Remove intro text; extend learn more button text 2021-01-08 10:25:33 +01:00
Sebastian Kürten
f9d6bca64e Make learn more dialog content scrollable 2021-01-08 09:59:29 +01:00
Sebastian Kürten
7aea2a99fa Reformat fragment source 2021-01-08 09:59:12 +01:00
Sebastian Kürten
322b8de5f7 Convert learn more button into blue TextView 2021-01-08 09:57:30 +01:00
Sebastian Kürten
620c9188ba Shorten intro text, break dialog text into paragraphs 2021-01-08 09:56:41 +01:00
Sebastian Kürten
c8b3a8221f Add divider, put into ScrollView 2021-01-07 16:16:30 +01:00
Sebastian Kürten
9fd27d7890 Add dialog to appear when user wants to learn more 2021-01-07 15:30:09 +01:00
Sebastian Kürten
63ae41994b Move context menu creation and processing from Activity to Fragment 2021-01-07 14:57:50 +01:00
Sebastian Kürten
7da57a1a1b Move learn-more button to left and make borderless 2021-01-07 10:41:33 +01:00
Sebastian Kürten
ea7e68d731 Delete now-unneeded layouts 2021-01-07 10:22:35 +01:00
Sebastian Kürten
c0989fb631 Make settings layout work using barrier 2021-01-06 21:45:29 +01:00
Sebastian Kürten
11ebaeaaea Start migrating the PreferenceFragment to regular Fragment with ConstrainedLayout 2021-01-06 19:23:26 +01:00
Sebastian Kürten
694ddd949f Set label for ConversationSettingsActivity 2021-01-04 17:47:56 +01:00
Sebastian Kürten
319adb6b8d Add help actions 2020-12-17 17:43:51 +01:00
Sebastian Kürten
10d76b120b Icon color, margins, positioning 2020-12-17 17:33:18 +01:00
Sebastian Kürten
b980307fcf Rename settings activity; remove other menu item 2020-12-17 17:07:28 +01:00
Sebastian Kürten
35c57cfa2c Use bomb drawable, remove hourglass 2020-12-17 16:51:29 +01:00
Sebastian Kürten
baa6d93034 Add explanation and learn more button 2020-12-17 15:56:28 +01:00
Sebastian Kürten
c23d67c765 Improve wording 2020-12-17 10:34:55 +01:00
Sebastian Kürten
86ea384f71 Add preference category, adapt text 2020-12-17 10:04:55 +01:00
Sebastian Kürten
145c1e1c64 Remove timer setting which we won't need for iteration 1 2020-12-17 09:51:08 +01:00
Sebastian Kürten
b48811e9b8 Manipulate disappearing messages settings via settings screen 2020-12-17 09:41:17 +01:00
Sebastian Kürten
87b200f0b5 Add simple draft actvity/fragment for conversation settings 2020-12-14 11:02:49 +01:00
Sebastian Kürten
e313f61b9e Add settings item for settings screen 2020-12-14 11:02:49 +01:00
akwizgran
5ca24c0c10 Merge branch '1859-menu-item-for-disappearing-messages' into '804-self-destructing-messages'
Menu item to enable/disable disappearing messages

See merge request briar/briar!1321
2020-12-11 10:44:24 +00:00
Torsten Grote
a4ea1fd257 Allow setting a self-destruct timer
This is a rough prototype of #1837 meant to make testing the UI easier.
2020-12-10 20:52:08 +01:00
Torsten Grote
630b4ff561 Merge branch '1832-mirror-remote-self-destruct-timer' into '804-self-destructing-messages'
Mirror the contact's changes to the self-destruct timer

See merge request briar/briar!1312
2020-12-04 14:59:15 +00:00
akwizgran
45c205e4ba Use Collections.sort() to satisfy Animal Sniffer. 2020-12-04 12:16:58 +00:00
akwizgran
aff649cb06 Add integration tests for timer mirroring. 2020-12-04 12:10:43 +00:00
akwizgran
501ca326d7 Add method for UI and tests to get current timer. 2020-12-04 12:10:10 +00:00
Torsten Grote
0b2a581f81 Merge branch '1832-use-conversation-timestamp' into '804-self-destructing-messages'
Add integration tests for auto-delete timer

See merge request briar/briar!1315
2020-12-03 18:48:06 +00:00
akwizgran
04cdf27a1c Update integration tests. 2020-12-03 18:00:31 +00:00
akwizgran
6bac5b08ab Don't receive auto-delete timer from remote accept message as introducee. 2020-12-03 17:58:50 +00:00
akwizgran
482c90a45e Hook up incoming messages to the auto-delete manager. 2020-12-03 17:58:50 +00:00
akwizgran
c042b1c6d0 Mirror the remote auto-delete timer. 2020-12-03 17:58:50 +00:00
akwizgran
df43a3d461 Add integration tests for auto-delete timer. 2020-12-03 17:58:10 +00:00
akwizgran
1f73137e52 Merge branch '1832-use-conversation-timestamp' into '804-self-destructing-messages'
Use latest conversation timestamp for all invitation/introduction messages

See merge request briar/briar!1310
2020-12-03 17:32:33 +00:00
Torsten Grote
e662d942f0 Merge branch '804-send-current-minor-version' into '804-self-destructing-messages'
Send current minor version of messaging client to contacts

See merge request briar/briar!1314
2020-12-03 17:24:34 +00:00
akwizgran
6c6c3ab3a8 Forwarded accept messages aren't visible to the introducee. 2020-12-03 17:12:52 +00:00
akwizgran
b8b8894f48 Only use conversation timestamp for messages that will be visible in conversation. 2020-12-03 16:33:55 +00:00
akwizgran
c9ad852aee Send current minor version of messaging client to contacts. 2020-12-03 14:15:12 +00:00
akwizgran
9d0c894fce Merge branch '1838-bomb' into '804-self-destructing-messages'
Show a bomb icon on messages with self-destruct timers

See merge request briar/briar!1313
2020-12-03 14:00:33 +00:00
Torsten Grote
2e3335ef66 Show bomb icon for messages with auto-destruct timer 2020-12-03 10:21:08 -03:00
Torsten Grote
dd216890ed Merge branch '1832-store-self-destruct-timer' into '804-self-destructing-messages'
Store local self-destruct timer duration

See merge request briar/briar!1307
2020-12-02 13:34:30 +00:00
akwizgran
238512e9bf Get timestamp for abort message in same way as other messages. 2020-12-02 11:55:52 +00:00
akwizgran
ae41e1f780 Look up auto-delete timer when creating private group invitation. 2020-12-02 11:30:54 +00:00
akwizgran
2b41700fa7 Use the right timestamp when signing private group invitation. 2020-12-02 11:08:58 +00:00
akwizgran
18f98766db Provide TransactionManager. 2020-12-01 17:38:49 +00:00
akwizgran
7e6871149b Look up conversation timestamp when creating group invitation messages. 2020-12-01 17:21:09 +00:00
akwizgran
524d6a93f1 Move lookup of latest conversation timestamp to core for blog and forum sharing. 2020-12-01 16:21:06 +00:00
akwizgran
67b9ebff8e Move lookup of latest conversation timestamp to core. 2020-12-01 16:02:42 +00:00
akwizgran
d559e821ca Add transactional variant of getGroupCount(). 2020-11-30 09:49:07 +00:00
akwizgran
d829c25717 Check that timer argument is legal before storing. 2020-11-26 13:45:58 +00:00
akwizgran
433e4e79ae Add unit tests for AutoDeleteManagerImpl. 2020-11-26 13:45:41 +00:00
akwizgran
647f179016 Implement AutoDeleteManager. 2020-11-26 13:15:01 +00:00
akwizgran
f57b16e9bf Add dummy implementation of AutoDeleteManager. 2020-11-26 12:16:34 +00:00
akwizgran
2430cc409f Refactor auto-delete code from Bramble to Briar. 2020-11-26 11:20:31 +00:00
akwizgran
8693546170 Merge branch '804-self-destructing-messages-refactoring' into '804-self-destructing-messages'
Factor out some duplicated client code

See merge request briar/briar!1304
2020-11-24 11:03:24 +00:00
akwizgran
7b97bb1f20 Rewrap lines. 2020-11-24 10:51:19 +00:00
Torsten Grote
92d04e0417 Merge branch '1831-self-destruct-timers-private-groups' into '804-self-destructing-messages'
Update private group sharing client to include a self-destruct timer in each message

See merge request briar/briar!1303
2020-11-23 17:52:20 +00:00
akwizgran
bab2b4594d Factor out methods for storing and retrieving contact ID. 2020-11-23 17:15:57 +00:00
akwizgran
029ddddd27 Factor out method for validating auto-delete timers. 2020-11-23 16:42:45 +00:00
akwizgran
3ee75643fc Update comments. 2020-11-23 16:29:06 +00:00
akwizgran
e88de213fb Add unit tests for validating auto-delete timer. 2020-11-23 16:17:36 +00:00
akwizgran
c26bad9f94 Update private group invitation client to include self-destruct timers. 2020-11-23 15:42:39 +00:00
akwizgran
bce1ce0a81 Merge branch '1830-self-destruct-timer-blogs-forums' into '804-self-destructing-messages'
Update blog and forum sharing clients to include self-destruct timers

See merge request briar/briar!1302
2020-11-23 13:56:16 +00:00
akwizgran
1601a85ad1 Merge branch '1829-self-destruct-timer-introductions' into '804-self-destructing-messages'
Update introduction client to include a self-destruct timer in each message

See merge request briar/briar!1300
2020-11-20 17:14:57 +00:00
akwizgran
b6b1bdbf82 Update blog and forum sharing clients to include self-destruct timers. 2020-11-20 17:08:55 +00:00
akwizgran
28ecece34d Update message parsing and encoding to include auto-delete timer. 2020-11-19 17:26:52 +00:00
Torsten Grote
f9e6b3ed3a Merge branch '1828-self-destruct-timer-private-messages' into '804-self-destructing-messages'
Update messaging client to include a self-destruct timer in each message

See merge request briar/briar!1299
2020-11-19 16:57:51 +00:00
akwizgran
28cd086972 Update introduction validator to support auto-delete timers. 2020-11-19 16:10:51 +00:00
akwizgran
3b6b77ccf5 Add constant for NO_AUTO_DELETE_TIMER, address review comments. 2020-11-19 15:58:33 +00:00
akwizgran
dd9c6697b2 Add unit tests for private message validation. 2020-11-19 13:40:51 +00:00
akwizgran
228907543e Fix comments in PrivateMessageValidator. 2020-11-19 13:29:57 +00:00
akwizgran
b477962321 Add integration test for auto-delete timer in private messages. 2020-11-19 13:12:02 +00:00
akwizgran
98b0f64785 Add auto-deletion timer to private messages. 2020-11-19 12:57:07 +00:00
Torsten Grote
8d735b3023 Merge branch 'tor-0.3.5.12' into 'master'
Upgrade Tor to 0.3.5.12

Closes #1849

See merge request briar/briar!1298
2020-11-16 14:42:30 +00:00
akwizgran
b24a0e4bc3 Upgrade Tor to 0.3.5.12. 2020-11-16 13:29:24 +00:00
akwizgran
07da91a6f5 Merge branch 'gradle-plugin-4.1' into 'master'
Upgrade Gradle plugin to 4.1.1

See merge request briar/briar!1296
2020-11-11 17:45:47 +00:00
akwizgran
e4e0e712dc Update translations. 2020-11-11 16:59:08 +00:00
Torsten Grote
9294794448 Merge branch '1841-keep-dependency-injection-annotations' into 'master'
Keep dependency injection annotations at runtime

Closes #1841

See merge request briar/briar!1297
2020-11-11 16:54:44 +00:00
akwizgran
5a9958793d Keep dependency injection annotations at runtime. 2020-11-11 16:43:16 +00:00
akwizgran
651d2ca377 Add comment to explain suppressed warning. 2020-11-11 14:22:20 +00:00
akwizgran
ecd64f08cd Upgrade Gradle plugin to 4.1.1. 2020-11-11 12:33:36 +00:00
akwizgran
f3bffb6aa6 Fix some more lint errors. 2020-11-10 17:48:48 +00:00
akwizgran
33331dee3e Fix some lint errors and warnings. 2020-11-10 17:30:53 +00:00
akwizgran
641525fa74 Upgrade Android and Kotlin dependencies, Gradle Witness. 2020-11-10 16:57:51 +00:00
akwizgran
4b82079e33 Upgrade Gradle plugin to 4.1. 2020-11-10 15:18:50 +00:00
akwizgran
caa55ffa14 Merge branch 'android-studio-4.1-update-run-configurations' into 'master'
Update run configurations for Android Studio 4.1

See merge request briar/briar!1295
2020-11-09 13:49:28 +00:00
akwizgran
47ae594921 Update run configurations for Android Studio 4.1. 2020-11-09 12:43:29 +00:00
akwizgran
a17b154024 Update translations. 2020-11-09 12:42:13 +00:00
267 changed files with 5843 additions and 2208 deletions

View File

@@ -31,6 +31,15 @@
<option name="PACKAGES_TO_USE_STAR_IMPORTS"> <option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value /> <value />
</option> </option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" /> <option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" /> <option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />

View File

@@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests" type="AndroidJUnit" factoryName="Android JUnit"> <configuration default="false" name="All tests" type="AndroidJUnit" factoryName="Android JUnit">
<module name="briar-android" /> <module name="briar.briar-android" />
<option name="PACKAGE_NAME" value="" /> <option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" /> <option name="METHOD_NAME" value="" />

View File

@@ -1,20 +1,14 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-android" type="AndroidJUnit" factoryName="Android JUnit"> <configuration default="false" name="All tests in bramble-android" type="AndroidJUnit" factoryName="Android JUnit">
<module name="bramble-android" /> <module name="briar.bramble-android" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" /> <option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" /> <option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" /> <option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" /> <option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-android" /> <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-android" />
<option name="PASS_PARENT_ENVS" value="true" /> <method v="2">
<option name="TEST_SEARCH_SCOPE"> <option name="Android.Gradle.BeforeRunTask" enabled="true" />
<value defaultName="singleModule" /> </method>
</option>
<patterns />
<method />
</configuration> </configuration>
</component> </component>

View File

@@ -1,20 +1,14 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-api" type="AndroidJUnit" factoryName="Android JUnit"> <configuration default="false" name="All tests in bramble-api" type="AndroidJUnit" factoryName="Android JUnit">
<module name="bramble-api" /> <module name="briar.bramble-api" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" /> <option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" /> <option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" /> <option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" /> <option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-api" /> <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-api" />
<option name="PASS_PARENT_ENVS" value="true" /> <method v="2">
<option name="TEST_SEARCH_SCOPE"> <option name="Android.Gradle.BeforeRunTask" enabled="true" />
<value defaultName="singleModule" /> </method>
</option>
<patterns />
<method />
</configuration> </configuration>
</component> </component>

View File

@@ -1,20 +1,14 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-core" type="AndroidJUnit" factoryName="Android JUnit"> <configuration default="false" name="All tests in bramble-core" type="AndroidJUnit" factoryName="Android JUnit">
<module name="bramble-core" /> <module name="briar.bramble-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" /> <option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" /> <option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" /> <option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" /> <option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-core" /> <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-core" />
<option name="PASS_PARENT_ENVS" value="true" /> <method v="2">
<option name="TEST_SEARCH_SCOPE"> <option name="Android.Gradle.BeforeRunTask" enabled="true" />
<value defaultName="singleModule" /> </method>
</option>
<patterns />
<method />
</configuration> </configuration>
</component> </component>

View File

@@ -1,8 +1,6 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in bramble-java" type="AndroidJUnit" factoryName="Android JUnit"> <configuration default="false" name="All tests in bramble-java" type="AndroidJUnit" factoryName="Android JUnit">
<module name="bramble-java" /> <module name="briar.bramble-java" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" /> <option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" /> <option name="METHOD_NAME" value="" />
@@ -10,11 +8,8 @@
<option name="VM_PARAMETERS" value="-ea -Djava.library.path=libs" /> <option name="VM_PARAMETERS" value="-ea -Djava.library.path=libs" />
<option name="PARAMETERS" value="" /> <option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-java" /> <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/bramble-java" />
<option name="PASS_PARENT_ENVS" value="true" /> <method v="2">
<option name="TEST_SEARCH_SCOPE"> <option name="Android.Gradle.BeforeRunTask" enabled="true" />
<value defaultName="singleModule" /> </method>
</option>
<patterns />
<method />
</configuration> </configuration>
</component> </component>

View File

@@ -1,20 +1,14 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-android" type="AndroidJUnit" factoryName="Android JUnit"> <configuration default="false" name="All tests in briar-android" type="AndroidJUnit" factoryName="Android JUnit">
<module name="briar-android" /> <module name="briar.briar-android" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" /> <option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" /> <option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" /> <option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" /> <option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-android" /> <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-android" />
<option name="PASS_PARENT_ENVS" value="true" /> <method v="2">
<option name="TEST_SEARCH_SCOPE"> <option name="Android.Gradle.BeforeRunTask" enabled="true" />
<value defaultName="singleModule" /> </method>
</option>
<patterns />
<method />
</configuration> </configuration>
</component> </component>

View File

@@ -1,20 +1,14 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-core" type="AndroidJUnit" factoryName="Android JUnit"> <configuration default="false" name="All tests in briar-core" type="AndroidJUnit" factoryName="Android JUnit">
<module name="briar-core" /> <module name="briar.briar-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="" /> <option name="PACKAGE_NAME" value="" />
<option name="MAIN_CLASS_NAME" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" /> <option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="package" /> <option name="TEST_OBJECT" value="package" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" /> <option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-core" /> <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/briar-core" />
<option name="PASS_PARENT_ENVS" value="true" /> <method v="2">
<option name="TEST_SEARCH_SCOPE"> <option name="Android.Gradle.BeforeRunTask" enabled="true" />
<value defaultName="singleModule" /> </method>
</option>
<patterns />
<method />
</configuration> </configuration>
</component> </component>

View File

@@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests in briar-headless" type="AndroidJUnit" factoryName="Android JUnit"> <configuration default="false" name="All tests in briar-headless" type="AndroidJUnit" factoryName="Android JUnit">
<module name="briar-headless" /> <module name="briar.briar-headless" />
<option name="PACKAGE_NAME" value="org.briarproject.briar.headless" /> <option name="PACKAGE_NAME" value="org.briarproject.briar.headless" />
<option name="MAIN_CLASS_NAME" value="" /> <option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" /> <option name="METHOD_NAME" value="" />

View File

@@ -1,20 +1,14 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="H2 Performance Test" type="AndroidJUnit" factoryName="Android JUnit"> <configuration default="false" name="H2 Performance Test" type="AndroidJUnit" factoryName="Android JUnit">
<module name="bramble-core" /> <module name="briar.bramble-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="org.briarproject.bramble.db" /> <option name="PACKAGE_NAME" value="org.briarproject.bramble.db" />
<option name="MAIN_CLASS_NAME" value="org.briarproject.bramble.db.H2DatabasePerformanceTest" /> <option name="MAIN_CLASS_NAME" value="org.briarproject.bramble.db.H2DatabasePerformanceTest" />
<option name="METHOD_NAME" value="" /> <option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" /> <option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" /> <option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="" /> <option name="WORKING_DIRECTORY" value="" />
<option name="PASS_PARENT_ENVS" value="true" /> <method v="2">
<option name="TEST_SEARCH_SCOPE"> <option name="Android.Gradle.BeforeRunTask" enabled="true" />
<value defaultName="singleModule" /> </method>
</option>
<patterns />
<method />
</configuration> </configuration>
</component> </component>

View File

@@ -1,20 +1,14 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="HyperSQL Performance Test" type="AndroidJUnit" factoryName="Android JUnit"> <configuration default="false" name="HyperSQL Performance Test" type="AndroidJUnit" factoryName="Android JUnit">
<module name="bramble-core" /> <module name="briar.bramble-core" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="PACKAGE_NAME" value="org.briarproject.bramble.db" /> <option name="PACKAGE_NAME" value="org.briarproject.bramble.db" />
<option name="MAIN_CLASS_NAME" value="org.briarproject.bramble.db.HyperSqlDatabasePerformanceTest" /> <option name="MAIN_CLASS_NAME" value="org.briarproject.bramble.db.HyperSqlDatabasePerformanceTest" />
<option name="METHOD_NAME" value="" /> <option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" /> <option name="TEST_OBJECT" value="class" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" /> <option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="" /> <option name="WORKING_DIRECTORY" value="" />
<option name="PASS_PARENT_ENVS" value="true" /> <method v="2">
<option name="TEST_SEARCH_SCOPE"> <option name="Android.Gradle.BeforeRunTask" enabled="true" />
<value defaultName="singleModule" /> </method>
</option>
<patterns />
<method />
</configuration> </configuration>
</component> </component>

View File

@@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="briar-headless" type="JetRunConfigurationType" factoryName="Kotlin" singleton="true"> <configuration default="false" name="briar-headless" type="JetRunConfigurationType" singleton="true">
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" /> <module name="briar.briar-headless" />
<option name="VM_PARAMETERS" value="" /> <option name="VM_PARAMETERS" value="" />
<option name="PROGRAM_PARAMETERS" value="-v" /> <option name="PROGRAM_PARAMETERS" value="-v" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
@@ -8,9 +8,8 @@
<option name="PASS_PARENT_ENVS" value="true" /> <option name="PASS_PARENT_ENVS" value="true" />
<option name="MAIN_CLASS_NAME" value="org.briarproject.briar.headless.MainKt" /> <option name="MAIN_CLASS_NAME" value="org.briarproject.briar.headless.MainKt" />
<option name="WORKING_DIRECTORY" value="" /> <option name="WORKING_DIRECTORY" value="" />
<module name="briar-headless" /> <method v="2">
<envs /> <option name="Make" enabled="true" />
<method>
<option name="Gradle.BeforeRunTask" enabled="true" tasks="jar" externalProjectPath="$PROJECT_DIR$/briar-headless" vmOptions="" scriptParameters="" /> <option name="Gradle.BeforeRunTask" enabled="true" tasks="jar" externalProjectPath="$PROJECT_DIR$/briar-headless" vmOptions="" scriptParameters="" />
</method> </method>
</configuration> </configuration>

View File

@@ -38,7 +38,7 @@ configurations {
dependencies { dependencies {
implementation project(path: ':bramble-core', configuration: 'default') implementation project(path: ':bramble-core', configuration: 'default')
tor 'org.briarproject:tor-android:0.3.5.10@zip' tor 'org.briarproject:tor-android:0.3.5.12@zip'
tor 'org.briarproject:obfs4proxy-android:0.0.11-2@zip' tor 'org.briarproject:obfs4proxy-android:0.0.11-2@zip'
annotationProcessor 'com.google.dagger:dagger-compiler:2.24' annotationProcessor 'com.google.dagger:dagger-compiler:2.24'

View File

@@ -1,33 +1,36 @@
dependencyVerification { dependencyVerification {
verify = [ verify = [
'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861', 'cglib:cglib:3.2.0:cglib-3.2.0.jar:adb13bab79712ad6bdf1bd59f2a3918018a8016e722e8a357065afb9e6690861',
'com.android.tools.analytics-library:protos:26.5.1:protos-26.5.1.jar:8dde1130725461fe827f2a343d353f2b51e8870661fc860d7d5ebddb097ead4e', 'com.android.tools.analytics-library:protos:27.1.1:protos-27.1.1.jar:13f77e73762e58ab372d140b3a6be6903aea9775b62dd14fbc62d4cc7069c9a4',
'com.android.tools.analytics-library:shared:26.5.1:shared-26.5.1.jar:ccc2f3b00ec17b11401610ba68553544fc8fc517120e84439ac6eb86b875e18d', 'com.android.tools.analytics-library:shared:27.1.1:shared-27.1.1.jar:82930a52001410e97d809930b670f4de3002286975f046b9de5f6b777b06d366',
'com.android.tools.analytics-library:tracker:26.5.1:tracker-26.5.1.jar:3a76984c0fe2e847ca7a8b35b4780ef0447a9d1666946cb8e60466318e0ab5ae', 'com.android.tools.analytics-library:tracker:27.1.1:tracker-27.1.1.jar:31bc5a00be0055bac89c9b2f34751883e987cd89e3ac1783720645c164f591d9',
'com.android.tools.build:aapt2-proto:0.4.0:aapt2-proto-0.4.0.jar:fac0435e08898f89eeeb9ca236bea707155ff816c12205ced285ad53604133ca', 'com.android.tools.build:aapt2-proto:4.1.0-alpha01-6193524:aapt2-proto-4.1.0-alpha01-6193524.jar:17e75523e1e92dd4f222c7368ee41df9e964a508232f591e265d0c499baf9dca',
'com.android.tools.build:apksig:3.5.1:apksig-3.5.1.jar:1fd33e7f009a2a0da766cfeec4211a09f548034b015c289a66d75dd8a9302f4a', 'com.android.tools.build:apksig:4.1.1:apksig-4.1.1.jar:e0a69da9e5a03986d608b45bbf954ef0e6a0b3f58c1b8315bd169ec08b279e72',
'com.android.tools.build:apkzlib:3.5.1:apkzlib-3.5.1.jar:9f330167cbe973b7db407692f74f4f6453b7ffa5f2048934b06280c2ceee60fa', 'com.android.tools.build:apkzlib:4.1.1:apkzlib-4.1.1.jar:ba4b5e419b6be0130eae7f8301c3a551ad3976f487d2e0c6852ebb175ac41127',
'com.android.tools.build:builder-model:3.5.1:builder-model-3.5.1.jar:39ea3c82b76b6e0c9f9fa88d93e0edc1dd4a0f1dfae0ef6fbf2d451da47e5450', 'com.android.tools.build:builder-model:4.1.1:builder-model-4.1.1.jar:e95c99cc298ad67b8deb6ced99c51abc8f59afebedad044b1a10dde14646a4dd',
'com.android.tools.build:builder-test-api:3.5.1:builder-test-api-3.5.1.jar:a1b59305584cbcaa078fdc9cfb80871012755b822dd32e8da19add6f7bbcb762', 'com.android.tools.build:builder-test-api:4.1.1:builder-test-api-4.1.1.jar:464f596ab261c051c3847406748e843770dea123f6fa5fee8a9390644e709b7a',
'com.android.tools.build:builder:3.5.1:builder-3.5.1.jar:e3a8d382434c5f60990730c4719fc814e85a898a33a1e96c1df8d627d3c6eea6', 'com.android.tools.build:builder:4.1.1:builder-4.1.1.jar:0f78d4759d2f7b57b95865522ec34596ba419b9982f3b25e3449213f9c98b80d',
'com.android.tools.build:gradle-api:3.5.1:gradle-api-3.5.1.jar:be9b41859bace11998f66b04ed944f87e413f3ad6da3c4665587699da125addc', 'com.android.tools.build:gradle-api:4.1.1:gradle-api-4.1.1.jar:d42e6b539e4c1353ad3546e75ec8ce11a017b97481023e8ea18577eefe374358',
'com.android.tools.build:manifest-merger:26.5.1:manifest-merger-26.5.1.jar:dcad9ecb967251f4d750f55a4204a2b400e8fbfe5cb930a1d0d5dbe10ae8bdfc', 'com.android.tools.build:manifest-merger:27.1.1:manifest-merger-27.1.1.jar:7a45fa143687859bb2e5a961dcf6ee88094d3853de0cb543dc03dbcb0f4b554b',
'com.android.tools.ddms:ddmlib:26.5.1:ddmlib-26.5.1.jar:b081aef2a4ed3f4d47cae4cdb128469735f25a114e026d37123bf9ffdec742a8', 'com.android.tools.ddms:ddmlib:27.1.1:ddmlib-27.1.1.jar:da6e4bd834b6a85dae8019039849d8bd96933347dfbf460df74913ddade6e40a',
'com.android.tools.external.com-intellij:intellij-core:26.5.1:intellij-core-26.5.1.jar:20eced30adc124805bd93488d9cd9d3e33e6bf7b48e9fe5a703d4983f894d450', 'com.android.tools.external.com-intellij:intellij-core:27.1.1:intellij-core-27.1.1.jar:2591a7363c4443c59bf9f793730acafce9d6ec3076e2f46716edaf53a41b6fb6',
'com.android.tools.external.com-intellij:kotlin-compiler:26.5.1:kotlin-compiler-26.5.1.jar:5aed762dd54875b77ae7018d97c05756ff0c5b9fd02ec595dd396ccd14cc22cb', 'com.android.tools.external.com-intellij:kotlin-compiler:27.1.1:kotlin-compiler-27.1.1.jar:5054ae770ba788f110303c65abd6b1fa28eccf52dee1274510e201b2b81885c8',
'com.android.tools.external.org-jetbrains:uast:26.5.1:uast-26.5.1.jar:4bc8653d6c0943f40fee963a149e36c6baa45683d2530968a13f5007e3c40740', 'com.android.tools.external.org-jetbrains:uast:27.1.1:uast-27.1.1.jar:54cd8f6886a9d2f5641659dd5c91f626629672cd48301f7f0bd6aad9bd448714',
'com.android.tools.layoutlib:layoutlib-api:26.5.1:layoutlib-api-26.5.1.jar:88732f11396c427273e515d23042e35633f4fe4295528a99b866aa2adf0efd9c', 'com.android.tools.layoutlib:layoutlib-api:27.1.1:layoutlib-api-27.1.1.jar:8a9a22e3b309521ea83b724e5a89cfdac6076f52d675c0e17d77b05527bc0f8c',
'com.android.tools.lint:lint-api:26.5.1:lint-api-26.5.1.jar:ec33fcd72bfaf70dd841e03fbfd93f109c2e575aec146067c606689c3972f0de', 'com.android.tools.lint:lint-api:27.1.1:lint-api-27.1.1.jar:c1d8176094cb0478786070d40533efb578ebc53529a82f6ef5bee879bdca418b',
'com.android.tools.lint:lint-checks:26.5.1:lint-checks-26.5.1.jar:a1b9607d484aaae7a71dcecdc76f8003d8239af226c776894a2cf63f9e6c60d7', 'com.android.tools.lint:lint-checks:27.1.1:lint-checks-27.1.1.jar:3899c91e00bd059b40c31a9ca00cd0f8303191947608735ae1b657323693fb61',
'com.android.tools.lint:lint-gradle-api:26.5.1:lint-gradle-api-26.5.1.jar:82453fd98a8394cc84ed995c04d2cd744abd1d6589403427ba7eef53115406f3', 'com.android.tools.lint:lint-gradle-api:27.1.1:lint-gradle-api-27.1.1.jar:26aa89d38b9825cc73229daa82a68875801c8b8491f30497ce62aff1f206eb0d',
'com.android.tools.lint:lint-gradle:26.5.1:lint-gradle-26.5.1.jar:59465b56cf7db77c656d5f8195d721c3d48b6bdd0502d774de335bfe4baff00b', 'com.android.tools.lint:lint-gradle:27.1.1:lint-gradle-27.1.1.jar:f7355823ead869f4d28184ba28b7a0c693b507519a2d3705bb9848a0f35b3756',
'com.android.tools.lint:lint:26.5.1:lint-26.5.1.jar:336e4b04ec6f8b0f25879131b7a7862d77df83a1879ee5b71be26128755f8e2e', 'com.android.tools.lint:lint-model:27.1.1:lint-model-27.1.1.jar:bc23c0c413bdfca59dac2cd56b870d8360d009e9ec0d365e71f774bcf127971d',
'com.android.tools:annotations:26.5.1:annotations-26.5.1.jar:2c43c82f8c59d8f7a61e3239e1a2dc9f69dc342ec09af9b7c9f69b25337c0b6e', 'com.android.tools.lint:lint:27.1.1:lint-27.1.1.jar:2f6038a5398a42bd591883c3f5e5894f4ec52ca1c3683bf94fa8553c1700af81',
'com.android.tools:common:26.5.1:common-26.5.1.jar:eccfa54486ed54c4e3123cc42195d023bd0dd21bcd2f0e4868e8c6fc70f8ef6b', 'com.android.tools:annotations:27.1.1:annotations-27.1.1.jar:ff28c504d2acb9fd1a5ffbd97ae85cf59ee18c76927525aad250509bccf2cab1',
'com.android.tools:dvlib:26.5.1:dvlib-26.5.1.jar:46f93ad498b4756e7d867d2fe38c38890a80e7407a4ae459e4a8c8d5c5aeacfe', 'com.android.tools:common:27.1.1:common-27.1.1.jar:63d9a2a9ad6d278db319f3749b9f50bdf5457ef7020074a1bebe124e714b535c',
'com.android.tools:repository:26.5.1:repository-26.5.1.jar:2b3ee791aa4c3e8ce60498c161a27ca7228816fc630eed4d9f25f2f36a106dce', 'com.android.tools:dvlib:27.1.1:dvlib-27.1.1.jar:998a54201fc1cefee5f2399215e95c42b1f64f9e1d8f4452eb8255c68ba5440f',
'com.android.tools:sdk-common:26.5.1:sdk-common-26.5.1.jar:365f749676c3574676fd465177c8a492f340816db2b520d6ed114d3b6e77bea7', 'com.android.tools:repository:27.1.1:repository-27.1.1.jar:d25b74ccabf4d876903efb375e9af6fb380d8ae0445bb74bbdcc225c1e37fa1d',
'com.android.tools:sdklib:26.5.1:sdklib-26.5.1.jar:007da104afb27c8c682a1628023fe9ec438249c8d15ef0fd6624c5bb8e23b696', 'com.android.tools:sdk-common:27.1.1:sdk-common-27.1.1.jar:4473ae97d0ef7061ee1de61041d5aa97405ae08e44c09cf7bb278b42e4b97c7c',
'com.android.tools:sdklib:27.1.1:sdklib-27.1.1.jar:08e6b83961ac9724b3c1e3d0eff971f13be6701292c77914b8794480f3391250',
'com.android:signflinger:4.1.1:signflinger-4.1.1.jar:0c66825988873ec2d51057fa463f54a8f18fc7326ff4530b9da363b71e97ce60',
'com.android:zipflinger:4.1.1:zipflinger-4.1.1.jar:0a8c3e52ac13dd031236f9fb5ba4408b1d5dcd12325a05440b36da09d8881446',
'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7', 'com.google.code.findbugs:jsr305:3.0.2:jsr305-3.0.2.jar:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7',
'com.google.code.gson:gson:2.8.5:gson-2.8.5.jar:233a0149fc365c9f6edbd683cfe266b19bdc773be98eabdaf6b3c924b48e7d81', 'com.google.code.gson:gson:2.8.5:gson-2.8.5.jar:233a0149fc365c9f6edbd683cfe266b19bdc773be98eabdaf6b3c924b48e7d81',
'com.google.dagger:dagger-compiler:2.24:dagger-compiler-2.24.jar:3c5afb955fb188da485cb2c048eff37dce0e1530b9780a0f2f7187d16d1ccc1f', 'com.google.dagger:dagger-compiler:2.24:dagger-compiler-2.24.jar:3c5afb955fb188da485cb2c048eff37dce0e1530b9780a0f2f7187d16d1ccc1f',
@@ -35,27 +38,30 @@ dependencyVerification {
'com.google.dagger:dagger-spi:2.24:dagger-spi-2.24.jar:c038445d14dbcb4054e61bf49e05009edf26fce4fdc7ec1a9db544784f68e718', 'com.google.dagger:dagger-spi:2.24:dagger-spi-2.24.jar:c038445d14dbcb4054e61bf49e05009edf26fce4fdc7ec1a9db544784f68e718',
'com.google.dagger:dagger:2.24:dagger-2.24.jar:550a6e46a6dfcdf1d764887b6090cea94f783327e50e5c73754f18facfc70b64', 'com.google.dagger:dagger:2.24:dagger-2.24.jar:550a6e46a6dfcdf1d764887b6090cea94f783327e50e5c73754f18facfc70b64',
'com.google.errorprone:error_prone_annotations:2.2.0:error_prone_annotations-2.2.0.jar:6ebd22ca1b9d8ec06d41de8d64e0596981d9607b42035f9ed374f9de271a481a', 'com.google.errorprone:error_prone_annotations:2.2.0:error_prone_annotations-2.2.0.jar:6ebd22ca1b9d8ec06d41de8d64e0596981d9607b42035f9ed374f9de271a481a',
'com.google.errorprone:error_prone_annotations:2.3.2:error_prone_annotations-2.3.2.jar:357cd6cfb067c969226c442451502aee13800a24e950fdfde77bcdb4565a668d',
'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30', 'com.google.errorprone:javac-shaded:9-dev-r4023-3:javac-shaded-9-dev-r4023-3.jar:65bfccf60986c47fbc17c9ebab0be626afc41741e0a6ec7109e0768817a36f30',
'com.google.googlejavaformat:google-java-format:1.5:google-java-format-1.5.jar:aa19ad7850fb85178aa22f2fddb163b84d6ce4d0035872f30d4408195ca1144e', '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:failureaccess:1.0.1:failureaccess-1.0.1.jar:a171ee4c734dd2da837e4b16be9df4661afab72a41adaf31eb84dfdaf936ca26',
'com.google.guava:guava:27.0.1-jre:guava-27.0.1-jre.jar:e1c814fd04492a27c38e0317eabeaa1b3e950ec8010239e400fe90ad6c9107b4',
'com.google.guava:guava:27.1-jre:guava-27.1-jre.jar:4a5aa70cc968a4d137e599ad37553e5cfeed2265e8c193476d7119036c536fe7', 'com.google.guava:guava:27.1-jre:guava-27.1-jre.jar:4a5aa70cc968a4d137e599ad37553e5cfeed2265e8c193476d7119036c536fe7',
'com.google.guava:guava:28.1-jre:guava-28.1-jre.jar:30beb8b8527bd07c6e747e77f1a92122c2f29d57ce347461a4a55eb26e382da4',
'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava:listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99', 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava:listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99',
'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:2994a7eb78f2710bd3d3bfb639b2c94e219cedac0d4d084d516e78c16dddecf6', 'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:2994a7eb78f2710bd3d3bfb639b2c94e219cedac0d4d084d516e78c16dddecf6',
'com.google.j2objc:j2objc-annotations:1.3:j2objc-annotations-1.3.jar:21af30c92267bd6122c0e0b4d20cccb6641a37eaf956c6540ec471d584e64a7b',
'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd', 'com.google.jimfs:jimfs:1.1:jimfs-1.1.jar:c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd',
'com.google.protobuf:protobuf-java:3.4.0:protobuf-java-3.4.0.jar:dce7e66b32456a1b1198da0caff3a8acb71548658391e798c79369241e6490a4', 'com.google.protobuf:protobuf-java:3.10.0:protobuf-java-3.10.0.jar:161d7d61a8cb3970891c299578702fd079646e032329d6c2cabf998d191437c9',
'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439', 'com.googlecode.json-simple:json-simple:1.1:json-simple-1.1.jar:2d9484f4c649f708f47f9a479465fc729770ee65617dca3011836602264f6439',
'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90', 'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90',
'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0', 'com.squareup:javawriter:2.5.0:javawriter-2.5.0.jar:fcfb09fb0ea0aa97d3cfe7ea792398081348e468f126b3603cb3803f240197f0',
'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce', 'com.sun.activation:javax.activation:1.2.0:javax.activation-1.2.0.jar:993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce',
'com.sun.istack:istack-commons-runtime:2.21:istack-commons-runtime-2.21.jar:c33e67a0807095f02a0e2da139412dd7c4f9cc1a4c054b3e434f96831ba950f4', 'com.sun.istack:istack-commons-runtime:3.0.7:istack-commons-runtime-3.0.7.jar:6443e10ba2e259fb821d9b6becf10db5316285fc30c53cec9d7b19a3877e7fdf',
'com.sun.xml.fastinfoset:FastInfoset:1.2.13:FastInfoset-1.2.13.jar:27a77db909f3c2833c0b1a37c55af1db06045118ad2eed96ce567b6632bce038', 'com.sun.xml.fastinfoset:FastInfoset:1.2.15:FastInfoset-1.2.15.jar:785861db11ca1bd0d1956682b974ad73eb19cd3e01a4b3fa82d62eca97210aec',
'commons-codec:commons-codec:1.10:commons-codec-1.10.jar:4241dfa94e711d435f29a4604a3e2de5c4aa3c165e23bd066be6fc1fc4309569', 'commons-codec:commons-codec:1.10:commons-codec-1.10.jar:4241dfa94e711d435f29a4604a3e2de5c4aa3c165e23bd066be6fc1fc4309569',
'commons-logging:commons-logging:1.2:commons-logging-1.2.jar:daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636', 'commons-logging:commons-logging:1.2:commons-logging-1.2.jar:daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636',
'it.unimi.dsi:fastutil:7.2.0:fastutil-7.2.0.jar:74fa208043740642f7e6eb09faba15965218ad2f50ce3020efb100136e4b591c', 'it.unimi.dsi:fastutil:7.2.0:fastutil-7.2.0.jar:74fa208043740642f7e6eb09faba15965218ad2f50ce3020efb100136e4b591c',
'javax.activation:javax.activation-api:1.2.0:javax.activation-api-1.2.0.jar:43fdef0b5b6ceb31b0424b208b930c74ab58fac2ceeb7b3f6fd3aeb8b5ca4393',
'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f', 'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f',
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', 'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'javax.xml.bind:jaxb-api:2.2.12-b140109.1041:jaxb-api-2.2.12-b140109.1041.jar:b5e60cd8b7b5ff01ce4a74c5dd008f4fbd14ced3495d0b47b85cfedc182211f2', 'javax.xml.bind:jaxb-api:2.3.1:jaxb-api-2.3.1.jar:88b955a0df57880a26a74708bc34f74dcaf8ebf4e78843a28b50eae945732b06',
'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a', 'junit:junit:4.12:junit-4.12.jar:59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a',
'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd', 'net.ltgt.gradle.incap:incap:0.2:incap-0.2.jar:b625b9806b0f1e4bc7a2e3457119488de3cd57ea20feedd513db070a573a4ffd',
'net.sf.jopt-simple:jopt-simple:4.9:jopt-simple-4.9.jar:26c5856e954b5f864db76f13b86919b59c6eecf9fd930b96baa8884626baf2f5', 'net.sf.jopt-simple:jopt-simple:4.9:jopt-simple-4.9.jar:26c5856e954b5f864db76f13b86919b59c6eecf9fd930b96baa8884626baf2f5',
@@ -70,34 +76,35 @@ dependencyVerification {
'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca', 'org.bouncycastle:bcpkix-jdk15on:1.56:bcpkix-jdk15on-1.56.jar:7043dee4e9e7175e93e0b36f45b1ec1ecb893c5f755667e8b916eb8dd201c6ca',
'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349', 'org.bouncycastle:bcprov-jdk15on:1.56:bcprov-jdk15on-1.56.jar:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349',
'org.briarproject:obfs4proxy-android:0.0.11-2:obfs4proxy-android-0.0.11-2.zip:57e55cbe87aa2aac210fdbb6cd8cdeafe15f825406a08ebf77a8b787aa2c6a8a', 'org.briarproject:obfs4proxy-android:0.0.11-2:obfs4proxy-android-0.0.11-2.zip:57e55cbe87aa2aac210fdbb6cd8cdeafe15f825406a08ebf77a8b787aa2c6a8a',
'org.briarproject:tor-android:0.3.5.10:tor-android-0.3.5.10.zip:edd83bf557fcff2105eaa0bdb3f607a6852ebe7360920929ae3039dd5f4774c5', 'org.briarproject:tor-android:0.3.5.12:tor-android-0.3.5.12.zip:db71fb3290acff79d572af0752570eaf6aad7c4d88c9b9aa0b4d5afe2b9ead9c',
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d', 'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a', 'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a',
'org.checkerframework:checker-qual:2.8.1:checker-qual-2.8.1.jar:9103499008bcecd4e948da29b17864abb64304e15706444ae209d17ebe0575df',
'org.codehaus.groovy:groovy-all:2.4.15:groovy-all-2.4.15.jar:51d6c4e71782e85674239189499854359d380fb75e1a703756e3aaa5b98a5af0', 'org.codehaus.groovy:groovy-all:2.4.15:groovy-all-2.4.15.jar:51d6c4e71782e85674239189499854359d380fb75e1a703756e3aaa5b98a5af0',
'org.codehaus.mojo:animal-sniffer-annotations:1.17:animal-sniffer-annotations-1.17.jar:92654f493ecfec52082e76354f0ebf87648dc3d5cec2e3c3cdb947c016747a53', 'org.codehaus.mojo:animal-sniffer-annotations:1.17:animal-sniffer-annotations-1.17.jar:92654f493ecfec52082e76354f0ebf87648dc3d5cec2e3c3cdb947c016747a53',
'org.glassfish.jaxb:jaxb-core:2.2.11:jaxb-core-2.2.11.jar:37bcaee8ebb04362c8352a5bf6221b86967ecdab5164c696b10b9a2bb587b2aa', 'org.codehaus.mojo:animal-sniffer-annotations:1.18:animal-sniffer-annotations-1.18.jar:47f05852b48ee9baefef80fa3d8cea60efa4753c0013121dd7fe5eef2e5c729d',
'org.glassfish.jaxb:jaxb-runtime:2.2.11:jaxb-runtime-2.2.11.jar:a874f2351cfba8e2946be3002d10c18a6da8f21b52ba2acf52f2b85d5520ed70', 'org.glassfish.jaxb:jaxb-runtime:2.3.1:jaxb-runtime-2.3.1.jar:45fecfa5c8217ce1f3652ab95179790ec8cc0dec0384bca51cbeb94a293d9f2f',
'org.glassfish.jaxb:txw2:2.2.11:txw2-2.2.11.jar:272a3ccad45a4511351920cd2a8633c53cab8d5220c7a92954da5526bb5eafea', 'org.glassfish.jaxb:txw2:2.3.1:txw2-2.3.1.jar:34975dde1c6920f1a39791142235689bc3cd357e24d05edd8ff93b885bd68d60',
'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9', 'org.hamcrest:hamcrest-core:1.3:hamcrest-core-1.3.jar:66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9',
'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c', 'org.hamcrest:hamcrest-library:1.3:hamcrest-library-1.3.jar:711d64522f9ec410983bd310934296da134be4254a125080a0416ec178dfad1c',
'org.jetbrains.kotlin:kotlin-reflect:1.3.50:kotlin-reflect-1.3.50.jar:64583199ea5a54aefd1bd1595288925f784226ee562d1dd279011c6075b3d7a4', 'org.jetbrains.kotlin:kotlin-reflect:1.3.72:kotlin-reflect-1.3.72.jar:a188d9367de1c4ee9479db630985c0597b20709c83161b1430d24edb27e38c40',
'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.50:kotlin-stdlib-common-1.3.50.jar:8ce678e88e4ba018b66dacecf952471e4d7dfee156a8a819760a5a5ff29d323c', 'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72:kotlin-stdlib-common-1.3.72.jar:5e7d1552863e480c1628b1cc39ce230ef829f5b7230106215a05acda5172203a',
'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.50:kotlin-stdlib-jdk7-1.3.50.jar:9a026639e76212f8d57b86d55b075394c2e009f1979110751d34c05c5f75d57b', 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72:kotlin-stdlib-jdk7-1.3.72.jar:40566c0c08d414b9413ba556ff7f8a0b04b98b9f0f424d122dd2088510efccc4',
'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.50:kotlin-stdlib-jdk8-1.3.50.jar:1b351fb6e09c14b55525c74c1f4cf48942eae43c348b7bc764a5e6e423d4da0c', 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72:kotlin-stdlib-jdk8-1.3.72.jar:133da70cfc07b56094282eac5c59bccd59f167ee2ead22e5282876d8bc10bf95',
'org.jetbrains.kotlin:kotlin-stdlib:1.3.50:kotlin-stdlib-1.3.50.jar:e6f05746ee0366d0b52825a090fac474dcf44082c9083bbb205bd16976488d6c', 'org.jetbrains.kotlin:kotlin-stdlib:1.3.72:kotlin-stdlib-1.3.72.jar:3856a7349ebacd6d1be6802b2fed9c4dc2c5a564ea92b6b945ac988243d4b16b',
'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7', 'org.jetbrains.trove4j:trove4j:20160824:trove4j-20160824.jar:1917871c8deb468307a584680c87a44572f5a8b0b98c6d397fc0f5f86596dbe7',
'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478', 'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478',
'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c', 'org.jmock:jmock-junit4:2.8.2:jmock-junit4-2.8.2.jar:f7ee4df4f7bd7b7f1cafad3b99eb74d579f109d5992ff625347352edb55e674c',
'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b', 'org.jmock:jmock-legacy:2.8.2:jmock-legacy-2.8.2.jar:f2b985a5c08a9edb7f37612330c058809da3f6a6d63ce792426ebf8ff0d6d31b',
'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760', 'org.jmock:jmock-testjar:2.8.2:jmock-testjar-2.8.2.jar:8900860f72c474e027cf97fe78dcbf154a1aa7fc62b6845c5fb4e4f3c7bc8760',
'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16', 'org.jmock:jmock:2.8.2:jmock-2.8.2.jar:6c73cb4a2e6dbfb61fd99c9a768539c170ab6568e57846bd60dbf19596b65b16',
'org.jvnet.staxex:stax-ex:1.7.7:stax-ex-1.7.7.jar:a31ff7d77163c0deb09e7fee59ad35ae44c2cee2cc8552a116ccd1583d813fb4', 'org.jvnet.staxex:stax-ex:1.8:stax-ex-1.8.jar:95b05d9590af4154c6513b9c5dc1fb2e55b539972ba0a9ef28e9a0c01d83ad77',
'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80', 'org.objenesis:objenesis:2.1:objenesis-2.1.jar:c74330cc6b806c804fd37e74487b4fe5d7c2750c5e15fbc6efa13bdee1bdef80',
'org.ow2.asm:asm-analysis:6.0:asm-analysis-6.0.jar:2f1a6387219c3a6cc4856481f221b03bd9f2408a326d416af09af5d6f608c1f4', 'org.ow2.asm:asm-analysis:7.0:asm-analysis-7.0.jar:e981f8f650c4d900bb033650b18e122fa6b161eadd5f88978d08751f72ee8474',
'org.ow2.asm:asm-commons:6.0:asm-commons-6.0.jar:f1bce5c648a96a017bdcd01fe5d59af9845297fd7b79b81c015a6fbbd9719abf', 'org.ow2.asm:asm-commons:7.0:asm-commons-7.0.jar:fed348ef05958e3e846a3ac074a12af5f7936ef3d21ce44a62c4fa08a771927d',
'org.ow2.asm:asm-tree:6.0:asm-tree-6.0.jar:887998fb69727c8759e4d253f856822801e33f9fd4caa566b3ac58ee92106215', 'org.ow2.asm:asm-tree:7.0:asm-tree-7.0.jar:cfd7a0874f9de36a999c127feeadfbfe6e04d4a71ee954d7af3d853f0be48a6c',
'org.ow2.asm:asm-util:6.0:asm-util-6.0.jar:356afebdb0f870175262e5188f8709a3b17aa2a5a6a4b0340b04d4b449bca5f6', 'org.ow2.asm:asm-util:7.0:asm-util-7.0.jar:75fbbca440ef463f41c2b0ab1a80abe67e910ac486da60a7863cbcb5bae7e145',
'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220', 'org.ow2.asm:asm:5.0.4:asm-5.0.4.jar:896618ed8ae62702521a78bc7be42b7c491a08e6920a15f89a3ecdec31e9a220',
'org.ow2.asm:asm:6.0:asm-6.0.jar:dd8971c74a4e697899a8e95caae4ea8760ea6c486dc6b97b1795e75760420461', 'org.ow2.asm:asm:7.0:asm-7.0.jar:b88ef66468b3c978ad0c97fd6e90979e56155b4ac69089ba7a44e9aa7ffe9acf',
] ]
} }

View File

@@ -1,25 +0,0 @@
package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Nullable;
/**
* An item that can be consumed once.
*/
@NotNullByDefault
public class Consumable<T> {
private final AtomicReference<T> reference;
public Consumable(T item) {
reference = new AtomicReference<>(item);
}
@Nullable
public T consume() {
return reference.getAndSet(null);
}
}

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.api.client; package org.briarproject.bramble.api.client;
import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.crypto.PrivateKey; import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey; import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfDictionary;
@@ -35,24 +36,24 @@ public interface ClientHelper {
Message createMessageForStoringMetadata(GroupId g); Message createMessageForStoringMetadata(GroupId g);
Message getSmallMessage(MessageId m) throws DbException; Message getMessage(MessageId m) throws DbException;
Message getSmallMessage(Transaction txn, MessageId m) throws DbException; Message getMessage(Transaction txn, MessageId m) throws DbException;
BdfList getSmallMessageAsList(MessageId m) BdfList getMessageAsList(MessageId m) throws DbException, FormatException;
throws DbException, FormatException;
BdfList getSmallMessageAsList(Transaction txn, MessageId m) BdfList getMessageAsList(Transaction txn, MessageId m) throws DbException,
throws DbException, FormatException; FormatException;
BdfDictionary getGroupMetadataAsDictionary(GroupId g) BdfDictionary getGroupMetadataAsDictionary(GroupId g) throws DbException,
throws DbException, FormatException; FormatException;
BdfDictionary getGroupMetadataAsDictionary(Transaction txn, GroupId g) BdfDictionary getGroupMetadataAsDictionary(Transaction txn, GroupId g)
throws DbException, FormatException; throws DbException, FormatException;
BdfDictionary getMessageMetadataAsDictionary(MessageId m) BdfDictionary getMessageMetadataAsDictionary(MessageId m)
throws DbException, FormatException; throws DbException,
FormatException;
BdfDictionary getMessageMetadataAsDictionary(Transaction txn, MessageId m) BdfDictionary getMessageMetadataAsDictionary(Transaction txn, MessageId m)
throws DbException, FormatException; throws DbException, FormatException;
@@ -67,8 +68,8 @@ public interface ClientHelper {
BdfDictionary query) throws DbException, FormatException; BdfDictionary query) throws DbException, FormatException;
Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary( Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
Transaction txn, GroupId g, BdfDictionary query) Transaction txn, GroupId g, BdfDictionary query) throws DbException,
throws DbException, FormatException; FormatException;
void mergeGroupMetadata(GroupId g, BdfDictionary metadata) void mergeGroupMetadata(GroupId g, BdfDictionary metadata)
throws DbException, FormatException; throws DbException, FormatException;
@@ -119,4 +120,17 @@ public interface ClientHelper {
Map<TransportId, TransportProperties> parseAndValidateTransportPropertiesMap( Map<TransportId, TransportProperties> parseAndValidateTransportPropertiesMap(
BdfDictionary properties) throws FormatException; BdfDictionary properties) throws FormatException;
/**
* Retrieves the contact ID from the group metadata of the given contact
* group.
*/
ContactId getContactId(Transaction txn, GroupId contactGroupId)
throws DbException, FormatException;
/**
* Stores the given contact ID in the group metadata of the given contact
* group.
*/
void setContactId(Transaction txn, GroupId contactGroupId, ContactId c)
throws DbException;
} }

View File

@@ -0,0 +1,9 @@
package org.briarproject.bramble.api.client;
public interface ContactGroupConstants {
/**
* Group metadata key for associating a contact ID with a contact group.
*/
String GROUP_KEY_CONTACT_ID = "contactId";
}

View File

@@ -163,23 +163,27 @@ public interface DatabaseComponent extends TransactionManager {
* less than or equal to the given length, for transmission over a * less than or equal to the given length, for transmission over a
* transport with the given maximum latency. Returns null if there are no * transport with the given maximum latency. Returns null if there are no
* sendable messages that fit in the given length. * sendable messages that fit in the given length.
*
* @param small True if only single-block messages should be sent
*/ */
@Nullable @Nullable
Collection<Message> generateBatch(Transaction txn, ContactId c, Collection<Message> generateBatch(Transaction txn, ContactId c,
int maxLength, int maxLatency, boolean small) throws DbException; int maxLength, int maxLatency) throws DbException;
/** /**
* Returns an offer for the given contact for transmission over a * Returns an offer for the given contact for transmission over a
* transport with the given maximum latency, or null if there are no * transport with the given maximum latency, or null if there are no
* messages to offer. * messages to offer.
*
* @param small True if only single-block messages should be offered
*/ */
@Nullable @Nullable
Offer generateOffer(Transaction txn, ContactId c, int maxMessages, Offer generateOffer(Transaction txn, ContactId c, int maxMessages,
int maxLatency, boolean small) throws DbException; int maxLatency) throws DbException;
/**
* Returns a request for the given contact, or null if there are no
* messages to request.
*/
@Nullable
Request generateRequest(Transaction txn, ContactId c, int maxMessages)
throws DbException;
/** /**
* Returns a batch of messages for the given contact, with a total length * Returns a batch of messages for the given contact, with a total length
@@ -268,14 +272,13 @@ public interface DatabaseComponent extends TransactionManager {
Collection<Identity> getIdentities(Transaction txn) throws DbException; Collection<Identity> getIdentities(Transaction txn) throws DbException;
/** /**
* Returns the single-block message with the given ID. * Returns the message with the given ID.
* <p/> * <p/>
* Read-only. * Read-only.
* *
* @throws MessageDeletedException if the message has been deleted * @throws MessageDeletedException if the message has been deleted
* @throws MessageTooLargeException if the message has more than one block
*/ */
Message getSmallMessage(Transaction txn, MessageId m) throws DbException; Message getMessage(Transaction txn, MessageId m) throws DbException;
/** /**
* Returns the IDs of all delivered messages in the given group. * Returns the IDs of all delivered messages in the given group.

View File

@@ -1,8 +0,0 @@
package org.briarproject.bramble.api.db;
/**
* Thrown when a multi-block message is requested from the database via a
* method that is only suitable for requesting single-block messages.
*/
public class MessageTooLargeException extends DbException {
}

View File

@@ -29,15 +29,10 @@ public interface SyncConstants {
*/ */
int MESSAGE_HEADER_LENGTH = UniqueId.LENGTH + 8; int MESSAGE_HEADER_LENGTH = UniqueId.LENGTH + 8;
/**
* The maximum length of a block in bytes.
*/
int MAX_BLOCK_LENGTH = 32 * 1024; // 32 KiB
/** /**
* The maximum length of a message body in bytes. * The maximum length of a message body in bytes.
*/ */
int MAX_MESSAGE_BODY_LENGTH = MAX_BLOCK_LENGTH; int MAX_MESSAGE_BODY_LENGTH = 32 * 1024; // 32 KiB
/** /**
* The maximum length of a message in bytes. * The maximum length of a message in bytes.

View File

@@ -7,16 +7,16 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
/** /**
* An event that is broadcast when one or more messages are received from, or * An event that is broadcast when a message is received from, or offered by, a
* offered by, a contact and need to be acknowledged. * contact and needs to be acknowledged.
*/ */
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class MessagesToAckEvent extends Event { public class MessageToAckEvent extends Event {
private final ContactId contactId; private final ContactId contactId;
public MessagesToAckEvent(ContactId contactId) { public MessageToAckEvent(ContactId contactId) {
this.contactId = contactId; this.contactId = contactId;
} }

View File

@@ -0,0 +1,26 @@
package org.briarproject.bramble.api.sync.event;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a message is offered by a contact and needs
* to be requested.
*/
@Immutable
@NotNullByDefault
public class MessageToRequestEvent extends Event {
private final ContactId contactId;
public MessageToRequestEvent(ContactId contactId) {
this.contactId = contactId;
}
public ContactId getContactId() {
return contactId;
}
}

View File

@@ -1,39 +0,0 @@
package org.briarproject.bramble.api.sync.event;
import org.briarproject.bramble.api.Consumable;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageId;
import java.util.Collection;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when one or more messages are offered by a
* contact and need to be requested.
*/
@Immutable
@NotNullByDefault
public class MessagesToRequestEvent extends Event {
private final ContactId contactId;
private final Consumable<Collection<MessageId>> ids;
public MessagesToRequestEvent(ContactId contactId,
Collection<MessageId> ids) {
this.contactId = contactId;
this.ids = new Consumable<>(ids);
}
public ContactId getContactId() {
return contactId;
}
@Nullable
public Collection<MessageId> consumeIds() {
return ids.consume();
}
}

View File

@@ -6,7 +6,9 @@ import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault @NotNullByDefault
public class ValidationUtils { public class ValidationUtils {
@@ -64,4 +66,9 @@ public class ValidationUtils {
if (dictionary != null && dictionary.size() != size) if (dictionary != null && dictionary.size() != size)
throw new FormatException(); throw new FormatException();
} }
public static void checkRange(@Nullable Long l, long min, long max)
throws FormatException {
if (l != null && (l < min || l > max)) throw new FormatException();
}
} }

View File

@@ -2,11 +2,13 @@ package org.briarproject.bramble.client;
import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.crypto.CryptoComponent; import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.KeyParser; import org.briarproject.bramble.api.crypto.KeyParser;
import org.briarproject.bramble.api.crypto.PrivateKey; import org.briarproject.bramble.api.crypto.PrivateKey;
import org.briarproject.bramble.api.crypto.PublicKey; import org.briarproject.bramble.api.crypto.PublicKey;
import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfEntry;
import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.data.BdfReader; import org.briarproject.bramble.api.data.BdfReader;
import org.briarproject.bramble.api.data.BdfReaderFactory; import org.briarproject.bramble.api.data.BdfReaderFactory;
@@ -39,6 +41,7 @@ import java.util.Map.Entry;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import javax.inject.Inject; import javax.inject.Inject;
import static org.briarproject.bramble.api.client.ContactGroupConstants.GROUP_KEY_CONTACT_ID;
import static org.briarproject.bramble.api.identity.Author.FORMAT_VERSION; import static org.briarproject.bramble.api.identity.Author.FORMAT_VERSION;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
@@ -116,27 +119,25 @@ class ClientHelperImpl implements ClientHelper {
} }
@Override @Override
public Message getSmallMessage(MessageId m) throws DbException { public Message getMessage(MessageId m) throws DbException {
return db.transactionWithResult(true, txn -> getSmallMessage(txn, m)); return db.transactionWithResult(true, txn -> getMessage(txn, m));
} }
@Override @Override
public Message getSmallMessage(Transaction txn, MessageId m) public Message getMessage(Transaction txn, MessageId m) throws DbException {
throws DbException { return db.getMessage(txn, m);
return db.getSmallMessage(txn, m);
} }
@Override @Override
public BdfList getSmallMessageAsList(MessageId m) public BdfList getMessageAsList(MessageId m) throws DbException,
FormatException {
return db.transactionWithResult(true, txn -> getMessageAsList(txn, m));
}
@Override
public BdfList getMessageAsList(Transaction txn, MessageId m)
throws DbException, FormatException { throws DbException, FormatException {
return db.transactionWithResult(true, txn -> return toList(db.getMessage(txn, m).getBody());
getSmallMessageAsList(txn, m));
}
@Override
public BdfList getSmallMessageAsList(Transaction txn, MessageId m)
throws DbException, FormatException {
return toList(db.getSmallMessage(txn, m).getBody());
} }
@Override @Override
@@ -391,4 +392,27 @@ class ClientHelperImpl implements ClientHelper {
return tpMap; return tpMap;
} }
@Override
public ContactId getContactId(Transaction txn, GroupId contactGroupId)
throws DbException {
try {
BdfDictionary meta =
getGroupMetadataAsDictionary(txn, contactGroupId);
return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue());
} catch (FormatException e) {
throw new DbException(e); // Invalid group metadata
}
}
@Override
public void setContactId(Transaction txn, GroupId contactGroupId,
ContactId c) throws DbException {
BdfDictionary meta = BdfDictionary.of(
new BdfEntry(GROUP_KEY_CONTACT_ID, c.getInt()));
try {
mergeGroupMetadata(txn, contactGroupId, meta);
} catch (FormatException e) {
throw new AssertionError(e);
}
}
} }

View File

@@ -12,7 +12,6 @@ import org.briarproject.bramble.api.db.DataTooOldException;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MessageDeletedException; import org.briarproject.bramble.api.db.MessageDeletedException;
import org.briarproject.bramble.api.db.MessageTooLargeException;
import org.briarproject.bramble.api.db.Metadata; import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.MigrationListener; import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
@@ -126,6 +125,11 @@ interface Database<T> {
void addMessageDependency(T txn, Message dependent, MessageId dependency, void addMessageDependency(T txn, Message dependent, MessageId dependency,
MessageState dependentState) throws DbException; MessageState dependentState) throws DbException;
/**
* Records that a message has been offered by the given contact.
*/
void addOfferedMessage(T txn, ContactId c, MessageId m) throws DbException;
/** /**
* Stores a pending contact. * Stores a pending contact.
*/ */
@@ -214,6 +218,13 @@ interface Database<T> {
boolean containsVisibleMessage(T txn, ContactId c, MessageId m) boolean containsVisibleMessage(T txn, ContactId c, MessageId m)
throws DbException; throws DbException;
/**
* Returns the number of messages offered by the given contact.
* <p/>
* Read-only.
*/
int countOfferedMessages(T txn, ContactId c) throws DbException;
/** /**
* Deletes the message with the given ID. Unlike * Deletes the message with the given ID. Unlike
* {@link #removeMessage(Object, MessageId)}, the message ID and any other * {@link #removeMessage(Object, MessageId)}, the message ID and any other
@@ -321,14 +332,13 @@ interface Database<T> {
Collection<Identity> getIdentities(T txn) throws DbException; Collection<Identity> getIdentities(T txn) throws DbException;
/** /**
* Returns the single-block message with the given ID. * Returns the message with the given ID.
* <p/> * <p/>
* Read-only. * Read-only.
* *
* @throws MessageDeletedException if the message has been deleted * @throws MessageDeletedException if the message has been deleted
* @throws MessageTooLargeException if the message has more than one block
*/ */
Message getSmallMessage(T txn, MessageId m) throws DbException; Message getMessage(T txn, MessageId m) throws DbException;
/** /**
* Returns the IDs and states of all dependencies of the given message. * Returns the IDs and states of all dependencies of the given message.
@@ -447,13 +457,13 @@ interface Database<T> {
int maxMessages, int maxLatency) throws DbException; int maxMessages, int maxLatency) throws DbException;
/** /**
* Returns the IDs of some single-block messages that are eligible to be * Returns the IDs of some messages that are eligible to be requested from
* offered to the given contact, up to the given number of messages. * the given contact, up to the given number of messages.
* <p/> * <p/>
* Read-only. * Read-only.
*/ */
Collection<MessageId> getSmallMessagesToOffer(T txn, ContactId c, Collection<MessageId> getMessagesToRequest(T txn, ContactId c,
int maxMessages, int maxLatency) throws DbException; int maxMessages) throws DbException;
/** /**
* Returns the IDs of some messages that are eligible to be sent to the * Returns the IDs of some messages that are eligible to be sent to the
@@ -464,15 +474,6 @@ interface Database<T> {
Collection<MessageId> getMessagesToSend(T txn, ContactId c, int maxLength, Collection<MessageId> getMessagesToSend(T txn, ContactId c, int maxLength,
int maxLatency) throws DbException; int maxLatency) throws DbException;
/**
* Returns the IDs of some single-block messages that are eligible to be
* sent to the given contact, up to the given total length.
* <p/>
* Read-only.
*/
Collection<MessageId> getSmallMessagesToSend(T txn, ContactId c,
int maxLength, int maxLatency) throws DbException;
/** /**
* Returns the IDs of any messages that need to be validated. * Returns the IDs of any messages that need to be validated.
* <p/> * <p/>
@@ -635,6 +636,13 @@ interface Database<T> {
*/ */
void removeMessage(T txn, MessageId m) throws DbException; void removeMessage(T txn, MessageId m) throws DbException;
/**
* Removes the given offered messages that were offered by the given
* contact.
*/
void removeOfferedMessages(T txn, ContactId c,
Collection<MessageId> requested) throws DbException;
/** /**
* Removes a pending contact (and all associated state) from the database. * Removes a pending contact (and all associated state) from the database.
*/ */

View File

@@ -61,10 +61,10 @@ import org.briarproject.bramble.api.sync.event.MessageAddedEvent;
import org.briarproject.bramble.api.sync.event.MessageRequestedEvent; import org.briarproject.bramble.api.sync.event.MessageRequestedEvent;
import org.briarproject.bramble.api.sync.event.MessageSharedEvent; import org.briarproject.bramble.api.sync.event.MessageSharedEvent;
import org.briarproject.bramble.api.sync.event.MessageStateChangedEvent; import org.briarproject.bramble.api.sync.event.MessageStateChangedEvent;
import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent; import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
import org.briarproject.bramble.api.sync.event.MessagesSentEvent; import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
import org.briarproject.bramble.api.sync.event.MessagesToAckEvent;
import org.briarproject.bramble.api.sync.event.MessagesToRequestEvent;
import org.briarproject.bramble.api.sync.event.SyncVersionsUpdatedEvent; import org.briarproject.bramble.api.sync.event.SyncVersionsUpdatedEvent;
import org.briarproject.bramble.api.sync.validation.MessageState; import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.KeySetId;
@@ -91,6 +91,7 @@ import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED; import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
import static org.briarproject.bramble.api.sync.validation.MessageState.UNKNOWN; import static org.briarproject.bramble.api.sync.validation.MessageState.UNKNOWN;
import static org.briarproject.bramble.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
@@ -405,22 +406,19 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Nullable @Nullable
@Override @Override
public Collection<Message> generateBatch(Transaction transaction, public Collection<Message> generateBatch(Transaction transaction,
ContactId c, int maxLength, int maxLatency, boolean small) ContactId c, int maxLength, int maxLatency) throws DbException {
throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException(); if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsContact(txn, c)) if (!db.containsContact(txn, c))
throw new NoSuchContactException(); throw new NoSuchContactException();
Collection<MessageId> ids; Collection<MessageId> ids =
if (small) db.getMessagesToSend(txn, c, maxLength, maxLatency);
ids = db.getSmallMessagesToSend(txn, c, maxLength, maxLatency);
else ids = db.getMessagesToSend(txn, c, maxLength, maxLatency);
if (ids.isEmpty()) return null;
List<Message> messages = new ArrayList<>(ids.size()); List<Message> messages = new ArrayList<>(ids.size());
for (MessageId m : ids) { for (MessageId m : ids) {
messages.add(db.getSmallMessage(txn, m)); messages.add(db.getMessage(txn, m));
db.updateExpiryTimeAndEta(txn, c, m, maxLatency); db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
} }
if (ids.isEmpty()) return null;
db.lowerRequestedFlag(txn, c, ids); db.lowerRequestedFlag(txn, c, ids);
transaction.attach(new MessagesSentEvent(c, ids)); transaction.attach(new MessagesSentEvent(c, ids));
return messages; return messages;
@@ -429,21 +427,34 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Nullable @Nullable
@Override @Override
public Offer generateOffer(Transaction transaction, ContactId c, public Offer generateOffer(Transaction transaction, ContactId c,
int maxMessages, int maxLatency, boolean small) throws DbException { int maxMessages, int maxLatency) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException(); if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsContact(txn, c)) if (!db.containsContact(txn, c))
throw new NoSuchContactException(); throw new NoSuchContactException();
Collection<MessageId> ids; Collection<MessageId> ids =
if (small) db.getMessagesToOffer(txn, c, maxMessages, maxLatency);
ids = db.getSmallMessagesToOffer(txn, c, maxMessages, maxLatency);
else ids = db.getMessagesToOffer(txn, c, maxMessages, maxLatency);
if (ids.isEmpty()) return null; if (ids.isEmpty()) return null;
for (MessageId m : ids) for (MessageId m : ids)
db.updateExpiryTimeAndEta(txn, c, m, maxLatency); db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
return new Offer(ids); return new Offer(ids);
} }
@Nullable
@Override
public Request generateRequest(Transaction transaction, ContactId c,
int maxMessages) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
Collection<MessageId> ids = db.getMessagesToRequest(txn, c,
maxMessages);
if (ids.isEmpty()) return null;
db.removeOfferedMessages(txn, c, ids);
return new Request(ids);
}
@Nullable @Nullable
@Override @Override
public Collection<Message> generateRequestedBatch(Transaction transaction, public Collection<Message> generateRequestedBatch(Transaction transaction,
@@ -454,12 +465,12 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
throw new NoSuchContactException(); throw new NoSuchContactException();
Collection<MessageId> ids = Collection<MessageId> ids =
db.getRequestedMessagesToSend(txn, c, maxLength, maxLatency); db.getRequestedMessagesToSend(txn, c, maxLength, maxLatency);
if (ids.isEmpty()) return null;
List<Message> messages = new ArrayList<>(ids.size()); List<Message> messages = new ArrayList<>(ids.size());
for (MessageId m : ids) { for (MessageId m : ids) {
messages.add(db.getSmallMessage(txn, m)); messages.add(db.getMessage(txn, m));
db.updateExpiryTimeAndEta(txn, c, m, maxLatency); db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
} }
if (ids.isEmpty()) return null;
db.lowerRequestedFlag(txn, c, ids); db.lowerRequestedFlag(txn, c, ids);
transaction.attach(new MessagesSentEvent(c, ids)); transaction.attach(new MessagesSentEvent(c, ids));
return messages; return messages;
@@ -548,12 +559,12 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
} }
@Override @Override
public Message getSmallMessage(Transaction transaction, MessageId m) public Message getMessage(Transaction transaction, MessageId m)
throws DbException { throws DbException {
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsMessage(txn, m)) if (!db.containsMessage(txn, m))
throw new NoSuchMessageException(); throw new NoSuchMessageException();
return db.getSmallMessage(txn, m); return db.getMessage(txn, m);
} }
@Override @Override
@@ -808,7 +819,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
db.addMessage(txn, m, UNKNOWN, false, false, c); db.addMessage(txn, m, UNKNOWN, false, false, c);
transaction.attach(new MessageAddedEvent(m, c)); transaction.attach(new MessageAddedEvent(m, c));
} }
transaction.attach(new MessagesToAckEvent(c)); transaction.attach(new MessageToAckEvent(c));
} }
} }
@@ -819,20 +830,21 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
T txn = unbox(transaction); T txn = unbox(transaction);
if (!db.containsContact(txn, c)) if (!db.containsContact(txn, c))
throw new NoSuchContactException(); throw new NoSuchContactException();
boolean ack = false; boolean ack = false, request = false;
List<MessageId> request = new ArrayList<>(o.getMessageIds().size()); int count = db.countOfferedMessages(txn, c);
for (MessageId m : o.getMessageIds()) { for (MessageId m : o.getMessageIds()) {
if (db.containsVisibleMessage(txn, c, m)) { if (db.containsVisibleMessage(txn, c, m)) {
db.raiseSeenFlag(txn, c, m); db.raiseSeenFlag(txn, c, m);
db.raiseAckFlag(txn, c, m); db.raiseAckFlag(txn, c, m);
ack = true; ack = true;
} else { } else if (count < MAX_OFFERED_MESSAGES) {
request.add(m); db.addOfferedMessage(txn, c, m);
request = true;
count++;
} }
} }
if (ack) transaction.attach(new MessagesToAckEvent(c)); if (ack) transaction.attach(new MessageToAckEvent(c));
if (!request.isEmpty()) if (request) transaction.attach(new MessageToRequestEvent(c));
transaction.attach(new MessagesToRequestEvent(c, request));
} }
@Override @Override

View File

@@ -6,6 +6,13 @@ import static java.util.concurrent.TimeUnit.DAYS;
interface DatabaseConstants { interface DatabaseConstants {
/**
* The maximum number of offered messages from each contact that will be
* stored. If offers arrive more quickly than requests can be sent and this
* limit is reached, additional offers will not be stored.
*/
int MAX_OFFERED_MESSAGES = 1000;
/** /**
* The namespace of the {@link Settings} where the database schema version * The namespace of the {@link Settings} where the database schema version
* is stored. * is stored.

View File

@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventExecutor; import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.lifecycle.ShutdownManager; import org.briarproject.bramble.api.lifecycle.ShutdownManager;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import java.sql.Connection; import java.sql.Connection;
@@ -21,8 +22,9 @@ public class DatabaseModule {
@Provides @Provides
@Singleton @Singleton
Database<Connection> provideDatabase(DatabaseConfig config, Clock clock) { Database<Connection> provideDatabase(DatabaseConfig config,
return new H2Database(config, clock); MessageFactory messageFactory, Clock clock) {
return new H2Database(config, messageFactory, clock);
} }
@Provides @Provides

View File

@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.db.DbClosedException;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MigrationListener; import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.StringUtils; import org.briarproject.bramble.util.StringUtils;
@@ -50,8 +51,9 @@ class H2Database extends JdbcDatabase {
private volatile SecretKey key = null; private volatile SecretKey key = null;
@Inject @Inject
H2Database(DatabaseConfig config, Clock clock) { H2Database(DatabaseConfig config, MessageFactory messageFactory,
super(dbTypes, clock); Clock clock) {
super(dbTypes, messageFactory, clock);
this.config = config; this.config = config;
File dir = config.getDatabaseDirectory(); File dir = config.getDatabaseDirectory();
String path = new File(dir, "db").getAbsolutePath(); String path = new File(dir, "db").getAbsolutePath();

View File

@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.db.DbClosedException;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MigrationListener; import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.StringUtils; import org.briarproject.bramble.util.StringUtils;
@@ -50,8 +51,9 @@ class HyperSqlDatabase extends JdbcDatabase {
private volatile SecretKey key = null; private volatile SecretKey key = null;
@Inject @Inject
HyperSqlDatabase(DatabaseConfig config, Clock clock) { HyperSqlDatabase(DatabaseConfig config, MessageFactory messageFactory,
super(dbTypes, clock); Clock clock) {
super(dbTypes, messageFactory, clock);
this.config = config; this.config = config;
File dir = config.getDatabaseDirectory(); File dir = config.getDatabaseDirectory();
String path = new File(dir, "db").getAbsolutePath(); String path = new File(dir, "db").getAbsolutePath();

View File

@@ -16,7 +16,6 @@ import org.briarproject.bramble.api.db.DataTooOldException;
import org.briarproject.bramble.api.db.DbClosedException; import org.briarproject.bramble.api.db.DbClosedException;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MessageDeletedException; import org.briarproject.bramble.api.db.MessageDeletedException;
import org.briarproject.bramble.api.db.MessageTooLargeException;
import org.briarproject.bramble.api.db.Metadata; import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.MigrationListener; import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
@@ -31,6 +30,7 @@ import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.Group.Visibility; import org.briarproject.bramble.api.sync.Group.Visibility;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus; import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.validation.MessageState; import org.briarproject.bramble.api.sync.validation.MessageState;
@@ -76,7 +76,6 @@ import static org.briarproject.bramble.api.db.Metadata.REMOVE;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_BLOCK_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED; import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
import static org.briarproject.bramble.api.sync.validation.MessageState.PENDING; import static org.briarproject.bramble.api.sync.validation.MessageState.PENDING;
@@ -99,7 +98,7 @@ import static org.briarproject.bramble.util.LogUtils.now;
abstract class JdbcDatabase implements Database<Connection> { abstract class JdbcDatabase implements Database<Connection> {
// Package access for testing // Package access for testing
static final int CODE_SCHEMA_VERSION = 49; static final int CODE_SCHEMA_VERSION = 47;
// Time period offsets for incoming transport keys // Time period offsets for incoming transport keys
private static final int OFFSET_PREV = -1; private static final int OFFSET_PREV = -1;
@@ -181,9 +180,8 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " state INT NOT NULL," + " state INT NOT NULL,"
+ " shared BOOLEAN NOT NULL," + " shared BOOLEAN NOT NULL,"
+ " temporary BOOLEAN NOT NULL," + " temporary BOOLEAN NOT NULL,"
+ " length INT NOT NULL," // Includes message header + " length INT NOT NULL,"
+ " deleted BOOLEAN NOT NULL," + " raw BLOB," // Null if message has been deleted
+ " blockCount INT NOT NULL,"
+ " PRIMARY KEY (messageId)," + " PRIMARY KEY (messageId),"
+ " FOREIGN KEY (groupId)" + " FOREIGN KEY (groupId)"
+ " REFERENCES groups (groupId)" + " REFERENCES groups (groupId)"
@@ -220,15 +218,13 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " REFERENCES messages (messageId)" + " REFERENCES messages (messageId)"
+ " ON DELETE CASCADE)"; + " ON DELETE CASCADE)";
private static final String CREATE_BLOCKS = private static final String CREATE_OFFERS =
"CREATE TABLE blocks" "CREATE TABLE offers"
+ " (messageId _HASH NOT NULL," + " (messageId _HASH NOT NULL," // Not a foreign key
+ " blockNumber INT NOT NULL," + " contactId INT NOT NULL,"
+ " blockLength INT NOT NULL," // Excludes block header + " PRIMARY KEY (messageId, contactId),"
+ " data BLOB," // Null if message has been deleted + " FOREIGN KEY (contactId)"
+ " PRIMARY KEY (messageId, blockNumber)," + " REFERENCES contacts (contactId)"
+ " FOREIGN KEY (messageId)"
+ " REFERENCES messages (messageId)"
+ " ON DELETE CASCADE)"; + " ON DELETE CASCADE)";
private static final String CREATE_STATUSES = private static final String CREATE_STATUSES =
@@ -343,6 +339,7 @@ abstract class JdbcDatabase implements Database<Connection> {
private static final Logger LOG = private static final Logger LOG =
getLogger(JdbcDatabase.class.getName()); getLogger(JdbcDatabase.class.getName());
private final MessageFactory messageFactory;
private final Clock clock; private final Clock clock;
private final DatabaseTypes dbTypes; private final DatabaseTypes dbTypes;
@@ -362,8 +359,10 @@ abstract class JdbcDatabase implements Database<Connection> {
protected abstract void compactAndClose() throws DbException; protected abstract void compactAndClose() throws DbException;
JdbcDatabase(DatabaseTypes databaseTypes, Clock clock) { JdbcDatabase(DatabaseTypes databaseTypes, MessageFactory messageFactory,
Clock clock) {
this.dbTypes = databaseTypes; this.dbTypes = databaseTypes;
this.messageFactory = messageFactory;
this.clock = clock; this.clock = clock;
} }
@@ -441,12 +440,10 @@ abstract class JdbcDatabase implements Database<Connection> {
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Migrating from schema " + start + " to " + end); LOG.info("Migrating from schema " + start + " to " + end);
if (listener != null) listener.onDatabaseMigration(); if (listener != null) listener.onDatabaseMigration();
long startTime = now();
// Apply the migration // Apply the migration
m.migrate(txn); m.migrate(txn);
// Store the new schema version // Store the new schema version
storeSchemaVersion(txn, end); storeSchemaVersion(txn, end);
logDuration(LOG, "Migration", startTime);
dataSchemaVersion = end; dataSchemaVersion = end;
} }
} }
@@ -466,9 +463,7 @@ abstract class JdbcDatabase implements Database<Connection> {
new Migration43_44(dbTypes), new Migration43_44(dbTypes),
new Migration44_45(), new Migration44_45(),
new Migration45_46(), new Migration45_46(),
new Migration46_47(dbTypes), new Migration46_47(dbTypes)
new Migration47_48(dbTypes),
new Migration48_49()
); );
} }
@@ -513,7 +508,7 @@ abstract class JdbcDatabase implements Database<Connection> {
s.executeUpdate(dbTypes.replaceTypes(CREATE_MESSAGES)); s.executeUpdate(dbTypes.replaceTypes(CREATE_MESSAGES));
s.executeUpdate(dbTypes.replaceTypes(CREATE_MESSAGE_METADATA)); s.executeUpdate(dbTypes.replaceTypes(CREATE_MESSAGE_METADATA));
s.executeUpdate(dbTypes.replaceTypes(CREATE_MESSAGE_DEPENDENCIES)); s.executeUpdate(dbTypes.replaceTypes(CREATE_MESSAGE_DEPENDENCIES));
s.executeUpdate(dbTypes.replaceTypes(CREATE_BLOCKS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_OFFERS));
s.executeUpdate(dbTypes.replaceTypes(CREATE_STATUSES)); s.executeUpdate(dbTypes.replaceTypes(CREATE_STATUSES));
s.executeUpdate(dbTypes.replaceTypes(CREATE_TRANSPORTS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_TRANSPORTS));
s.executeUpdate(dbTypes.replaceTypes(CREATE_PENDING_CONTACTS)); s.executeUpdate(dbTypes.replaceTypes(CREATE_PENDING_CONTACTS));
@@ -731,7 +726,7 @@ abstract class JdbcDatabase implements Database<Connection> {
ResultSet rs = null; ResultSet rs = null;
try { try {
String sql = "SELECT messageId, timestamp, state, shared," String sql = "SELECT messageId, timestamp, state, shared,"
+ " length, deleted" + " length, raw IS NULL"
+ " FROM messages" + " FROM messages"
+ " WHERE groupId = ?"; + " WHERE groupId = ?";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
@@ -744,8 +739,9 @@ abstract class JdbcDatabase implements Database<Connection> {
boolean messageShared = rs.getBoolean(4); boolean messageShared = rs.getBoolean(4);
int length = rs.getInt(5); int length = rs.getInt(5);
boolean deleted = rs.getBoolean(6); boolean deleted = rs.getBoolean(6);
boolean seen = removeOfferedMessage(txn, c, id);
addStatus(txn, id, c, g, timestamp, length, state, groupShared, addStatus(txn, id, c, g, timestamp, length, state, groupShared,
messageShared, deleted, false); messageShared, deleted, seen);
} }
rs.close(); rs.close();
ps.close(); ps.close();
@@ -792,8 +788,8 @@ abstract class JdbcDatabase implements Database<Connection> {
PreparedStatement ps = null; PreparedStatement ps = null;
try { try {
String sql = "INSERT INTO messages (messageId, groupId, timestamp," String sql = "INSERT INTO messages (messageId, groupId, timestamp,"
+ " state, shared, temporary, length, deleted, blockCount)" + " state, shared, temporary, length, raw)"
+ " VALUES (?, ?, ?, ?, ?, ?, ?, FALSE, 1)"; + " VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getId().getBytes()); ps.setBytes(1, m.getId().getBytes());
ps.setBytes(2, m.getGroupId().getBytes()); ps.setBytes(2, m.getGroupId().getBytes());
@@ -801,29 +797,21 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.setInt(4, state.getValue()); ps.setInt(4, state.getValue());
ps.setBoolean(5, shared); ps.setBoolean(5, shared);
ps.setBoolean(6, temporary); ps.setBoolean(6, temporary);
ps.setInt(7, m.getRawLength()); byte[] raw = messageFactory.getRawMessage(m);
ps.setInt(7, raw.length);
ps.setBytes(8, raw);
int affected = ps.executeUpdate(); int affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException(); if (affected != 1) throw new DbStateException();
ps.close(); ps.close();
sql = "INSERT INTO blocks (messageId, blockNumber, blockLength,"
+ " data)"
+ " VALUES (?, 0, ?, ?)";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getId().getBytes());
ps.setInt(2, m.getBody().length);
ps.setBytes(3, m.getBody());
affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException();
ps.close();
// Create a status row for each contact that can see the group // Create a status row for each contact that can see the group
Map<ContactId, Boolean> visibility = Map<ContactId, Boolean> visibility =
getGroupVisibility(txn, m.getGroupId()); getGroupVisibility(txn, m.getGroupId());
for (Entry<ContactId, Boolean> e : visibility.entrySet()) { for (Entry<ContactId, Boolean> e : visibility.entrySet()) {
ContactId c = e.getKey(); ContactId c = e.getKey();
boolean seen = c.equals(sender); boolean offered = removeOfferedMessage(txn, c, m.getId());
boolean seen = offered || c.equals(sender);
addStatus(txn, m.getId(), c, m.getGroupId(), m.getTimestamp(), addStatus(txn, m.getId(), c, m.getGroupId(), m.getTimestamp(),
m.getRawLength(), state, e.getValue(), shared, false, raw.length, state, e.getValue(), shared, false, seen);
seen);
} }
// Update denormalised column in messageDependencies if dependency // Update denormalised column in messageDependencies if dependency
// is in same group as dependent // is in same group as dependent
@@ -842,6 +830,37 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
@Override
public void addOfferedMessage(Connection txn, ContactId c, MessageId m)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT NULL FROM offers"
+ " WHERE messageId = ? AND contactId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
ps.setInt(2, c.getInt());
rs = ps.executeQuery();
boolean found = rs.next();
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
if (found) return;
sql = "INSERT INTO offers (messageId, contactId) VALUES (?, ?)";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
ps.setInt(2, c.getInt());
int affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
private void addStatus(Connection txn, MessageId m, ContactId c, GroupId g, private void addStatus(Connection txn, MessageId m, ContactId c, GroupId g,
long timestamp, int length, MessageState state, boolean groupShared, long timestamp, int length, MessageState state, boolean groupShared,
boolean messageShared, boolean deleted, boolean seen) boolean messageShared, boolean deleted, boolean seen)
@@ -1243,22 +1262,40 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
@Override
public int countOfferedMessages(Connection txn, ContactId c)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT COUNT (messageId) FROM offers "
+ " WHERE contactId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
rs = ps.executeQuery();
if (!rs.next()) throw new DbException();
int count = rs.getInt(1);
if (rs.next()) throw new DbException();
rs.close();
ps.close();
return count;
} catch (SQLException e) {
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override @Override
public void deleteMessage(Connection txn, MessageId m) throws DbException { public void deleteMessage(Connection txn, MessageId m) throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
try { try {
String sql = "UPDATE messages SET deleted = TRUE" String sql = "UPDATE messages SET raw = NULL WHERE messageId = ?";
+ " WHERE messageId = ?";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes()); ps.setBytes(1, m.getBytes());
int affected = ps.executeUpdate(); int affected = ps.executeUpdate();
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
sql = "UPDATE blocks SET data = NULL WHERE messageId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
affected = ps.executeUpdate();
if (affected < 0) throw new DbStateException(); if (affected < 0) throw new DbStateException();
if (affected > 1) throw new DbStateException();
ps.close(); ps.close();
// Update denormalised column in statuses // Update denormalised column in statuses
sql = "UPDATE statuses SET deleted = TRUE WHERE messageId = ?"; sql = "UPDATE statuses SET deleted = TRUE WHERE messageId = ?";
@@ -1651,13 +1688,11 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
@Override @Override
public Message getSmallMessage(Connection txn, MessageId m) public Message getMessage(Connection txn, MessageId m) throws DbException {
throws DbException {
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
String sql = "SELECT groupId, timestamp, deleted, blockCount" String sql = "SELECT groupId, timestamp, raw FROM messages"
+ " FROM messages"
+ " WHERE messageId = ?"; + " WHERE messageId = ?";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes()); ps.setBytes(1, m.getBytes());
@@ -1665,25 +1700,15 @@ abstract class JdbcDatabase implements Database<Connection> {
if (!rs.next()) throw new DbStateException(); if (!rs.next()) throw new DbStateException();
GroupId g = new GroupId(rs.getBytes(1)); GroupId g = new GroupId(rs.getBytes(1));
long timestamp = rs.getLong(2); long timestamp = rs.getLong(2);
boolean deleted = rs.getBoolean(3); byte[] raw = rs.getBytes(3);
int blockCount = rs.getInt(4);
if (rs.next()) throw new DbStateException(); if (rs.next()) throw new DbStateException();
rs.close(); rs.close();
ps.close(); ps.close();
if (deleted) throw new MessageDeletedException(); if (raw == null) throw new MessageDeletedException();
if (blockCount > 1) throw new MessageTooLargeException(); if (raw.length <= MESSAGE_HEADER_LENGTH) throw new AssertionError();
sql = "SELECT data FROM blocks" byte[] body = new byte[raw.length - MESSAGE_HEADER_LENGTH];
+ " WHERE messageId = ? AND blockNumber = 0"; System.arraycopy(raw, MESSAGE_HEADER_LENGTH, body, 0, body.length);
ps = txn.prepareStatement(sql); return new Message(m, g, timestamp, body);
ps.setBytes(1, m.getBytes());
rs = ps.executeQuery();
if (!rs.next()) throw new DbStateException();
byte[] data = rs.getBytes(1);
if (data == null) throw new DbStateException();
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
return new Message(m, g, timestamp, data);
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(rs, LOG, WARNING); tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING); tryToClose(ps, LOG, WARNING);
@@ -2076,28 +2101,17 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
@Override @Override
public Collection<MessageId> getSmallMessagesToOffer(Connection txn, public Collection<MessageId> getMessagesToRequest(Connection txn,
ContactId c, int maxMessages, int maxLatency) throws DbException { ContactId c, int maxMessages) throws DbException {
long now = clock.currentTimeMillis();
long eta = now + maxLatency;
PreparedStatement ps = null; PreparedStatement ps = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
String sql = "SELECT messageId FROM statuses" String sql = "SELECT messageId FROM offers"
+ " WHERE contactId = ? AND state = ?" + " WHERE contactId = ?"
+ " AND length <= ?" + " LIMIT ?";
+ " AND groupShared = TRUE AND messageShared = TRUE"
+ " AND deleted = FALSE"
+ " AND seen = FALSE AND requested = FALSE"
+ " AND (expiry <= ? OR eta > ?)"
+ " ORDER BY timestamp LIMIT ?";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt()); ps.setInt(1, c.getInt());
ps.setInt(2, DELIVERED.getValue()); ps.setInt(2, maxMessages);
ps.setInt(3, MESSAGE_HEADER_LENGTH + MAX_BLOCK_LENGTH);
ps.setLong(4, now);
ps.setLong(5, eta);
ps.setInt(6, maxMessages);
rs = ps.executeQuery(); rs = ps.executeQuery();
List<MessageId> ids = new ArrayList<>(); List<MessageId> ids = new ArrayList<>();
while (rs.next()) ids.add(new MessageId(rs.getBytes(1))); while (rs.next()) ids.add(new MessageId(rs.getBytes(1)));
@@ -2150,47 +2164,6 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
@Override
public Collection<MessageId> getSmallMessagesToSend(Connection txn,
ContactId c, int maxLength, int maxLatency) throws DbException {
long now = clock.currentTimeMillis();
long eta = now + maxLatency;
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT length, messageId FROM statuses"
+ " WHERE contactId = ? AND state = ?"
+ " AND length <= ?"
+ " AND groupShared = TRUE AND messageShared = TRUE"
+ " AND deleted = FALSE"
+ " AND seen = FALSE"
+ " AND (expiry <= ? OR eta > ?)"
+ " ORDER BY timestamp";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setInt(2, DELIVERED.getValue());
ps.setInt(3, MESSAGE_HEADER_LENGTH + MAX_BLOCK_LENGTH);
ps.setLong(4, now);
ps.setLong(5, eta);
rs = ps.executeQuery();
List<MessageId> ids = new ArrayList<>();
int total = 0;
while (rs.next()) {
int length = rs.getInt(1);
if (total + length > maxLength) break;
ids.add(new MessageId(rs.getBytes(2)));
total += length;
}
rs.close();
ps.close();
return ids;
} catch (SQLException e) {
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override @Override
public Collection<MessageId> getMessagesToValidate(Connection txn) public Collection<MessageId> getMessagesToValidate(Connection txn)
throws DbException { throws DbException {
@@ -2209,7 +2182,7 @@ abstract class JdbcDatabase implements Database<Connection> {
ResultSet rs = null; ResultSet rs = null;
try { try {
String sql = "SELECT messageId FROM messages" String sql = "SELECT messageId FROM messages"
+ " WHERE state = ? AND deleted = FALSE"; + " WHERE state = ? AND raw IS NOT NULL";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setInt(1, state.getValue()); ps.setInt(1, state.getValue());
rs = ps.executeQuery(); rs = ps.executeQuery();
@@ -2914,6 +2887,50 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
private boolean removeOfferedMessage(Connection txn, ContactId c,
MessageId m) throws DbException {
PreparedStatement ps = null;
try {
String sql = "DELETE FROM offers"
+ " WHERE contactId = ? AND messageId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setBytes(2, m.getBytes());
int affected = ps.executeUpdate();
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
return affected == 1;
} catch (SQLException e) {
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public void removeOfferedMessages(Connection txn, ContactId c,
Collection<MessageId> requested) throws DbException {
PreparedStatement ps = null;
try {
String sql = "DELETE FROM offers"
+ " WHERE contactId = ? AND messageId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
for (MessageId m : requested) {
ps.setBytes(2, m.getBytes());
ps.addBatch();
}
int[] batchAffected = ps.executeBatch();
if (batchAffected.length != requested.size())
throw new DbStateException();
for (int rows : batchAffected)
if (rows != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override @Override
public void removePendingContact(Connection txn, PendingContactId p) public void removePendingContact(Connection txn, PendingContactId p)
throws DbException { throws DbException {

View File

@@ -37,7 +37,6 @@ class Migration38_39 implements Migration<Connection> {
s.execute("ALTER TABLE incomingKeys" s.execute("ALTER TABLE incomingKeys"
+ " ALTER COLUMN contactId" + " ALTER COLUMN contactId"
+ " SET NOT NULL"); + " SET NOT NULL");
s.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s, LOG, WARNING); tryToClose(s, LOG, WARNING);
throw new DbException(e); throw new DbException(e);

View File

@@ -36,7 +36,6 @@ class Migration39_40 implements Migration<Connection> {
s.execute("ALTER TABLE statuses" s.execute("ALTER TABLE statuses"
+ " ALTER COLUMN eta" + " ALTER COLUMN eta"
+ " SET NOT NULL"); + " SET NOT NULL");
s.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s, LOG, WARNING); tryToClose(s, LOG, WARNING);
throw new DbException(e); throw new DbException(e);

View File

@@ -38,7 +38,6 @@ class Migration40_41 implements Migration<Connection> {
s = txn.createStatement(); s = txn.createStatement();
s.execute("ALTER TABLE contacts" s.execute("ALTER TABLE contacts"
+ dbTypes.replaceTypes(" ADD alias _STRING")); + dbTypes.replaceTypes(" ADD alias _STRING"));
s.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s, LOG, WARNING); tryToClose(s, LOG, WARNING);
throw new DbException(e); throw new DbException(e);

View File

@@ -89,7 +89,6 @@ class Migration41_42 implements Migration<Connection> {
+ " FOREIGN KEY (keySetId)" + " FOREIGN KEY (keySetId)"
+ " REFERENCES outgoingHandshakeKeys (keySetId)" + " REFERENCES outgoingHandshakeKeys (keySetId)"
+ " ON DELETE CASCADE)")); + " ON DELETE CASCADE)"));
s.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s, LOG, WARNING); tryToClose(s, LOG, WARNING);
throw new DbException(e); throw new DbException(e);

View File

@@ -44,7 +44,6 @@ class Migration42_43 implements Migration<Connection> {
+ " ADD COLUMN handshakePublicKey _BINARY")); + " ADD COLUMN handshakePublicKey _BINARY"));
s.execute("ALTER TABLE contacts" s.execute("ALTER TABLE contacts"
+ " DROP COLUMN active"); + " DROP COLUMN active");
s.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s, LOG, WARNING); tryToClose(s, LOG, WARNING);
throw new DbException(e); throw new DbException(e);

View File

@@ -50,7 +50,6 @@ class Migration43_44 implements Migration<Connection> {
+ " ADD COLUMN rootKey _SECRET")); + " ADD COLUMN rootKey _SECRET"));
s.execute("ALTER TABLE outgoingKeys" s.execute("ALTER TABLE outgoingKeys"
+ " ADD COLUMN alice BOOLEAN"); + " ADD COLUMN alice BOOLEAN");
s.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s, LOG, WARNING); tryToClose(s, LOG, WARNING);
throw new DbException(e); throw new DbException(e);

View File

@@ -31,7 +31,6 @@ class Migration44_45 implements Migration<Connection> {
try { try {
s = txn.createStatement(); s = txn.createStatement();
s.execute("ALTER TABLE pendingContacts DROP COLUMN state"); s.execute("ALTER TABLE pendingContacts DROP COLUMN state");
s.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s, LOG, WARNING); tryToClose(s, LOG, WARNING);
throw new DbException(e); throw new DbException(e);

View File

@@ -32,7 +32,6 @@ class Migration45_46 implements Migration<Connection> {
s = txn.createStatement(); s = txn.createStatement();
s.execute("ALTER TABLE messages" s.execute("ALTER TABLE messages"
+ " ADD COLUMN temporary BOOLEAN DEFAULT FALSE NOT NULL"); + " ADD COLUMN temporary BOOLEAN DEFAULT FALSE NOT NULL");
s.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s, LOG, WARNING); tryToClose(s, LOG, WARNING);
throw new DbException(e); throw new DbException(e);

View File

@@ -39,7 +39,6 @@ class Migration46_47 implements Migration<Connection> {
s.execute(dbTypes.replaceTypes("ALTER TABLE contacts" s.execute(dbTypes.replaceTypes("ALTER TABLE contacts"
+ " ADD COLUMN syncVersions" + " ADD COLUMN syncVersions"
+ " _BINARY DEFAULT '00' NOT NULL")); + " _BINARY DEFAULT '00' NOT NULL"));
s.close();
} catch (SQLException e) { } catch (SQLException e) {
tryToClose(s, LOG, WARNING); tryToClose(s, LOG, WARNING);
throw new DbException(e); throw new DbException(e);

View File

@@ -1,95 +0,0 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DbException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Logger;
import static java.lang.System.arraycopy;
import static java.sql.Types.BINARY;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
class Migration47_48 implements Migration<Connection> {
private static final Logger LOG = getLogger(Migration47_48.class.getName());
private final DatabaseTypes dbTypes;
Migration47_48(DatabaseTypes dbTypes) {
this.dbTypes = dbTypes;
}
@Override
public int getStartVersion() {
return 47;
}
@Override
public int getEndVersion() {
return 48;
}
@Override
public void migrate(Connection txn) throws DbException {
Statement s = null;
ResultSet rs = null;
PreparedStatement ps = null;
try {
s = txn.createStatement();
s.execute("ALTER TABLE messages"
+ " ADD COLUMN deleted BOOLEAN DEFAULT FALSE NOT NULL");
s.execute("UPDATE messages SET deleted = TRUE WHERE raw IS NULL");
s.execute("ALTER TABLE messages"
+ " ADD COLUMN blockCount INT DEFAULT 1 NOT NULL");
s.execute(dbTypes.replaceTypes("CREATE TABLE blocks"
+ " (messageId _HASH NOT NULL,"
+ " blockNumber INT NOT NULL,"
+ " blockLength INT NOT NULL," // Excludes block header
+ " data BLOB," // Null if message has been deleted
+ " PRIMARY KEY (messageId, blockNumber),"
+ " FOREIGN KEY (messageId)"
+ " REFERENCES messages (messageId)"
+ " ON DELETE CASCADE)"));
rs = s.executeQuery("SELECT messageId, length, raw FROM messages");
ps = txn.prepareStatement("INSERT INTO blocks"
+ " (messageId, blockNumber, blockLength, data)"
+ " VALUES (?, 0, ?, ?)");
int migrated = 0;
while (rs.next()) {
byte[] id = rs.getBytes(1);
int length = rs.getInt(2);
byte[] raw = rs.getBytes(3);
ps.setBytes(1, id);
ps.setInt(2, length - MESSAGE_HEADER_LENGTH);
if (raw == null) {
ps.setNull(3, BINARY);
} else {
byte[] data = new byte[raw.length - MESSAGE_HEADER_LENGTH];
arraycopy(raw, MESSAGE_HEADER_LENGTH, data, 0, data.length);
ps.setBytes(3, data);
}
if (ps.executeUpdate() != 1) throw new DbStateException();
migrated++;
}
ps.close();
rs.close();
s.execute("ALTER TABLE messages DROP COLUMN raw");
s.close();
if (LOG.isLoggable(INFO))
LOG.info("Migrated " + migrated + " messages");
} catch (SQLException e) {
tryToClose(ps, LOG, WARNING);
tryToClose(rs, LOG, WARNING);
tryToClose(s, LOG, WARNING);
throw new DbException(e);
}
}
}

View File

@@ -1,40 +0,0 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DbException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Logger;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
class Migration48_49 implements Migration<Connection> {
private static final Logger LOG = getLogger(Migration48_49.class.getName());
@Override
public int getStartVersion() {
return 48;
}
@Override
public int getEndVersion() {
return 49;
}
@Override
public void migrate(Connection txn) throws DbException {
Statement s = null;
try {
s = txn.createStatement();
s.execute("DROP TABLE offers");
s.close();
} catch (SQLException e) {
tryToClose(s, LOG, WARNING);
throw new DbException(e);
}
}
}

View File

@@ -199,7 +199,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
Map<TransportId, LatestUpdate> latest = findLatestLocal(txn); Map<TransportId, LatestUpdate> latest = findLatestLocal(txn);
// Retrieve and parse the latest local properties // Retrieve and parse the latest local properties
for (Entry<TransportId, LatestUpdate> e : latest.entrySet()) { for (Entry<TransportId, LatestUpdate> e : latest.entrySet()) {
BdfList message = clientHelper.getSmallMessageAsList(txn, BdfList message = clientHelper.getMessageAsList(txn,
e.getValue().messageId); e.getValue().messageId);
local.put(e.getKey(), parseProperties(message)); local.put(e.getKey(), parseProperties(message));
} }
@@ -220,7 +220,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
true); true);
if (latest != null) { if (latest != null) {
// Retrieve and parse the latest local properties // Retrieve and parse the latest local properties
BdfList message = clientHelper.getSmallMessageAsList(txn, BdfList message = clientHelper.getMessageAsList(txn,
latest.messageId); latest.messageId);
p = parseProperties(message); p = parseProperties(message);
} }
@@ -250,7 +250,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
if (latest == null) { if (latest == null) {
local = new TransportProperties(); local = new TransportProperties();
} else { } else {
BdfList message = clientHelper.getSmallMessageAsList(txn, BdfList message = clientHelper.getMessageAsList(txn,
latest.messageId); latest.messageId);
local = parseProperties(message); local = parseProperties(message);
} }
@@ -271,8 +271,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
remote = new TransportProperties(); remote = new TransportProperties();
} else { } else {
// Retrieve and parse the latest remote properties // Retrieve and parse the latest remote properties
BdfList message = clientHelper.getSmallMessageAsList(txn, BdfList message =
latest.messageId); clientHelper.getMessageAsList(txn, latest.messageId);
remote = parseProperties(message); remote = parseProperties(message);
} }
// Merge in any discovered properties // Merge in any discovered properties
@@ -315,7 +315,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
} }
changed = true; changed = true;
} else { } else {
BdfList message = clientHelper.getSmallMessageAsList(txn, BdfList message = clientHelper.getMessageAsList(txn,
latest.messageId); latest.messageId);
TransportProperties old = parseProperties(message); TransportProperties old = parseProperties(message);
merged = new TransportProperties(old); merged = new TransportProperties(old);

View File

@@ -15,7 +15,6 @@ import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.event.TransportInactiveEvent; import org.briarproject.bramble.api.plugin.event.TransportInactiveEvent;
import org.briarproject.bramble.api.sync.Ack; import org.briarproject.bramble.api.sync.Ack;
import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.Offer; import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Priority; import org.briarproject.bramble.api.sync.Priority;
import org.briarproject.bramble.api.sync.Request; import org.briarproject.bramble.api.sync.Request;
@@ -26,8 +25,8 @@ import org.briarproject.bramble.api.sync.event.CloseSyncConnectionsEvent;
import org.briarproject.bramble.api.sync.event.GroupVisibilityUpdatedEvent; import org.briarproject.bramble.api.sync.event.GroupVisibilityUpdatedEvent;
import org.briarproject.bramble.api.sync.event.MessageRequestedEvent; import org.briarproject.bramble.api.sync.event.MessageRequestedEvent;
import org.briarproject.bramble.api.sync.event.MessageSharedEvent; import org.briarproject.bramble.api.sync.event.MessageSharedEvent;
import org.briarproject.bramble.api.sync.event.MessagesToAckEvent; import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
import org.briarproject.bramble.api.sync.event.MessagesToRequestEvent; import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.transport.StreamWriter; import org.briarproject.bramble.api.transport.StreamWriter;
@@ -88,6 +87,8 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
private final AtomicBoolean generateAckQueued = new AtomicBoolean(false); private final AtomicBoolean generateAckQueued = new AtomicBoolean(false);
private final AtomicBoolean generateBatchQueued = new AtomicBoolean(false); private final AtomicBoolean generateBatchQueued = new AtomicBoolean(false);
private final AtomicBoolean generateOfferQueued = new AtomicBoolean(false); private final AtomicBoolean generateOfferQueued = new AtomicBoolean(false);
private final AtomicBoolean generateRequestQueued =
new AtomicBoolean(false);
private final AtomicLong nextSendTime = new AtomicLong(Long.MAX_VALUE); private final AtomicLong nextSendTime = new AtomicLong(Long.MAX_VALUE);
private volatile boolean interrupted = false; private volatile boolean interrupted = false;
@@ -124,6 +125,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
generateAck(); generateAck();
generateBatch(); generateBatch();
generateOffer(); generateOffer();
generateRequest();
long now = clock.currentTimeMillis(); long now = clock.currentTimeMillis();
long nextKeepalive = now + maxIdleTime; long nextKeepalive = now + maxIdleTime;
boolean dataToFlush = true; boolean dataToFlush = true;
@@ -195,6 +197,11 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
dbExecutor.execute(new GenerateOffer()); dbExecutor.execute(new GenerateOffer());
} }
private void generateRequest() {
if (generateRequestQueued.compareAndSet(false, true))
dbExecutor.execute(new GenerateRequest());
}
private void setNextSendTime(long time) { private void setNextSendTime(long time) {
long old = nextSendTime.getAndSet(time); long old = nextSendTime.getAndSet(time);
if (time < old) writerTasks.add(NEXT_SEND_TIME_DECREASED); if (time < old) writerTasks.add(NEXT_SEND_TIME_DECREASED);
@@ -220,16 +227,12 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
} else if (e instanceof MessageRequestedEvent) { } else if (e instanceof MessageRequestedEvent) {
if (((MessageRequestedEvent) e).getContactId().equals(contactId)) if (((MessageRequestedEvent) e).getContactId().equals(contactId))
generateBatch(); generateBatch();
} else if (e instanceof MessagesToAckEvent) { } else if (e instanceof MessageToAckEvent) {
if (((MessagesToAckEvent) e).getContactId().equals(contactId)) if (((MessageToAckEvent) e).getContactId().equals(contactId))
generateAck(); generateAck();
} else if (e instanceof MessagesToRequestEvent) { } else if (e instanceof MessageToRequestEvent) {
MessagesToRequestEvent m = (MessagesToRequestEvent) e; if (((MessageToRequestEvent) e).getContactId().equals(contactId))
if (m.getContactId().equals(contactId)) { generateRequest();
Collection<MessageId> ids = m.consumeIds();
if (ids != null)
writerTasks.add(new WriteRequest(new Request(ids)));
}
} else if (e instanceof LifecycleEvent) { } else if (e instanceof LifecycleEvent) {
LifecycleEvent l = (LifecycleEvent) e; LifecycleEvent l = (LifecycleEvent) e;
if (l.getLifecycleState() == STOPPING) interrupt(); if (l.getLifecycleState() == STOPPING) interrupt();
@@ -337,7 +340,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
try { try {
Offer o = db.transactionWithNullableResult(false, txn -> { Offer o = db.transactionWithNullableResult(false, txn -> {
Offer offer = db.generateOffer(txn, contactId, Offer offer = db.generateOffer(txn, contactId,
MAX_MESSAGE_IDS, maxLatency, true); MAX_MESSAGE_IDS, maxLatency);
setNextSendTime(db.getNextSendTime(txn, contactId)); setNextSendTime(db.getNextSendTime(txn, contactId));
return offer; return offer;
}); });
@@ -369,6 +372,27 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
} }
} }
private class GenerateRequest implements Runnable {
@DatabaseExecutor
@Override
public void run() {
if (interrupted) return;
if (!generateRequestQueued.getAndSet(false))
throw new AssertionError();
try {
Request r = db.transactionWithNullableResult(false, txn ->
db.generateRequest(txn, contactId, MAX_MESSAGE_IDS));
if (LOG.isLoggable(INFO))
LOG.info("Generated request: " + (r != null));
if (r != null) writerTasks.add(new WriteRequest(r));
} catch (DbException e) {
logException(LOG, WARNING, e);
interrupt();
}
}
}
private class WriteRequest implements ThrowingRunnable<IOException> { private class WriteRequest implements ThrowingRunnable<IOException> {
private final Request request; private final Request request;
@@ -383,6 +407,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
if (interrupted) return; if (interrupted) return;
recordWriter.writeRequest(request); recordWriter.writeRequest(request);
LOG.info("Sent request"); LOG.info("Sent request");
generateRequest();
} }
} }
} }

View File

@@ -186,8 +186,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
Collection<Message> b = Collection<Message> b =
db.transactionWithNullableResult(false, txn -> db.transactionWithNullableResult(false, txn ->
db.generateBatch(txn, contactId, db.generateBatch(txn, contactId,
MAX_RECORD_PAYLOAD_BYTES, maxLatency, MAX_RECORD_PAYLOAD_BYTES, maxLatency));
true));
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Generated batch: " + (b != null)); LOG.info("Generated batch: " + (b != null));
if (b == null) decrementOutstandingQueries(); if (b == null) decrementOutstandingQueries();

View File

@@ -120,7 +120,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
Pair<Message, Group> mg = db.transactionWithResult(true, txn -> { Pair<Message, Group> mg = db.transactionWithResult(true, txn -> {
MessageId id = unvalidated.poll(); MessageId id = unvalidated.poll();
if (id == null) throw new AssertionError(); if (id == null) throw new AssertionError();
Message m = db.getSmallMessage(txn, id); Message m = db.getMessage(txn, id);
Group g = db.getGroup(txn, m.getGroupId()); Group g = db.getGroup(txn, m.getGroupId());
return new Pair<>(m, g); return new Pair<>(m, g);
}); });
@@ -179,7 +179,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
invalidateMessage(txn, id); invalidateMessage(txn, id);
addDependentsToInvalidate(txn, id, invalidate); addDependentsToInvalidate(txn, id, invalidate);
} else if (allDelivered) { } else if (allDelivered) {
Message m = db.getSmallMessage(txn, id); Message m = db.getMessage(txn, id);
Group g = db.getGroup(txn, m.getGroupId()); Group g = db.getGroup(txn, m.getGroupId());
ClientId c = g.getClientId(); ClientId c = g.getClientId();
int majorVersion = g.getMajorVersion(); int majorVersion = g.getMajorVersion();

View File

@@ -5,6 +5,5 @@ interface ClientVersioningConstants {
// Metadata keys // Metadata keys
String MSG_KEY_UPDATE_VERSION = "version"; String MSG_KEY_UPDATE_VERSION = "version";
String MSG_KEY_LOCAL = "local"; String MSG_KEY_LOCAL = "local";
String GROUP_KEY_CONTACT_ID = "contactId";
} }

View File

@@ -50,7 +50,6 @@ import static java.util.Collections.emptyList;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
import static org.briarproject.bramble.versioning.ClientVersioningConstants.GROUP_KEY_CONTACT_ID;
import static org.briarproject.bramble.versioning.ClientVersioningConstants.MSG_KEY_LOCAL; import static org.briarproject.bramble.versioning.ClientVersioningConstants.MSG_KEY_LOCAL;
import static org.briarproject.bramble.versioning.ClientVersioningConstants.MSG_KEY_UPDATE_VERSION; import static org.briarproject.bramble.versioning.ClientVersioningConstants.MSG_KEY_UPDATE_VERSION;
@@ -161,13 +160,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
db.addGroup(txn, g); db.addGroup(txn, g);
db.setGroupVisibility(txn, c.getId(), g.getId(), SHARED); db.setGroupVisibility(txn, c.getId(), g.getId(), SHARED);
// Attach the contact ID to the group // Attach the contact ID to the group
BdfDictionary meta = new BdfDictionary(); clientHelper.setContactId(txn, g.getId(), c.getId());
meta.put(GROUP_KEY_CONTACT_ID, c.getId().getInt());
try {
clientHelper.mergeGroupMetadata(txn, g.getId(), meta);
} catch (FormatException e) {
throw new AssertionError(e);
}
// Create and store the first local update // Create and store the first local update
List<ClientVersion> versions = new ArrayList<>(clients); List<ClientVersion> versions = new ArrayList<>(clients);
Collections.sort(versions); Collections.sort(versions);
@@ -229,7 +222,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
Map<ClientMajorVersion, Visibility> after = Map<ClientMajorVersion, Visibility> after =
getVisibilities(newLocalStates, newRemoteStates); getVisibilities(newLocalStates, newRemoteStates);
// Call hooks for any visibilities that have changed // Call hooks for any visibilities that have changed
ContactId c = getContactId(txn, m.getGroupId()); ContactId c = clientHelper.getContactId(txn, m.getGroupId());
if (!before.equals(after)) { if (!before.equals(after)) {
Contact contact = db.getContact(txn, c); Contact contact = db.getContact(txn, c);
callVisibilityHooks(txn, contact, before, after); callVisibilityHooks(txn, contact, before, after);
@@ -298,8 +291,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
private List<ClientVersion> loadClientVersions(Transaction txn, private List<ClientVersion> loadClientVersions(Transaction txn,
MessageId m) throws DbException { MessageId m) throws DbException {
try { try {
return parseClientVersions( return parseClientVersions(clientHelper.getMessageAsList(txn, m));
clientHelper.getSmallMessageAsList(txn, m));
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }
@@ -392,7 +384,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
private Update loadUpdate(Transaction txn, MessageId m) throws DbException { private Update loadUpdate(Transaction txn, MessageId m) throws DbException {
try { try {
return parseUpdate(clientHelper.getSmallMessageAsList(txn, m)); return parseUpdate(clientHelper.getMessageAsList(txn, m));
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }
@@ -522,17 +514,6 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
storeUpdate(txn, g, states, 1); storeUpdate(txn, g, states, 1);
} }
private ContactId getContactId(Transaction txn, GroupId g)
throws DbException {
try {
BdfDictionary meta =
clientHelper.getGroupMetadataAsDictionary(txn, g);
return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue());
} catch (FormatException e) {
throw new DbException(e);
}
}
private List<ClientState> updateStatesFromRemoteStates( private List<ClientState> updateStatesFromRemoteStates(
List<ClientState> oldLocalStates, List<ClientState> remoteStates) { List<ClientState> oldLocalStates, List<ClientState> remoteStates) {
Set<ClientMajorVersion> remoteSet = new HashSet<>(); Set<ClientMajorVersion> remoteSet = new HashSet<>();

View File

@@ -122,11 +122,11 @@ public class ClientHelperImplTest extends BrambleTestCase {
expectToList(true); expectToList(true);
context.checking(new DbExpectations() {{ context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getSmallMessage(txn, messageId); oneOf(db).getMessage(txn, messageId);
will(returnValue(message)); will(returnValue(message));
}}); }});
clientHelper.getSmallMessageAsList(messageId); clientHelper.getMessageAsList(messageId);
context.assertIsSatisfied(); context.assertIsSatisfied();
} }

View File

@@ -44,10 +44,10 @@ import org.briarproject.bramble.api.sync.event.MessageAddedEvent;
import org.briarproject.bramble.api.sync.event.MessageRequestedEvent; import org.briarproject.bramble.api.sync.event.MessageRequestedEvent;
import org.briarproject.bramble.api.sync.event.MessageSharedEvent; import org.briarproject.bramble.api.sync.event.MessageSharedEvent;
import org.briarproject.bramble.api.sync.event.MessageStateChangedEvent; import org.briarproject.bramble.api.sync.event.MessageStateChangedEvent;
import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent; import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
import org.briarproject.bramble.api.sync.event.MessagesSentEvent; import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
import org.briarproject.bramble.api.sync.event.MessagesToAckEvent;
import org.briarproject.bramble.api.sync.event.MessagesToRequestEvent;
import org.briarproject.bramble.api.transport.IncomingKeys; import org.briarproject.bramble.api.transport.IncomingKeys;
import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.OutgoingKeys; import org.briarproject.bramble.api.transport.OutgoingKeys;
@@ -76,6 +76,7 @@ import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED; import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
import static org.briarproject.bramble.api.sync.validation.MessageState.UNKNOWN; import static org.briarproject.bramble.api.sync.validation.MessageState.UNKNOWN;
import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE; import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
import static org.briarproject.bramble.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
import static org.briarproject.bramble.test.TestUtils.getAgreementPrivateKey; import static org.briarproject.bramble.test.TestUtils.getAgreementPrivateKey;
import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey; import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey;
import static org.briarproject.bramble.test.TestUtils.getAuthor; import static org.briarproject.bramble.test.TestUtils.getAuthor;
@@ -294,11 +295,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
throws Exception { throws Exception {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
// Check whether the contact is in the DB (which it's not) // Check whether the contact is in the DB (which it's not)
exactly(17).of(database).startTransaction(); exactly(18).of(database).startTransaction();
will(returnValue(txn)); will(returnValue(txn));
exactly(17).of(database).containsContact(txn, contactId); exactly(18).of(database).containsContact(txn, contactId);
will(returnValue(false)); will(returnValue(false));
exactly(17).of(database).abortTransaction(txn); exactly(18).of(database).abortTransaction(txn);
}}); }});
DatabaseComponent db = createDatabaseComponent(database, eventBus, DatabaseComponent db = createDatabaseComponent(database, eventBus,
eventExecutor, shutdownManager); eventExecutor, shutdownManager);
@@ -322,7 +323,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
try { try {
db.transaction(false, transaction -> db.transaction(false, transaction ->
db.generateBatch(transaction, contactId, 123, 456, true)); db.generateBatch(transaction, contactId, 123, 456));
fail(); fail();
} catch (NoSuchContactException expected) { } catch (NoSuchContactException expected) {
// Expected // Expected
@@ -330,7 +331,15 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
try { try {
db.transaction(false, transaction -> db.transaction(false, transaction ->
db.generateOffer(transaction, contactId, 123, 456, true)); db.generateOffer(transaction, contactId, 123, 456));
fail();
} catch (NoSuchContactException expected) {
// Expected
}
try {
db.transaction(false, transaction ->
db.generateRequest(transaction, contactId, 123));
fail(); fail();
} catch (NoSuchContactException expected) { } catch (NoSuchContactException expected) {
// Expected // Expected
@@ -615,7 +624,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
try { try {
db.transaction(false, transaction -> db.transaction(false, transaction ->
db.getSmallMessage(transaction, messageId)); db.getMessage(transaction, messageId));
fail(); fail();
} catch (NoSuchMessageException expected) { } catch (NoSuchMessageException expected) {
// Expected // Expected
@@ -856,14 +865,14 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
will(returnValue(txn)); will(returnValue(txn));
oneOf(database).containsContact(txn, contactId); oneOf(database).containsContact(txn, contactId);
will(returnValue(true)); will(returnValue(true));
oneOf(database).getSmallMessagesToSend(txn, contactId, oneOf(database).getMessagesToSend(txn, contactId,
MAX_MESSAGE_LENGTH * 2, maxLatency); MAX_MESSAGE_LENGTH * 2, maxLatency);
will(returnValue(ids)); will(returnValue(ids));
oneOf(database).getSmallMessage(txn, messageId); oneOf(database).getMessage(txn, messageId);
will(returnValue(message)); will(returnValue(message));
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId, oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
maxLatency); maxLatency);
oneOf(database).getSmallMessage(txn, messageId1); oneOf(database).getMessage(txn, messageId1);
will(returnValue(message1)); will(returnValue(message1));
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1, oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1,
maxLatency); maxLatency);
@@ -876,7 +885,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
db.transaction(false, transaction -> db.transaction(false, transaction ->
assertEquals(messages, db.generateBatch(transaction, contactId, assertEquals(messages, db.generateBatch(transaction, contactId,
MAX_MESSAGE_LENGTH * 2, maxLatency, true))); MAX_MESSAGE_LENGTH * 2, maxLatency)));
} }
@Test @Test
@@ -888,8 +897,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
will(returnValue(txn)); will(returnValue(txn));
oneOf(database).containsContact(txn, contactId); oneOf(database).containsContact(txn, contactId);
will(returnValue(true)); will(returnValue(true));
oneOf(database).getSmallMessagesToOffer(txn, contactId, 123, oneOf(database).getMessagesToOffer(txn, contactId, 123, maxLatency);
maxLatency);
will(returnValue(ids)); will(returnValue(ids));
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId, oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
maxLatency); maxLatency);
@@ -901,13 +909,36 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
eventExecutor, shutdownManager); eventExecutor, shutdownManager);
db.transaction(false, transaction -> { db.transaction(false, transaction -> {
Offer o = db.generateOffer(transaction, contactId, 123, maxLatency, Offer o = db.generateOffer(transaction, contactId, 123, maxLatency);
true);
assertNotNull(o); assertNotNull(o);
assertEquals(ids, o.getMessageIds()); assertEquals(ids, o.getMessageIds());
}); });
} }
@Test
public void testGenerateRequest() throws Exception {
MessageId messageId1 = new MessageId(getRandomId());
Collection<MessageId> ids = asList(messageId, messageId1);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsContact(txn, contactId);
will(returnValue(true));
oneOf(database).getMessagesToRequest(txn, contactId, 123);
will(returnValue(ids));
oneOf(database).removeOfferedMessages(txn, contactId, ids);
oneOf(database).commitTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, eventBus,
eventExecutor, shutdownManager);
db.transaction(false, transaction -> {
Request r = db.generateRequest(transaction, contactId, 123);
assertNotNull(r);
assertEquals(ids, r.getMessageIds());
});
}
@Test @Test
public void testGenerateRequestedBatch() throws Exception { public void testGenerateRequestedBatch() throws Exception {
Collection<MessageId> ids = asList(messageId, messageId1); Collection<MessageId> ids = asList(messageId, messageId1);
@@ -920,11 +951,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
oneOf(database).getRequestedMessagesToSend(txn, contactId, oneOf(database).getRequestedMessagesToSend(txn, contactId,
MAX_MESSAGE_LENGTH * 2, maxLatency); MAX_MESSAGE_LENGTH * 2, maxLatency);
will(returnValue(ids)); will(returnValue(ids));
oneOf(database).getSmallMessage(txn, messageId); oneOf(database).getMessage(txn, messageId);
will(returnValue(message)); will(returnValue(message));
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId, oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
maxLatency); maxLatency);
oneOf(database).getSmallMessage(txn, messageId1); oneOf(database).getMessage(txn, messageId1);
will(returnValue(message1)); will(returnValue(message1));
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1, oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1,
maxLatency); maxLatency);
@@ -987,10 +1018,10 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
oneOf(database).raiseAckFlag(txn, contactId, messageId); oneOf(database).raiseAckFlag(txn, contactId, messageId);
oneOf(database).commitTransaction(txn); oneOf(database).commitTransaction(txn);
// First time: the message was received and added // First time: the message was received and added
oneOf(eventBus).broadcast(with(any(MessagesToAckEvent.class))); oneOf(eventBus).broadcast(with(any(MessageToAckEvent.class)));
oneOf(eventBus).broadcast(with(any(MessageAddedEvent.class))); oneOf(eventBus).broadcast(with(any(MessageAddedEvent.class)));
// Second time: the message needs to be acked // Second time: the message needs to be acked
oneOf(eventBus).broadcast(with(any(MessagesToAckEvent.class))); oneOf(eventBus).broadcast(with(any(MessageToAckEvent.class)));
}}); }});
DatabaseComponent db = createDatabaseComponent(database, eventBus, DatabaseComponent db = createDatabaseComponent(database, eventBus,
eventExecutor, shutdownManager); eventExecutor, shutdownManager);
@@ -1018,7 +1049,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
oneOf(database).raiseAckFlag(txn, contactId, messageId); oneOf(database).raiseAckFlag(txn, contactId, messageId);
oneOf(database).commitTransaction(txn); oneOf(database).commitTransaction(txn);
// The message was received but not added // The message was received but not added
oneOf(eventBus).broadcast(with(any(MessagesToAckEvent.class))); oneOf(eventBus).broadcast(with(any(MessageToAckEvent.class)));
}}); }});
DatabaseComponent db = createDatabaseComponent(database, eventBus, DatabaseComponent db = createDatabaseComponent(database, eventBus,
eventExecutor, shutdownManager); eventExecutor, shutdownManager);
@@ -1049,15 +1080,19 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
public void testReceiveOffer() throws Exception { public void testReceiveOffer() throws Exception {
MessageId messageId1 = new MessageId(getRandomId()); MessageId messageId1 = new MessageId(getRandomId());
MessageId messageId2 = new MessageId(getRandomId()); MessageId messageId2 = new MessageId(getRandomId());
MessageId messageId3 = new MessageId(getRandomId());
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(database).startTransaction(); oneOf(database).startTransaction();
will(returnValue(txn)); will(returnValue(txn));
oneOf(database).containsContact(txn, contactId); oneOf(database).containsContact(txn, contactId);
will(returnValue(true)); will(returnValue(true));
// There's room for two more offered messages
oneOf(database).countOfferedMessages(txn, contactId);
will(returnValue(MAX_OFFERED_MESSAGES - 2));
// The first message isn't visible - request it // The first message isn't visible - request it
oneOf(database).containsVisibleMessage(txn, contactId, messageId); oneOf(database).containsVisibleMessage(txn, contactId, messageId);
will(returnValue(false)); will(returnValue(false));
oneOf(database).addOfferedMessage(txn, contactId, messageId);
// The second message is visible - ack it // The second message is visible - ack it
oneOf(database).containsVisibleMessage(txn, contactId, messageId1); oneOf(database).containsVisibleMessage(txn, contactId, messageId1);
will(returnValue(true)); will(returnValue(true));
@@ -1066,14 +1101,19 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
// The third message isn't visible - request it // The third message isn't visible - request it
oneOf(database).containsVisibleMessage(txn, contactId, messageId2); oneOf(database).containsVisibleMessage(txn, contactId, messageId2);
will(returnValue(false)); will(returnValue(false));
oneOf(database).addOfferedMessage(txn, contactId, messageId2);
// The fourth message isn't visible, but there's no room to store it
oneOf(database).containsVisibleMessage(txn, contactId, messageId3);
will(returnValue(false));
oneOf(database).commitTransaction(txn); oneOf(database).commitTransaction(txn);
oneOf(eventBus).broadcast(with(any(MessagesToAckEvent.class))); oneOf(eventBus).broadcast(with(any(MessageToAckEvent.class)));
oneOf(eventBus).broadcast(with(any(MessagesToRequestEvent.class))); oneOf(eventBus).broadcast(with(any(MessageToRequestEvent.class)));
}}); }});
DatabaseComponent db = createDatabaseComponent(database, eventBus, DatabaseComponent db = createDatabaseComponent(database, eventBus,
eventExecutor, shutdownManager); eventExecutor, shutdownManager);
Offer o = new Offer(asList(messageId, messageId1, messageId2)); Offer o = new Offer(asList(messageId, messageId1,
messageId2, messageId3));
db.transaction(false, transaction -> db.transaction(false, transaction ->
db.receiveOffer(transaction, contactId, o)); db.receiveOffer(transaction, contactId, o));
} }

View File

@@ -3,9 +3,11 @@ package org.briarproject.bramble.db;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.system.SystemClock; import org.briarproject.bramble.system.SystemClock;
import org.briarproject.bramble.test.TestDatabaseConfig; import org.briarproject.bramble.test.TestDatabaseConfig;
import org.briarproject.bramble.test.TestMessageFactory;
import org.briarproject.bramble.test.UTest; import org.briarproject.bramble.test.UTest;
import java.io.IOException; import java.io.IOException;
@@ -30,7 +32,8 @@ public abstract class DatabasePerformanceComparisonTest
private SecretKey databaseKey = getSecretKey(); private SecretKey databaseKey = getSecretKey();
abstract Database<Connection> createDatabase(boolean conditionA, abstract Database<Connection> createDatabase(boolean conditionA,
DatabaseConfig databaseConfig, Clock clock); DatabaseConfig databaseConfig, MessageFactory messageFactory,
Clock clock);
@Override @Override
protected void benchmark(String name, protected void benchmark(String name,
@@ -73,7 +76,8 @@ public abstract class DatabasePerformanceComparisonTest
private Database<Connection> openDatabase(boolean conditionA) private Database<Connection> openDatabase(boolean conditionA)
throws DbException { throws DbException {
Database<Connection> db = createDatabase(conditionA, Database<Connection> db = createDatabase(conditionA,
new TestDatabaseConfig(testDir), new SystemClock()); new TestDatabaseConfig(testDir), new TestMessageFactory(),
new SystemClock());
db.open(databaseKey, null); db.open(databaseKey, null);
return db; return db;
} }

View File

@@ -41,6 +41,7 @@ import static org.briarproject.bramble.test.TestUtils.getGroup;
import static org.briarproject.bramble.test.TestUtils.getIdentity; import static org.briarproject.bramble.test.TestUtils.getIdentity;
import static org.briarproject.bramble.test.TestUtils.getMessage; import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory; import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
import static org.briarproject.bramble.test.UTest.Result.INCONCLUSIVE; import static org.briarproject.bramble.test.UTest.Result.INCONCLUSIVE;
import static org.briarproject.bramble.test.UTest.Z_CRITICAL_0_1; import static org.briarproject.bramble.test.UTest.Z_CRITICAL_0_1;
@@ -80,6 +81,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
private static final int METADATA_KEYS_PER_MESSAGE = 5; private static final int METADATA_KEYS_PER_MESSAGE = 5;
private static final int METADATA_KEY_LENGTH = 10; private static final int METADATA_KEY_LENGTH = 10;
private static final int METADATA_VALUE_LENGTH = 100; private static final int METADATA_VALUE_LENGTH = 100;
private static final int OFFERED_MESSAGES_PER_CONTACT = 100;
/** /**
* How many benchmark iterations to run in each block. * How many benchmark iterations to run in each block.
@@ -190,6 +192,16 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
}); });
} }
@Test
public void testCountOfferedMessages() throws Exception {
String name = "countOfferedMessages(T, ContactId)";
benchmark(name, db -> {
Connection txn = db.startTransaction();
db.countOfferedMessages(txn, pickRandom(contacts).getId());
db.commitTransaction(txn);
});
}
@Test @Test
public void testGetContact() throws Exception { public void testGetContact() throws Exception {
String name = "getContact(T, ContactId)"; String name = "getContact(T, ContactId)";
@@ -442,6 +454,17 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
}); });
} }
@Test
public void testGetMessagesToRequest() throws Exception {
String name = "getMessagesToRequest(T, ContactId, int)";
benchmark(name, db -> {
Connection txn = db.startTransaction();
db.getMessagesToRequest(txn, pickRandom(contacts).getId(),
MAX_MESSAGE_IDS);
db.commitTransaction(txn);
});
}
@Test @Test
public void testGetMessagesToSend() throws Exception { public void testGetMessagesToSend() throws Exception {
String name = "getMessagesToSend(T, ContactId, int)"; String name = "getMessagesToSend(T, ContactId, int)";
@@ -484,11 +507,11 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
} }
@Test @Test
public void testGetSmallMessage() throws Exception { public void testGetMessage() throws Exception {
String name = "getSmallMessage(T, MessageId)"; String name = "getMessage(T, MessageId)";
benchmark(name, db -> { benchmark(name, db -> {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
db.getSmallMessage(txn, pickRandom(messages).getId()); db.getMessage(txn, pickRandom(messages).getId());
db.commitTransaction(txn); db.commitTransaction(txn);
}); });
} }
@@ -560,6 +583,9 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
groupMessages.get(g.getId()).add(m.getId()); groupMessages.get(g.getId()).add(m.getId());
} }
} }
for (int j = 0; j < OFFERED_MESSAGES_PER_CONTACT; j++) {
db.addOfferedMessage(txn, c, new MessageId(getRandomId()));
}
} }
for (int i = 0; i < LOCAL_GROUPS; i++) { for (int i = 0; i < LOCAL_GROUPS; i++) {
Group g = getGroup(clientIds.get(i % CLIENTS), 123); Group g = getGroup(clientIds.get(i % CLIENTS), 123);

View File

@@ -3,9 +3,11 @@ package org.briarproject.bramble.db;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.system.SystemClock; import org.briarproject.bramble.system.SystemClock;
import org.briarproject.bramble.test.TestDatabaseConfig; import org.briarproject.bramble.test.TestDatabaseConfig;
import org.briarproject.bramble.test.TestMessageFactory;
import org.briarproject.bramble.util.IoUtils; import org.briarproject.bramble.util.IoUtils;
import java.io.File; import java.io.File;
@@ -24,7 +26,7 @@ public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
private SecretKey databaseKey = getSecretKey(); private SecretKey databaseKey = getSecretKey();
abstract Database<Connection> createDatabase(DatabaseConfig databaseConfig, abstract Database<Connection> createDatabase(DatabaseConfig databaseConfig,
Clock clock); MessageFactory messageFactory, Clock clock);
@Nullable @Nullable
protected abstract File getTraceFile(); protected abstract File getTraceFile();
@@ -46,7 +48,8 @@ public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
private Database<Connection> openDatabase() throws DbException { private Database<Connection> openDatabase() throws DbException {
Database<Connection> db = createDatabase( Database<Connection> db = createDatabase(
new TestDatabaseConfig(testDir), new SystemClock()); new TestDatabaseConfig(testDir), new TestMessageFactory(),
new SystemClock());
db.open(databaseKey, null); db.open(databaseKey, null);
return db; return db;
} }

View File

@@ -16,6 +16,6 @@ public class H2DatabasePerformanceTest extends SingleDatabasePerformanceTest {
@Override @Override
protected JdbcDatabase createDatabase(DatabaseConfig config, protected JdbcDatabase createDatabase(DatabaseConfig config,
MessageFactory messageFactory, Clock clock) { MessageFactory messageFactory, Clock clock) {
return new H2Database(config, clock); return new H2Database(config, messageFactory, clock);
} }
} }

View File

@@ -9,6 +9,6 @@ public class H2DatabaseTest extends JdbcDatabaseTest {
@Override @Override
protected JdbcDatabase createDatabase(DatabaseConfig config, protected JdbcDatabase createDatabase(DatabaseConfig config,
MessageFactory messageFactory, Clock clock) { MessageFactory messageFactory, Clock clock) {
return new H2Database(config, clock); return new H2Database(config, messageFactory, clock);
} }
} }

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.db; package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore; import org.junit.Ignore;
@@ -14,8 +15,8 @@ public class H2DatabaseTraceTest extends DatabaseTraceTest {
@Override @Override
Database<Connection> createDatabase(DatabaseConfig databaseConfig, Database<Connection> createDatabase(DatabaseConfig databaseConfig,
Clock clock) { MessageFactory messageFactory, Clock clock) {
return new H2Database(databaseConfig, clock) { return new H2Database(databaseConfig, messageFactory, clock) {
@Override @Override
@Nonnull @Nonnull
String getUrl() { String getUrl() {

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.db; package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore; import org.junit.Ignore;
@@ -12,11 +13,11 @@ public class H2HyperSqlDatabasePerformanceComparisonTest
@Override @Override
Database<Connection> createDatabase(boolean conditionA, Database<Connection> createDatabase(boolean conditionA,
DatabaseConfig databaseConfig, DatabaseConfig databaseConfig, MessageFactory messageFactory,
Clock clock) { Clock clock) {
if (conditionA) if (conditionA)
return new H2Database(databaseConfig, clock); return new H2Database(databaseConfig, messageFactory, clock);
else return new HyperSqlDatabase(databaseConfig, clock); else return new HyperSqlDatabase(databaseConfig, messageFactory, clock);
} }
@Override @Override

View File

@@ -11,7 +11,7 @@ public class H2MigrationTest extends DatabaseMigrationTest {
@Override @Override
Database<Connection> createDatabase( Database<Connection> createDatabase(
List<Migration<Connection>> migrations) { List<Migration<Connection>> migrations) {
return new H2Database(config, clock) { return new H2Database(config, messageFactory, clock) {
@Override @Override
List<Migration<Connection>> getMigrations() { List<Migration<Connection>> getMigrations() {
return migrations; return migrations;

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.db; package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore; import org.junit.Ignore;
@@ -17,9 +18,9 @@ public class H2SelfDatabasePerformanceComparisonTest
@Override @Override
Database<Connection> createDatabase(boolean conditionA, Database<Connection> createDatabase(boolean conditionA,
DatabaseConfig databaseConfig, DatabaseConfig databaseConfig, MessageFactory messageFactory,
Clock clock) { Clock clock) {
return new H2Database(databaseConfig, clock); return new H2Database(databaseConfig, messageFactory, clock);
} }
@Override @Override

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig; import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore; import org.junit.Ignore;
@@ -19,11 +20,12 @@ public class H2SleepDatabasePerformanceComparisonTest
@Override @Override
Database<Connection> createDatabase(boolean conditionA, Database<Connection> createDatabase(boolean conditionA,
DatabaseConfig databaseConfig, Clock clock) { DatabaseConfig databaseConfig, MessageFactory messageFactory,
Clock clock) {
if (conditionA) { if (conditionA) {
return new H2Database(databaseConfig, clock); return new H2Database(databaseConfig, messageFactory, clock);
} else { } else {
return new H2Database(databaseConfig, clock) { return new H2Database(databaseConfig, messageFactory, clock) {
@Override @Override
@NotNullByDefault @NotNullByDefault
public void commitTransaction(Connection txn) public void commitTransaction(Connection txn)

View File

@@ -17,6 +17,6 @@ public class HyperSqlDatabasePerformanceTest
@Override @Override
protected JdbcDatabase createDatabase(DatabaseConfig config, protected JdbcDatabase createDatabase(DatabaseConfig config,
MessageFactory messageFactory, Clock clock) { MessageFactory messageFactory, Clock clock) {
return new HyperSqlDatabase(config, clock); return new HyperSqlDatabase(config, messageFactory, clock);
} }
} }

View File

@@ -9,6 +9,6 @@ public class HyperSqlDatabaseTest extends JdbcDatabaseTest {
@Override @Override
protected JdbcDatabase createDatabase(DatabaseConfig config, protected JdbcDatabase createDatabase(DatabaseConfig config,
MessageFactory messageFactory, Clock clock) { MessageFactory messageFactory, Clock clock) {
return new HyperSqlDatabase(config, clock); return new HyperSqlDatabase(config, messageFactory ,clock);
} }
} }

View File

@@ -11,7 +11,7 @@ public class HyperSqlMigrationTest extends DatabaseMigrationTest {
@Override @Override
Database<Connection> createDatabase( Database<Connection> createDatabase(
List<Migration<Connection>> migrations) { List<Migration<Connection>> migrations) {
return new HyperSqlDatabase(config, clock) { return new HyperSqlDatabase(config, messageFactory, clock) {
@Override @Override
List<Migration<Connection>> getMigrations() { List<Migration<Connection>> getMigrations() {
return migrations; return migrations;

View File

@@ -41,6 +41,7 @@ import org.junit.Test;
import java.io.File; import java.io.File;
import java.sql.Connection; import java.sql.Connection;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -165,7 +166,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
assertTrue(db.containsGroup(txn, groupId)); assertTrue(db.containsGroup(txn, groupId));
assertTrue(db.containsMessage(txn, messageId)); assertTrue(db.containsMessage(txn, messageId));
assertArrayEquals(message.getBody(), assertArrayEquals(message.getBody(),
db.getSmallMessage(txn, messageId).getBody()); db.getMessage(txn, messageId).getBody());
// Delete the records // Delete the records
db.removeMessage(txn, messageId); db.removeMessage(txn, messageId);
@@ -1186,6 +1187,35 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
db.close(); db.close();
} }
@Test
public void testOfferedMessages() throws Exception {
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
// Add a contact - initially there should be no offered messages
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), null, true));
assertEquals(0, db.countOfferedMessages(txn, contactId));
// Add some offered messages and count them
List<MessageId> ids = new ArrayList<>();
for (int i = 0; i < 10; i++) {
MessageId m = new MessageId(getRandomId());
db.addOfferedMessage(txn, contactId, m);
ids.add(m);
}
assertEquals(10, db.countOfferedMessages(txn, contactId));
// Remove some of the offered messages and count again
List<MessageId> half = ids.subList(0, 5);
db.removeOfferedMessages(txn, contactId, half);
assertEquals(5, db.countOfferedMessages(txn, contactId));
db.commitTransaction(txn);
db.close();
}
@Test @Test
public void testGroupMetadata() throws Exception { public void testGroupMetadata() throws Exception {
Database<Connection> db = open(false); Database<Connection> db = open(false);
@@ -1899,7 +1929,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
assertEquals(singletonList(messageId), ids); assertEquals(singletonList(messageId), ids);
// The message should be available // The message should be available
Message m = db.getSmallMessage(txn, messageId); Message m = db.getMessage(txn, messageId);
assertEquals(messageId, m.getId()); assertEquals(messageId, m.getId());
assertEquals(groupId, m.getGroupId()); assertEquals(groupId, m.getGroupId());
assertEquals(message.getTimestamp(), m.getTimestamp()); assertEquals(message.getTimestamp(), m.getTimestamp());
@@ -1919,7 +1949,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
// Requesting the message should throw an exception // Requesting the message should throw an exception
try { try {
db.getSmallMessage(txn, messageId); db.getMessage(txn, messageId);
fail(); fail();
} catch (MessageDeletedException expected) { } catch (MessageDeletedException expected) {
// Expected // Expected
@@ -2057,7 +2087,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction(); Connection txn = db.startTransaction();
try { try {
// Ask for a nonexistent message - an exception should be thrown // Ask for a nonexistent message - an exception should be thrown
db.getSmallMessage(txn, messageId); db.getMessage(txn, messageId);
fail(); fail();
} catch (DbException expected) { } catch (DbException expected) {
// It should be possible to abort the transaction without error // It should be possible to abort the transaction without error

View File

@@ -402,7 +402,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId()); localGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getSmallMessageAsList(txn, fooUpdateId); oneOf(clientHelper).getMessageAsList(txn, fooUpdateId);
will(returnValue(fooUpdate)); will(returnValue(fooUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict); fooPropertiesDict);
@@ -469,7 +469,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup2.getId()); contactGroup2.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getSmallMessageAsList(txn, fooUpdateId); oneOf(clientHelper).getMessageAsList(txn, fooUpdateId);
will(returnValue(fooUpdate)); will(returnValue(fooUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict); fooPropertiesDict);
@@ -524,7 +524,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId()); contactGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getSmallMessageAsList(txn, updateId); oneOf(clientHelper).getMessageAsList(txn, updateId);
will(returnValue(update)); will(returnValue(update));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict); fooPropertiesDict);
@@ -562,7 +562,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId()); localGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getSmallMessageAsList(txn, updateId); oneOf(clientHelper).getMessageAsList(txn, updateId);
will(returnValue(update)); will(returnValue(update));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict); fooPropertiesDict);
@@ -693,7 +693,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId()); localGroup.getId());
will(returnValue(localGroupMessageMetadata)); will(returnValue(localGroupMessageMetadata));
oneOf(clientHelper).getSmallMessageAsList(txn, localGroupUpdateId); oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId);
will(returnValue(oldUpdate)); will(returnValue(oldUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
oldPropertiesDict); oldPropertiesDict);
@@ -758,7 +758,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId()); localGroup.getId());
will(returnValue(localGroupMessageMetadata)); will(returnValue(localGroupMessageMetadata));
oneOf(clientHelper).getSmallMessageAsList(txn, localGroupUpdateId); oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId);
will(returnValue(oldUpdate)); will(returnValue(oldUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
oldPropertiesDict); oldPropertiesDict);
@@ -817,12 +817,12 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
localGroup.getId()); localGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
// Retrieve and parse the latest local properties // Retrieve and parse the latest local properties
oneOf(clientHelper).getSmallMessageAsList(txn, fooVersion999); oneOf(clientHelper).getMessageAsList(txn, fooVersion999);
will(returnValue(fooUpdate)); will(returnValue(fooUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict); fooPropertiesDict);
will(returnValue(fooProperties)); will(returnValue(fooProperties));
oneOf(clientHelper).getSmallMessageAsList(txn, barVersion3); oneOf(clientHelper).getMessageAsList(txn, barVersion3);
will(returnValue(barUpdate)); will(returnValue(barUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
barPropertiesDict); barPropertiesDict);

View File

@@ -64,7 +64,7 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
oneOf(db).transactionWithNullableResult(with(false), oneOf(db).transactionWithNullableResult(with(false),
withNullableDbCallable(noMsgTxn)); withNullableDbCallable(noMsgTxn));
oneOf(db).generateBatch(with(noMsgTxn), with(contactId), oneOf(db).generateBatch(with(noMsgTxn), with(contactId),
with(any(int.class)), with(MAX_LATENCY), with(true)); with(any(int.class)), with(MAX_LATENCY));
will(returnValue(null)); will(returnValue(null));
// Send the end of stream marker // Send the end of stream marker
oneOf(streamWriter).sendEndOfStream(); oneOf(streamWriter).sendEndOfStream();
@@ -101,7 +101,7 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
oneOf(db).transactionWithNullableResult(with(false), oneOf(db).transactionWithNullableResult(with(false),
withNullableDbCallable(msgTxn)); withNullableDbCallable(msgTxn));
oneOf(db).generateBatch(with(msgTxn), with(contactId), oneOf(db).generateBatch(with(msgTxn), with(contactId),
with(any(int.class)), with(MAX_LATENCY), with(true)); with(any(int.class)), with(MAX_LATENCY));
will(returnValue(singletonList(message))); will(returnValue(singletonList(message)));
oneOf(recordWriter).writeMessage(message); oneOf(recordWriter).writeMessage(message);
// No more acks // No more acks
@@ -113,7 +113,7 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
oneOf(db).transactionWithNullableResult(with(false), oneOf(db).transactionWithNullableResult(with(false),
withNullableDbCallable(noMsgTxn)); withNullableDbCallable(noMsgTxn));
oneOf(db).generateBatch(with(noMsgTxn), with(contactId), oneOf(db).generateBatch(with(noMsgTxn), with(contactId),
with(any(int.class)), with(MAX_LATENCY), with(true)); with(any(int.class)), with(MAX_LATENCY));
will(returnValue(null)); will(returnValue(null));
// Send the end of stream marker // Send the end of stream marker
oneOf(streamWriter).sendEndOfStream(); oneOf(streamWriter).sendEndOfStream();

View File

@@ -99,7 +99,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
context.checking(new DbExpectations() {{ context.checking(new DbExpectations() {{
// Load the first raw message and group // Load the first raw message and group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getSmallMessage(txn, messageId); oneOf(db).getMessage(txn, messageId);
will(returnValue(message)); will(returnValue(message));
oneOf(db).getGroup(txn, groupId); oneOf(db).getGroup(txn, groupId);
will(returnValue(group)); will(returnValue(group));
@@ -118,7 +118,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
will(returnValue(emptyMap())); will(returnValue(emptyMap()));
// Load the second raw message and group // Load the second raw message and group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn2)); oneOf(db).transactionWithResult(with(true), withDbCallable(txn2));
oneOf(db).getSmallMessage(txn2, messageId1); oneOf(db).getMessage(txn2, messageId1);
will(returnValue(message1)); will(returnValue(message1));
oneOf(db).getGroup(txn2, groupId); oneOf(db).getGroup(txn2, groupId);
will(returnValue(group)); will(returnValue(group));
@@ -159,7 +159,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageDependencies(txn, messageId); oneOf(db).getMessageDependencies(txn, messageId);
will(returnValue(singletonMap(messageId1, DELIVERED))); will(returnValue(singletonMap(messageId1, DELIVERED)));
// Get the message and its metadata to deliver // Get the message and its metadata to deliver
oneOf(db).getSmallMessage(txn, messageId); oneOf(db).getMessage(txn, messageId);
will(returnValue(message)); will(returnValue(message));
oneOf(db).getGroup(txn, groupId); oneOf(db).getGroup(txn, groupId);
will(returnValue(group)); will(returnValue(group));
@@ -179,7 +179,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageDependencies(txn1, messageId2); oneOf(db).getMessageDependencies(txn1, messageId2);
will(returnValue(singletonMap(messageId1, DELIVERED))); will(returnValue(singletonMap(messageId1, DELIVERED)));
// Get the dependent and its metadata to deliver // Get the dependent and its metadata to deliver
oneOf(db).getSmallMessage(txn1, messageId2); oneOf(db).getMessage(txn1, messageId2);
will(returnValue(message2)); will(returnValue(message2));
oneOf(db).getGroup(txn1, groupId); oneOf(db).getGroup(txn1, groupId);
will(returnValue(group)); will(returnValue(group));
@@ -276,11 +276,11 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
context.checking(new DbExpectations() {{ context.checking(new DbExpectations() {{
// Load the first raw message - *gasp* it's gone! // Load the first raw message - *gasp* it's gone!
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getSmallMessage(txn, messageId); oneOf(db).getMessage(txn, messageId);
will(throwException(new NoSuchMessageException())); will(throwException(new NoSuchMessageException()));
// Load the second raw message and group // Load the second raw message and group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn1)); oneOf(db).transactionWithResult(with(true), withDbCallable(txn1));
oneOf(db).getSmallMessage(txn1, messageId1); oneOf(db).getMessage(txn1, messageId1);
will(returnValue(message1)); will(returnValue(message1));
oneOf(db).getGroup(txn1, groupId); oneOf(db).getGroup(txn1, groupId);
will(returnValue(group)); will(returnValue(group));
@@ -317,14 +317,14 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
context.checking(new DbExpectations() {{ context.checking(new DbExpectations() {{
// Load the first raw message // Load the first raw message
oneOf(db).transactionWithResult(with(true), withDbCallable(txn)); oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getSmallMessage(txn, messageId); oneOf(db).getMessage(txn, messageId);
will(returnValue(message)); will(returnValue(message));
// Load the group - *gasp* it's gone! // Load the group - *gasp* it's gone!
oneOf(db).getGroup(txn, groupId); oneOf(db).getGroup(txn, groupId);
will(throwException(new NoSuchGroupException())); will(throwException(new NoSuchGroupException()));
// Load the second raw message and group // Load the second raw message and group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn1)); oneOf(db).transactionWithResult(with(true), withDbCallable(txn1));
oneOf(db).getSmallMessage(txn1, messageId1); oneOf(db).getMessage(txn1, messageId1);
will(returnValue(message1)); will(returnValue(message1));
oneOf(db).getGroup(txn1, groupId); oneOf(db).getGroup(txn1, groupId);
will(returnValue(group)); will(returnValue(group));
@@ -614,7 +614,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageDependencies(txn2, messageId1); oneOf(db).getMessageDependencies(txn2, messageId1);
will(returnValue(singletonMap(messageId, DELIVERED))); will(returnValue(singletonMap(messageId, DELIVERED)));
// Get message 1 and its metadata // Get message 1 and its metadata
oneOf(db).getSmallMessage(txn2, messageId1); oneOf(db).getMessage(txn2, messageId1);
will(returnValue(message1)); will(returnValue(message1));
oneOf(db).getGroup(txn2, groupId); oneOf(db).getGroup(txn2, groupId);
will(returnValue(group)); will(returnValue(group));
@@ -634,7 +634,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageDependencies(txn3, messageId2); oneOf(db).getMessageDependencies(txn3, messageId2);
will(returnValue(singletonMap(messageId, DELIVERED))); will(returnValue(singletonMap(messageId, DELIVERED)));
// Get message 2 and its metadata // Get message 2 and its metadata
oneOf(db).getSmallMessage(txn3, messageId2); oneOf(db).getMessage(txn3, messageId2);
will(returnValue(message2)); will(returnValue(message2));
oneOf(db).getGroup(txn3, groupId); oneOf(db).getGroup(txn3, groupId);
will(returnValue(group)); will(returnValue(group));
@@ -654,7 +654,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageDependencies(txn4, messageId3); oneOf(db).getMessageDependencies(txn4, messageId3);
will(returnValue(twoDependencies)); will(returnValue(twoDependencies));
// Get message 3 and its metadata // Get message 3 and its metadata
oneOf(db).getSmallMessage(txn4, messageId3); oneOf(db).getMessage(txn4, messageId3);
will(returnValue(message3)); will(returnValue(message3));
oneOf(db).getGroup(txn4, groupId); oneOf(db).getGroup(txn4, groupId);
will(returnValue(group)); will(returnValue(group));
@@ -677,7 +677,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageDependencies(txn6, messageId4); oneOf(db).getMessageDependencies(txn6, messageId4);
will(returnValue(singletonMap(messageId3, DELIVERED))); will(returnValue(singletonMap(messageId3, DELIVERED)));
// Get message 4 and its metadata // Get message 4 and its metadata
oneOf(db).getSmallMessage(txn6, messageId4); oneOf(db).getMessage(txn6, messageId4);
will(returnValue(message4)); will(returnValue(message4));
oneOf(db).getGroup(txn6, groupId); oneOf(db).getGroup(txn6, groupId);
will(returnValue(group)); will(returnValue(group));

View File

@@ -38,7 +38,6 @@ import static org.briarproject.bramble.test.TestUtils.getContact;
import static org.briarproject.bramble.test.TestUtils.getGroup; import static org.briarproject.bramble.test.TestUtils.getGroup;
import static org.briarproject.bramble.test.TestUtils.getMessage; import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.bramble.versioning.ClientVersioningConstants.GROUP_KEY_CONTACT_ID;
import static org.briarproject.bramble.versioning.ClientVersioningConstants.MSG_KEY_LOCAL; import static org.briarproject.bramble.versioning.ClientVersioningConstants.MSG_KEY_LOCAL;
import static org.briarproject.bramble.versioning.ClientVersioningConstants.MSG_KEY_UPDATE_VERSION; import static org.briarproject.bramble.versioning.ClientVersioningConstants.MSG_KEY_UPDATE_VERSION;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@@ -60,8 +59,6 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
private final ClientId clientId = getClientId(); private final ClientId clientId = getClientId();
private final long now = System.currentTimeMillis(); private final long now = System.currentTimeMillis();
private final Transaction txn = new Transaction(null, false); private final Transaction txn = new Transaction(null, false);
private final BdfDictionary groupMeta = BdfDictionary.of(
new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt()));
private ClientVersioningManagerImpl createInstance() { private ClientVersioningManagerImpl createInstance() {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
@@ -123,8 +120,8 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(db).addGroup(txn, contactGroup); oneOf(db).addGroup(txn, contactGroup);
oneOf(db).setGroupVisibility(txn, contact.getId(), oneOf(db).setGroupVisibility(txn, contact.getId(),
contactGroup.getId(), SHARED); contactGroup.getId(), SHARED);
oneOf(clientHelper).mergeGroupMetadata(txn, contactGroup.getId(), oneOf(clientHelper).setContactId(txn, contactGroup.getId(),
groupMeta); contact.getId());
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(now)); will(returnValue(now));
oneOf(clientHelper).createMessage(contactGroup.getId(), now, oneOf(clientHelper).createMessage(contactGroup.getId(), now,
@@ -184,7 +181,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
contactGroup.getId()); contactGroup.getId());
will(returnValue(singletonMap(localUpdateId, localUpdateMeta))); will(returnValue(singletonMap(localUpdateId, localUpdateMeta)));
// Load the latest local update // Load the latest local update
oneOf(clientHelper).getSmallMessageAsList(txn, localUpdateId); oneOf(clientHelper).getMessageAsList(txn, localUpdateId);
will(returnValue(localUpdateBody)); will(returnValue(localUpdateBody));
// Latest local update is up-to-date, no visibilities have changed // Latest local update is up-to-date, no visibilities have changed
}}); }});
@@ -206,7 +203,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
// Load the old client versions // Load the old client versions
oneOf(db).getMessageIds(txn, localGroup.getId()); oneOf(db).getMessageIds(txn, localGroup.getId());
will(returnValue(singletonList(localVersionsId))); will(returnValue(singletonList(localVersionsId)));
oneOf(clientHelper).getSmallMessageAsList(txn, localVersionsId); oneOf(clientHelper).getMessageAsList(txn, localVersionsId);
will(returnValue(localVersionsBody)); will(returnValue(localVersionsBody));
// Client versions are up-to-date // Client versions are up-to-date
}}); }});
@@ -248,7 +245,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
// Load the old client versions // Load the old client versions
oneOf(db).getMessageIds(txn, localGroup.getId()); oneOf(db).getMessageIds(txn, localGroup.getId());
will(returnValue(singletonList(oldLocalVersionsId))); will(returnValue(singletonList(oldLocalVersionsId)));
oneOf(clientHelper).getSmallMessageAsList(txn, oldLocalVersionsId); oneOf(clientHelper).getMessageAsList(txn, oldLocalVersionsId);
will(returnValue(oldLocalVersionsBody)); will(returnValue(oldLocalVersionsBody));
// Delete the old client versions // Delete the old client versions
oneOf(db).removeMessage(txn, oldLocalVersionsId); oneOf(db).removeMessage(txn, oldLocalVersionsId);
@@ -272,7 +269,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
will(returnValue(singletonMap(oldLocalUpdateId, will(returnValue(singletonMap(oldLocalUpdateId,
oldLocalUpdateMeta))); oldLocalUpdateMeta)));
// Load the latest local update // Load the latest local update
oneOf(clientHelper).getSmallMessageAsList(txn, oldLocalUpdateId); oneOf(clientHelper).getMessageAsList(txn, oldLocalUpdateId);
will(returnValue(oldLocalUpdateBody)); will(returnValue(oldLocalUpdateBody));
// Delete the latest local update // Delete the latest local update
oneOf(db).deleteMessage(txn, oldLocalUpdateId); oneOf(db).deleteMessage(txn, oldLocalUpdateId);
@@ -344,7 +341,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
// Load the old client versions // Load the old client versions
oneOf(db).getMessageIds(txn, localGroup.getId()); oneOf(db).getMessageIds(txn, localGroup.getId());
will(returnValue(singletonList(oldLocalVersionsId))); will(returnValue(singletonList(oldLocalVersionsId)));
oneOf(clientHelper).getSmallMessageAsList(txn, oldLocalVersionsId); oneOf(clientHelper).getMessageAsList(txn, oldLocalVersionsId);
will(returnValue(oldLocalVersionsBody)); will(returnValue(oldLocalVersionsBody));
// Delete the old client versions // Delete the old client versions
oneOf(db).removeMessage(txn, oldLocalVersionsId); oneOf(db).removeMessage(txn, oldLocalVersionsId);
@@ -367,10 +364,10 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
contactGroup.getId()); contactGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
// Load the latest local update // Load the latest local update
oneOf(clientHelper).getSmallMessageAsList(txn, oldLocalUpdateId); oneOf(clientHelper).getMessageAsList(txn, oldLocalUpdateId);
will(returnValue(oldLocalUpdateBody)); will(returnValue(oldLocalUpdateBody));
// Load the latest remote update // Load the latest remote update
oneOf(clientHelper).getSmallMessageAsList(txn, oldRemoteUpdateId); oneOf(clientHelper).getMessageAsList(txn, oldRemoteUpdateId);
will(returnValue(oldRemoteUpdateBody)); will(returnValue(oldRemoteUpdateBody));
// Delete the latest local update // Delete the latest local update
oneOf(db).deleteMessage(txn, oldLocalUpdateId); oneOf(db).deleteMessage(txn, oldLocalUpdateId);
@@ -451,18 +448,17 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
contactGroup.getId()); contactGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
// Load the latest local update // Load the latest local update
oneOf(clientHelper).getSmallMessageAsList(txn, oldLocalUpdateId); oneOf(clientHelper).getMessageAsList(txn, oldLocalUpdateId);
will(returnValue(oldLocalUpdateBody)); will(returnValue(oldLocalUpdateBody));
// Load the latest remote update // Load the latest remote update
oneOf(clientHelper).getSmallMessageAsList(txn, oldRemoteUpdateId); oneOf(clientHelper).getMessageAsList(txn, oldRemoteUpdateId);
will(returnValue(oldRemoteUpdateBody)); will(returnValue(oldRemoteUpdateBody));
// Delete the old remote update // Delete the old remote update
oneOf(db).deleteMessage(txn, oldRemoteUpdateId); oneOf(db).deleteMessage(txn, oldRemoteUpdateId);
oneOf(db).deleteMessageMetadata(txn, oldRemoteUpdateId); oneOf(db).deleteMessageMetadata(txn, oldRemoteUpdateId);
// Get contact ID // Get contact ID
oneOf(clientHelper).getGroupMetadataAsDictionary(txn, oneOf(clientHelper).getContactId(txn, contactGroup.getId());
contactGroup.getId()); will(returnValue(contact.getId()));
will(returnValue(groupMeta));
// No states or visibilities have changed // No states or visibilities have changed
}}); }});
@@ -490,12 +486,11 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
will(returnValue(singletonMap(oldLocalUpdateId, will(returnValue(singletonMap(oldLocalUpdateId,
oldLocalUpdateMeta))); oldLocalUpdateMeta)));
// Load the latest local update // Load the latest local update
oneOf(clientHelper).getSmallMessageAsList(txn, oldLocalUpdateId); oneOf(clientHelper).getMessageAsList(txn, oldLocalUpdateId);
will(returnValue(oldLocalUpdateBody)); will(returnValue(oldLocalUpdateBody));
// Get client ID // Get contact ID
oneOf(clientHelper).getGroupMetadataAsDictionary(txn, oneOf(clientHelper).getContactId(txn, contactGroup.getId());
contactGroup.getId()); will(returnValue(contact.getId()));
will(returnValue(groupMeta));
// No states or visibilities have changed // No states or visibilities have changed
}}); }});
@@ -546,8 +541,6 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
BdfDictionary newLocalUpdateMeta = BdfDictionary.of( BdfDictionary newLocalUpdateMeta = BdfDictionary.of(
new BdfEntry(MSG_KEY_UPDATE_VERSION, 2L), new BdfEntry(MSG_KEY_UPDATE_VERSION, 2L),
new BdfEntry(MSG_KEY_LOCAL, true)); new BdfEntry(MSG_KEY_LOCAL, true));
BdfDictionary groupMeta = BdfDictionary.of(
new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt()));
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(clientHelper).toList(newRemoteUpdate); oneOf(clientHelper).toList(newRemoteUpdate);
@@ -557,10 +550,10 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
contactGroup.getId()); contactGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
// Load the latest local update // Load the latest local update
oneOf(clientHelper).getSmallMessageAsList(txn, oldLocalUpdateId); oneOf(clientHelper).getMessageAsList(txn, oldLocalUpdateId);
will(returnValue(oldLocalUpdateBody)); will(returnValue(oldLocalUpdateBody));
// Load the latest remote update // Load the latest remote update
oneOf(clientHelper).getSmallMessageAsList(txn, oldRemoteUpdateId); oneOf(clientHelper).getMessageAsList(txn, oldRemoteUpdateId);
will(returnValue(oldRemoteUpdateBody)); will(returnValue(oldRemoteUpdateBody));
// Delete the old remote update // Delete the old remote update
oneOf(db).deleteMessage(txn, oldRemoteUpdateId); oneOf(db).deleteMessage(txn, oldRemoteUpdateId);
@@ -577,9 +570,8 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).addLocalMessage(txn, newLocalUpdate, oneOf(clientHelper).addLocalMessage(txn, newLocalUpdate,
newLocalUpdateMeta, true, false); newLocalUpdateMeta, true, false);
// The client's visibility has changed // The client's visibility has changed
oneOf(clientHelper).getGroupMetadataAsDictionary(txn, oneOf(clientHelper).getContactId(txn, contactGroup.getId());
contactGroup.getId()); will(returnValue(contact.getId()));
will(returnValue(groupMeta));
oneOf(db).getContact(txn, contact.getId()); oneOf(db).getContact(txn, contact.getId());
will(returnValue(contact)); will(returnValue(contact));
oneOf(hook).onClientVisibilityChanging(txn, contact, visibility); oneOf(hook).onClientVisibilityChanging(txn, contact, visibility);
@@ -619,8 +611,6 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
BdfDictionary newLocalUpdateMeta = BdfDictionary.of( BdfDictionary newLocalUpdateMeta = BdfDictionary.of(
new BdfEntry(MSG_KEY_UPDATE_VERSION, 2L), new BdfEntry(MSG_KEY_UPDATE_VERSION, 2L),
new BdfEntry(MSG_KEY_LOCAL, true)); new BdfEntry(MSG_KEY_LOCAL, true));
BdfDictionary groupMeta = BdfDictionary.of(
new BdfEntry(GROUP_KEY_CONTACT_ID, contact.getId().getInt()));
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(clientHelper).toList(newRemoteUpdate); oneOf(clientHelper).toList(newRemoteUpdate);
@@ -630,10 +620,10 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
contactGroup.getId()); contactGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
// Load the latest local update // Load the latest local update
oneOf(clientHelper).getSmallMessageAsList(txn, oldLocalUpdateId); oneOf(clientHelper).getMessageAsList(txn, oldLocalUpdateId);
will(returnValue(oldLocalUpdateBody)); will(returnValue(oldLocalUpdateBody));
// Load the latest remote update // Load the latest remote update
oneOf(clientHelper).getSmallMessageAsList(txn, oldRemoteUpdateId); oneOf(clientHelper).getMessageAsList(txn, oldRemoteUpdateId);
will(returnValue(oldRemoteUpdateBody)); will(returnValue(oldRemoteUpdateBody));
// Delete the old remote update // Delete the old remote update
oneOf(db).deleteMessage(txn, oldRemoteUpdateId); oneOf(db).deleteMessage(txn, oldRemoteUpdateId);
@@ -650,9 +640,8 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).addLocalMessage(txn, newLocalUpdate, oneOf(clientHelper).addLocalMessage(txn, newLocalUpdate,
newLocalUpdateMeta, true, false); newLocalUpdateMeta, true, false);
// The client's visibility has changed // The client's visibility has changed
oneOf(clientHelper).getGroupMetadataAsDictionary(txn, oneOf(clientHelper).getContactId(txn, contactGroup.getId());
contactGroup.getId()); will(returnValue(contact.getId()));
will(returnValue(groupMeta));
oneOf(db).getContact(txn, contact.getId()); oneOf(db).getContact(txn, contact.getId());
will(returnValue(contact)); will(returnValue(contact));
oneOf(hook).onClientVisibilityChanging(txn, contact, INVISIBLE); oneOf(hook).onClientVisibilityChanging(txn, contact, INVISIBLE);
@@ -734,9 +723,9 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId()); contactGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getSmallMessageAsList(txn, localUpdateId); oneOf(clientHelper).getMessageAsList(txn, localUpdateId);
will(returnValue(localUpdateBody)); will(returnValue(localUpdateBody));
oneOf(clientHelper).getSmallMessageAsList(txn, remoteUpdateId); oneOf(clientHelper).getMessageAsList(txn, remoteUpdateId);
will(returnValue(remoteUpdateBody)); will(returnValue(remoteUpdateBody));
}}); }});
@@ -769,9 +758,9 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId()); contactGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getSmallMessageAsList(txn, localUpdateId); oneOf(clientHelper).getMessageAsList(txn, localUpdateId);
will(returnValue(localUpdateBody)); will(returnValue(localUpdateBody));
oneOf(clientHelper).getSmallMessageAsList(txn, remoteUpdateId); oneOf(clientHelper).getMessageAsList(txn, remoteUpdateId);
will(returnValue(remoteUpdateBody)); will(returnValue(remoteUpdateBody));
}}); }});
@@ -804,9 +793,9 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId()); contactGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getSmallMessageAsList(txn, localUpdateId); oneOf(clientHelper).getMessageAsList(txn, localUpdateId);
will(returnValue(localUpdateBody)); will(returnValue(localUpdateBody));
oneOf(clientHelper).getSmallMessageAsList(txn, remoteUpdateId); oneOf(clientHelper).getMessageAsList(txn, remoteUpdateId);
will(returnValue(remoteUpdateBody)); will(returnValue(remoteUpdateBody));
}}); }});
@@ -839,9 +828,9 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId()); contactGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getSmallMessageAsList(txn, localUpdateId); oneOf(clientHelper).getMessageAsList(txn, localUpdateId);
will(returnValue(localUpdateBody)); will(returnValue(localUpdateBody));
oneOf(clientHelper).getSmallMessageAsList(txn, remoteUpdateId); oneOf(clientHelper).getMessageAsList(txn, remoteUpdateId);
will(returnValue(remoteUpdateBody)); will(returnValue(remoteUpdateBody));
}}); }});
@@ -901,7 +890,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId()); contactGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getSmallMessageAsList(txn, remoteUpdateId); oneOf(clientHelper).getMessageAsList(txn, remoteUpdateId);
will(returnValue(remoteUpdateBody)); will(returnValue(remoteUpdateBody));
}}); }});
@@ -933,7 +922,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId()); contactGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getSmallMessageAsList(txn, remoteUpdateId); oneOf(clientHelper).getMessageAsList(txn, remoteUpdateId);
will(returnValue(remoteUpdateBody)); will(returnValue(remoteUpdateBody));
}}); }});
@@ -965,7 +954,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId()); contactGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getSmallMessageAsList(txn, remoteUpdateId); oneOf(clientHelper).getMessageAsList(txn, remoteUpdateId);
will(returnValue(remoteUpdateBody)); will(returnValue(remoteUpdateBody));
}}); }});

View File

@@ -16,7 +16,7 @@ dependencies {
implementation fileTree(dir: 'libs', include: '*.jar') implementation fileTree(dir: 'libs', include: '*.jar')
implementation 'net.java.dev.jna:jna:4.5.2' implementation 'net.java.dev.jna:jna:4.5.2'
implementation 'net.java.dev.jna:jna-platform:4.5.2' implementation 'net.java.dev.jna:jna-platform:4.5.2'
tor 'org.briarproject:tor:0.3.5.10@zip' tor 'org.briarproject:tor:0.3.5.12@zip'
tor 'org.briarproject:obfs4proxy:0.0.7@zip' tor 'org.briarproject:obfs4proxy:0.0.7@zip'
annotationProcessor 'com.google.dagger:dagger-compiler:2.24' annotationProcessor 'com.google.dagger:dagger-compiler:2.24'

View File

@@ -24,7 +24,7 @@ dependencyVerification {
'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8', 'org.apache.ant:ant:1.9.4:ant-1.9.4.jar:649ae0730251de07b8913f49286d46bba7b92d47c5f332610aa426c4f02161d8',
'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8', 'org.beanshell:bsh:1.3.0:bsh-1.3.0.jar:9b04edc75d19db54f1b4e8b5355e9364384c6cf71eb0a1b9724c159d779879f8',
'org.briarproject:obfs4proxy:0.0.7:obfs4proxy-0.0.7.zip:5b2f693262ce43a7e130f7cc7d5d1617925330640a2eb6d71085e95df8ee0642', 'org.briarproject:obfs4proxy:0.0.7:obfs4proxy-0.0.7.zip:5b2f693262ce43a7e130f7cc7d5d1617925330640a2eb6d71085e95df8ee0642',
'org.briarproject:tor:0.3.5.10:tor-0.3.5.10.zip:7b387d3523ae8af289c23be59dc4c64ec5d3721385d7825a09705095e3318d5c', 'org.briarproject:tor:0.3.5.12:tor-0.3.5.12.zip:2f542c4befd216f2226bf7c76e3b8b2d99af6f146a8cb28bf727f42014587006',
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d', 'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a', 'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a',
'org.codehaus.mojo:animal-sniffer-annotations:1.17:animal-sniffer-annotations-1.17.jar:92654f493ecfec52082e76354f0ebf87648dc3d5cec2e3c3cdb947c016747a53', 'org.codehaus.mojo:animal-sniffer-annotations:1.17:animal-sniffer-annotations-1.17.jar:92654f493ecfec52082e76354f0ebf87648dc3d5cec2e3c3cdb947c016747a53',

View File

@@ -93,12 +93,12 @@ dependencies {
implementation project(path: ':bramble-core', configuration: 'default') implementation project(path: ':bramble-core', configuration: 'default')
implementation project(':bramble-android') implementation project(':bramble-android')
implementation 'androidx.preference:preference:1.1.0' implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.exifinterface:exifinterface:1.0.0' implementation 'androidx.exifinterface:exifinterface:1.3.1'
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.google.android.material:material:1.1.0-beta01' implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.recyclerview:recyclerview-selection:1.1.0-rc01' implementation 'androidx.recyclerview:recyclerview-selection:1.1.0-rc03'
implementation 'ch.acra:acra:4.11' implementation 'ch.acra:acra:4.11'
implementation 'info.guardianproject.panic:panic:1.0' implementation 'info.guardianproject.panic:panic:1.0'
@@ -106,7 +106,7 @@ dependencies {
implementation 'de.hdodenhof:circleimageview:3.0.1' implementation 'de.hdodenhof:circleimageview:3.0.1'
implementation 'com.google.zxing:core:3.3.3' // newer version need minSdk 24 implementation 'com.google.zxing:core:3.3.3' // newer version need minSdk 24
implementation 'uk.co.samuelwall:material-tap-target-prompt:3.0.0' implementation 'uk.co.samuelwall:material-tap-target-prompt:3.0.0'
implementation 'com.vanniktech:emoji-google:0.6.0' implementation 'com.vanniktech:emoji-google:0.6.0' // newer versions need minSdk 21
implementation 'com.github.kobakei:MaterialFabSpeedDial:1.2.1' implementation 'com.github.kobakei:MaterialFabSpeedDial:1.2.1'
implementation 'com.github.chrisbanes:PhotoView:2.3.0' implementation 'com.github.chrisbanes:PhotoView:2.3.0'
def glideVersion = '4.10.0' def glideVersion = '4.10.0'
@@ -120,13 +120,13 @@ dependencies {
compileOnly 'javax.annotation:jsr250-api:1.0' compileOnly 'javax.annotation:jsr250-api:1.0'
def espressoVersion = '3.2.0' def espressoVersion = '3.3.0'
def jmockVersion = '2.8.2' def jmockVersion = '2.8.2'
testImplementation project(path: ':bramble-api', configuration: 'testOutput') testImplementation project(path: ':bramble-api', configuration: 'testOutput')
testImplementation project(path: ':bramble-core', configuration: 'testOutput') testImplementation project(path: ':bramble-core', configuration: 'testOutput')
testImplementation 'androidx.test:runner:1.2.0' testImplementation 'androidx.test:runner:1.3.0'
testImplementation 'androidx.test.ext:junit:1.1.1' testImplementation 'androidx.test.ext:junit:1.1.2'
testImplementation 'androidx.fragment:fragment-testing:1.1.0' testImplementation 'androidx.fragment:fragment-testing:1.2.5'
testImplementation "androidx.test.espresso:espresso-core:$espressoVersion" testImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
testImplementation 'org.robolectric:robolectric:4.3.1' testImplementation 'org.robolectric:robolectric:4.3.1'
testImplementation 'org.mockito:mockito-core:3.1.0' testImplementation 'org.mockito:mockito-core:3.1.0'
@@ -136,7 +136,7 @@ dependencies {
testImplementation "org.jmock:jmock-legacy:$jmockVersion" testImplementation "org.jmock:jmock-legacy:$jmockVersion"
androidTestImplementation project(path: ':bramble-api', configuration: 'testOutput') androidTestImplementation project(path: ':bramble-api', configuration: 'testOutput')
androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion" androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion" androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"
androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion" androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion"

View File

@@ -37,3 +37,6 @@
# Glide # Glide
-dontwarn com.bumptech.glide.load.engine.cache.DiskLruCacheWrapper -dontwarn com.bumptech.glide.load.engine.cache.DiskLruCacheWrapper
# Dependency injection annotations, needed for UI tests on older API levels
-keep class javax.inject.**

View File

@@ -141,6 +141,16 @@
android:value="org.briarproject.briar.android.conversation.ConversationActivity" /> android:value="org.briarproject.briar.android.conversation.ConversationActivity" />
</activity> </activity>
<activity
android:name=".android.conversation.ConversationSettingsActivity"
android:parentActivityName="org.briarproject.briar.android.conversation.ConversationActivity"
android:label="@string/disappearing_messages_title"
android:theme="@style/BriarTheme">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.briarproject.briar.android.conversation.ConversationActivity" />
</activity>
<activity <activity
android:name="org.briarproject.briar.android.privategroup.creation.CreateGroupActivity" android:name="org.briarproject.briar.android.privategroup.creation.CreateGroupActivity"
android:label="@string/groups_create_group_title" android:label="@string/groups_create_group_title"

View File

@@ -14,6 +14,7 @@ import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.crypto.CryptoExecutor; import org.briarproject.bramble.api.crypto.CryptoExecutor;
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.keyagreement.KeyAgreementTask; import org.briarproject.bramble.api.keyagreement.KeyAgreementTask;
@@ -39,6 +40,7 @@ import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.android.DozeWatchdog; import org.briarproject.briar.api.android.DozeWatchdog;
import org.briarproject.briar.api.android.LockManager; import org.briarproject.briar.api.android.LockManager;
import org.briarproject.briar.api.android.ScreenFilterMonitor; import org.briarproject.briar.api.android.ScreenFilterMonitor;
import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.blog.BlogManager; import org.briarproject.briar.api.blog.BlogManager;
import org.briarproject.briar.api.blog.BlogPostFactory; import org.briarproject.briar.api.blog.BlogPostFactory;
import org.briarproject.briar.api.blog.BlogSharingManager; import org.briarproject.briar.api.blog.BlogSharingManager;
@@ -169,6 +171,10 @@ public interface AndroidComponent
AndroidWakeLockManager wakeLockManager(); AndroidWakeLockManager wakeLockManager();
TransactionManager transactionManager();
AutoDeleteManager autoDeleteManager();
void inject(SignInReminderReceiver briarService); void inject(SignInReminderReceiver briarService);
void inject(BriarService briarService); void inject(BriarService briarService);

View File

@@ -17,7 +17,6 @@ import org.briarproject.briar.android.activity.ActivityComponent;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static java.util.Objects.requireNonNull;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.util.StringUtils.toUtf8; import static org.briarproject.bramble.util.StringUtils.toUtf8;
import static org.briarproject.briar.android.util.UiUtils.setError; import static org.briarproject.briar.android.util.UiUtils.setError;
@@ -45,7 +44,7 @@ public class AuthorNameFragment extends SetupFragment {
public View onCreateView(LayoutInflater inflater, public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) { @Nullable Bundle savedInstanceState) {
requireNonNull(getActivity()).setTitle(getString(R.string.setup_title)); requireActivity().setTitle(getString(R.string.setup_title));
View v = inflater.inflate(R.layout.fragment_setup_author_name, View v = inflater.inflate(R.layout.fragment_setup_author_name,
container, false); container, false);
authorNameWrapper = v.findViewById(R.id.nickname_entry_wrapper); authorNameWrapper = v.findViewById(R.id.nickname_entry_wrapper);

View File

@@ -20,7 +20,6 @@ import androidx.annotation.Nullable;
import static android.view.View.INVISIBLE; import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE; import static android.view.View.VISIBLE;
import static java.util.Objects.requireNonNull;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING;
import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog; import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog;
@@ -50,10 +49,10 @@ public class DozeFragment extends SetupFragment
public View onCreateView(LayoutInflater inflater, public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) { @Nullable Bundle savedInstanceState) {
requireNonNull(getActivity()).setTitle(getString(R.string.setup_doze_title)); requireActivity().setTitle(getString(R.string.setup_doze_title));
setHasOptionsMenu(false); setHasOptionsMenu(false);
View v = inflater.inflate(R.layout.fragment_setup_doze, container, View v = inflater.inflate(R.layout.fragment_setup_doze, container,
false); false);
dozeView = v.findViewById(R.id.dozeView); dozeView = v.findViewById(R.id.dozeView);
dozeView.setOnCheckedChangedListener(this); dozeView.setOnCheckedChangedListener(this);
huaweiView = v.findViewById(R.id.huaweiView); huaweiView = v.findViewById(R.id.huaweiView);
@@ -78,7 +77,8 @@ public class DozeFragment extends SetupFragment
} }
@Override @Override
public void onActivityResult(int request, int result, Intent data) { public void onActivityResult(int request, int result,
@Nullable Intent data) {
super.onActivityResult(request, result, data); super.onActivityResult(request, result, data);
if (request == REQUEST_DOZE_WHITELISTING) { if (request == REQUEST_DOZE_WHITELISTING) {
if (!dozeView.needsToBeShown() || secondAttempt) { if (!dozeView.needsToBeShown() || secondAttempt) {
@@ -92,11 +92,7 @@ public class DozeFragment extends SetupFragment
@Override @Override
public void onCheckedChanged() { public void onCheckedChanged() {
if (dozeView.isChecked() && huaweiView.isChecked()) { next.setEnabled(dozeView.isChecked() && huaweiView.isChecked());
next.setEnabled(true);
} else {
next.setEnabled(false);
}
} }
@SuppressLint("BatteryLife") @SuppressLint("BatteryLife")

View File

@@ -24,7 +24,6 @@ import static android.content.Context.INPUT_METHOD_SERVICE;
import static android.view.View.INVISIBLE; import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE; import static android.view.View.VISIBLE;
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE; import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
import static java.util.Objects.requireNonNull;
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK; import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK;
import static org.briarproject.briar.android.util.UiUtils.setError; import static org.briarproject.briar.android.util.UiUtils.setError;
@@ -55,7 +54,7 @@ public class SetPasswordFragment extends SetupFragment {
public View onCreateView(LayoutInflater inflater, public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) { @Nullable Bundle savedInstanceState) {
requireNonNull(getActivity()).setTitle(getString(R.string.setup_password_intro)); requireActivity().setTitle(getString(R.string.setup_password_intro));
View v = inflater.inflate(R.layout.fragment_setup_password, container, View v = inflater.inflate(R.layout.fragment_setup_password, container,
false); false);

View File

@@ -28,6 +28,8 @@ import org.briarproject.briar.android.contact.add.remote.NicknameFragment;
import org.briarproject.briar.android.contact.add.remote.PendingContactListActivity; import org.briarproject.briar.android.contact.add.remote.PendingContactListActivity;
import org.briarproject.briar.android.conversation.AliasDialogFragment; import org.briarproject.briar.android.conversation.AliasDialogFragment;
import org.briarproject.briar.android.conversation.ConversationActivity; import org.briarproject.briar.android.conversation.ConversationActivity;
import org.briarproject.briar.android.conversation.ConversationSettingsActivity;
import org.briarproject.briar.android.conversation.ConversationSettingsFragment;
import org.briarproject.briar.android.conversation.ImageActivity; import org.briarproject.briar.android.conversation.ImageActivity;
import org.briarproject.briar.android.conversation.ImageFragment; import org.briarproject.briar.android.conversation.ImageFragment;
import org.briarproject.briar.android.forum.CreateForumActivity; import org.briarproject.briar.android.forum.CreateForumActivity;
@@ -184,6 +186,8 @@ public interface ActivityComponent {
void inject(PendingContactListActivity activity); void inject(PendingContactListActivity activity);
void inject(ConversationSettingsActivity activity);
// Fragments // Fragments
void inject(AuthorNameFragment fragment); void inject(AuthorNameFragment fragment);
@@ -234,4 +238,6 @@ public interface ActivityComponent {
void inject(ImageFragment imageFragment); void inject(ImageFragment imageFragment);
void inject(ConversationSettingsFragment conversationSettingsFragment);
} }

View File

@@ -25,7 +25,6 @@ import androidx.annotation.UiThread;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.view.View.INVISIBLE; import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE; import static android.view.View.VISIBLE;
import static java.util.Objects.requireNonNull;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID; import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
import static org.briarproject.briar.android.util.UiUtils.MIN_DATE_RESOLUTION; import static org.briarproject.briar.android.util.UiUtils.MIN_DATE_RESOLUTION;
@@ -55,7 +54,7 @@ abstract class BasePostFragment extends BaseFragment {
@Nullable ViewGroup container, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) { @Nullable Bundle savedInstanceState) {
// retrieve MessageId of blog post from arguments // retrieve MessageId of blog post from arguments
byte[] p = requireNonNull(getArguments()).getByteArray(POST_ID); byte[] p = requireArguments().getByteArray(POST_ID);
if (p == null) throw new IllegalStateException("No post ID in args"); if (p == null) throw new IllegalStateException("No post ID in args");
postId = new MessageId(p); postId = new MessageId(p);

View File

@@ -46,7 +46,6 @@ import static android.app.Activity.RESULT_OK;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.widget.Toast.LENGTH_SHORT; import static android.widget.Toast.LENGTH_SHORT;
import static com.google.android.material.snackbar.Snackbar.LENGTH_LONG; import static com.google.android.material.snackbar.Snackbar.LENGTH_LONG;
import static java.util.Objects.requireNonNull;
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID; import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_SHARE_BLOG; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_SHARE_BLOG;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_WRITE_BLOG_POST; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_WRITE_BLOG_POST;
@@ -97,14 +96,14 @@ public class BlogFragment extends BaseFragment
public View onCreateView(LayoutInflater inflater, public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) { @Nullable Bundle savedInstanceState) {
Bundle args = requireNonNull(getArguments()); Bundle args = requireArguments();
byte[] b = args.getByteArray(GROUP_ID); byte[] b = args.getByteArray(GROUP_ID);
if (b == null) throw new IllegalStateException("No group ID in args"); if (b == null) throw new IllegalStateException("No group ID in args");
groupId = new GroupId(b); groupId = new GroupId(b);
View v = inflater.inflate(R.layout.fragment_blog, container, false); View v = inflater.inflate(R.layout.fragment_blog, container, false);
adapter = new BlogPostAdapter(requireNonNull(getActivity()), this, adapter = new BlogPostAdapter(requireActivity(), this,
getFragmentManager()); getFragmentManager());
list = v.findViewById(R.id.postList); list = v.findViewById(R.id.postList);
layoutManager = new LinearLayoutManager(getActivity()); layoutManager = new LinearLayoutManager(getActivity());
@@ -196,7 +195,8 @@ public class BlogFragment extends BaseFragment
} }
@Override @Override
public void onActivityResult(int request, int result, Intent data) { public void onActivityResult(int request, int result,
@Nullable Intent data) {
super.onActivityResult(request, result, data); super.onActivityResult(request, result, data);
if (request == REQUEST_WRITE_BLOG_POST && result == RESULT_OK) { if (request == REQUEST_WRITE_BLOG_POST && result == RESULT_OK) {

View File

@@ -35,7 +35,6 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import static android.app.Activity.RESULT_OK; import static android.app.Activity.RESULT_OK;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static com.google.android.material.snackbar.Snackbar.LENGTH_LONG; import static com.google.android.material.snackbar.Snackbar.LENGTH_LONG;
import static java.util.Objects.requireNonNull;
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID; import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_WRITE_BLOG_POST; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_WRITE_BLOG_POST;
@@ -79,7 +78,7 @@ public class FeedFragment extends BaseFragment implements
public View onCreateView(LayoutInflater inflater, public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) { @Nullable Bundle savedInstanceState) {
requireNonNull(getActivity()).setTitle(R.string.blogs_button); requireActivity().setTitle(R.string.blogs_button);
View v = inflater.inflate(R.layout.fragment_blog, container, false); View v = inflater.inflate(R.layout.fragment_blog, container, false);
@@ -103,7 +102,8 @@ public class FeedFragment extends BaseFragment implements
} }
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode,
@Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
// The BlogPostAddedEvent arrives when the controller is not listening // The BlogPostAddedEvent arrives when the controller is not listening

View File

@@ -18,7 +18,6 @@ import javax.inject.Inject;
import androidx.annotation.UiThread; import androidx.annotation.UiThread;
import static java.util.Objects.requireNonNull;
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID; import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
@UiThread @UiThread
@@ -54,7 +53,7 @@ public class FeedPostFragment extends BasePostFragment {
public View onCreateView(LayoutInflater inflater, public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) { @Nullable Bundle savedInstanceState) {
Bundle args = requireNonNull(getArguments()); Bundle args = requireArguments();
byte[] b = args.getByteArray(GROUP_ID); byte[] b = args.getByteArray(GROUP_ID);
if (b == null) throw new IllegalStateException("No group ID in args"); if (b == null) throw new IllegalStateException("No group ID in args");
blogId = new GroupId(b); blogId = new GroupId(b);

View File

@@ -74,7 +74,7 @@ public class ReblogFragment extends BaseFragment implements SendListener {
@Nullable ViewGroup container, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) { @Nullable Bundle savedInstanceState) {
Bundle args = requireNonNull(getArguments()); Bundle args = requireArguments();
GroupId blogId = GroupId blogId =
new GroupId(requireNonNull(args.getByteArray(GROUP_ID))); new GroupId(requireNonNull(args.getByteArray(GROUP_ID)));
MessageId postId = MessageId postId =

View File

@@ -62,7 +62,6 @@ import static android.os.Build.VERSION.SDK_INT;
import static androidx.core.app.ActivityOptionsCompat.makeSceneTransitionAnimation; import static androidx.core.app.ActivityOptionsCompat.makeSceneTransitionAnimation;
import static androidx.core.view.ViewCompat.getTransitionName; import static androidx.core.view.ViewCompat.getTransitionName;
import static com.google.android.material.snackbar.BaseTransientBottomBar.LENGTH_INDEFINITE; import static com.google.android.material.snackbar.BaseTransientBottomBar.LENGTH_INDEFINITE;
import static java.util.Objects.requireNonNull;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
@@ -122,7 +121,7 @@ public class ContactListFragment extends BaseFragment implements EventListener,
public View onCreateView(LayoutInflater inflater, public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) { @Nullable Bundle savedInstanceState) {
requireNonNull(getActivity()).setTitle(R.string.contact_list_button); requireActivity().setTitle(R.string.contact_list_button);
View contentView = inflater.inflate(R.layout.fragment_contact_list, View contentView = inflater.inflate(R.layout.fragment_contact_list,
container, false); container, false);
@@ -274,8 +273,8 @@ public class ContactListFragment extends BaseFragment implements EventListener,
removeItem(((ContactRemovedEvent) e).getContactId()); removeItem(((ContactRemovedEvent) e).getContactId());
} else if (e instanceof ConversationMessageReceivedEvent) { } else if (e instanceof ConversationMessageReceivedEvent) {
LOG.info("Conversation message received, updating item"); LOG.info("Conversation message received, updating item");
ConversationMessageReceivedEvent p = ConversationMessageReceivedEvent<?> p =
(ConversationMessageReceivedEvent) e; (ConversationMessageReceivedEvent<?>) e;
ConversationMessageHeader h = p.getMessageHeader(); ConversationMessageHeader h = p.getMessageHeader();
updateItem(p.getContactId(), h); updateItem(p.getContactId(), h);
} else if (e instanceof PendingContactAddedEvent || } else if (e instanceof PendingContactAddedEvent ||
@@ -317,7 +316,7 @@ public class ContactListFragment extends BaseFragment implements EventListener,
@UiThread @UiThread
private void showSnackBar() { private void showSnackBar() {
if (snackbar != null) return; if (snackbar != null) return;
View v = requireNonNull(getView()); View v = requireView();
int stringRes = R.string.pending_contact_requests_snackbar; int stringRes = R.string.pending_contact_requests_snackbar;
snackbar = new BriarSnackbarBuilder() snackbar = new BriarSnackbarBuilder()
.setAction(R.string.show, view -> showPendingContactList()) .setAction(R.string.show, view -> showPendingContactList())

View File

@@ -33,7 +33,6 @@ import androidx.lifecycle.ViewModelProviders;
import static android.content.Context.CLIPBOARD_SERVICE; import static android.content.Context.CLIPBOARD_SERVICE;
import static android.widget.Toast.LENGTH_SHORT; import static android.widget.Toast.LENGTH_SHORT;
import static java.util.Objects.requireNonNull;
import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.LINK_REGEX; import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.LINK_REGEX;
import static org.briarproject.briar.android.util.UiUtils.observeOnce; import static org.briarproject.briar.android.util.UiUtils.observeOnce;
@@ -83,8 +82,8 @@ public class LinkExchangeFragment extends BaseFragment
linkInput.setText(viewModel.getRemoteHandshakeLink()); linkInput.setText(viewModel.getRemoteHandshakeLink());
} }
clipboard = (ClipboardManager) requireNonNull( clipboard = (ClipboardManager)
getContext().getSystemService(CLIPBOARD_SERVICE)); requireContext().getSystemService(CLIPBOARD_SERVICE);
Button pasteButton = v.findViewById(R.id.pasteButton); Button pasteButton = v.findViewById(R.id.pasteButton);
pasteButton.setOnClickListener(view -> { pasteButton.setOnClickListener(view -> {
@@ -107,7 +106,7 @@ public class LinkExchangeFragment extends BaseFragment
@Override @Override
public void onGlobalLayout() { public void onGlobalLayout() {
ScrollView scrollView = (ScrollView) requireNonNull(getView()); ScrollView scrollView = (ScrollView) requireView();
View layout = scrollView.getChildAt(0); View layout = scrollView.getChildAt(0);
int scrollBy = layout.getHeight() - scrollView.getHeight(); int scrollBy = layout.getHeight() - scrollView.getHeight();
if (scrollBy > 0) { if (scrollBy > 0) {
@@ -121,7 +120,7 @@ public class LinkExchangeFragment extends BaseFragment
} }
private void onHandshakeLinkLoaded(String link) { private void onHandshakeLinkLoaded(String link) {
View v = requireNonNull(getView()); View v = requireView();
TextView linkView = v.findViewById(R.id.linkView); TextView linkView = v.findViewById(R.id.linkView);
linkView.setText(link); linkView.setText(link);

View File

@@ -31,6 +31,7 @@ import javax.inject.Inject;
import androidx.annotation.StringRes; import androidx.annotation.StringRes;
import androidx.appcompat.app.AlertDialog.Builder; import androidx.appcompat.app.AlertDialog.Builder;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders; import androidx.lifecycle.ViewModelProviders;
@@ -117,7 +118,8 @@ public class NicknameFragment extends BaseFragment {
addButton.setVisibility(INVISIBLE); addButton.setVisibility(INVISIBLE);
progressBar.setVisibility(VISIBLE); progressBar.setVisibility(VISIBLE);
viewModel.getAddContactResult().observe(this, result -> { LifecycleOwner owner = getViewLifecycleOwner();
viewModel.getAddContactResult().observe(owner, result -> {
if (result == null) return; if (result == null) return;
if (result.hasError()) if (result.hasError())
handleException(name, requireNonNull(result.getException())); handleException(name, requireNonNull(result.getException()));

View File

@@ -26,7 +26,6 @@ import javax.annotation.Nullable;
import androidx.annotation.CallSuper; import androidx.annotation.CallSuper;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import static java.util.Objects.requireNonNull;
import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID; import static org.briarproject.briar.android.activity.BriarActivity.GROUP_ID;
import static org.briarproject.briar.android.contactselection.ContactSelectorActivity.CONTACTS; import static org.briarproject.briar.android.contactselection.ContactSelectorActivity.CONTACTS;
import static org.briarproject.briar.android.contactselection.ContactSelectorActivity.getContactsFromIds; import static org.briarproject.briar.android.contactselection.ContactSelectorActivity.getContactsFromIds;
@@ -55,7 +54,7 @@ public abstract class BaseContactSelectorFragment<I extends SelectableContactIte
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
Bundle args = requireNonNull(getArguments()); Bundle args = requireArguments();
byte[] b = args.getByteArray(GROUP_ID); byte[] b = args.getByteArray(GROUP_ID);
if (b == null) throw new IllegalStateException("No GroupId"); if (b == null) throw new IllegalStateException("No GroupId");
groupId = new GroupId(b); groupId = new GroupId(b);
@@ -74,7 +73,7 @@ public abstract class BaseContactSelectorFragment<I extends SelectableContactIte
list.setEmptyImage(R.drawable.ic_empty_state_contact_list); list.setEmptyImage(R.drawable.ic_empty_state_contact_list);
list.setEmptyText(getString(R.string.no_contacts_selector)); list.setEmptyText(getString(R.string.no_contacts_selector));
list.setEmptyAction(getString(R.string.no_contacts_selector_action)); list.setEmptyAction(getString(R.string.no_contacts_selector_action));
adapter = getAdapter(requireNonNull(getContext()), this); adapter = getAdapter(requireContext(), this);
list.setAdapter(adapter); list.setAdapter(adapter);
// restore selected contacts if available // restore selected contacts if available

View File

@@ -140,6 +140,8 @@ import static org.briarproject.briar.android.util.UiUtils.getBulbTransitionName;
import static org.briarproject.briar.android.util.UiUtils.observeOnce; import static org.briarproject.briar.android.util.UiUtils.observeOnce;
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE;
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH; import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_PRIVATE_MESSAGE_TEXT_LENGTH;
import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES_AUTO_DELETE;
import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_ONLY;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
@@ -273,15 +275,11 @@ public class ConversationActivity extends BriarActivity
ImagePreview imagePreview = findViewById(R.id.imagePreview); ImagePreview imagePreview = findViewById(R.id.imagePreview);
sendController = new TextAttachmentController(textInputView, sendController = new TextAttachmentController(textInputView,
imagePreview, this, viewModel); imagePreview, this, viewModel);
viewModel.hasImageSupport().observe(this, new Observer<Boolean>() { observeOnce(viewModel.getPrivateMessageFormat(), this, format -> {
@Override if (format != TEXT_ONLY) {
public void onChanged(@Nullable Boolean hasSupport) { // TODO: remove cast when removing feature flag
if (hasSupport != null && hasSupport) { ((TextAttachmentController) sendController)
// TODO: remove cast when removing feature flag .setImagesSupported();
((TextAttachmentController) sendController)
.setImagesSupported();
viewModel.hasImageSupport().removeObserver(this);
}
} }
}); });
} else { } else {
@@ -384,6 +382,12 @@ public class ConversationActivity extends BriarActivity
// enable alias action if available // enable alias action if available
observeOnce(viewModel.getContact(), this, contact -> observeOnce(viewModel.getContact(), this, contact ->
menu.findItem(R.id.action_set_alias).setEnabled(true)); menu.findItem(R.id.action_set_alias).setEnabled(true));
// show auto-delete timer setting only, if contacts supports it
observeOnce(viewModel.getPrivateMessageFormat(), this, format -> {
boolean visible = format == TEXT_IMAGES_AUTO_DELETE;
menu.findItem(R.id.action_conversation_settings)
.setVisible(visible);
});
return super.onCreateOptionsMenu(menu); return super.onCreateOptionsMenu(menu);
} }
@@ -405,6 +409,12 @@ public class ConversationActivity extends BriarActivity
AliasDialogFragment.newInstance().show( AliasDialogFragment.newInstance().show(
getSupportFragmentManager(), AliasDialogFragment.TAG); getSupportFragmentManager(), AliasDialogFragment.TAG);
return true; return true;
case R.id.action_conversation_settings:
if (contactId == null) return false;
intent = new Intent(this, ConversationSettingsActivity.class);
intent.putExtra(CONTACT_ID, contactId.getInt());
startActivity(intent);
return true;
case R.id.action_delete_all_messages: case R.id.action_delete_all_messages:
askToDeleteAllMessages(); askToDeleteAllMessages();
return true; return true;
@@ -657,8 +667,8 @@ public class ConversationActivity extends BriarActivity
supportFinishAfterTransition(); supportFinishAfterTransition();
} }
} else if (e instanceof ConversationMessageReceivedEvent) { } else if (e instanceof ConversationMessageReceivedEvent) {
ConversationMessageReceivedEvent p = ConversationMessageReceivedEvent<?> p =
(ConversationMessageReceivedEvent) e; (ConversationMessageReceivedEvent<?>) e;
if (p.getContactId().equals(contactId)) { if (p.getContactId().equals(contactId)) {
LOG.info("Message received, adding"); LOG.info("Message received, adding");
onNewConversationMessage(p.getMessageHeader()); onNewConversationMessage(p.getMessageHeader());
@@ -756,18 +766,10 @@ public class ConversationActivity extends BriarActivity
List<AttachmentHeader> attachmentHeaders) { List<AttachmentHeader> attachmentHeaders) {
if (isNullOrEmpty(text) && attachmentHeaders.isEmpty()) if (isNullOrEmpty(text) && attachmentHeaders.isEmpty())
throw new AssertionError(); throw new AssertionError();
long timestamp = System.currentTimeMillis(); viewModel.sendMessage(text, attachmentHeaders);
timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
viewModel.sendMessage(text, attachmentHeaders, timestamp);
textInputView.clearText(); textInputView.clearText();
} }
private long getMinTimestampForNewMessage() {
// Don't use an earlier timestamp than the newest message
ConversationItem item = adapter.getLastItem();
return item == null ? 0 : item.getTime() + 1;
}
private void onAddedPrivateMessage(@Nullable PrivateMessageHeader h) { private void onAddedPrivateMessage(@Nullable PrivateMessageHeader h) {
if (h == null) return; if (h == null) return;
addConversationItem(h.accept(visitor)); addConversationItem(h.accept(visitor));
@@ -972,13 +974,11 @@ public class ConversationActivity extends BriarActivity
adapter.notifyItemChanged(position, item); adapter.notifyItemChanged(position, item);
} }
runOnDbThread(() -> { runOnDbThread(() -> {
long timestamp = System.currentTimeMillis();
timestamp = Math.max(timestamp, getMinTimestampForNewMessage());
try { try {
switch (item.getRequestType()) { switch (item.getRequestType()) {
case INTRODUCTION: case INTRODUCTION:
respondToIntroductionRequest(item.getSessionId(), respondToIntroductionRequest(item.getSessionId(),
accept, timestamp); accept);
break; break;
case FORUM: case FORUM:
respondToForumRequest(item.getSessionId(), accept); respondToForumRequest(item.getSessionId(), accept);
@@ -1054,9 +1054,8 @@ public class ConversationActivity extends BriarActivity
@DatabaseExecutor @DatabaseExecutor
private void respondToIntroductionRequest(SessionId sessionId, private void respondToIntroductionRequest(SessionId sessionId,
boolean accept, long time) throws DbException { boolean accept) throws DbException {
introductionManager.respondToIntroduction(contactId, sessionId, time, introductionManager.respondToIntroduction(contactId, sessionId, accept);
accept);
} }
@DatabaseExecutor @DatabaseExecutor

View File

@@ -22,7 +22,7 @@ abstract class ConversationItem {
protected String text; protected String text;
private final MessageId id; private final MessageId id;
private final GroupId groupId; private final GroupId groupId;
private final long time; private final long time, autoDeleteTimer;
private final boolean isIncoming; private final boolean isIncoming;
private boolean read, sent, seen; private boolean read, sent, seen;
@@ -32,6 +32,7 @@ abstract class ConversationItem {
this.id = h.getId(); this.id = h.getId();
this.groupId = h.getGroupId(); this.groupId = h.getGroupId();
this.time = h.getTimestamp(); this.time = h.getTimestamp();
this.autoDeleteTimer = h.getAutoDeleteTimer();
this.read = h.isRead(); this.read = h.isRead();
this.sent = h.isSent(); this.sent = h.isSent();
this.seen = h.isSeen(); this.seen = h.isSeen();
@@ -68,6 +69,10 @@ abstract class ConversationItem {
return time; return time;
} }
public long getAutoDeleteTimer() {
return autoDeleteTimer;
}
/** /**
* Only useful for incoming messages. * Only useful for incoming messages.
*/ */

View File

@@ -12,8 +12,11 @@ import androidx.annotation.UiThread;
import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.recyclerview.widget.RecyclerView.ViewHolder; import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static org.briarproject.bramble.util.StringUtils.trim; import static org.briarproject.bramble.util.StringUtils.trim;
import static org.briarproject.briar.android.util.UiUtils.formatDate; import static org.briarproject.briar.android.util.UiUtils.formatDate;
import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
@UiThread @UiThread
@NotNullByDefault @NotNullByDefault
@@ -26,6 +29,7 @@ abstract class ConversationItemViewHolder extends ViewHolder {
private final OutItemViewHolder outViewHolder; private final OutItemViewHolder outViewHolder;
private final TextView text; private final TextView text;
protected final TextView time; protected final TextView time;
private final View bomb;
@Nullable @Nullable
private String itemKey = null; private String itemKey = null;
@@ -38,6 +42,7 @@ abstract class ConversationItemViewHolder extends ViewHolder {
layout = v.findViewById(R.id.layout); layout = v.findViewById(R.id.layout);
text = v.findViewById(R.id.text); text = v.findViewById(R.id.text);
time = v.findViewById(R.id.time); time = v.findViewById(R.id.time);
bomb = v.findViewById(R.id.bomb);
} }
@CallSuper @CallSuper
@@ -52,6 +57,9 @@ abstract class ConversationItemViewHolder extends ViewHolder {
long timestamp = item.getTime(); long timestamp = item.getTime();
time.setText(formatDate(time.getContext(), timestamp)); time.setText(formatDate(time.getContext(), timestamp));
boolean showBomb = item.getAutoDeleteTimer() != NO_AUTO_DELETE_TIMER;
bomb.setVisibility(showBomb ? VISIBLE : GONE);
if (outViewHolder != null) outViewHolder.bind(item); if (outViewHolder != null) outViewHolder.bind(item);
} }

View File

@@ -0,0 +1,80 @@
package org.briarproject.briar.android.conversation;
import android.content.Intent;
import android.os.Bundle;
import android.view.MenuItem;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity;
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
import javax.annotation.Nullable;
import javax.inject.Inject;
import androidx.appcompat.app.ActionBar;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
import static org.briarproject.briar.android.conversation.ConversationActivity.CONTACT_ID;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class ConversationSettingsActivity extends BriarActivity implements
BaseFragmentListener {
@Inject
ViewModelProvider.Factory viewModelFactory;
private ConversationViewModel viewModel;
private ContactId contactId;
@Override
public void onCreate(@Nullable Bundle bundle) {
super.onCreate(bundle);
Intent i = getIntent();
int id = i.getIntExtra(CONTACT_ID, -1);
if (id == -1) throw new IllegalStateException();
contactId = new ContactId(id);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setHomeButtonEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
}
setContentView(R.layout.activity_conversation_settings);
viewModel = ViewModelProviders.of(this, viewModelFactory)
.get(ConversationViewModel.class);
}
@Override
public void onResume() {
super.onResume();
// Trigger loading of contact data, noop if data was loaded already.
//
// We can only start loading data *after* we are sure
// the user has signed in. After sign-in, onCreate() isn't run again.
if (signedIn()) viewModel.setContactId(contactId);
}
@Override
public void injectActivity(ActivityComponent component) {
component.inject(this);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
}
return false;
}
}

View File

@@ -0,0 +1,158 @@
package org.briarproject.briar.android.conversation;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
import androidx.appcompat.widget.SwitchCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.briar.android.util.UiUtils.observeOnce;
import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class ConversationSettingsFragment extends BaseFragment {
public static final String TAG =
ConversationSettingsFragment.class.getName();
private static final Logger LOG =
Logger.getLogger(ConversationSettingsFragment.class.getName());
@Inject
ViewModelProvider.Factory viewModelFactory;
@Inject
@DatabaseExecutor
Executor dbExecutor;
@Inject
TransactionManager db;
@Inject
AutoDeleteManager autoDeleteManager;
private ConversationSettingsActivity listener;
private ConversationViewModel viewModel;
private SwitchCompat switchDisappearingMessages;
private volatile boolean disappearingMessages = false;
@Override
public String getUniqueTag() {
return TAG;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
listener = (ConversationSettingsActivity) context;
listener.getActivityComponent().inject(this);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View contentView =
inflater.inflate(R.layout.fragment_conversation_settings,
container, false);
switchDisappearingMessages =
contentView.findViewById(R.id.switchDisappearingMessages);
switchDisappearingMessages
.setOnCheckedChangeListener((button, value) -> viewModel
.setAutoDeleteTimerEnabled(value));
TextView buttonLearnMore =
contentView.findViewById(R.id.buttonLearnMore);
buttonLearnMore.setOnClickListener(e -> showLearnMoreDialog());
viewModel = ViewModelProviders.of(requireActivity(), viewModelFactory)
.get(ConversationViewModel.class);
return contentView;
}
@Override
public void onStart() {
super.onStart();
switchDisappearingMessages.setEnabled(false);
loadSettings();
}
private void loadSettings() {
observeOnce(viewModel.getContact(), this, c -> {
dbExecutor.execute(() -> {
try {
db.transaction(false, txn -> {
long timer = autoDeleteManager
.getAutoDeleteTimer(txn, c.getId());
disappearingMessages = timer != NO_AUTO_DELETE_TIMER;
});
listener.runOnUiThreadUnlessDestroyed(
this::displaySettings);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
});
}
private void displaySettings() {
switchDisappearingMessages.setChecked(disappearingMessages);
switchDisappearingMessages.setEnabled(true);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.help_action, menu);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_help) {
showLearnMoreDialog();
return true;
}
return super.onOptionsItemSelected(item);
}
private void showLearnMoreDialog() {
ConversationSettingsLearnMoreDialog
dialog = new ConversationSettingsLearnMoreDialog();
dialog.show(requireActivity().getSupportFragmentManager(),
ConversationSettingsLearnMoreDialog.TAG);
}
}

View File

@@ -0,0 +1,44 @@
package org.briarproject.briar.android.conversation;
import android.app.Dialog;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.briar.R;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
@MethodsNotNullByDefault
public class ConversationSettingsLearnMoreDialog extends DialogFragment {
final static String TAG =
ConversationSettingsLearnMoreDialog.class.getName();
static ConversationSettingsLearnMoreDialog newInstance() {
return new ConversationSettingsLearnMoreDialog();
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
FragmentActivity activity = requireActivity();
AlertDialog.Builder builder =
new AlertDialog.Builder(activity, R.style.BriarDialogTheme);
LayoutInflater inflater = LayoutInflater.from(getContext());
View view = inflater.inflate(
R.layout.fragment_conversation_settings_learn_more, null);
builder.setView(view);
builder.setTitle(R.string.disappearing_messages_title);
builder.setNeutralButton(R.string.ok, null);
return builder.create();
}
}

View File

@@ -10,6 +10,7 @@ import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.NoSuchContactException; import org.briarproject.bramble.api.db.NoSuchContactException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.db.TransactionManager; import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
@@ -28,10 +29,13 @@ import org.briarproject.briar.android.attachment.AttachmentRetriever;
import org.briarproject.briar.android.util.UiUtils; import org.briarproject.briar.android.util.UiUtils;
import org.briarproject.briar.android.viewmodel.LiveEvent; import org.briarproject.briar.android.viewmodel.LiveEvent;
import org.briarproject.briar.android.viewmodel.MutableLiveEvent; import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
import org.briarproject.briar.api.autodelete.AutoDeleteManager;
import org.briarproject.briar.api.conversation.ConversationManager;
import org.briarproject.briar.api.messaging.AttachmentHeader; import org.briarproject.briar.api.messaging.AttachmentHeader;
import org.briarproject.briar.api.messaging.MessagingManager; import org.briarproject.briar.api.messaging.MessagingManager;
import org.briarproject.briar.api.messaging.PrivateMessage; import org.briarproject.briar.api.messaging.PrivateMessage;
import org.briarproject.briar.api.messaging.PrivateMessageFactory; import org.briarproject.briar.api.messaging.PrivateMessageFactory;
import org.briarproject.briar.api.messaging.PrivateMessageFormat;
import org.briarproject.briar.api.messaging.PrivateMessageHeader; import org.briarproject.briar.api.messaging.PrivateMessageHeader;
import org.briarproject.briar.api.messaging.event.AttachmentReceivedEvent; import org.briarproject.briar.api.messaging.event.AttachmentReceivedEvent;
@@ -50,6 +54,7 @@ import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Transformations; import androidx.lifecycle.Transformations;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
@@ -57,12 +62,15 @@ import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE; import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE;
import static org.briarproject.briar.android.util.UiUtils.observeForeverOnce; import static org.briarproject.briar.android.util.UiUtils.observeForeverOnce;
import static org.briarproject.briar.api.autodelete.AutoDeleteConstants.NO_AUTO_DELETE_TIMER;
import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_IMAGES;
import static org.briarproject.briar.api.messaging.PrivateMessageFormat.TEXT_ONLY;
@NotNullByDefault @NotNullByDefault
public class ConversationViewModel extends AndroidViewModel public class ConversationViewModel extends AndroidViewModel
implements EventListener, AttachmentManager { implements EventListener, AttachmentManager {
private static Logger LOG = private static final Logger LOG =
getLogger(ConversationViewModel.class.getName()); getLogger(ConversationViewModel.class.getName());
private static final String SHOW_ONBOARDING_IMAGE = private static final String SHOW_ONBOARDING_IMAGE =
@@ -80,6 +88,8 @@ public class ConversationViewModel extends AndroidViewModel
private final PrivateMessageFactory privateMessageFactory; private final PrivateMessageFactory privateMessageFactory;
private final AttachmentRetriever attachmentRetriever; private final AttachmentRetriever attachmentRetriever;
private final AttachmentCreator attachmentCreator; private final AttachmentCreator attachmentCreator;
private final AutoDeleteManager autoDeleteManager;
private final ConversationManager conversationManager;
@Nullable @Nullable
private ContactId contactId = null; private ContactId contactId = null;
@@ -89,7 +99,7 @@ public class ConversationViewModel extends AndroidViewModel
private final LiveData<String> contactName = private final LiveData<String> contactName =
Transformations.map(contact, UiUtils::getContactDisplayName); Transformations.map(contact, UiUtils::getContactDisplayName);
private final LiveData<GroupId> messagingGroupId; private final LiveData<GroupId> messagingGroupId;
private final MutableLiveData<Boolean> imageSupport = private final MutableLiveData<PrivateMessageFormat> privateMessageFormat =
new MutableLiveData<>(); new MutableLiveData<>();
private final MutableLiveEvent<Boolean> showImageOnboarding = private final MutableLiveEvent<Boolean> showImageOnboarding =
new MutableLiveEvent<>(); new MutableLiveEvent<>();
@@ -112,7 +122,9 @@ public class ConversationViewModel extends AndroidViewModel
SettingsManager settingsManager, SettingsManager settingsManager,
PrivateMessageFactory privateMessageFactory, PrivateMessageFactory privateMessageFactory,
AttachmentRetriever attachmentRetriever, AttachmentRetriever attachmentRetriever,
AttachmentCreator attachmentCreator) { AttachmentCreator attachmentCreator,
AutoDeleteManager autoDeleteManager,
ConversationManager conversationManager) {
super(application); super(application);
this.dbExecutor = dbExecutor; this.dbExecutor = dbExecutor;
this.db = db; this.db = db;
@@ -123,6 +135,8 @@ public class ConversationViewModel extends AndroidViewModel
this.privateMessageFactory = privateMessageFactory; this.privateMessageFactory = privateMessageFactory;
this.attachmentRetriever = attachmentRetriever; this.attachmentRetriever = attachmentRetriever;
this.attachmentCreator = attachmentCreator; this.attachmentCreator = attachmentCreator;
this.autoDeleteManager = autoDeleteManager;
this.conversationManager = conversationManager;
messagingGroupId = Transformations messagingGroupId = Transformations
.map(contact, c -> messagingManager.getContactGroup(c).getId()); .map(contact, c -> messagingManager.getContactGroup(c).getId());
contactDeleted.setValue(false); contactDeleted.setValue(false);
@@ -205,16 +219,13 @@ public class ConversationViewModel extends AndroidViewModel
} }
@UiThread @UiThread
void sendMessage(@Nullable String text, void sendMessage(@Nullable String text, List<AttachmentHeader> headers) {
List<AttachmentHeader> headers, long timestamp) {
// messagingGroupId is loaded with the contact // messagingGroupId is loaded with the contact
observeForeverOnce(messagingGroupId, groupId -> { observeForeverOnce(messagingGroupId, groupId -> {
requireNonNull(groupId); requireNonNull(groupId);
observeForeverOnce(imageSupport, hasImageSupport -> { observeForeverOnce(privateMessageFormat, format ->
requireNonNull(hasImageSupport); storeMessage(requireNonNull(contactId), groupId, text,
createMessage(groupId, text, headers, timestamp, headers, format));
hasImageSupport);
});
}); });
} }
@@ -244,10 +255,10 @@ public class ConversationViewModel extends AndroidViewModel
@DatabaseExecutor @DatabaseExecutor
private void checkFeaturesAndOnboarding(ContactId c) throws DbException { private void checkFeaturesAndOnboarding(ContactId c) throws DbException {
// check if images are supported // check if images and auto-deletion are supported
boolean imagesSupported = db.transactionWithResult(true, txn -> PrivateMessageFormat format = db.transactionWithResult(true, txn ->
messagingManager.contactSupportsImages(txn, c)); messagingManager.getContactMessageFormat(txn, c));
imageSupport.postValue(imagesSupported); privateMessageFormat.postValue(format);
// check if introductions are supported // check if introductions are supported
Collection<Contact> contacts = contactManager.getContacts(); Collection<Contact> contacts = contactManager.getContacts();
@@ -256,7 +267,7 @@ public class ConversationViewModel extends AndroidViewModel
// we only show one onboarding dialog at a time // we only show one onboarding dialog at a time
Settings settings = settingsManager.getSettings(SETTINGS_NAMESPACE); Settings settings = settingsManager.getSettings(SETTINGS_NAMESPACE);
if (imagesSupported && if (format != TEXT_ONLY &&
settings.getBoolean(SHOW_ONBOARDING_IMAGE, true)) { settings.getBoolean(SHOW_ONBOARDING_IMAGE, true)) {
onOnboardingShown(SHOW_ONBOARDING_IMAGE); onOnboardingShown(SHOW_ONBOARDING_IMAGE);
showImageOnboarding.postEvent(true); showImageOnboarding.postEvent(true);
@@ -274,40 +285,67 @@ public class ConversationViewModel extends AndroidViewModel
settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE); settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE);
} }
@UiThread private PrivateMessage createMessage(Transaction txn, ContactId c,
private void createMessage(GroupId groupId, @Nullable String text, GroupId groupId, @Nullable String text,
List<AttachmentHeader> headers, long timestamp, List<AttachmentHeader> headers, PrivateMessageFormat format)
boolean hasImageSupport) { throws DbException {
long timestamp =
conversationManager.getTimestampForOutgoingMessage(txn, c);
try { try {
PrivateMessage pm; if (format == TEXT_ONLY) {
if (hasImageSupport) { return privateMessageFactory.createLegacyPrivateMessage(
pm = privateMessageFactory.createPrivateMessage(groupId, groupId, timestamp, requireNonNull(text));
} else if (format == TEXT_IMAGES) {
return privateMessageFactory.createPrivateMessage(groupId,
timestamp, text, headers); timestamp, text, headers);
} else { } else {
pm = privateMessageFactory.createLegacyPrivateMessage( long timer = autoDeleteManager.getAutoDeleteTimer(txn, c,
groupId, timestamp, requireNonNull(text)); timestamp);
return privateMessageFactory.createPrivateMessage(groupId,
timestamp, text, headers, timer);
} }
storeMessage(pm);
} catch (FormatException e) { } catch (FormatException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }
} }
@UiThread @UiThread
private void storeMessage(PrivateMessage m) { private void storeMessage(ContactId c, GroupId groupId,
attachmentCreator.onAttachmentsSent(m.getMessage().getId()); @Nullable String text, List<AttachmentHeader> headers,
PrivateMessageFormat format) {
dbExecutor.execute(() -> { dbExecutor.execute(() -> {
try { try {
long start = now(); db.transaction(false, txn -> {
messagingManager.addLocalMessage(m); long start = now();
logDuration(LOG, "Storing message", start); PrivateMessage m = createMessage(txn, c, groupId, text,
Message message = m.getMessage(); headers, format);
PrivateMessageHeader h = new PrivateMessageHeader( messagingManager.addLocalMessage(txn, m);
message.getId(), message.getGroupId(), logDuration(LOG, "Storing message", start);
message.getTimestamp(), true, true, false, false, Message message = m.getMessage();
m.hasText(), m.getAttachmentHeaders()); PrivateMessageHeader h = new PrivateMessageHeader(
// TODO add text to cache when available here message.getId(), message.getGroupId(),
addedHeader.postEvent(h); message.getTimestamp(), true, true, false, false,
m.hasText(), m.getAttachmentHeaders(),
m.getAutoDeleteTimer());
// TODO add text to cache when available here
MessageId id = message.getId();
txn.attach(() -> attachmentCreator.onAttachmentsSent(id));
addedHeader.postEvent(h);
});
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
}
void setAutoDeleteTimerEnabled(boolean enabled) {
final long timer = enabled ? DAYS.toMillis(7) : NO_AUTO_DELETE_TIMER;
// ContactId is set before menu gets inflated and UI interaction
final ContactId c = requireNonNull(contactId);
dbExecutor.execute(() -> {
try {
db.transaction(false, txn ->
autoDeleteManager.setAutoDeleteTimer(txn, c, timer));
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
} }
@@ -330,8 +368,8 @@ public class ConversationViewModel extends AndroidViewModel
return contactName; return contactName;
} }
LiveData<Boolean> hasImageSupport() { LiveData<PrivateMessageFormat> getPrivateMessageFormat() {
return imageSupport; return privateMessageFormat;
} }
LiveEvent<Boolean> showImageOnboarding() { LiveEvent<Boolean> showImageOnboarding() {

View File

@@ -27,6 +27,7 @@ import javax.inject.Inject;
import androidx.annotation.DrawableRes; import androidx.annotation.DrawableRes;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders; import androidx.lifecycle.ViewModelProviders;
@@ -78,7 +79,7 @@ public class ImageFragment extends Fragment
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
Bundle args = requireNonNull(getArguments()); Bundle args = requireArguments();
attachment = requireNonNull(args.getParcelable(ATTACHMENT_POSITION)); attachment = requireNonNull(args.getParcelable(ATTACHMENT_POSITION));
isFirst = args.getBoolean(IS_FIRST); isFirst = args.getBoolean(IS_FIRST);
conversationItemId = conversationItemId =
@@ -93,7 +94,7 @@ public class ImageFragment extends Fragment
View v = inflater.inflate(R.layout.fragment_image, container, View v = inflater.inflate(R.layout.fragment_image, container,
false); false);
viewModel = ViewModelProviders.of(requireNonNull(getActivity()), viewModel = ViewModelProviders.of(requireActivity(),
viewModelFactory).get(ImageViewModel.class); viewModelFactory).get(ImageViewModel.class);
photoView = v.findViewById(R.id.photoView); photoView = v.findViewById(R.id.photoView);
@@ -110,8 +111,9 @@ public class ImageFragment extends Fragment
photoView.setImageResource(R.drawable.ic_image_missing); photoView.setImageResource(R.drawable.ic_image_missing);
startPostponedTransition(); startPostponedTransition();
// state is not final, so observe state changes // state is not final, so observe state changes
LifecycleOwner owner = getViewLifecycleOwner();
viewModel.getOnAttachmentReceived(attachment.getMessageId()) viewModel.getOnAttachmentReceived(attachment.getMessageId())
.observeEvent(this, this::onAttachmentReceived); .observeEvent(owner, this::onAttachmentReceived);
} }
return v; return v;

View File

@@ -47,7 +47,6 @@ import androidx.annotation.UiThread;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import static com.google.android.material.snackbar.Snackbar.LENGTH_INDEFINITE; import static com.google.android.material.snackbar.Snackbar.LENGTH_INDEFINITE;
import static java.util.Objects.requireNonNull;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
@@ -95,7 +94,7 @@ public class ForumListFragment extends BaseEventFragment implements
@Nullable ViewGroup container, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) { @Nullable Bundle savedInstanceState) {
requireNonNull(getActivity()).setTitle(R.string.forums_button); requireActivity().setTitle(R.string.forums_button);
View contentView = View contentView =
inflater.inflate(R.layout.fragment_forum_list, container, inflater.inflate(R.layout.fragment_forum_list, container,

View File

@@ -32,7 +32,6 @@ import androidx.annotation.Nullable;
import androidx.annotation.UiThread; import androidx.annotation.UiThread;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import static java.util.Objects.requireNonNull;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.briar.android.conversation.ConversationActivity.CONTACT_ID; import static org.briarproject.briar.android.conversation.ConversationActivity.CONTACT_ID;
@@ -84,7 +83,7 @@ public class ContactChooserFragment extends BaseFragment {
Contact c2 = item.getContact(); Contact c2 = item.getContact();
showMessageScreen(c1, c2); showMessageScreen(c1, c2);
}; };
adapter = new ContactListAdapter(requireNonNull(getActivity()), adapter = new ContactListAdapter(requireActivity(),
onContactClickListener); onContactClickListener);
list = contentView.findViewById(R.id.list); list = contentView.findViewById(R.id.list);
@@ -92,8 +91,7 @@ public class ContactChooserFragment extends BaseFragment {
list.setAdapter(adapter); list.setAdapter(adapter);
list.setEmptyText(R.string.no_contacts); list.setEmptyText(R.string.no_contacts);
contactId = new ContactId( contactId = new ContactId(requireArguments().getInt(CONTACT_ID));
requireNonNull(getArguments()).getInt(CONTACT_ID));
return contentView; return contentView;
} }

View File

@@ -39,7 +39,6 @@ import static android.app.Activity.RESULT_OK;
import static android.view.View.GONE; import static android.view.View.GONE;
import static android.view.View.VISIBLE; import static android.view.View.VISIBLE;
import static android.widget.Toast.LENGTH_SHORT; import static android.widget.Toast.LENGTH_SHORT;
import static java.util.Objects.requireNonNull;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName; import static org.briarproject.briar.android.util.UiUtils.getContactDisplayName;
@@ -102,7 +101,7 @@ public class IntroductionMessageFragment extends BaseFragment
} }
// get contact IDs from fragment arguments // get contact IDs from fragment arguments
Bundle args = requireNonNull(getArguments()); Bundle args = requireArguments();
int contactId1 = args.getInt(CONTACT_ID_1, -1); int contactId1 = args.getInt(CONTACT_ID_1, -1);
int contactId2 = args.getInt(CONTACT_ID_2, -1); int contactId2 = args.getInt(CONTACT_ID_2, -1);
if (contactId1 == -1 || contactId2 == -1) { if (contactId1 == -1 || contactId2 == -1) {
@@ -212,8 +211,7 @@ public class IntroductionMessageFragment extends BaseFragment
introductionActivity.runOnDbThread(() -> { introductionActivity.runOnDbThread(() -> {
// actually make the introduction // actually make the introduction
try { try {
long timestamp = System.currentTimeMillis(); introductionManager.makeIntroduction(c1, c2, text);
introductionManager.makeIntroduction(c1, c2, text, timestamp);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
introductionError(); introductionError();

View File

@@ -54,7 +54,6 @@ import static android.view.View.VISIBLE;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.widget.LinearLayout.HORIZONTAL; import static android.widget.LinearLayout.HORIZONTAL;
import static android.widget.Toast.LENGTH_LONG; import static android.widget.Toast.LENGTH_LONG;
import static java.util.Objects.requireNonNull;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
@@ -67,6 +66,7 @@ public class KeyAgreementFragment extends BaseEventFragment
static final String TAG = KeyAgreementFragment.class.getName(); static final String TAG = KeyAgreementFragment.class.getName();
private static final Logger LOG = Logger.getLogger(TAG); private static final Logger LOG = Logger.getLogger(TAG);
@SuppressWarnings("CharsetObjectCanBeUsed") // Requires minSdkVersion >= 19
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
@Inject @Inject
@@ -138,8 +138,7 @@ public class KeyAgreementFragment extends BaseEventFragment
@Override @Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) { public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
requireNonNull(getActivity()) requireActivity().setRequestedOrientation(SCREEN_ORIENTATION_NOSENSOR);
.setRequestedOrientation(SCREEN_ORIENTATION_NOSENSOR);
cameraView.setPreviewConsumer(new QrCodeDecoder(this)); cameraView.setPreviewConsumer(new QrCodeDecoder(this));
} }

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