Compare commits

...

321 Commits

Author SHA1 Message Date
Ernir Erlingsson
71d8947265 fixing the result handlers and orientation changes 2016-11-24 23:59:26 +01:00
Torsten Grote
6fc42f7296 Update also Malaysian translation (removes unused strings) 2016-11-23 21:08:51 -02:00
Torsten Grote
55af22ca04 Update translations and expiry date 2016-11-23 21:05:06 -02:00
akwizgran
6ab8219394 Merge branch '666-transport-icons-overlap-navigation-items' into 'master'
Make navigation drawer scrollable

![device-2016-11-22-095642](/uploads/bcd5f68d40816ed2e44c3194eb977695/device-2016-11-22-095642.png)![device-2016-11-22-095658](/uploads/da1807e981632936ba04db24dc7b8ae7/device-2016-11-22-095658.png)

Closes #666

See merge request !432
2016-11-23 15:11:43 +00:00
akwizgran
7d1ddb6d65 Merge branch '504-define-and-design-primary-and-secondary-actions' into 'master'
Make dialog actions consistent

Closes #504

See merge request !430
2016-11-23 15:08:58 +00:00
akwizgran
f1371f1db8 Merge branch '774-adding-contacts-via-bluetooth-only-fails' into 'master'
Use uuid created from the commitment/payload instead of the uuid returned from getUuid()

Signed-off-by: goapunk <noobie@goapunks.net>

Closes #774

See merge request !435
2016-11-23 15:06:16 +00:00
goapunk
491e0adc9c Use uuid created from the commitment/payload instead of the uuid returned from getUuid()
Signed-off-by: goapunk <noobie@goapunks.net>
2016-11-23 10:07:47 +01:00
Torsten Grote
f10ac13350 Make navigation drawer scrollable 2016-11-22 09:59:42 -02:00
Torsten Grote
38f46a9c60 Make dialog actions consistent 2016-11-21 17:42:23 -02:00
Torsten Grote
20de6f1aa5 Merge branch '747-remove-injected-field-from-unit-test' into 'master'
Remove injected field from unit test

Getting this off my todo list...

Closes #747

See merge request !428
2016-11-21 16:43:49 +00:00
akwizgran
cbdeb0ad32 Replace unused injected field with a mock. 2016-11-21 16:41:01 +00:00
akwizgran
a60414517c Merge branch '639-reblogger-and-author-look-similar-their-roles-are-unclear' into 'master'
Make original author look like commenter when reblogged

This wasn't as simple as changing the persona in the XML,
because the same layout is used for a post whether reblogged or not.
So the persona needs to be changed programmatically for reblogged posts.
For this, the `AuthorView#setPersona()` method has been made public and
was changed to always set all views into the desired state to support
usage in a RecyclerView.

![device-2016-11-21-094221](/uploads/e508937ad2d2d84f97f5be29bdeaac2e/device-2016-11-21-094221.png)

Closes #639

See merge request !426
2016-11-21 15:51:43 +00:00
akwizgran
988c3e4b58 Merge branch '768-keyagreementconnector-regression-unsupportedoperationexception' into 'master'
Fix KeyAgreement after regression

Closes #768

See merge request !427
2016-11-21 12:34:33 +00:00
Torsten Grote
b0098fb054 Fix KeyAgreement after regression 2016-11-21 10:32:06 -02:00
Torsten Grote
a7c28f04de Make original author look like commenter when reblogged
This wasn't as simple as changing the persona in the XML,
because the same layout is used for a post whether reblogged or not.
So the persona needs to be changed programmatically for reblogged posts.
For this, the `AuthorView#setPersona()` method has been made public and
was changed to always set all views into the desired state to support
usage in a RecyclerView.
2016-11-21 09:43:22 -02:00
akwizgran
4eec29a631 Merge branch '762-textinput_does_not_increase' into 'master'
make TextInputView resizable again

* TextInputView can resize up to 3 lines again

Signed-off-by: goapunk <noobie@goapunks.net>

Closes #762

See merge request !425
2016-11-21 10:11:00 +00:00
goapunk
76504387ff make TextInputView resizable again
* TextInputView can resize up to 3 lines again

Signed-off-by: goapunk <noobie@goapunks.net>
2016-11-18 18:05:31 +01:00
Torsten Grote
ea0ad08f57 Merge branch '763-remove-signature-api' into 'master'
Remove old signature class from API

I decided not to remove the SignatureImpl class, as it's not a trivial wrapper around the Bouncy Castle class, but I moved the interface into briar-core and made it  package-private.

Closes #763

See merge request !424
2016-11-18 16:23:01 +00:00
akwizgran
e4676517ef Merge branch '524-check-that-acra-is-catching-all-uncaught-exceptions' into 'master'
Introduce a @Scheduler annotation

and make sure work is offloaded to an executor, so exceptions can be caught.

Closes #524

See merge request !422
2016-11-18 16:00:22 +00:00
akwizgran
dbbeb37485 Merge branch '757-remove-deviceid-code' into 'master'
Remove Device ID

Closes #757

See merge request !423
2016-11-18 15:54:28 +00:00
akwizgran
89a7f41a07 Remove old signature class from API. 2016-11-18 15:30:18 +00:00
akwizgran
936ee5e95b Merge branch '549-require-a-label-for-signing' into 'master'
Require a label for signing

This adds a sign() and a verify() method to the CryptoComponent
that take a mandatory label argument to ensure that signatures can't be
repurposed.

Closes #549

See merge request !419
2016-11-18 15:16:41 +00:00
Torsten Grote
1697c2af04 Remove Device ID 2016-11-18 12:30:25 -02:00
Torsten Grote
cb8e0beea9 Fix Transport IDs 2016-11-18 12:29:57 -02:00
Torsten Grote
98cb077dd9 Migrate all custom signature code to new methods and add test 2016-11-18 12:19:03 -02:00
akwizgran
e6a8ad5d49 Merge branch '754-add-visibility-information-to-group-member-list' into 'master'
Add visibility information to group member list

![device-2016-11-17-120740](/uploads/f16dd42c3637e0030722559bace9c391/device-2016-11-17-120740.png)![device-2016-11-17-121008](/uploads/a83fe1f27cd3a505cf45a94fec76cdcf/device-2016-11-17-121008.png)

Closes #754

See merge request !418
2016-11-18 13:19:45 +00:00
akwizgran
5e4116efa0 Merge branch '761-keyboard_doesnt_close_on_userinteraction' into 'master'
use SHOW_IMPLICIT when showing the softkeyboard, otherwise it won't auto hide

* remove the forced hiding in ThreadListActivity as it should no longer be required

Signed-off-by: goapunk <noobie@goapunks.net>

Closes #761

See merge request !421
2016-11-18 13:14:51 +00:00
akwizgran
a01eeafe4e Merge branch '752-refactor-android-dagger-module' into 'master'
Activity module refactor

Broke the Activity module into numerous modules to be able to make numerous controller's package visible

Closes #752

See merge request !417
2016-11-18 13:13:12 +00:00
Torsten Grote
c86d971166 Require a label for signing
This adds a sign() and a verify() method to the CryptoComponent
that take a mandatory label argument to ensure that signatures can't be
repurposed.
2016-11-18 11:05:19 -02:00
Torsten Grote
d5f8808597 Add visibility information to group member list 2016-11-18 11:02:54 -02:00
goapunk
e98f4901f5 use SHOW_IMPLICIT when showing the softkeyboard, otherwise it won't auto hide
* remove the forced hiding in ThreadListActivity as it should no longer be required

Signed-off-by: goapunk <noobie@goapunks.net>
2016-11-18 13:50:04 +01:00
akwizgran
9b09b64ad3 Merge branch '558-use-namespaced-strings-for-transport-ids' into 'master'
Use namespaced strings for Transport IDs

Closes #558

See merge request !420
2016-11-18 12:49:57 +00:00
Torsten Grote
20708bc156 Introduce a @Scheduler annotation
and make sure work is offloaded to an executor, so exceptions can be
caught.
2016-11-18 10:48:20 -02:00
akwizgran
0814458cb9 Merge branch '759-introduction-responses-are-not-marked-as-read' into 'master'
Do not track incoming positive introduction responses

Positive introduction responses are not shown in the UI (for introducees) and are therefore not marked as read. If they would be tracked, the unread message count would be higher than it actually is and would never decrease.

This is a minimal fix that could be better, but I didn't bother to refactor anything, because we need to rewrite the introduction client eventually anyway once more.

Closes #759

See merge request !416
2016-11-18 12:20:40 +00:00
Torsten Grote
e32313c30b Use namespaced strings for Transport IDs 2016-11-17 17:06:26 -02:00
Torsten Grote
593152e7cd Do not track incoming positive introduction responses
because they are not shown in the UI and are therefore not marked as
read. This fixes the unread message count.
2016-11-17 10:59:20 -02:00
Ernir Erlingsson
ab91520813 refactored the activity module 2016-11-17 13:57:02 +01:00
Torsten Grote
37e61c97ea Merge branch 'remove-unmodifiable-wrappers' into 'master'
Remove unnecessary unmodifiable collection wrappers

Part of #379.

See merge request !414
2016-11-16 18:02:34 +00:00
Torsten Grote
303fcc9ece Merge branch 'validator-unit-tests' into 'master'
Unit tests for some validators

See merge request !413
2016-11-16 17:44:08 +00:00
akwizgran
e2bbe7429b Moved some boilerplate into a field. 2016-11-16 17:00:53 +00:00
akwizgran
eaf17c054f Moved common fields to superclass. 2016-11-16 16:39:30 +00:00
Torsten Grote
f97f30ce42 Merge branch '756-avoid-lost-messages' into 'master'
Use new group visibility state to avoid lost messages

Depends on !410. Closes #756.

See merge request !411
2016-11-16 16:22:30 +00:00
akwizgran
f4c26d9cc7 Remove unnecessary unmodifiable collection wrappers. 2016-11-16 16:19:47 +00:00
akwizgran
68abf8ba1a Merge branch '756-group-visibility' into 'master'
Add third group visibility state

This branch adds a third group visibility state: each group is either invisible, visible, or shared with respect to each contact.

Invisible means that the contact doesn't see any sign that we subscribe to the group. Visible means that the contact can send us messages in the group, but we won't send the contact messages in the group. Shared means that the contact can send us messages in the group and we'll send the contact any shared messages in the group.

This is a preparatory step for #756. I'll put up another MR with the changes that close that ticket.

See merge request !410
2016-11-16 15:56:37 +00:00
akwizgran
58f6af513d Use new group visibility state to avoid lost messages. #756 2016-11-16 15:50:07 +00:00
akwizgran
c9170fa5a0 Removed unnecessary use of unmodifiable collections. 2016-11-16 15:48:08 +00:00
akwizgran
ec1f4dccdb Added third group visibility state. 2016-11-16 15:40:51 +00:00
akwizgran
8c3b598ab2 Unit tests for ForumSharingValidator. 2016-11-16 15:35:27 +00:00
akwizgran
bd3bba6e8a Unit tests for ForumPostValidator. 2016-11-16 14:36:22 +00:00
akwizgran
11fcad89c6 Unit tests for BdfMessageValidator. 2016-11-16 14:32:22 +00:00
Torsten Grote
007df4288b Merge branch '709-track-private-group-invitation-messages' into 'master'
Use MessageTracker for private group invitation messages

Depends on !405.

See merge request !412
2016-11-16 14:14:48 +00:00
Torsten Grote
9798654c23 Merge branch 'message-tracker-refactoring' into 'master'
Factor MessageTracker out of BdfIncomingMessageHook

The branch moves the MessageTracker implementation from BdfIncomingMessageHook to a separate class. This will allow the private group invitation client to track messages from classes other than the one that implements the delivery hook.

I've also fixed a couple of bugs, removed some redundant code from the validation manager, and added null-safety annotations (which is how I noticed the bugs).

See merge request !405
2016-11-16 14:04:14 +00:00
akwizgran
7b58d003a1 Merge branch '732-reveal-contacts-ui-join-notices' into 'master'
Add visibility and OPTIONS button to private group join notices

![device-2016-11-11-180658](/uploads/e00d175a1e1f34307c5f0d80fa0d1cdf/device-2016-11-11-180658.png)
![device-2016-11-11-181325](/uploads/0f6010094d529a4f151db8ebce974885/device-2016-11-11-181325.png)

Closes #732

See merge request !408
2016-11-16 13:44:32 +00:00
akwizgran
b60f6b0789 Merge branch '755-group-message-timestamp' into 'master'
Made private group timestamp greater than that of latest message

I did not change `getPreviousMsgId()` to `getPreviousMsgHeader()` because there doesn't seem to be a need for it anymore.

Closes #755

See merge request !409
2016-11-16 13:29:59 +00:00
Torsten Grote
914b72505a Made private group timestamp greater than that of latest message 2016-11-16 11:20:25 -02:00
Torsten Grote
24dd4fda69 Address review issues 2016-11-16 11:08:00 -02:00
akwizgran
52eb261a11 Unit tests for PrivateMessageValidator. 2016-11-16 11:49:49 +00:00
Torsten Grote
980a6d18bb Add visibility and OPTIONS button to private group join notices 2016-11-16 09:25:22 -02:00
akwizgran
c4a152b543 Merge branch '732-reveal-contacts-ui-onboarding' into 'master'
Add onboarding dialog for revealing contacts screen

This MR is based on !406.

![device-2016-11-11-162417](/uploads/8df831905eebf41ecdbe368890cdd429/device-2016-11-11-162417.png)

See merge request !407
2016-11-14 12:44:41 +00:00
Torsten Grote
ed728e816e Add onboarding dialog for revealing contacts screen 2016-11-14 09:14:30 -02:00
akwizgran
efbce95399 Merge branch '732-reveal-contacts-ui' into 'master'
Add UI for revealing contacts within a private group

This addresses one part of #732. Join notices and onboarding will follow in separate MRs.

Although this MR is technically not based on !402, it does require it to be merged first to compile.

![device-2016-11-11-160454](/uploads/8cb6d8bdd0f3761657875024739e730a/device-2016-11-11-160454.png)

See merge request !406
2016-11-14 10:48:42 +00:00
akwizgran
98c81f71b4 Merge branch '709-reveal-relationships' into 'master'
Mark relationship visible when syncing group with peer

This branch updates the private group invitation protocol to use @grote's new method for marking a contact relationship visible to the group.

I've changed the method slightly because the protocol state machine allows us to leave and re-enter the BOTH_JOINED state (see diagram on #659), so the relationship may already be visible when the method is called. In that case the visibility isn't updated, so we stick with whichever of revealed-by-us and revealed-by-contact happened first.

See merge request !402
2016-11-14 10:32:56 +00:00
akwizgran
da543c1004 Added javadocs, removed redundant exception. 2016-11-14 10:30:38 +00:00
akwizgran
7ab4d12d83 Track private group invitation messages. 2016-11-14 10:10:14 +00:00
Torsten Grote
59964c5087 Add UI for revealing contacts within a private group 2016-11-11 15:40:02 -02:00
Torsten Grote
b885e49ba2 Don't indicate that we are sharing with ourselves in group memberlist 2016-11-11 15:40:01 -02:00
akwizgran
63da860681 Merge branch '732-reveal-contacts-ui-preparation' into 'master'
Prepare UI for revealing contacts

This changes the visibility of some methods (that need to be accessed from another package), removes unnecessary abstractions and fixes erroneous static import of GroupId constant.

See merge request !404
2016-11-11 17:33:54 +00:00
akwizgran
aa210fc555 Factor MessageTracker out of BdfIncomingMessageHook. 2016-11-11 16:59:10 +00:00
Torsten Grote
68f0e91f32 Prepare UI for revealing contacts
This changes the visibility of some methods, removes unnecessary
abstractions and fixes static import of GroupId constant.
2016-11-11 14:49:26 -02:00
akwizgran
3a2205123f Added a method for revealing a contact to a private group. 2016-11-11 13:49:49 +00:00
akwizgran
ab16ee7465 Merge branch 'exception-handler' into 'master'
Add new Exception handler

While working on #732 I again needed to use a `UiResultExceptionHandler`  when I actually don't need to return a result. We have some other places in the code like this. So I introduced a `UiExceptionHandler` without the result part and used it where appropriate. While I was touching some classes, I also added the new annotations.

This MR includes another small commit that notifies only on local group messages. Joining a group is a message as well and without this change, you are notified about a new message when you yourself joined your newly created group.

See merge request !403
2016-11-11 13:34:09 +00:00
Torsten Grote
eb66924e21 Do not show notification for local group messages 2016-11-11 10:03:03 -02:00
Torsten Grote
563d897651 Introduce Exception handler for when no result needs to be returned
Also add NotNull annotation to classes that were touched
2016-11-11 10:03:02 -02:00
akwizgran
98cf6b5bba Mark relationship visible when syncing group with peer. 2016-11-11 11:29:55 +00:00
akwizgran
ade7e50f65 Merge branch 'contact-selector-controller' into 'master'
Add a controller for contact selection lists

See merge request !401
2016-11-11 10:54:07 +00:00
Torsten Grote
ccc9d53ac7 Address review comments 2016-11-10 16:49:20 -02:00
Torsten Grote
d232529eb3 Add a controller for contact selection lists 2016-11-10 15:33:53 -02:00
akwizgran
a532f03784 Merge branch '732-reveal-backennd' into 'master'
Add support for revealing contacts to the PrivateGroupManager

This also adds three integration tests and improves some small details here and there in the private group client.

Prerequisite for #732.

See merge request !396
2016-11-10 17:00:31 +00:00
Torsten Grote
5e5bf7ec05 Add ContactRelationshipRevealedEvent and address review comments 2016-11-10 13:56:42 -02:00
akwizgran
7414abd1ce Merge branch '748-qr-code-payload-order' into 'master'
Preserve the order of descriptors in QR code payloads

This fixes a regression caused by my recent changes to the Payload class.

Closes #748

See merge request !399
2016-11-10 12:21:36 +00:00
Torsten Grote
dc76ce2be2 Merge branch '720-camera-surface-illegal-state-exception' into 'master'
Don't crash if camera is reopened or surface is recreated

This branch fixes the crash is described in #720, which can be reproduced easily by scanning a QR code and failing to connect (for example, scan a screenshot of a QR code from a device that's no longer listening). When the camera view becomes visible again after trying to connect, its surfaceCreated() callback is called again with the same surface. An IllegalStateException added in !340 causes the crash.

Closes #720

See merge request !397
2016-11-10 11:12:24 +00:00
Torsten Grote
3eed0bfe81 Add visibility of contact relationship to JoinMessageHeader 2016-11-09 16:35:27 -02:00
Torsten Grote
ec8982438a Add support for revealing contacts to the PrivateGroupManager
This also adds two integration tests and improves some small details
2016-11-09 16:34:58 -02:00
akwizgran
501c2dab31 Preserve the order of descriptors in QR code payloads. 2016-11-09 15:57:41 +00:00
akwizgran
2fe69af6d8 Don't try to get parameters after releasing camera. 2016-11-09 14:51:05 +00:00
Torsten Grote
b20c107010 Merge branch 'feed-pager-events' into 'master'
Make the feed pager respond to events, block notifications

This branch fixes a bug I found while working on #705: FeedPostPagerFragment doesn't start or stop the controller, so it doesn't load newly received posts or block notifications, unlike FeedFragment.

See merge request !398
2016-11-09 14:16:57 +00:00
akwizgran
f410e4eddd Make the feed pager respond to events, block notifications. 2016-11-09 13:24:44 +00:00
akwizgran
bb82bd70e2 Don't crash if camera is reopened or surface is recreated. 2016-11-09 12:43:33 +00:00
akwizgran
138a6e11a7 Merge branch '346-smaller-qr-codes' into 'master'
Encode transport properties more compactly in QR codes

The [original BQP spec](https://code.briarproject.org/akwizgran/briar/wikis/BQP) described a compact encoding for transport properties, with the goal of making the QR code as small as possible. At some point during the implementation, I asked @str4d to use TransportIds and TransportProperties instead, as described in the [current spec](https://code.briarproject.org/akwizgran/briar-spec/blob/master/protocols/BQP.md). That was a mistake.

Using the original format reduces the payload from 60 to 34 bytes (43% smaller) for Bluetooth only, and from 96 to 49 bytes (49% smaller) for Bluetooth and LAN. This makes it easier to scan codes from low-resolution screens using fixed-focus and/or low-resolution cameras. Using this branch I can exchange codes between the Sony Xperia Tipo (320x480 screen, fixed focus, 640x480 preview size) and the Huawei Ascend Y300 (480x800 screen, infinity focus, 1280x720 preview size).

This also removes an obstacle to implementing #558, as TransportIds are no longer included in QR codes.

Closes #346.

See merge request !394
2016-11-08 17:32:26 +00:00
akwizgran
178d72114b Merge branch '709-private-group-invitation-protocol' into 'master'
Private group invitation protocol

This branch implements the private group invitation protocol. The implementation is something of an experiment with a new way of writing client protocols.

We start with a role enum that lists the roles in the protocol, and a state enum for each role, which lists the states in the role's state machine. Then there's a session class, parameterised by the state class and therefore by the role, which represents the session information held by that role. Then there's an engine interface, parameterised by the session class and therefore by the role, which encapsulates the protocol logic for the role. Most of this stuff can be created pretty mechanically from the state machine diagrams.

The engine interface has a method for each type of message and each local action. I started out with one method for all messages and another for all local actions, but that turned out to be a bad design - the information about what kind of message was being handled was lost when the message was passed to the engine, and had to be recovered using an instanceof ladder.

Each engine method takes a message or an action and a session, and returns an updated session. A transaction is passed in so the engine can send messages, attach events, and do any other work it needs to do (such as changing the visibility of groups, in the case of this protocol). This removes the need to run tasks outside the engine, so the protocol logic is better encapsulated inside the engine.

Parsing and encoding of messages and sessions is separated from protocol logic. MessageParser, MessageEncoder and the validator are the only classes that know how messages and their metadata are formatted, and likewise SessionParser and SessionEncoder are the only classes that know how sessions are formatted. The metadata keys are declared in a package-private interface.

It's common knowledge that I never make mistakes, so to keep things interesting I've hidden 114 deliberate mistakes in this code. See how many you can spot!

Needs tests before #709 is closed.

See merge request !382
2016-11-08 17:22:00 +00:00
Torsten Grote
c1f1eb7dfa Merge branch '709-preliminaries' into 'master'
Preliminaries for private group invitation protocol

As promised, here's the preliminary stuff for #709 as a separate MR.

See merge request !395
2016-11-08 17:02:45 +00:00
akwizgran
d2a3804cfe Added null safety annotations to plugin interfaces. 2016-11-08 16:59:56 +00:00
akwizgran
fb095c1f4d Broadcast events for private group invitations. 2016-11-08 16:08:51 +00:00
akwizgran
f89d8cbe38 Updated peer state machine for automatic join response. 2016-11-08 16:08:50 +00:00
akwizgran
d2434123a9 Private group invitation protocol. 2016-11-08 16:08:50 +00:00
akwizgran
edbf5ff5b4 Preliminaries for private group invitation protocol. 2016-11-08 15:45:04 +00:00
akwizgran
32f0b53d15 Increase test timeouts to avoid spurious failures. 2016-11-08 15:17:08 +00:00
akwizgran
55ecdd9a13 Merge branch '557-use-namespaced-strings-for-client-ids' into 'master'
Use namespaced strings for client IDs

Closes #557

See merge request !393
2016-11-08 13:25:41 +00:00
akwizgran
e47e3242a6 Merge branch '196-mark-messages-read' into 'master'
Mark private messages read properly

Depends on !386.

This branch uses the same approach as forums to mark messages read, i.e. each message is marked read when it becomes visible, rather than marking all messages read in a batch when the activity finishes. This fixes two problems: messages not being marked read when isFinishing() is false, for example when leaving the activity via the home button, and a race condition between updating and loading the group count when leaving the activity, resulting in a stale unread message count in the contact list.

Closes #196.

See merge request !388
2016-11-08 13:25:00 +00:00
Torsten Grote
4387bfc5bd Merge branch '733-incoming-messages-aren-t-added-to-private-group-conversation' into 'master'
Broadcast GroupMessageAddedEvent for the UI to update when received

Closes #733

See merge request !390
2016-11-08 13:24:20 +00:00
Torsten Grote
d11ee5e43b Broadcast GroupMessageAddedEvent for the UI to update when received 2016-11-08 11:23:52 -02:00
akwizgran
ce53589c33 Merge branch '736-private-group-list-is-not-updated-when-group-is-dissolved' into 'master'
Create GroupDissolvedEvent and react to it

This MR also makes the private group list react to incoming group invitations (once they are implemented).

![device-2016-11-07-155240](/uploads/84ed51cf72bf2c7c597a0fd68b5d868c/device-2016-11-07-155240.png)
![device-2016-11-07-155302](/uploads/446c98d70d674d0bcd79bfb7682dfed5/device-2016-11-07-155302.png)

Closes #736, #737

See merge request !392
2016-11-08 13:20:28 +00:00
Torsten Grote
e96b3a8c68 Use namespaced strings for client IDs 2016-11-08 11:17:52 -02:00
Torsten Grote
62040d45b8 Create GroupDissolvedEvent and react to it
Also react to incoming group invitations
2016-11-08 10:28:54 -02:00
akwizgran
1809943f1d Merge branch '734-notifications-for-private-group-messages' into 'master'
Show Notifications for Group Messages

Closes #734

See merge request !391
2016-11-08 12:06:15 +00:00
akwizgran
d204757395 Merge branch '735-back-button-in-invite-members-screen-returns-to-group-list' into 'master'
Return to group after not inviting new members

This MR also closes the keyboard when returning from the message fragment.

Closes #735

See merge request !389
2016-11-08 11:55:36 +00:00
akwizgran
c640ee8e51 Merge branch '714-asynchronous-context-leaks' into 'master'
Fixed asynchronous Activity leaks in Fragments

If a Fragment has been detached its `getActivity()` method will return null, providing numerous crash possibilities within the app.

My approach to fixing this is to make Fragments use their own `runOnUiThreadUnlessDestroyed` method, which also checks if the Fragment has been detached before running the Runnable

Closes #714

See merge request !387
2016-11-08 11:49:45 +00:00
akwizgran
04d4ecad05 Encode transport properties more compactly in QR codes. 2016-11-08 11:28:44 +00:00
Ernir Erlingsson
c36bb3e60e created runOnUiThreadUnlessDestroyed fragment wrapper 2016-11-07 17:11:57 +01:00
akwizgran
7327029fca Log the QR code payload length. 2016-11-07 16:04:07 +00:00
Torsten Grote
81d341374d Show Notifications for Group Messages 2016-11-07 13:52:59 -02:00
Torsten Grote
7b884d2425 Return to group after not inviting new members
Also close keyboard when returning from message fragment
2016-11-07 10:44:22 -02:00
Torsten Grote
fbcf334941 Merge branch 'use-contact-id-as-conversation-id' into 'master'
Use contact ID rather than messaging group ID to identify conversation

We originally used the private messaging group ID to identify the private conversation, but now that the conversation includes messages from multiple clients it's more appropriate to use the contact ID.

This refactoring isn't urgent - I've had the branch lying around for a while, but I'm putting it up for review because #734 will touch some of the same code.

See merge request !386
2016-11-07 11:24:11 +00:00
akwizgran
238100bcac Mark messages read properly in private conversation. 2016-11-07 10:43:24 +00:00
akwizgran
7c3805260d Merge branch '643-allow-messages-to-be-deleted-in-the-delivery-hook' into 'master'
Allow messages to be deleted in delivery hook

Closes #643

See merge request !385
2016-11-04 16:14:44 +00:00
akwizgran
51bcf7b1b8 Don't use messaging group ID as proxy for contact ID. 2016-11-04 15:50:44 +00:00
Torsten Grote
719a53dc94 Address review comments 2016-11-04 12:58:12 -02:00
Torsten Grote
3f9a254a0b Allow messages to be deleted in delivery hook 2016-11-04 12:52:33 -02:00
akwizgran
e810a1265a Merge branch '205-unit-tests-for-keymanagerimpl-and-transportkeymanager' into 'master'
Add unit tests for KeyManagerImpl

This also creates a `TransportKeyManager` interface and a factory for that to be able to test things separately.

Closes #205

See merge request !380
2016-11-04 14:29:21 +00:00
Torsten Grote
c36f5c795b Address review comments for TransportKeyManagerImplTest 2016-11-04 11:04:44 -02:00
Torsten Grote
f52186ac8c Add unit tests for KeyManagerImpl and create TransportKeyManager
interface and a factory for that.
2016-11-04 10:54:56 -02:00
akwizgran
e0f4be931d Merge branch '708-private-group-fixup' into 'master'
Let only the creator invite new members to private groups

A little bug I noticed when reviewing the implementation of the invitation protocol.

See merge request !383
2016-11-04 09:33:50 +00:00
akwizgran
7536c00a34 Merge branch '708-private-group-remove-new-member-announcement' into 'master'
Remove new member announcement and add signature to join message



See merge request !384
2016-11-04 09:32:40 +00:00
akwizgran
847b6e4179 Added comments to integration test. 2016-11-04 09:32:21 +00:00
Torsten Grote
58793068c3 Address review comments 2016-11-03 17:26:37 -02:00
Torsten Grote
7125248677 Remove new member announcement and add signature to invitation 2016-11-03 17:24:31 -02:00
Torsten Grote
4bad7076e7 Merge branch '674-ending-a-transaction-can-throw-an-exception-in-a-finally-block' into 'master'
Replace transaction.setComplete() by database.commitTransaction()

Closes #674

See merge request !374
2016-11-03 19:23:16 +00:00
akwizgran
2bb16bb75f Merge branch '348-testers-did-not-understand-qr-code-workflow' into 'master'
Improve QR code workflow slightly

* Improve wording so contacts know they need meet up to scan
  and scan each other's codes
* Use consistent progress bar styles

Closes #348

See merge request !381
2016-11-03 15:56:19 +00:00
Torsten Grote
b5a427f876 Let only the creator invite new members to private groups 2016-11-02 17:40:33 -02:00
Torsten Grote
b34b4623ed Replace transaction.setComplete() by database.commitTransaction() 2016-11-02 13:04:31 -02:00
Torsten Grote
f3b9214702 Improve QR code workflow slightly
* Improve wording so contacts know they need meet up to scan
  and scan each other's codes
* Use consistent progress bar styles
2016-11-02 12:43:41 -02:00
akwizgran
36f087c512 Merge branch '724-unit-tests-for-clienthelperimpl' into 'master'
Add Unit Tests for ClientHelper

Closes #724

See merge request !379
2016-11-02 11:04:07 +00:00
akwizgran
0c30f16d7e Merge branch '731-bdf-reader-open-lists-and-dictionaries' into 'master'
Don't throw IllegalStateException if BDF input is incomplete

Closes #731

See merge request !378
2016-11-01 17:40:13 +00:00
akwizgran
4d8a84a48d Don't throw IllegalStateException if BDF input is incomplete. 2016-11-01 17:38:23 +00:00
akwizgran
2650f3114e Merge branch '518-limit-the-depth-of-nested-bdf-structures' into 'master'
Limit the depth of nested BDF structures

Closes #518

See merge request !375
2016-11-01 17:30:50 +00:00
Torsten Grote
dfdde9799f Add Unit Tests for ClientHelper 2016-11-01 15:28:28 -02:00
akwizgran
114a2dc8f2 Merge branch '427-local-author-caching' into 'master'
Cache the local author and load before the db latch is released

Closes #427, #588 

See merge request !354
2016-11-01 17:21:14 +00:00
akwizgran
642fa7df18 Removed unused field, renamed nickname methods. 2016-11-01 17:17:40 +00:00
akwizgran
c85767d2a0 Nickname is all one word. 2016-11-01 17:12:30 +00:00
Torsten Grote
55af1b954e Limit the depth of nested BDF structures 2016-11-01 14:52:00 -02:00
Ernir Erlingsson
88272c5d61 improvements after dev comments 2016-11-01 13:33:12 +01:00
Ernir Erlingsson
eaa393a7ed added a cache to the IdentityManager, changed its signature, modified when and where the author is stored
made the author creation single-threaded again in the LifecycleManager, removed redundant code
2016-11-01 12:51:49 +01:00
akwizgran
19080ad957 Merge branch '723-unit-tests-for-contactmanagerimpl' into 'master'
Add Unit tests for ContactManager

Closes #723

See merge request !376
2016-11-01 11:50:47 +00:00
Torsten Grote
7eeeb5f1ed Add Unit tests for ContactManager 2016-11-01 09:40:05 -02:00
akwizgran
d55503ee92 Merge branch '722-implement-ux-design-for-inviting-new-members-to-a-group' into 'master'
Implement UX design for inviting new members to a group

Closes #722

See merge request !373
2016-11-01 11:38:29 +00:00
Torsten Grote
8448d27d20 Implement UX design for inviting new members to a group 2016-11-01 09:27:23 -02:00
akwizgran
47d6fc526f Merge branch '678-implement-ux-for-viewing-the-membership-of-a-private-group' into 'master'
Implement UX for viewing the membership of a private group

This MR is the second and last MR to address #678. The first part is in !377.

![device-2016-10-26-112000](/uploads/8cbdee65c123a6d5329e208d9983d0b0/device-2016-10-26-112000.png)

Closes #678

See merge request !364
2016-11-01 11:12:21 +00:00
Torsten Grote
3da879cfd9 Address review comments for group member list 2016-11-01 09:09:22 -02:00
Torsten Grote
8fdce5ba51 Group Member List UI 2016-11-01 09:09:20 -02:00
akwizgran
f759a7506f Merge branch '600-remove-content-type-from-private-messages' into 'master'
Remove content-type and parentId from private messages

and turn them into a regular string.

Closes #600

See merge request !372
2016-11-01 11:05:30 +00:00
akwizgran
0b11aea7a2 Merge branch '672-implement-ux-for-dissolving-a-group' into 'master'
Implement UX for when a group has been dissolved

This MR is based on !367.

Closes #672

See merge request !369
2016-11-01 11:02:27 +00:00
akwizgran
aa954cee63 Merge branch '671-implement-ux-for-leaving-a-group' into 'master'
Implement UX for leaving a group

This MR also includes the creator's part of the UX for dissolving a group since it is almost the same.

![device-2016-10-26-185615](/uploads/8689a1ee103fcee23105a469b37c59de/device-2016-10-26-185615.png)

Closes #671

See merge request !367
2016-11-01 10:57:33 +00:00
akwizgran
68024c264e Merge branch '700-update-blog-backend-to-match-current-usage' into 'master'
Update blog backend to match current usage

Closes #700

See merge request !371
2016-11-01 10:56:02 +00:00
Torsten Grote
78740a6942 Remove content-type and parentId from private messages
and turn them into a regular string.
2016-11-01 08:39:15 -02:00
Torsten Grote
9e553ef9c8 Update blog backend to match current usage 2016-11-01 08:34:29 -02:00
Torsten Grote
1147b8ffaf Disable group before loading messages 2016-11-01 08:26:40 -02:00
Torsten Grote
67866dbe66 Implement UX for when a group has been dissolved 2016-11-01 07:41:55 -02:00
Torsten Grote
8dac2d1ca6 Implement UI for dissolving and leaving group 2016-11-01 07:40:56 -02:00
Torsten Grote
b0a5a69b81 Remove group from database in PrivateGroupManager 2016-11-01 07:39:35 -02:00
akwizgran
a18317e912 Merge branch '681-convert-forum-post-bodies-to-strings-remove-content-type' into 'master'
Remove forum content type and change bodies to string

Also removes support for anonymous forum posts.

This MR depends on !360.

Closes #698, #681

See merge request !370
2016-10-31 21:34:24 +00:00
akwizgran
ad7d0d8e74 Merge branch '678-private-group-hooks-and-membership' into 'master'
Add methods and hooks to PrivateGroupManager related to members and removal

This MR is the first of two MRs related to #678.

See merge request !377
2016-10-31 16:27:15 +00:00
akwizgran
fe79131f4a Merge branch '678-contact-list-refactoring' into 'master'
Refactor contact lists, their adapters and items

This was supposed to be a preparation for #678 to make the contacts lists cleaner and easier to re-use for different use-cases. Turns out #678 can't use this work, but it is probably nice to have anyway.

During this work, support for multiple identities has been removed from the various contact lists.

See merge request !363
2016-10-31 15:39:48 +00:00
Torsten Grote
cb61d91074 Add methods and hooks to PrivateGroupManager related to members and removal 2016-10-31 13:23:03 -02:00
akwizgran
399a4890de Merge branch '708-implement-protocol-for-private-group-messaging' into 'master'
Implement protocol for private group messaging

Closes #708

See merge request !360
2016-10-31 15:17:51 +00:00
Torsten Grote
656a947f5a Last minor review comments addressed 2016-10-31 13:13:59 -02:00
Torsten Grote
7191967092 Refactor contact lists, their adapters and items 2016-10-31 10:29:53 -02:00
Torsten Grote
5ce8b1978d Remove forum content type and move bodies to string
Also removes support for anonymous forum posts.
Closes #698
2016-10-31 10:25:12 -02:00
Torsten Grote
c0aa255bb6 Address review comments 2016-10-31 10:16:48 -02:00
Torsten Grote
c79ce61f6d Add PrivateGroupManager integration tests 2016-10-31 10:13:21 -02:00
Torsten Grote
0caabda303 Do additional validation on incoming private group messages 2016-10-31 10:13:21 -02:00
Torsten Grote
679b54b2b4 Show join messages properly in the threaded conversation 2016-10-31 10:13:20 -02:00
Torsten Grote
349a34ffd8 Return actual private group message headers and bodies to the UI 2016-10-31 10:12:26 -02:00
Torsten Grote
2c8aaa215c Posting group messages takes previous message into account 2016-10-31 10:11:35 -02:00
Torsten Grote
4f4f1956eb Creator automatically joins the group after creating it 2016-10-31 10:11:33 -02:00
Torsten Grote
e06726b2f9 Implement New Member and Join Announcements in GroupMessageFactory 2016-10-31 10:10:14 -02:00
Torsten Grote
a6e3827127 Implement first prototype of GroupMessageValidator 2016-10-31 10:09:17 -02:00
Torsten Grote
8dc529cc3f Move validator's signature verification into ClientHelper 2016-10-31 10:08:26 -02:00
akwizgran
1e36f21cc8 Merge branch '707-implement-ux-for-showing-and-answering-private-group-invitations' into 'master'
Implement UX for showing and answering private group invitations

As usual, this MR contains several logically separate commits that could be split out into smaller MRs if desired. It consists of two main parts:
* Showing open invitations in the list of private groups with a snackbar
* Showing invitations and responses in the private conversation

For both parts, the existing code was refactored to allow for a smooth implementation and to leave maintainable code behind.

![device-2016-10-18-101549](/uploads/66582dbe97736fdcd2498e87e1c7dfd1/device-2016-10-18-101549.png)
![device-2016-10-18-101612](/uploads/8c25eff8171f330796a55cb27cdb2552/device-2016-10-18-101612.png)
![device-2016-10-18-101534](/uploads/ebba4c0a2c0f727dcadac8c2ec57b48f/device-2016-10-18-101534.png)

Closes #707

See merge request !357
2016-10-31 12:02:22 +00:00
Torsten Grote
2cc650d85f Address review comments 2016-10-28 15:29:47 -02:00
akwizgran
3407d0c0a8 Merge branch 'protocol-state-exception' into 'master'
ProtocolStateException for client protocols

Methods that implement local actions in a client protocol (for example, accepting an invitation) can throw this exception to indicate that the action wasn't taken because the action isn't applicable to the current state. This can happen if the protocol state machine is updated by an incoming message and the user takes an action before the UI has been updated.

See merge request !368
2016-10-27 15:46:03 +00:00
akwizgran
ca8d3babaa Added ProtocolStateException for client protocols. 2016-10-27 11:57:36 +01:00
Torsten Grote
7b627bb427 Remove PartialItem interface and the need for casting ConversationItems 2016-10-27 08:22:52 -02:00
Torsten Grote
f027b832d4 Address review issues 2016-10-27 08:14:33 -02:00
Torsten Grote
42175dca7a Show group invitations and responses in private conversation 2016-10-27 08:14:33 -02:00
Torsten Grote
5ffcdc4e46 Refactor ConversationAdapter and its ConversationItems 2016-10-27 08:14:32 -02:00
Torsten Grote
e00219c15f Allow responding to sharing invitations based on SessionId 2016-10-27 08:14:32 -02:00
Torsten Grote
96666273d3 Show group invitations in group list 2016-10-27 08:14:32 -02:00
Torsten Grote
a92f7e1c9f Controllerize invitation activities 2016-10-27 08:14:31 -02:00
Torsten Grote
02a39f5694 Refactor events based on InvitationRequestReceivedEvent 2016-10-27 08:14:31 -02:00
Torsten Grote
a33d7d1663 Add a stub for a GroupInvitationManager 2016-10-27 08:14:30 -02:00
Ernir Erlingsson
8eeaf4e347 Merge branch '688-proguard-warns-about-missing-descriptor-classes' into 'master'
Fix proguard notes about unkept descriptor classes

Closes #688

See merge request !366
2016-10-26 20:32:43 +00:00
Torsten Grote
835bd86346 Fix proguard notes about unkept descriptor classes 2016-10-26 15:57:52 -02:00
akwizgran
84b2a171ab Merge branch '718-creating-a-group-without-having-contacts-can-cause-crash' into 'master'
Fix crash when navigating back in contact selector

Closes #718

See merge request !365
2016-10-26 17:08:07 +00:00
Torsten Grote
1df00f5702 Fix crash when navigating back in contact selector 2016-10-26 14:49:45 -02:00
akwizgran
292e1c3e8e Merge branch '715-long-posts-aren-t-rendered' into 'master'
Disable EmojiTextView software layer rendering when cache is too small

This needs to be tested if it works as intended on several devices.

See merge request !362
2016-10-26 15:09:56 +00:00
akwizgran
c8c0281efc Merge branch '686-crash-when-transitioning-out-of-reblogactivity' into 'master'
Limit scene transition animations to API 23 and above

to work-around [android bug #224270](https://code.google.com/p/android/issues/detail?id=224270).
This is only necessary if the transitioning view might not be available anymore when the exit transition is made.

Closes #686

See merge request !361
2016-10-26 10:11:32 +00:00
akwizgran
e8c48ccf8d Merge branch '661-implement-ux-for-creating-a-private-group' into 'master'
Implement UX for creating a private group

This MR allows the user to create a new private group and select contacts to be invited into the group.

There are currently 6 commits starting with some small refactoring for code reuse and making more functionality available in the backend. Each commit could be split up into a dedicated MR if desired.

![create-groups](/uploads/5229f102ee2611c05d5e9d1e2aac510d/create-groups.gif)

Closes #661

See merge request !353
2016-10-26 09:32:34 +00:00
Torsten Grote
09baa2ebe1 Add own constant for maximum group invitation message length 2016-10-26 07:28:51 -02:00
Torsten Grote
1176741ea4 Address actual review issues 2016-10-25 15:22:11 -02:00
Torsten Grote
e6def70030 Pre-address potential review issues 2016-10-25 14:58:50 -02:00
Torsten Grote
1a812f1327 UI for creating private groups 2016-10-25 14:58:47 -02:00
Torsten Grote
8dc3bd2c4c Implement private group creation and fetching in PrivateGroupManager 2016-10-25 14:57:43 -02:00
Torsten Grote
c934ec30aa Move Up button handling into BaseFragment 2016-10-25 14:57:43 -02:00
Torsten Grote
d5f6e71cba Create a reusable ContactSelectorActivity 2016-10-25 14:57:41 -02:00
Torsten Grote
feed2581c9 Factor out a reuseable MessageFragment 2016-10-25 14:56:25 -02:00
Torsten Grote
bd1f3fc2bd Make ContactSelectorFragment reusable 2016-10-25 14:52:27 -02:00
akwizgran
d25f4d1fbe Merge branch 'string-truncation' into 'master'
Truncate all messages to valid length before sending



See merge request !358
2016-10-25 15:52:35 +00:00
Torsten Grote
e84d1c5996 Update translations and expiry date 2016-10-25 08:19:15 -02:00
Torsten Grote
06831bafc3 Disable EmojiTextView software layer rendering when cache is too small 2016-10-24 17:20:57 -02:00
Torsten Grote
9284167a2e Limit scene transition animations to API 23 and above
to work-around android bug #224270.
This is only necessary if the transitioning view might not be available
anymore when the exit transition is made.
2016-10-24 15:34:24 -02:00
akwizgran
df44015ccb Merge branch '705-adapter-revisions' into 'master'
Fix race conditions when updating UI from events (again)

This is my second attempt at fixing race conditions caused by updating the UI from events while background tasks are loading data from the DB. Unlike my first attempt, this one is pretty simple and doesn't require too much reasoning about possible races.

The first commit fixes a few list loading bugs I found while working on this problem, and moves the lifecycle callbacks from resume/pause to start/stop, closing #609. The second commit contains the fix for #705, which works as follows:

* Each BriarAdapter has a revision counter
* Before making a change to the adapter that could be overwritten by a background task, increment the revision
* Before starting a background task that could overwrite other changes, get the current revision
* Before applying changes from a background task that could overwrite other changes, check whether the revision has changed
* If the revision has changed, restart the background task
* Otherwise apply the changes

Closes #609. #705 remains open because the PagerAdapters for blogs need to be updated.

See merge request !356
2016-10-21 10:28:02 +00:00
akwizgran
c4716ca457 BlogFragment doesn't need to use adapter revisions.
All changes to the adapter are cumulative.
2016-10-20 14:21:10 +01:00
akwizgran
9bb16b424f Moved revision counter methods into their own interface. 2016-10-20 12:44:09 +01:00
akwizgran
e8ebdc2884 Don't finish nav drawer fragments on error. 2016-10-20 11:55:39 +01:00
akwizgran
2140a290e4 Avoid race conditions when updating the UI from events. 2016-10-20 11:28:03 +01:00
akwizgran
50a70f7649 Use start/stop lifecycle callbacks rather than pause/resume.
Also fixed a couple of bugs.
2016-10-20 10:40:10 +01:00
akwizgran
b3e5d1ff85 Finished renaming entry to item, reduced some visibility. 2016-10-19 20:49:45 +01:00
Torsten Grote
690142ce07 Merge branch '712-bdf-list-out-of-bounds' into 'master'
Throw FormatException if BdfList index is out of bounds

Closes #712

See merge request !359
2016-10-19 17:49:14 +00:00
akwizgran
82eea6bb77 Throw FormatException if BdfList index is out of bounds. 2016-10-19 18:11:31 +01:00
Torsten Grote
3ad3332649 Merge branch '663-implement-ux-for-displaying-message-threads-in-private-groups' into 'master'
Private Group Threaded Conversation

This MR refactors the forum activity, its controller, its adapter and view holder so *most* of the code can be re-used for private groups by making heavy use of generics.

The refactoring has 1383 additions and 1087 deletions, so just grows the code-base slightly and adding the private group conversation just takes an additional 400 lines.

The MR also includes one commit that moves post/message creation more into clients, so the UI doesn't need to keep track of timestamps. This commit can of course be split out into a separate MR if desired.

Closes #662, #663 

See merge request !350
2016-10-19 16:42:24 +00:00
Torsten Grote
5a0fa5dcc7 Last round of addressing review issues 2016-10-19 14:38:11 -02:00
akwizgran
97223cce97 Fixed a typo in a constant. 2016-10-19 15:14:07 +01:00
akwizgran
08b191d72e Fixed a typo in a comment in a test. URGENT STUFF! 2016-10-19 15:04:24 +01:00
akwizgran
06335c2c30 Truncate all messages to valid length before sending. 2016-10-19 14:49:09 +01:00
Torsten Grote
8f882dc910 Addressing second round of review issues 2016-10-19 10:43:02 -02:00
Torsten Grote
0523c4e718 Address issues found in code review 2016-10-19 10:43:01 -02:00
Torsten Grote
7bf4aebdaf Move post/message creation into clients
This way the forum and private group client do not need to keep track of
message timestamps themselves and do not need to interact with
post/message factories.
2016-10-19 10:43:01 -02:00
Torsten Grote
6db59ffce5 Parsing and retrieval of private groups in PrivateGroupManager 2016-10-19 10:43:01 -02:00
Torsten Grote
e0835ad460 Add "Created by" to ActionBar 2016-10-19 10:43:00 -02:00
Torsten Grote
c83d4bbb39 Implement first prototype of private group message threads 2016-10-19 10:43:00 -02:00
Torsten Grote
65b47bb5d2 Refactor Forum Controller, so it can be used by private groups 2016-10-19 10:42:59 -02:00
Torsten Grote
9ce95d6de7 Refactor Forum Activity and adapters to be re-used for private groups 2016-10-19 10:42:59 -02:00
akwizgran
9d2c56e75f Upgraded Gradle plugin to 2.2.1. 2016-10-19 12:24:22 +01:00
akwizgran
32c4f61e68 Merge branch '670-uncaught-exceptions-do-not-print-a-stack-trace-in-introductionintegrationtest' into 'master'
Print stack trace for uncaught exceptions during tests for easier debugging

Closes #670

See merge request !355
2016-10-14 12:14:05 +00:00
Torsten Grote
6e04664915 Print stack trace for uncaught exceptions during tests for easier debugging 2016-10-14 08:44:47 -03:00
akwizgran
5674ee2d88 Converted group list controller to constructor injection. 2016-10-12 17:28:44 +01:00
akwizgran
8637faf858 Merge branch '704-constructor-injection' into 'master'
Use constructor injection for controllers

Also made some listeners volatile.

This is part of #704 - if I don't find any other classes that need constructor injection I'll close the ticket.

See merge request !351
2016-10-12 16:02:53 +00:00
akwizgran
970cbbf557 Merge branch 'not-null-by-default' into 'master'
Null safety annotations

The @NotNullByDefault annotation marks all fields, methods and parameters in a class or package @NotNull, so Android Studio will warn if values that may be null are used. Please use this annotation for new classes, and specify @Nullable for any fields, methods and parameters that may be null.

Injected fields are initialised to null, so injected classes should use @MethodsNotNullByDefault and @ParametersNotNullByDefault, or specify @Nullable for injected fields.

See merge request !349
2016-10-12 16:00:54 +00:00
akwizgran
57ac4a5374 Removed Maven Central repo. 2016-10-12 17:00:03 +01:00
akwizgran
2b91631ba5 Use constructor injection for controllers.
Also made some listeners volatile.
2016-10-11 12:31:21 +01:00
akwizgran
b327122255 Merge branch '660-implement-ux-for-the-list-of-private-groups' into 'master'
Private Group List UI

This MR implements the UI for the list of private groups.

It reacts to three types of events to refresh the displayed data:
* new group message received
* private group added
* private group removed

Missing from final implementation:
* entering groups
* adding new groups
* reacting to a future group dissolved event
* actually removing a dissolved group

![device-2016-09-29-180741](/uploads/666f04e8c9e2c81bdfe7f5648c14e71d/device-2016-09-29-180741.png)
![device-2016-10-03-141200](/uploads/5d0a54ea5a31d64404591c03ccf1e3b6/device-2016-10-03-141200.png)
![groups](/uploads/3eba757e21837739a129aab15100c06a/groups.gif)

Closes #660

See merge request !335
2016-10-11 10:22:26 +00:00
akwizgran
0b3ec9aa4c Merge branch '676-keyboard-isn-t-shown-when-forum-text-entry-field-gets-focus' into 'master'
Always show the keyboard when asked for it

The main fix is maintaining the internal keyboard state when the entire view gets hidden, because `onMeasure()` isn't called anymore in that case and can't update it itself.

Closes #676

See merge request !348
2016-10-11 09:47:27 +00:00
Torsten Grote
154e02723f Always show the keyboard when asked for it
and maintain keyboard state when hiding view.
2016-10-10 13:53:53 -03:00
Torsten Grote
b09e30a95f Private Group List 2016-10-10 13:48:34 -03:00
akwizgran
3ea36bbd40 Merge branch '551-destroyable-context' into 'master'
Always check whether the context has been destroyed

#551 has the same root cause as #610, which is that when a background operation completes, we need to check whether the activity or fragment that started the operation has been destroyed before doing anything with the UI. 

DestroyableActivity has been renamed to DestroyableContext because it's now implemented by some fragments as well. Various existing listener interfaces now extend DestroyableContext.

I also modified the ActivityLifecycleController interface so the activity is passed into the onActivityCreate() method rather than being injected - @ernir please check I haven't broken anything!

Closes #551

See merge request !341
2016-10-10 15:00:15 +00:00
akwizgran
cb983f02c2 Always check whether context has been destroyed. 2016-10-10 15:54:08 +01:00
akwizgran
f1730aa7d9 Merge branch '696-npe-key-agreement-task' into 'master'
Fix NPE when stopping KeyAgreementTask, improve thread safety

This branch fixes #696 and improves the thread safety of the camera code, mostly by adding @UiThread annotations and occasionally by moving stuff onto the UI thread that might have happened on other threads before.

Closes #696

See merge request !345
2016-10-10 14:46:25 +00:00
akwizgran
857665db79 Merge branch '373-slow-contact-list' into 'master'
Use new group metadata for showing lists

What was supposed to be a minimal change turned into a rather large MR. I did my best to keep things in separate commits, so I can still split this into smaller MRs if desired.

While making use of the new group metadata in the contact and forum list, I noticed some other things in need of improvement to get rid of needing to load all messages:
* Refactor `SharingManager` so its events provide message headers that can be used to update list items
* Add `GroupId` to conversation items, so the metadata of the respective group can be updated as well when marking the items read
* Create a very basic `ConversationManager` so the GroupCount for the various clients can be queried in one go without needing to know all their groups per contact
* Fix a nasty bug that caused forum and blog invitation to not update their read state
* Fix some bugs related to displaying the forum list with proper unread count

Some casual measurements with just a few contacts and messages showed a reduction of the contact list load time by one third.

See merge request !343
2016-10-10 14:00:36 +00:00
Torsten Grote
7f2db71160 Address review comments 2016-10-10 10:46:30 -03:00
akwizgran
60dee5c4cb Added null safety annotations. 2016-10-10 14:32:26 +01:00
Torsten Grote
784561144a Use new GroupCount to display Forum List
Fixes #531, #532
2016-10-10 08:00:17 -03:00
Torsten Grote
70d39d03bc Use group metadata from ConversationManager for showing contact lists
Fixes #373
2016-10-10 08:00:17 -03:00
Torsten Grote
48a3db46bc Properly pass message read state for sharing invitations and responses
Fixes #350
2016-10-10 08:00:16 -03:00
Torsten Grote
f52819f4ca Create a basic ConversationManager for querying GroupCount
This is also lays the groundwork for #384
2016-10-10 08:00:16 -03:00
Torsten Grote
457c30f3f2 Add GroupId to conversation items 2016-10-10 08:00:15 -03:00
Torsten Grote
1731369d7a Refactor SharingManager so its events provide message header 2016-10-10 08:00:12 -03:00
akwizgran
064b920626 Merge branch '687-refactor-adapters' into 'master'
Refactor existing adapters into a generic superclass

This MR also moves various blog classes into their own packages and makes the required visibility changes.

Closes #687

See merge request !346
2016-10-10 10:15:13 +00:00
Torsten Grote
b2fa039474 Refactor existing adapters into a generic superclass
This commit also moves various blog classes into their own packages and
makes the required visibility changes.
2016-10-06 11:30:10 -03:00
akwizgran
9112d17a4b Merge branch '611-body-cache-thread-safety' into 'master'
Make body cache thread-safe, reduce visibility of classes

Closes #611

See merge request !347
2016-10-06 13:43:09 +00:00
akwizgran
86fbb89637 Make body cache thread-safe, reduce visibility of classes. 2016-10-06 14:41:55 +01:00
akwizgran
b3bea1f945 Merge branch 'fix-introduction-unit-tests' into 'master'
Fix IntroductionManager unit tests

I forgot to run the unit tests after changing the `GroupCount` serialization in response to a review comment. This MR fixes the tests.

See merge request !344
2016-10-06 10:59:27 +00:00
akwizgran
543304973e Fixed an NPE, improved thread safety of camera code. 2016-10-06 11:53:07 +01:00
akwizgran
fc38738428 Merge branch '598-remove-unused-code' into 'master'
Remove unused UI code and layouts

If we ever need this code, it will be in the git history.

Closes #598

See merge request !342
2016-10-06 08:55:33 +00:00
Torsten Grote
d661fa0661 Fix IntroductionManager unit tests 2016-10-05 18:51:03 -03:00
akwizgran
e2eda8fef0 Merge branch '584-store-latest-timestamp-and-unread-count-in-group-metadata-for-private-messaging' into 'master'
Store message count, unread count and timestamp of latest message in group metadata

This is to eventually address #373 and slowness of other lists. The group metadata is not yet used, but if this MR isn't merged fast, another commit that actually uses it and thus takes care of the slowness will be added.

Closes #584, #585, #586

See merge request !336
2016-10-05 16:20:32 +00:00
akwizgran
604542c19b Remove unused UI code and layouts. 2016-10-05 17:09:16 +01:00
Torsten Grote
a727a0817e Store message count, unread count and timestamp of latest message
in group metadata to be able to speed up group listings.

Closes #584, #586, #585
2016-10-05 12:34:37 -03:00
Torsten Grote
3fa84ec7a8 Merge branch '680-release-camera-surface' into 'master'
Release camera surface to work around Android bug #54285

Closes #680

See merge request !340
2016-10-05 14:41:19 +00:00
Torsten Grote
e5f5511112 Merge branch 'identicon-cleanup' into 'master'
Clean up identicon code, remove unused classes

I noticed some debug-level logging coming from the identicon code, went in there to remove it, and realised half the code was unused, so I removed that too.

No functional changes except that the logging is gone and the opacity is now OPAQUE rather than UNKNOWN, which wasn't valid in this context.

See merge request !339
2016-10-05 14:38:17 +00:00
akwizgran
16ecb2ce8d Release surface to work around Android bug #54285. 2016-10-05 14:47:23 +01:00
akwizgran
c49c888f9f Merge branch '644-missing-header' into 'master'
Remove loading callbacks from fragment listener

Now fragments are responsible for their own Progress bars.

Closes #642

See merge request !316
2016-10-05 13:34:09 +00:00
Ernir Erlingsson
6b3db67ef5 removed fragment progress callback and fixed missing header 2016-10-05 14:21:14 +02:00
akwizgran
293c06fd61 Merge branch '92-emoticons' into 'master'
Emoji Support for all user input

All text that can be generated by users will show emoji from the shipped sprites by using the `EmojiTextView` instead of the normal `TextView`.

For all messages and posts, the custom emoji keyboard is now available as well. For this, a new `LargeTextInputView` has been introduced that is a sub-class of `TextInputView`. In order for the emoticon keyboard to work properly the existing views had to be modified heavily, sometimes resulting in new behavior such as scroll views now being above the fixed input field. Actual testing on a device (preferably with a tiny screen) is recommended to make sure this still works as expected. Screenshots will be included at the end of this post.

This MR also disables menu actions rather than hiding them and it includes a fix for a regression that was not showing the keyboard automatically in forums.

![device-2016-09-28-104914](/uploads/8ce9c8f61b32dc5a46b89a3a2cf1e6a4/device-2016-09-28-104914.png)
![device-2016-09-28-105026](/uploads/96ef9c40547c7a44fbc4517c87637a7e/device-2016-09-28-105026.png)
![device-2016-09-28-105041](/uploads/a0d1ed23ccb66e8bf9541737407142e3/device-2016-09-28-105041.png)
![device-2016-09-28-105440](/uploads/fb76ed2adc87600cfb0fc33c3962d4a6/device-2016-09-28-105440.png)
![device-2016-09-28-105515](/uploads/51f845d697cee3df38d1b9eef3c0ddfc/device-2016-09-28-105515.png)

Closes #92

See merge request !329
2016-10-05 11:01:12 +00:00
akwizgran
1c55fae704 Merge branch '695-introduction-failure' into 'master'
Fix regression in IntroduceeManager

This was happening when the remote response arrives before the local
response is made and thus the local response needs to be send with the
ACK following. The problem was that we ACK was sent before the response
which is not allowed and resulted in the session being aborted by the
introducee. This was happening, because recursion is hard ;)

The fix is only restarting another protocol engine to send the ACK
after the first run has been completed.

An integration test was added to prevent such regression in the future
and to test this code path.

Closes #695

See merge request !338
2016-10-04 21:38:48 +00:00
Torsten Grote
95670937c3 Fix regression in IntroduceeManager
This was happening when the remote response arrives before the local
response is made and thus the local response needs to be send with the
ACK following. The problem was that we ACK was sent before the response
which is not allowed and resulted in the session being aborted by the
introducee. This was happening, because recursion is hard ;)

The fix is only restarting another protocol engine to send the ACK
after the first run has been completed.

An integration test was added to prevent such regression in the future
and to test this code path.
2016-10-04 17:44:47 -03:00
Ernir Erlingsson
165deebb40 Merge branch '690-introduction-onboarding-is-shown-again-if-it-s-dismissed' into 'master'
Don't show introduction onboarding again no matter how dismissed

Closes #690

See merge request !337
2016-10-04 20:30:08 +00:00
Torsten Grote
0b0cae06ae Don't show introduction onboarding again no matter how dismissed 2016-10-04 14:51:37 -03:00
Torsten Grote
f8e0441de8 Emoji Support for all user input
All text that can be generated by users will show emoji from the
shipped sprites.

For all messages and posts, the custom emoji keyboard is now available.

This also disables menu actions rather than hiding them and thus
closes #677

Included is a fix for a regression that was not showing the keyboard
automatically in forums and thus
closes #676
2016-10-04 14:12:17 -03:00
akwizgran
a422c626b3 Merge branch '673-privategroupmanager-facade' into 'master'
Create PrivateGroupManager Facade and stub implementation

Some classes were renamed and new base classes introduced in the process. I suggest to expand the "Changed files" before reviewing to get an overview over the changes.

Closes #673

See merge request !332
2016-10-03 19:46:55 +00:00
Torsten Grote
6ece398a21 Create PrivateGroupManager Facade and stub implementation 2016-09-30 12:05:35 -03:00
akwizgran
8b50cb1461 Merge branch 'fix-integration-tests' into 'master'
Fix integration tests

First problem was a race condition with message delivery and the second
one due to the fact that we no longer plan to allow adding of additional
blogs, so the test for that has simply been removed.

See merge request !333
2016-09-29 16:43:56 +00:00
Torsten Grote
f28bc691a5 Merge branch '685-teaser-length' into 'master'
Check length of text after spanning

Closes #685

See merge request !334
2016-09-29 14:12:10 +00:00
akwizgran
42056720fa Check length of text after spanning. #685 2016-09-29 15:06:50 +01:00
Torsten Grote
0861ee1f10 Fix integration tests
First problem was a race condition with message delivery and the second
one due to the fact that we no longer plan to allow adding of additional
blogs, so the test for that has simply been removed.
2016-09-29 11:02:44 -03:00
akwizgran
a30de6309d Removed translated strings that were causing lint errors.
The app _name string is marked as non-translatable and the new_identity_item string no longer exists.
2016-09-29 12:47:29 +01:00
akwizgran
d112b42d20 Fixed obsolete ID in layout. 2016-09-29 12:45:56 +01:00
akwizgran
fd6719301a Merge branch '556-thread-safety-blocking-issues' into 'master'
Forum controller thread safety and tree safety

This branch solves the concurrent forum issues by code restructure and refactoring.

Closes #556 
Closes #552 

See merge request !262
2016-09-29 09:30:51 +00:00
Ernir Erlingsson
92f2e7b0fc merge with master and fixes after comments 2016-09-29 01:30:13 +02:00
akwizgran
ee98900613 Merge branch '644-missing-header-only' into 'master'
Remove toolbar animation to fix the missing toolbar on first start

Closes #644

See merge request !331
2016-09-28 17:03:55 +00:00
akwizgran
747553f577 Cleaned up identicon code, removed unused classes. 2016-09-28 17:34:12 +01:00
Torsten Grote
8a4c162bba Remove toolbar animation to fix the missing toolbar on first start 2016-09-28 13:33:09 -03:00
akwizgran
7e806c8cf2 Merge branch '679-own-personal-blogs-can-be-removed' into 'master'
Prevent personal blogs from being removed

This also adds unit tests to prevent regressions like this in the future.

Closes #679

See merge request !330
2016-09-28 16:22:46 +00:00
akwizgran
e466ed580c Merge branch '589-when-a-message-is-shared-share-its-transitive-dependencies' into 'master'
When a message is shared, share its transitive dependencies

Like other recursive operations on the dependency graph, this is
not done in a single transaction to prevent an attacker from creating
arbitrary large transactions.

So at startup, the `ValidationManager` finds and resumes any
unfinished operations, by looking for unshared messages with shared
dependents.

Closes #589

See merge request !325
2016-09-28 16:19:43 +00:00
Torsten Grote
d058172429 When a message is shared, share its transitive dependencies
Like other recursive operations on the dependency graph, this is
not done in a single transaction to prevent an attacker from creating
arbitrary large transactions.

So at startup, the `ValidationManager` finds and resumes any
unfinished operations, by looking for shared messages with unshared
dependencies.
2016-09-28 13:17:11 -03:00
Torsten Grote
1f0b305139 Prevent personal blogs from being removed
This also adds unit tests to prevent regressions like this in the
future.
2016-09-28 13:12:20 -03:00
Torsten Grote
7a0db798d1 bump expiry date and update translations 2016-09-28 11:56:55 -03:00
Torsten Grote
7e6a522eee Merge branch '346-camera-parameters' into 'master'
Try harder to find suitable camera parameters

This branch fixes QR code scanning on the Galaxy Nexus running Cyanogen Mod 12.1 (Android 5.1.1), without breaking QR code scanning on any of the other test devices.

The problem on the Galaxy Nexus was that the selected scene mode was overriding the selected focus mode, so we asked for continuous picture mode but got macro mode. Macro mode requires startAutoFocus() to be called, but we weren't calling it because we'd asked for continuous picture mode.

The fix for that problem is to query the focus mode after applying the parameters and call startAutoFocus() based on the actual mode rather than the requested mode.

But then I discovered another problem: barcode scene mode was setting the flash to auto, so in low light the flash was turning on and off while trying to scan QR codes. That might work well for printed QR codes, but it's terrible when scanning from a screen.

The fix for the new problem is to select barcode scene mode, then try to disable the flash, and if that fails, reset the scene mode. Then we pick the best available video stabilisation, focus mode and preview size.

On the Galaxy Nexus with CM 12.1, that means we use continuous picture mode instead of barcode scene mode, which works fine. All the other test devices pick the same settings as before.

See merge request !321
2016-09-28 14:40:56 +00:00
akwizgran
33795e7046 Use compareAndSet() instead of locking. 2016-09-27 23:02:54 +02:00
Ernir Erlingsson
2d59b9095c Fixing concurrency issues and refactoring code 2016-09-27 23:02:44 +02:00
Torsten Grote
8fb820c967 Merge branch 'check-if-listfiles-returns-null' into 'master'
Check whether File#listFiles() returns null

The docs say this can happen if there's an I/O error. Also fixed a throw-in-finally-block warning and renamed an IoUtils method to make its contract clearer.

See merge request !328
2016-09-27 16:17:09 +00:00
akwizgran
53d0b8b21e Check whether File#listFiles() returns null.
The docs say this can happen for a directory if there's an I/O error.
2016-09-27 15:52:57 +01:00
akwizgran
d389f79a48 Merge branch '346-remove-base32-todos' into 'master'
Remove base32 TODOs, fix a potential NPE

I thought we'd be able to get higher data density in QR codes by using base32 instead of base64, allowing the QR code to use alphanumeric mode instead of byte mode. But I tried it, and although the QR code does use alphanumeric mode, it comes out at exactly the same size (see the 346-use-base32-for-qr-codes branch). So this MR removes the TODOs and fixes a potential NPE I spotted while working on the other branch.

See merge request !327
2016-09-27 14:19:45 +00:00
akwizgran
b278c7d9cb Remove base32 TODOs - base64 is just as good. 2016-09-27 13:31:07 +01:00
Torsten Grote
a85043efb5 Merge branch 'recreate-cache-dir' into 'master'
Recreate cache directory after deleting app data

This fixes a warning on the Moto G:
```
E/libEGL: error creating cache file /data/data/org.briarproject/cache/com.android.opengl.shaders_cache: No such file or directory (2)
```

@grote might possibly be related to hardware rendering issues.

See merge request !326
2016-09-27 12:07:43 +00:00
akwizgran
133722dd2c Code cleanup. 2016-09-27 11:51:24 +01:00
akwizgran
9e3db12ea2 Recreate the cache dir after deleting app data. 2016-09-27 11:44:14 +01:00
akwizgran
f461ec4ab0 Merge branch '627-tests-for-introduction-security-properties' into 'master'
Add more introduction tests for fake MAC and modified timestamp

Closes #627, #669

See merge request !315
2016-09-26 17:09:56 +00:00
Torsten Grote
e87c301e3a Add more introduction tests for fake MAC and modified timestamp 2016-09-26 13:31:00 -03:00
akwizgran
17bacc1116 Merge branch '357-introduction-feature-is-not-very-visible' into 'master'
Add first onboarding screen

When the user enters a private conversation after adding her second
contact, an onboarding screen will be shown highlighting the possibility
of introducing the contacts to each other.

![intro2](/uploads/b2cd4377f39974ca1fbd95649558e487/intro2.gif)

Closes #357

See merge request !324
2016-09-26 14:30:45 +00:00
Torsten Grote
401abf2c0c Add first onboarding screen
When the user enters a private conversation after adding her second
contact, an onboarding screen will be shown highlighting the possibility
of introducing the contacts to each other.
2016-09-26 10:42:20 -03:00
akwizgran
a4d08f4cf1 Try harder to find suitable camera parameters. #346 2016-09-26 12:14:23 +01:00
akwizgran
eb6189150f Merge branch '92-emoticons' into 'master'
Emoji

This MR introduces a custom Emoji implementation to Briar for devices that do not support Emoji sufficiently. It is heavily based on Signal's implementation. Hence, the license for the Android part has been changed to GPLv3.

So far, emoji input is only supported for forums and private conversations that both rely on the same `TextInputView`.

![emoji2](/uploads/f69af031e72efb0bd6f0f67a9574d11f/emoji2.gif)

See merge request !317
2016-09-23 16:31:38 +00:00
akwizgran
c917110e6a Emoji: minor bug fixes, code cleanup, logging, visibility, 2016-09-23 17:18:21 +01:00
Torsten Grote
d5beca5351 Port Signal's emoji implementation to Briar
Add functionality to save and restore recently used Emojis

Update emoji and add new categories based on AOSP's XML file
2016-09-23 17:18:18 +01:00
akwizgran
1fdbe65dde Fixed a broken test. 2016-09-23 11:34:02 +01:00
Torsten Grote
1583163f88 Merge branch '538-recipient-offers-message-to-sender' into 'master'
Don't offer messages back to the sender

Closes #538

See merge request !323
2016-09-22 15:02:06 +00:00
akwizgran
ee35110167 Merge branch '625-avoid-repeated-author-status-lookups' into 'master'
Avoid repeated author status lookups

Closes #625

See merge request !322
2016-09-22 13:18:45 +00:00
akwizgran
72bf701345 Mark a received message as seen by the sender. 2016-09-22 11:31:32 +01:00
Torsten Grote
fd4dbdc081 Avoid repeated author status lookups 2016-09-21 17:26:24 -03:00
akwizgran
97937428bb Merge branch '329-btp-header' into 'master'
Include stream number in stream header nonce

See the corresponding change in the BTP spec for an explanation:
388e1d23c0

Closes #329

See merge request !320
2016-09-21 08:58:36 +00:00
akwizgran
4be1c1bb7d Include stream number in stream header nonce. 2016-09-20 15:27:01 +01:00
748 changed files with 32491 additions and 12667 deletions

View File

@@ -31,6 +31,8 @@
</value> </value>
</option> </option>
<option name="RIGHT_MARGIN" value="100" /> <option name="RIGHT_MARGIN" value="100" />
<option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
<option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
<AndroidXmlCodeStyleSettings> <AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" /> <option name="USE_CUSTOM_SETTINGS" value="true" />
</AndroidXmlCodeStyleSettings> </AndroidXmlCodeStyleSettings>

View File

@@ -13,23 +13,6 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------
All files under the directories briar-android/src, briar-api/src,
briar-core/src, briar-desktop/src and briar-test/src are licensed
under the Apache License, version 2.0 (the "License"); you may not
use these files except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
------------------------------------------------------------------------- -------------------------------------------------------------------------
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE

View File

@@ -11,10 +11,6 @@ android {
consumerProguardFiles getDefaultProguardFile('proguard-android.txt'), '../briar-android/proguard-rules.txt' consumerProguardFiles getDefaultProguardFile('proguard-android.txt'), '../briar-android/proguard-rules.txt'
} }
dexOptions {
incremental true
}
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7 sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7

View File

@@ -12,7 +12,6 @@ import org.briarproject.api.blogs.BlogPostHeader;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.contact.ContactManager; import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyPair;
import org.briarproject.api.crypto.SecretKey; import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.event.Event; import org.briarproject.api.event.Event;
@@ -61,7 +60,7 @@ import static org.briarproject.api.sync.ValidationManager.State.PENDING;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
public class BlogManagerTest { public class BlogManagerTest extends BriarIntegrationTest {
private LifecycleManager lifecycleManager0, lifecycleManager1; private LifecycleManager lifecycleManager0, lifecycleManager1;
private SyncSessionFactory sync0, sync1; private SyncSessionFactory sync0, sync1;
@@ -94,7 +93,7 @@ public class BlogManagerTest {
private final String AUTHOR2 = "Author 2"; private final String AUTHOR2 = "Author 2";
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(ForumSharingIntegrationTest.class.getName()); Logger.getLogger(BlogManagerTest.class.getName());
private BlogManagerTestComponent t0, t1; private BlogManagerTestComponent t0, t1;
@@ -241,32 +240,6 @@ public class BlogManagerTest {
stopLifecycles(); stopLifecycles();
} }
@Test
public void testAddAndRemoveBlog() throws Exception {
startLifecycles();
defaultInit();
String name = "Test Blog";
String desc = "Description";
// add blog
Blog blog = blogManager0.addBlog(author0, name, desc);
Collection<Blog> blogs0 = blogManager0.getBlogs();
assertEquals(3, blogs0.size());
assertTrue(blogs0.contains(blog));
assertEquals(2, blogManager0.getBlogs(author0).size());
assertTrue(blogManager0.canBeRemoved(blog.getId()));
// remove blog
blogManager0.removeBlog(blog);
blogs0 = blogManager0.getBlogs();
assertEquals(2, blogs0.size());
assertFalse(blogs0.contains(blog));
assertEquals(1, blogManager0.getBlogs(author0).size());
stopLifecycles();
}
@Test @Test
public void testCanNotRemoveContactsPersonalBlog() throws Exception { public void testCanNotRemoveContactsPersonalBlog() throws Exception {
startLifecycles(); startLifecycles();
@@ -481,6 +454,7 @@ public class BlogManagerTest {
@Test @Test
public void testCommentOnOwnComment() throws Exception { public void testCommentOnOwnComment() throws Exception {
startLifecycles(); startLifecycles();
defaultInit(); defaultInit();
@@ -552,27 +526,16 @@ public class BlogManagerTest {
} }
private void defaultInit() throws DbException { private void defaultInit() throws DbException {
addDefaultIdentities(); getDefaultIdentities();
addDefaultContacts(); addDefaultContacts();
listenToEvents(); listenToEvents();
} }
private void addDefaultIdentities() throws DbException { private void getDefaultIdentities() throws DbException {
KeyPair keyPair0 = crypto.generateSignatureKeyPair(); author0 = identityManager0.getLocalAuthor();
byte[] publicKey0 = keyPair0.getPublic().getEncoded(); author1 = identityManager1.getLocalAuthor();
byte[] privateKey0 = keyPair0.getPrivate().getEncoded(); blog0 = blogFactory.createBlog(author0);
author0 = authorFactory blog1 = blogFactory.createBlog(author1);
.createLocalAuthor(AUTHOR1, publicKey0, privateKey0);
identityManager0.addLocalAuthor(author0);
blog0 = blogFactory.createPersonalBlog(author0);
KeyPair keyPair1 = crypto.generateSignatureKeyPair();
byte[] publicKey1 = keyPair1.getPublic().getEncoded();
byte[] privateKey1 = keyPair1.getPrivate().getEncoded();
author1 = authorFactory
.createLocalAuthor(AUTHOR2, publicKey1, privateKey1);
identityManager1.addLocalAuthor(author1);
blog1 = blogFactory.createPersonalBlog(author1);
} }
private void addDefaultContacts() throws DbException { private void addDefaultContacts() throws DbException {
@@ -629,8 +592,8 @@ public class BlogManagerTest {
// Start the lifecycle manager and wait for it to finish // Start the lifecycle manager and wait for it to finish
lifecycleManager0 = t0.getLifecycleManager(); lifecycleManager0 = t0.getLifecycleManager();
lifecycleManager1 = t1.getLifecycleManager(); lifecycleManager1 = t1.getLifecycleManager();
lifecycleManager0.startServices(); lifecycleManager0.startServices(AUTHOR1);
lifecycleManager1.startServices(); lifecycleManager1.startServices(AUTHOR2);
lifecycleManager0.waitForStartup(); lifecycleManager0.waitForStartup();
lifecycleManager1.waitForStartup(); lifecycleManager1.waitForStartup();
} }

View File

@@ -8,11 +8,12 @@ import org.briarproject.api.blogs.BlogInvitationResponse;
import org.briarproject.api.blogs.BlogManager; import org.briarproject.api.blogs.BlogManager;
import org.briarproject.api.blogs.BlogPostFactory; import org.briarproject.api.blogs.BlogPostFactory;
import org.briarproject.api.blogs.BlogSharingManager; import org.briarproject.api.blogs.BlogSharingManager;
import org.briarproject.api.clients.ContactGroupFactory;
import org.briarproject.api.clients.MessageTracker;
import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.contact.ContactManager; import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyPair;
import org.briarproject.api.crypto.SecretKey; import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.event.BlogInvitationReceivedEvent; import org.briarproject.api.event.BlogInvitationReceivedEvent;
@@ -25,6 +26,7 @@ import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.sharing.InvitationMessage; import org.briarproject.api.sharing.InvitationMessage;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.SyncSession; import org.briarproject.api.sync.SyncSession;
import org.briarproject.api.sync.SyncSessionFactory; import org.briarproject.api.sync.SyncSessionFactory;
import org.briarproject.api.sync.ValidationManager.State; import org.briarproject.api.sync.ValidationManager.State;
@@ -56,26 +58,28 @@ import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import static org.briarproject.TestPluginsModule.MAX_LATENCY; import static org.briarproject.TestPluginsModule.MAX_LATENCY;
import static org.briarproject.api.blogs.BlogSharingManager.CLIENT_ID;
import static org.briarproject.api.sync.ValidationManager.State.DELIVERED; import static org.briarproject.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.api.sync.ValidationManager.State.INVALID; import static org.briarproject.api.sync.ValidationManager.State.INVALID;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
public class BlogSharingIntegrationTest extends BriarTestCase { public class BlogSharingIntegrationTest extends BriarIntegrationTest {
private LifecycleManager lifecycleManager0, lifecycleManager1, private LifecycleManager lifecycleManager0, lifecycleManager1,
lifecycleManager2; lifecycleManager2;
private SyncSessionFactory sync0, sync1, sync2; private SyncSessionFactory sync0, sync1;
private BlogManager blogManager0, blogManager1, blogManager2; private BlogManager blogManager0, blogManager1;
private MessageTracker messageTracker0, messageTracker1;
private ContactManager contactManager0, contactManager1, contactManager2; private ContactManager contactManager0, contactManager1, contactManager2;
private Contact contact1, contact2, contact01, contact02; private Contact contact1, contact2, contact01, contact02;
private ContactId contactId1, contactId2, contactId01, contactId02; private ContactId contactId1, contactId01;
private IdentityManager identityManager0, identityManager1, private IdentityManager identityManager0, identityManager1,
identityManager2; identityManager2;
private LocalAuthor author0, author1, author2; private LocalAuthor author0, author1, author2;
private Blog blog0, blog1, blog2; private Blog blog0, blog1, blog2;
private SharerListener listener0, listener2; private SharerListener listener0;
private InviteeListener listener1; private InviteeListener listener1;
@Inject @Inject
@@ -83,6 +87,8 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
@Inject @Inject
AuthorFactory authorFactory; AuthorFactory authorFactory;
@Inject @Inject
ContactGroupFactory contactGroupFactory;
@Inject
BlogPostFactory blogPostFactory; BlogPostFactory blogPostFactory;
@Inject @Inject
CryptoComponent cryptoComponent; CryptoComponent cryptoComponent;
@@ -138,13 +144,13 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
contactManager2 = t2.getContactManager(); contactManager2 = t2.getContactManager();
blogManager0 = t0.getBlogManager(); blogManager0 = t0.getBlogManager();
blogManager1 = t1.getBlogManager(); blogManager1 = t1.getBlogManager();
blogManager2 = t2.getBlogManager(); messageTracker0 = t0.getMessageTracker();
messageTracker1 = t1.getMessageTracker();
blogSharingManager0 = t0.getBlogSharingManager(); blogSharingManager0 = t0.getBlogSharingManager();
blogSharingManager1 = t1.getBlogSharingManager(); blogSharingManager1 = t1.getBlogSharingManager();
blogSharingManager2 = t2.getBlogSharingManager(); blogSharingManager2 = t2.getBlogSharingManager();
sync0 = t0.getSyncSessionFactory(); sync0 = t0.getSyncSessionFactory();
sync1 = t1.getSyncSessionFactory(); sync1 = t1.getSyncSessionFactory();
sync2 = t2.getSyncSessionFactory();
// initialize waiters fresh for each test // initialize waiters fresh for each test
eventWaiter = new Waiter(); eventWaiter = new Waiter();
@@ -187,15 +193,22 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
// invitee has own blog and that of the sharer // invitee has own blog and that of the sharer
assertEquals(2, blogManager1.getBlogs().size()); assertEquals(2, blogManager1.getBlogs().size());
// get sharing group and assert group message count
GroupId g = contactGroupFactory.createContactGroup(CLIENT_ID, contact1)
.getId();
assertGroupCount(messageTracker0, g, 1, 0);
// sync first request message // sync first request message
sync0To1(); sync0To1();
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertTrue(listener1.requestReceived); assertTrue(listener1.requestReceived);
assertGroupCount(messageTracker1, g, 2, 1);
// sync response back // sync response back
sync1To0(); sync1To0();
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertTrue(listener0.responseReceived); assertTrue(listener0.responseReceived);
assertGroupCount(messageTracker0, g, 2, 1);
// blog was added successfully // blog was added successfully
assertEquals(0, blogSharingManager0.getInvitations().size()); assertEquals(0, blogSharingManager0.getInvitations().size());
@@ -232,6 +245,10 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
assertFalse(blogSharingManager0.canBeShared(blog2.getId(), contact1)); assertFalse(blogSharingManager0.canBeShared(blog2.getId(), contact1));
assertFalse(blogSharingManager1.canBeShared(blog2.getId(), contact01)); assertFalse(blogSharingManager1.canBeShared(blog2.getId(), contact01));
// group message count is still correct
assertGroupCount(messageTracker0, g, 2, 1);
assertGroupCount(messageTracker1, g, 2, 1);
stopLifecycles(); stopLifecycles();
} }
@@ -510,8 +527,7 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
private class SharerListener implements EventListener { private class SharerListener implements EventListener {
volatile boolean requestReceived = false; private volatile boolean responseReceived = false;
volatile boolean responseReceived = false;
@Override @Override
public void eventOccurred(Event e) { public void eventOccurred(Event e) {
@@ -534,8 +550,7 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
BlogInvitationReceivedEvent event = BlogInvitationReceivedEvent event =
(BlogInvitationReceivedEvent) e; (BlogInvitationReceivedEvent) e;
eventWaiter.assertEquals(contactId1, event.getContactId()); eventWaiter.assertEquals(contactId1, event.getContactId());
requestReceived = true; Blog b = event.getShareable();
Blog b = event.getBlog();
try { try {
Contact c = contactManager0.getContact(contactId1); Contact c = contactManager0.getContact(contactId1);
blogSharingManager0.respondToInvitation(b, c, true); blogSharingManager0.respondToInvitation(b, c, true);
@@ -550,17 +565,16 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
private class InviteeListener implements EventListener { private class InviteeListener implements EventListener {
volatile boolean requestReceived = false; private volatile boolean requestReceived = false;
volatile boolean responseReceived = false;
private final boolean accept, answer; private final boolean accept, answer;
InviteeListener(boolean accept, boolean answer) { private InviteeListener(boolean accept, boolean answer) {
this.accept = accept; this.accept = accept;
this.answer = answer; this.answer = answer;
} }
InviteeListener(boolean accept) { private InviteeListener(boolean accept) {
this(accept, true); this(accept, true);
} }
@@ -578,7 +592,7 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
(BlogInvitationReceivedEvent) e; (BlogInvitationReceivedEvent) e;
requestReceived = true; requestReceived = true;
if (!answer) return; if (!answer) return;
Blog b = event.getBlog(); Blog b = event.getShareable();
try { try {
eventWaiter.assertEquals(1, eventWaiter.assertEquals(1,
blogSharingManager1.getInvitations().size()); blogSharingManager1.getInvitations().size());
@@ -596,7 +610,6 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
BlogInvitationResponseReceivedEvent event = BlogInvitationResponseReceivedEvent event =
(BlogInvitationResponseReceivedEvent) e; (BlogInvitationResponseReceivedEvent) e;
eventWaiter.assertEquals(contactId01, event.getContactId()); eventWaiter.assertEquals(contactId01, event.getContactId());
responseReceived = true;
eventWaiter.resume(); eventWaiter.resume();
} }
} }
@@ -607,9 +620,9 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
lifecycleManager0 = t0.getLifecycleManager(); lifecycleManager0 = t0.getLifecycleManager();
lifecycleManager1 = t1.getLifecycleManager(); lifecycleManager1 = t1.getLifecycleManager();
lifecycleManager2 = t2.getLifecycleManager(); lifecycleManager2 = t2.getLifecycleManager();
lifecycleManager0.startServices(); lifecycleManager0.startServices(SHARER);
lifecycleManager1.startServices(); lifecycleManager1.startServices(INVITEE);
lifecycleManager2.startServices(); lifecycleManager2.startServices(CONTACT2);
lifecycleManager0.waitForStartup(); lifecycleManager0.waitForStartup();
lifecycleManager1.waitForStartup(); lifecycleManager1.waitForStartup();
lifecycleManager2.waitForStartup(); lifecycleManager2.waitForStartup();
@@ -626,30 +639,16 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
} }
private void defaultInit(boolean accept) throws DbException { private void defaultInit(boolean accept) throws DbException {
addDefaultIdentities(); getDefaultIdentities();
addDefaultContacts(); addDefaultContacts();
getPersonalBlogOfSharer(); getPersonalBlogOfSharer();
listenToEvents(accept); listenToEvents(accept);
} }
private void addDefaultIdentities() throws DbException { private void getDefaultIdentities() throws DbException {
KeyPair keyPair = cryptoComponent.generateSignatureKeyPair(); author0 = identityManager0.getLocalAuthor();
author0 = authorFactory.createLocalAuthor(SHARER, author1 = identityManager1.getLocalAuthor();
keyPair.getPublic().getEncoded(), author2 = identityManager2.getLocalAuthor();
keyPair.getPrivate().getEncoded());
identityManager0.addLocalAuthor(author0);
keyPair = cryptoComponent.generateSignatureKeyPair();
author1 = authorFactory.createLocalAuthor(INVITEE,
keyPair.getPublic().getEncoded(),
keyPair.getPrivate().getEncoded());
identityManager1.addLocalAuthor(author1);
keyPair = cryptoComponent.generateSignatureKeyPair();
author2 = authorFactory.createLocalAuthor(CONTACT2,
keyPair.getPublic().getEncoded(),
keyPair.getPrivate().getEncoded());
identityManager2.addLocalAuthor(author2);
} }
private void addDefaultContacts() throws DbException { private void addDefaultContacts() throws DbException {
@@ -660,7 +659,7 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
); );
contact1 = contactManager0.getContact(contactId1); contact1 = contactManager0.getContact(contactId1);
// sharer adds second contact // sharer adds second contact
contactId2 = contactManager0.addContact(author2, ContactId contactId2 = contactManager0.addContact(author2,
author0.getId(), master, clock.currentTimeMillis(), true, author0.getId(), master, clock.currentTimeMillis(), true,
true, true true, true
); );
@@ -671,7 +670,7 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
true, true true, true
); );
contact01 = contactManager1.getContact(contactId01); contact01 = contactManager1.getContact(contactId01);
contactId02 = contactManager2.addContact(author0, ContactId contactId02 = contactManager2.addContact(author0,
author2.getId(), master, clock.currentTimeMillis(), true, author2.getId(), master, clock.currentTimeMillis(), true,
true, true true, true
); );
@@ -689,7 +688,7 @@ public class BlogSharingIntegrationTest extends BriarTestCase {
t0.getEventBus().addListener(listener0); t0.getEventBus().addListener(listener0);
listener1 = new InviteeListener(accept); listener1 = new InviteeListener(accept);
t1.getEventBus().addListener(listener1); t1.getEventBus().addListener(listener1);
listener2 = new SharerListener(); SharerListener listener2 = new SharerListener();
t2.getEventBus().addListener(listener2); t2.getEventBus().addListener(listener2);
} }

View File

@@ -2,13 +2,9 @@ package org.briarproject;
import org.briarproject.api.blogs.BlogManager; import org.briarproject.api.blogs.BlogManager;
import org.briarproject.api.blogs.BlogSharingManager; import org.briarproject.api.blogs.BlogSharingManager;
import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.MessageTracker;
import org.briarproject.api.clients.MessageQueueManager;
import org.briarproject.api.clients.PrivateGroupFactory;
import org.briarproject.api.contact.ContactManager; import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventBus;
import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.sync.SyncSessionFactory; import org.briarproject.api.sync.SyncSessionFactory;
@@ -22,6 +18,7 @@ import org.briarproject.event.EventModule;
import org.briarproject.forum.ForumModule; import org.briarproject.forum.ForumModule;
import org.briarproject.identity.IdentityModule; import org.briarproject.identity.IdentityModule;
import org.briarproject.lifecycle.LifecycleModule; import org.briarproject.lifecycle.LifecycleModule;
import org.briarproject.messaging.MessagingModule;
import org.briarproject.properties.PropertiesModule; import org.briarproject.properties.PropertiesModule;
import org.briarproject.sharing.SharingModule; import org.briarproject.sharing.SharingModule;
import org.briarproject.sync.SyncModule; import org.briarproject.sync.SyncModule;
@@ -51,7 +48,8 @@ import dagger.Component;
SharingModule.class, SharingModule.class,
SyncModule.class, SyncModule.class,
SystemModule.class, SystemModule.class,
TransportModule.class TransportModule.class,
MessagingModule.class
}) })
interface BlogSharingIntegrationTestComponent { interface BlogSharingIntegrationTestComponent {
@@ -85,16 +83,8 @@ interface BlogSharingIntegrationTestComponent {
BlogManager getBlogManager(); BlogManager getBlogManager();
MessageTracker getMessageTracker();
SyncSessionFactory getSyncSessionFactory(); SyncSessionFactory getSyncSessionFactory();
/* the following methods are only needed to manually construct messages */
DatabaseComponent getDatabaseComponent();
PrivateGroupFactory getPrivateGroupFactory();
ClientHelper getClientHelper();
MessageQueueManager getMessageQueueManager();
} }

View File

@@ -0,0 +1,30 @@
package org.briarproject;
import org.briarproject.api.clients.MessageTracker;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.db.DbException;
import org.briarproject.api.sync.GroupId;
import static org.junit.Assert.assertEquals;
public abstract class BriarIntegrationTest extends BriarTestCase {
protected static void assertGroupCount(MessageTracker tracker, GroupId g,
long msgCount, long unreadCount, long latestMsg)
throws DbException {
GroupCount groupCount = tracker.getGroupCount(g);
assertEquals(msgCount, groupCount.getMsgCount());
assertEquals(unreadCount, groupCount.getUnreadCount());
assertEquals(latestMsg, groupCount.getLatestMsgTime());
}
protected static void assertGroupCount(MessageTracker tracker, GroupId g,
long msgCount, long unreadCount) throws DbException {
GroupCount c1 = tracker.getGroupCount(g);
assertEquals(msgCount, c1.getMsgCount());
assertEquals(unreadCount, c1.getUnreadCount());
}
}

View File

@@ -4,9 +4,11 @@ import junit.framework.Assert;
import net.jodah.concurrentunit.Waiter; import net.jodah.concurrentunit.Waiter;
import org.briarproject.api.clients.MessageTracker;
import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.contact.ContactManager; import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.SecretKey; import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.db.DbException; import org.briarproject.api.db.DbException;
import org.briarproject.api.event.Event; import org.briarproject.api.event.Event;
@@ -34,7 +36,7 @@ import org.briarproject.properties.PropertiesModule;
import org.briarproject.sharing.SharingModule; import org.briarproject.sharing.SharingModule;
import org.briarproject.sync.SyncModule; import org.briarproject.sync.SyncModule;
import org.briarproject.transport.TransportModule; import org.briarproject.transport.TransportModule;
import org.briarproject.util.StringUtils; import org.jetbrains.annotations.Nullable;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -53,18 +55,18 @@ import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertNull;
import static junit.framework.TestCase.assertFalse; import static junit.framework.TestCase.assertFalse;
import static org.briarproject.TestPluginsModule.MAX_LATENCY; import static org.briarproject.TestPluginsModule.MAX_LATENCY;
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.api.sync.ValidationManager.State.DELIVERED; import static org.briarproject.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.api.sync.ValidationManager.State.INVALID; import static org.briarproject.api.sync.ValidationManager.State.INVALID;
import static org.briarproject.api.sync.ValidationManager.State.PENDING; import static org.briarproject.api.sync.ValidationManager.State.PENDING;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
public class ForumManagerTest { public class ForumManagerTest extends BriarIntegrationTest {
private LifecycleManager lifecycleManager0, lifecycleManager1; private LifecycleManager lifecycleManager0, lifecycleManager1;
private SyncSessionFactory sync0, sync1; private SyncSessionFactory sync0, sync1;
private ForumManager forumManager0, forumManager1; private ForumManager forumManager0, forumManager1;
private ContactManager contactManager0, contactManager1; private ContactManager contactManager0, contactManager1;
private MessageTracker messageTracker0, messageTracker1;
private ContactId contactId0,contactId1; private ContactId contactId0,contactId1;
private IdentityManager identityManager0, identityManager1; private IdentityManager identityManager0, identityManager1;
private LocalAuthor author0, author1; private LocalAuthor author0, author1;
@@ -75,6 +77,8 @@ public class ForumManagerTest {
@Inject @Inject
AuthorFactory authorFactory; AuthorFactory authorFactory;
@Inject @Inject
CryptoComponent crypto;
@Inject
ForumPostFactory forumPostFactory; ForumPostFactory forumPostFactory;
// objects accessed from background threads need to be volatile // objects accessed from background threads need to be volatile
@@ -115,6 +119,8 @@ public class ForumManagerTest {
identityManager1 = t1.getIdentityManager(); identityManager1 = t1.getIdentityManager();
contactManager0 = t0.getContactManager(); contactManager0 = t0.getContactManager();
contactManager1 = t1.getContactManager(); contactManager1 = t1.getContactManager();
messageTracker0 = t0.getMessageTracker();
messageTracker1 = t1.getMessageTracker();
forumManager0 = t0.getForumManager(); forumManager0 = t0.getForumManager();
forumManager1 = t1.getForumManager(); forumManager1 = t1.getForumManager();
forumSharingManager0 = t0.getForumSharingManager(); forumSharingManager0 = t0.getForumSharingManager();
@@ -127,16 +133,17 @@ public class ForumManagerTest {
deliveryWaiter = new Waiter(); deliveryWaiter = new Waiter();
} }
private ForumPost createForumPost(GroupId groupId, ForumPost parent, private ForumPost createForumPost(GroupId groupId,
String body, long ms) throws Exception { @Nullable ForumPost parent, String body, long ms) throws Exception {
return forumPostFactory.createAnonymousPost(groupId, ms, return forumPostFactory.createPost(groupId, ms,
parent == null ? null : parent.getMessage().getId(), parent == null ? null : parent.getMessage().getId(),
"text/plain", StringUtils.toUtf8(body)); author0, body);
} }
@Test @Test
public void testForumPost() throws Exception { public void testForumPost() throws Exception {
startLifecycles(); startLifecycles();
getDefaultIdentities();
Forum forum = forumManager0.addForum("TestForum"); Forum forum = forumManager0.addForum("TestForum");
assertEquals(1, forumManager0.getForums().size()); assertEquals(1, forumManager0.getForums().size());
final long ms1 = clock.currentTimeMillis() - 1000L; final long ms1 = clock.currentTimeMillis() - 1000L;
@@ -150,15 +157,24 @@ public class ForumManagerTest {
createForumPost(forum.getGroup().getId(), post1, body2, ms2); createForumPost(forum.getGroup().getId(), post1, body2, ms2);
assertEquals(ms2, post2.getMessage().getTimestamp()); assertEquals(ms2, post2.getMessage().getTimestamp());
forumManager0.addLocalPost(post1); forumManager0.addLocalPost(post1);
forumManager0.setReadFlag(post1.getMessage().getId(), true); forumManager0.setReadFlag(forum.getGroup().getId(),
post1.getMessage().getId(), true);
assertGroupCount(messageTracker0, forum.getGroup().getId(), 1, 0,
post1.getMessage().getTimestamp());
forumManager0.addLocalPost(post2); forumManager0.addLocalPost(post2);
forumManager0.setReadFlag(post2.getMessage().getId(), false); forumManager0.setReadFlag(forum.getGroup().getId(),
post2.getMessage().getId(), false);
assertGroupCount(messageTracker0, forum.getGroup().getId(), 2, 1,
post2.getMessage().getTimestamp());
forumManager0.setReadFlag(forum.getGroup().getId(),
post2.getMessage().getId(), false);
assertGroupCount(messageTracker0, forum.getGroup().getId(), 2, 1,
post2.getMessage().getTimestamp());
Collection<ForumPostHeader> headers = Collection<ForumPostHeader> headers =
forumManager0.getPostHeaders(forum.getGroup().getId()); forumManager0.getPostHeaders(forum.getGroup().getId());
assertEquals(2, headers.size()); assertEquals(2, headers.size());
for (ForumPostHeader h : headers) { for (ForumPostHeader h : headers) {
final String hBody = final String hBody = forumManager0.getPostBody(h.getId());
StringUtils.fromUtf8(forumManager0.getPostBody(h.getId()));
boolean isPost1 = h.getId().equals(post1.getMessage().getId()); boolean isPost1 = h.getId().equals(post1.getMessage().getId());
boolean isPost2 = h.getId().equals(post2.getMessage().getId()); boolean isPost2 = h.getId().equals(post2.getMessage().getId());
@@ -202,23 +218,29 @@ public class ForumManagerTest {
forumManager0.addLocalPost(post1); forumManager0.addLocalPost(post1);
assertEquals(1, forumManager0.getPostHeaders(g).size()); assertEquals(1, forumManager0.getPostHeaders(g).size());
assertEquals(0, forumManager1.getPostHeaders(g).size()); assertEquals(0, forumManager1.getPostHeaders(g).size());
assertGroupCount(messageTracker0, g, 1, 0, time);
assertGroupCount(messageTracker1, g, 0, 0, 0);
// send post to 1 // send post to 1
sync0To1(); sync0To1();
deliveryWaiter.await(TIMEOUT, 1); deliveryWaiter.await(TIMEOUT, 1);
assertEquals(1, forumManager1.getPostHeaders(g).size()); assertEquals(1, forumManager1.getPostHeaders(g).size());
assertGroupCount(messageTracker1, g, 1, 1, time);
// add another forum post // add another forum post
time = clock.currentTimeMillis(); long time2 = clock.currentTimeMillis();
ForumPost post2 = createForumPost(g, null, "b", time); ForumPost post2 = createForumPost(g, null, "b", time2);
forumManager1.addLocalPost(post2); forumManager1.addLocalPost(post2);
assertEquals(1, forumManager0.getPostHeaders(g).size()); assertEquals(1, forumManager0.getPostHeaders(g).size());
assertEquals(2, forumManager1.getPostHeaders(g).size()); assertEquals(2, forumManager1.getPostHeaders(g).size());
assertGroupCount(messageTracker0, g, 1, 0, time);
assertGroupCount(messageTracker1, g, 2, 1, time2);
// send post to 0 // send post to 0
sync1To0(); sync1To0();
deliveryWaiter.await(TIMEOUT, 1); deliveryWaiter.await(TIMEOUT, 1);
assertEquals(2, forumManager1.getPostHeaders(g).size()); assertEquals(2, forumManager1.getPostHeaders(g).size());
assertGroupCount(messageTracker0, g, 2, 1, time2);
stopLifecycles(); stopLifecycles();
} }
@@ -343,21 +365,15 @@ public class ForumManagerTest {
} }
private void defaultInit() throws DbException { private void defaultInit() throws DbException {
addDefaultIdentities(); getDefaultIdentities();
addDefaultContacts(); addDefaultContacts();
addForum(); addForum();
listenToEvents(); listenToEvents();
} }
private void addDefaultIdentities() throws DbException { private void getDefaultIdentities() throws DbException {
author0 = authorFactory.createLocalAuthor(SHARER, author0 = identityManager0.getLocalAuthor();
TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH), author1 = identityManager1.getLocalAuthor();
TestUtils.getRandomBytes(123));
identityManager0.addLocalAuthor(author0);
author1 = authorFactory.createLocalAuthor(INVITEE,
TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH),
TestUtils.getRandomBytes(123));
identityManager1.addLocalAuthor(author1);
} }
private void addDefaultContacts() throws DbException { private void addDefaultContacts() throws DbException {
@@ -418,8 +434,8 @@ public class ForumManagerTest {
// Start the lifecycle manager and wait for it to finish // Start the lifecycle manager and wait for it to finish
lifecycleManager0 = t0.getLifecycleManager(); lifecycleManager0 = t0.getLifecycleManager();
lifecycleManager1 = t1.getLifecycleManager(); lifecycleManager1 = t1.getLifecycleManager();
lifecycleManager0.startServices(); lifecycleManager0.startServices(SHARER);
lifecycleManager1.startServices(); lifecycleManager1.startServices(INVITEE);
lifecycleManager0.waitForStartup(); lifecycleManager0.waitForStartup();
lifecycleManager1.waitForStartup(); lifecycleManager1.waitForStartup();
} }

View File

@@ -1,5 +1,6 @@
package org.briarproject; package org.briarproject;
import org.briarproject.api.clients.MessageTracker;
import org.briarproject.api.contact.ContactManager; import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventBus;
import org.briarproject.api.forum.ForumManager; import org.briarproject.api.forum.ForumManager;
@@ -17,6 +18,7 @@ import org.briarproject.event.EventModule;
import org.briarproject.forum.ForumModule; import org.briarproject.forum.ForumModule;
import org.briarproject.identity.IdentityModule; import org.briarproject.identity.IdentityModule;
import org.briarproject.lifecycle.LifecycleModule; import org.briarproject.lifecycle.LifecycleModule;
import org.briarproject.messaging.MessagingModule;
import org.briarproject.properties.PropertiesModule; import org.briarproject.properties.PropertiesModule;
import org.briarproject.sharing.SharingModule; import org.briarproject.sharing.SharingModule;
import org.briarproject.sync.SyncModule; import org.briarproject.sync.SyncModule;
@@ -46,7 +48,8 @@ import dagger.Component;
SharingModule.class, SharingModule.class,
SyncModule.class, SyncModule.class,
SystemModule.class, SystemModule.class,
TransportModule.class TransportModule.class,
MessagingModule.class
}) })
interface ForumManagerTestComponent { interface ForumManagerTestComponent {
@@ -76,6 +79,8 @@ interface ForumManagerTestComponent {
ContactManager getContactManager(); ContactManager getContactManager();
MessageTracker getMessageTracker();
ForumSharingManager getForumSharingManager(); ForumSharingManager getForumSharingManager();
ForumManager getForumManager(); ForumManager getForumManager();

View File

@@ -3,16 +3,13 @@ package org.briarproject;
import net.jodah.concurrentunit.Waiter; import net.jodah.concurrentunit.Waiter;
import org.briarproject.api.Bytes; import org.briarproject.api.Bytes;
import org.briarproject.api.clients.ContactGroupFactory;
import org.briarproject.api.clients.MessageQueueManager; import org.briarproject.api.clients.MessageQueueManager;
import org.briarproject.api.clients.PrivateGroupFactory;
import org.briarproject.api.clients.SessionId; import org.briarproject.api.clients.SessionId;
import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.contact.ContactManager; import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyPair;
import org.briarproject.api.crypto.KeyParser;
import org.briarproject.api.crypto.PrivateKey;
import org.briarproject.api.crypto.SecretKey; import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.data.BdfList; import org.briarproject.api.data.BdfList;
import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DatabaseComponent;
@@ -36,7 +33,7 @@ import org.briarproject.api.identity.AuthorFactory;
import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.sharing.InvitationItem; import org.briarproject.api.sharing.SharingInvitationItem;
import org.briarproject.api.sharing.InvitationMessage; import org.briarproject.api.sharing.InvitationMessage;
import org.briarproject.api.sync.Group; import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.SyncSession; import org.briarproject.api.sync.SyncSession;
@@ -71,6 +68,7 @@ import javax.inject.Inject;
import static org.briarproject.TestPluginsModule.MAX_LATENCY; import static org.briarproject.TestPluginsModule.MAX_LATENCY;
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT_LENGTH; import static org.briarproject.api.forum.ForumConstants.FORUM_SALT_LENGTH;
import static org.briarproject.api.forum.ForumSharingManager.CLIENT_ID;
import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION; import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION;
import static org.briarproject.api.sync.ValidationManager.State.DELIVERED; import static org.briarproject.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.api.sync.ValidationManager.State.INVALID; import static org.briarproject.api.sync.ValidationManager.State.INVALID;
@@ -423,13 +421,11 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
respond = false; respond = false;
// sync first request message and leave message // sync first request message and leave message
syncToInvitee(); deliverMessage(sync0, contactId0, sync1, contactId1, 2,
"Sharer to Invitee");
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertTrue(listener1.requestReceived); assertTrue(listener1.requestReceived);
// wait also for second message to arrive
msgWaiter.await(TIMEOUT, 1);
// ensure that invitee has no forum invitations available // ensure that invitee has no forum invitations available
assertEquals(0, forumSharingManager1.getInvitations().size()); assertEquals(0, forumSharingManager1.getInvitations().size());
assertEquals(0, forumManager1.getForums().size()); assertEquals(0, forumManager1.getForums().size());
@@ -446,13 +442,11 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
forumManager0.removeForum(forum0); forumManager0.removeForum(forum0);
// sync first request message and leave message // sync first request message and leave message
syncToInvitee(); deliverMessage(sync0, contactId0, sync1, contactId1, 2,
"Sharer to Invitee");
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertTrue(listener1.requestReceived); assertTrue(listener1.requestReceived);
// wait also for second message to arrive
msgWaiter.await(TIMEOUT, 1);
// ensure that invitee has no forum invitations available // ensure that invitee has no forum invitations available
assertEquals(0, forumSharingManager1.getInvitations().size()); assertEquals(0, forumSharingManager1.getInvitations().size());
assertEquals(1, forumManager1.getForums().size()); assertEquals(1, forumManager1.getForums().size());
@@ -501,9 +495,8 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
DatabaseComponent db = t0.getDatabaseComponent(); DatabaseComponent db = t0.getDatabaseComponent();
MessageQueueManager queue = t0.getMessageQueueManager(); MessageQueueManager queue = t0.getMessageQueueManager();
Contact c1 = contactManager0.getContact(contactId1); Contact c1 = contactManager0.getContact(contactId1);
PrivateGroupFactory groupFactory = t0.getPrivateGroupFactory(); ContactGroupFactory groupFactory = t0.getContactGroupFactory();
Group group = groupFactory Group group = groupFactory.createContactGroup(CLIENT_ID, c1);
.createPrivateGroup(forumSharingManager0.getClientId(), c1);
long time = clock.currentTimeMillis(); long time = clock.currentTimeMillis();
BdfList bodyList = BdfList.of(SHARE_MSG_TYPE_INVITATION, BdfList bodyList = BdfList.of(SHARE_MSG_TYPE_INVITATION,
sessionId.getBytes(), sessionId.getBytes(),
@@ -516,7 +509,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
Transaction txn = db.startTransaction(false); Transaction txn = db.startTransaction(false);
try { try {
queue.sendMessage(txn, group, time, body, new Metadata()); queue.sendMessage(txn, group, time, body, new Metadata());
txn.setComplete(); db.commitTransaction(txn);
} finally { } finally {
db.endTransaction(txn); db.endTransaction(txn);
} }
@@ -587,7 +580,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
DatabaseComponent db1 = t1.getDatabaseComponent(); DatabaseComponent db1 = t1.getDatabaseComponent();
Transaction txn = db1.startTransaction(false); Transaction txn = db1.startTransaction(false);
db1.addGroup(txn, forum0.getGroup()); db1.addGroup(txn, forum0.getGroup());
txn.setComplete(); db1.commitTransaction(txn);
db1.endTransaction(txn); db1.endTransaction(txn);
// send invitation // send invitation
@@ -697,9 +690,8 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
DatabaseComponent db = t0.getDatabaseComponent(); DatabaseComponent db = t0.getDatabaseComponent();
MessageQueueManager queue = t0.getMessageQueueManager(); MessageQueueManager queue = t0.getMessageQueueManager();
Contact c1 = contactManager0.getContact(contactId1); Contact c1 = contactManager0.getContact(contactId1);
PrivateGroupFactory groupFactory = t0.getPrivateGroupFactory(); ContactGroupFactory groupFactory = t0.getContactGroupFactory();
Group group = groupFactory Group group = groupFactory.createContactGroup(CLIENT_ID, c1);
.createPrivateGroup(forumSharingManager0.getClientId(), c1);
long time = clock.currentTimeMillis(); long time = clock.currentTimeMillis();
// construct a new message re-using the old SessionId // construct a new message re-using the old SessionId
@@ -714,7 +706,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
Transaction txn = db.startTransaction(false); Transaction txn = db.startTransaction(false);
try { try {
queue.sendMessage(txn, group, time, body, new Metadata()); queue.sendMessage(txn, group, time, body, new Metadata());
txn.setComplete(); db.commitTransaction(txn);
} finally { } finally {
db.endTransaction(txn); db.endTransaction(txn);
} }
@@ -735,7 +727,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
startLifecycles(); startLifecycles();
try { try {
// initialize // initialize
addDefaultIdentities(); getDefaultIdentities();
addDefaultContacts(); addDefaultContacts();
addForumForSharer(); addForumForSharer();
@@ -743,7 +735,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
DatabaseComponent db2 = t2.getDatabaseComponent(); DatabaseComponent db2 = t2.getDatabaseComponent();
Transaction txn = db2.startTransaction(false); Transaction txn = db2.startTransaction(false);
db2.addGroup(txn, forum0.getGroup()); db2.addGroup(txn, forum0.getGroup());
txn.setComplete(); db2.commitTransaction(txn);
db2.endTransaction(txn); db2.endTransaction(txn);
// add listeners // add listeners
@@ -764,11 +756,11 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
forumSharingManager2 forumSharingManager2
.sendInvitation(forum0.getId(), contactId1, null); .sendInvitation(forum0.getId(), contactId1, null);
// sync second request message // sync second request message
deliverMessage(sync2, contactId2, sync1, contactId1, deliverMessage(sync2, contactId2, sync1, contactId1, 1,
"Sharer2 to Invitee"); "Sharer2 to Invitee");
// make sure we now have two invitations to the same forum available // make sure we now have two invitations to the same forum available
Collection<InvitationItem> forums = Collection<SharingInvitationItem> forums =
forumSharingManager1.getInvitations(); forumSharingManager1.getInvitations();
assertEquals(1, forums.size()); assertEquals(1, forums.size());
assertEquals(2, forums.iterator().next().getNewSharers().size()); assertEquals(2, forums.iterator().next().getNewSharers().size());
@@ -785,7 +777,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
Contact c2 = contactManager1.getContact(contactId2); Contact c2 = contactManager1.getContact(contactId2);
forumSharingManager1.respondToInvitation(forum0, c2, true); forumSharingManager1.respondToInvitation(forum0, c2, true);
// sync response // sync response
deliverMessage(sync1, contactId21, sync2, contactId2, deliverMessage(sync1, contactId21, sync2, contactId2, 1,
"Invitee to Sharer2"); "Invitee to Sharer2");
eventWaiter.await(TIMEOUT, 1); eventWaiter.await(TIMEOUT, 1);
assertTrue(listener2.responseReceived); assertTrue(listener2.responseReceived);
@@ -824,12 +816,10 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
// sharer posts into the forum // sharer posts into the forum
long time = clock.currentTimeMillis(); long time = clock.currentTimeMillis();
byte[] body = TestUtils.getRandomBytes(42); String body = TestUtils.getRandomString(42);
KeyParser keyParser = cryptoComponent.getSignatureKeyParser();
PrivateKey key = keyParser.parsePrivateKey(author0.getPrivateKey());
ForumPost p = forumPostFactory ForumPost p = forumPostFactory
.createPseudonymousPost(forum0.getId(), time, null, author0, .createPost(forum0.getId(), time, null, author0,
"text/plain", body, key); body);
forumManager0.addLocalPost(p); forumManager0.addLocalPost(p);
// sync forum post // sync forum post
@@ -845,11 +835,10 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
// now invitee creates a post // now invitee creates a post
time = clock.currentTimeMillis(); time = clock.currentTimeMillis();
body = TestUtils.getRandomBytes(42); body = TestUtils.getRandomString(42);
key = keyParser.parsePrivateKey(author1.getPrivateKey());
p = forumPostFactory p = forumPostFactory
.createPseudonymousPost(forum0.getId(), time, null, author1, .createPost(forum0.getId(), time, null, author1,
"text/plain", body, key); body);
forumManager1.addLocalPost(p); forumManager1.addLocalPost(p);
// sync forum post // sync forum post
@@ -890,11 +879,10 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
// now invitee creates a post // now invitee creates a post
time = clock.currentTimeMillis(); time = clock.currentTimeMillis();
body = TestUtils.getRandomBytes(42); body = TestUtils.getRandomString(42);
key = keyParser.parsePrivateKey(author1.getPrivateKey());
p = forumPostFactory p = forumPostFactory
.createPseudonymousPost(forum0.getId(), time, null, author1, .createPost(forum0.getId(), time, null, author1,
"text/plain", body, key); body);
forumManager1.addLocalPost(p); forumManager1.addLocalPost(p);
// sync forum post // sync forum post
@@ -924,8 +912,8 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
private class SharerListener implements EventListener { private class SharerListener implements EventListener {
volatile boolean requestReceived = false; private volatile boolean requestReceived = false;
volatile boolean responseReceived = false; private volatile boolean responseReceived = false;
@Override @Override
public void eventOccurred(Event e) { public void eventOccurred(Event e) {
@@ -949,7 +937,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
(ForumInvitationReceivedEvent) e; (ForumInvitationReceivedEvent) e;
eventWaiter.assertEquals(contactId1, event.getContactId()); eventWaiter.assertEquals(contactId1, event.getContactId());
requestReceived = true; requestReceived = true;
Forum f = event.getForum(); Forum f = event.getShareable();
try { try {
Contact c = contactManager0.getContact(contactId1); Contact c = contactManager0.getContact(contactId1);
forumSharingManager0.respondToInvitation(f, c, true); forumSharingManager0.respondToInvitation(f, c, true);
@@ -964,17 +952,17 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
private class InviteeListener implements EventListener { private class InviteeListener implements EventListener {
volatile boolean requestReceived = false; private volatile boolean requestReceived = false;
volatile boolean responseReceived = false; private volatile boolean responseReceived = false;
private final boolean accept, answer; private final boolean accept, answer;
InviteeListener(boolean accept, boolean answer) { private InviteeListener(boolean accept, boolean answer) {
this.accept = accept; this.accept = accept;
this.answer = answer; this.answer = answer;
} }
InviteeListener(boolean accept) { private InviteeListener(boolean accept) {
this(accept, true); this(accept, true);
} }
@@ -992,11 +980,11 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
(ForumInvitationReceivedEvent) e; (ForumInvitationReceivedEvent) e;
requestReceived = true; requestReceived = true;
if (!answer) return; if (!answer) return;
Forum f = event.getForum(); Forum f = event.getShareable();
try { try {
eventWaiter.assertEquals(1, eventWaiter.assertEquals(1,
forumSharingManager1.getInvitations().size()); forumSharingManager1.getInvitations().size());
InvitationItem invitation = SharingInvitationItem invitation =
forumSharingManager1.getInvitations().iterator() forumSharingManager1.getInvitations().iterator()
.next(); .next();
eventWaiter.assertEquals(f, invitation.getShareable()); eventWaiter.assertEquals(f, invitation.getShareable());
@@ -1027,9 +1015,9 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
lifecycleManager0 = t0.getLifecycleManager(); lifecycleManager0 = t0.getLifecycleManager();
lifecycleManager1 = t1.getLifecycleManager(); lifecycleManager1 = t1.getLifecycleManager();
lifecycleManager2 = t2.getLifecycleManager(); lifecycleManager2 = t2.getLifecycleManager();
lifecycleManager0.startServices(); lifecycleManager0.startServices(SHARER);
lifecycleManager1.startServices(); lifecycleManager1.startServices(INVITEE);
lifecycleManager2.startServices(); lifecycleManager2.startServices(SHARER2);
lifecycleManager0.waitForStartup(); lifecycleManager0.waitForStartup();
lifecycleManager1.waitForStartup(); lifecycleManager1.waitForStartup();
lifecycleManager2.waitForStartup(); lifecycleManager2.waitForStartup();
@@ -1046,30 +1034,16 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
} }
private void defaultInit(boolean accept) throws DbException { private void defaultInit(boolean accept) throws DbException {
addDefaultIdentities(); getDefaultIdentities();
addDefaultContacts(); addDefaultContacts();
addForumForSharer(); addForumForSharer();
listenToEvents(accept); listenToEvents(accept);
} }
private void addDefaultIdentities() throws DbException { private void getDefaultIdentities() throws DbException {
KeyPair keyPair = cryptoComponent.generateSignatureKeyPair(); author0 = identityManager0.getLocalAuthor();
author0 = authorFactory.createLocalAuthor(SHARER, author1 = identityManager1.getLocalAuthor();
keyPair.getPublic().getEncoded(), author2 = identityManager2.getLocalAuthor();
keyPair.getPrivate().getEncoded());
identityManager0.addLocalAuthor(author0);
keyPair = cryptoComponent.generateSignatureKeyPair();
author1 = authorFactory.createLocalAuthor(INVITEE,
keyPair.getPublic().getEncoded(),
keyPair.getPrivate().getEncoded());
identityManager1.addLocalAuthor(author1);
keyPair = cryptoComponent.generateSignatureKeyPair();
author2 = authorFactory.createLocalAuthor(SHARER2,
keyPair.getPublic().getEncoded(),
keyPair.getPrivate().getEncoded());
identityManager2.addLocalAuthor(author2);
} }
private void addDefaultContacts() throws DbException { private void addDefaultContacts() throws DbException {
@@ -1109,17 +1083,17 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
} }
private void syncToInvitee() throws IOException, TimeoutException { private void syncToInvitee() throws IOException, TimeoutException {
deliverMessage(sync0, contactId0, sync1, contactId1, deliverMessage(sync0, contactId0, sync1, contactId1, 1,
"Sharer to Invitee"); "Sharer to Invitee");
} }
private void syncToSharer() throws IOException, TimeoutException { private void syncToSharer() throws IOException, TimeoutException {
deliverMessage(sync1, contactId1, sync0, contactId0, deliverMessage(sync1, contactId1, sync0, contactId0, 1,
"Invitee to Sharer"); "Invitee to Sharer");
} }
private void deliverMessage(SyncSessionFactory fromSync, ContactId fromId, private void deliverMessage(SyncSessionFactory fromSync, ContactId fromId,
SyncSessionFactory toSync, ContactId toId, String debug) SyncSessionFactory toSync, ContactId toId, int num, String debug)
throws IOException, TimeoutException { throws IOException, TimeoutException {
if (debug != null) LOG.info("TEST: Sending message from " + debug); if (debug != null) LOG.info("TEST: Sending message from " + debug);
@@ -1140,7 +1114,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase {
in.close(); in.close();
// wait for message to actually arrive // wait for message to actually arrive
msgWaiter.await(TIMEOUT, 1); msgWaiter.await(TIMEOUT, num);
} }
private void injectEagerSingletons( private void injectEagerSingletons(

View File

@@ -2,7 +2,7 @@ package org.briarproject;
import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.clients.MessageQueueManager; import org.briarproject.api.clients.MessageQueueManager;
import org.briarproject.api.clients.PrivateGroupFactory; import org.briarproject.api.clients.ContactGroupFactory;
import org.briarproject.api.contact.ContactManager; import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventBus;
@@ -21,6 +21,7 @@ import org.briarproject.event.EventModule;
import org.briarproject.forum.ForumModule; import org.briarproject.forum.ForumModule;
import org.briarproject.identity.IdentityModule; import org.briarproject.identity.IdentityModule;
import org.briarproject.lifecycle.LifecycleModule; import org.briarproject.lifecycle.LifecycleModule;
import org.briarproject.messaging.MessagingModule;
import org.briarproject.properties.PropertiesModule; import org.briarproject.properties.PropertiesModule;
import org.briarproject.sharing.SharingModule; import org.briarproject.sharing.SharingModule;
import org.briarproject.sync.SyncModule; import org.briarproject.sync.SyncModule;
@@ -50,7 +51,8 @@ import dagger.Component;
SharingModule.class, SharingModule.class,
SyncModule.class, SyncModule.class,
SystemModule.class, SystemModule.class,
TransportModule.class TransportModule.class,
MessagingModule.class
}) })
interface ForumSharingIntegrationTestComponent { interface ForumSharingIntegrationTestComponent {
@@ -90,7 +92,7 @@ interface ForumSharingIntegrationTestComponent {
DatabaseComponent getDatabaseComponent(); DatabaseComponent getDatabaseComponent();
PrivateGroupFactory getPrivateGroupFactory(); ContactGroupFactory getContactGroupFactory();
ClientHelper getClientHelper(); ClientHelper getClientHelper();

View File

@@ -6,14 +6,14 @@ import org.briarproject.api.crypto.PrivateKey;
import org.briarproject.api.forum.ForumConstants; import org.briarproject.api.forum.ForumConstants;
import org.briarproject.api.forum.ForumPost; import org.briarproject.api.forum.ForumPost;
import org.briarproject.api.forum.ForumPostFactory; import org.briarproject.api.forum.ForumPostFactory;
import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.AuthorFactory; import org.briarproject.api.identity.AuthorFactory;
import org.briarproject.api.messaging.MessagingConstants; import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.messaging.PrivateMessage; import org.briarproject.api.messaging.PrivateMessage;
import org.briarproject.api.messaging.PrivateMessageFactory; import org.briarproject.api.messaging.PrivateMessageFactory;
import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.MessageId;
import org.briarproject.system.SystemModule; import org.briarproject.system.SystemModule;
import org.briarproject.util.StringUtils;
import org.junit.Test; import org.junit.Test;
import javax.inject.Inject; import javax.inject.Inject;
@@ -48,17 +48,14 @@ public class MessageSizeIntegrationTest extends BriarTestCase {
// Create a maximum-length private message // Create a maximum-length private message
GroupId groupId = new GroupId(TestUtils.getRandomId()); GroupId groupId = new GroupId(TestUtils.getRandomId());
long timestamp = Long.MAX_VALUE; long timestamp = Long.MAX_VALUE;
MessageId parent = new MessageId(TestUtils.getRandomId()); String body =
String contentType = TestUtils.getRandomString( StringUtils.fromUtf8(new byte[MAX_PRIVATE_MESSAGE_BODY_LENGTH]);
MessagingConstants.MAX_CONTENT_TYPE_LENGTH);
byte[] body = new byte[MAX_PRIVATE_MESSAGE_BODY_LENGTH];
PrivateMessage message = privateMessageFactory.createPrivateMessage( PrivateMessage message = privateMessageFactory.createPrivateMessage(
groupId, timestamp, parent, contentType, body); groupId, timestamp, body);
// Check the size of the serialised message // Check the size of the serialised message
int length = message.getMessage().getRaw().length; int length = message.getMessage().getRaw().length;
assertTrue(length > UniqueId.LENGTH + 8 + UniqueId.LENGTH assertTrue(
+ MessagingConstants.MAX_CONTENT_TYPE_LENGTH length > UniqueId.LENGTH + 8 + MAX_PRIVATE_MESSAGE_BODY_LENGTH);
+ MAX_PRIVATE_MESSAGE_BODY_LENGTH);
assertTrue(length <= MAX_PACKET_PAYLOAD_LENGTH); assertTrue(length <= MAX_PACKET_PAYLOAD_LENGTH);
} }
@@ -68,17 +65,17 @@ public class MessageSizeIntegrationTest extends BriarTestCase {
String authorName = TestUtils.getRandomString( String authorName = TestUtils.getRandomString(
MAX_AUTHOR_NAME_LENGTH); MAX_AUTHOR_NAME_LENGTH);
byte[] authorPublic = new byte[MAX_PUBLIC_KEY_LENGTH]; byte[] authorPublic = new byte[MAX_PUBLIC_KEY_LENGTH];
Author author = authorFactory.createAuthor(authorName, authorPublic); PrivateKey privateKey = crypto.generateSignatureKeyPair().getPrivate();
LocalAuthor author = authorFactory
.createLocalAuthor(authorName, authorPublic,
privateKey.getEncoded());
// Create a maximum-length forum post // Create a maximum-length forum post
GroupId groupId = new GroupId(TestUtils.getRandomId()); GroupId groupId = new GroupId(TestUtils.getRandomId());
long timestamp = Long.MAX_VALUE; long timestamp = Long.MAX_VALUE;
MessageId parent = new MessageId(TestUtils.getRandomId()); MessageId parent = new MessageId(TestUtils.getRandomId());
String contentType = TestUtils.getRandomString( String body = TestUtils.getRandomString(MAX_FORUM_POST_BODY_LENGTH);
ForumConstants.MAX_CONTENT_TYPE_LENGTH); ForumPost post = forumPostFactory.createPost(groupId,
byte[] body = new byte[MAX_FORUM_POST_BODY_LENGTH]; timestamp, parent, author, body);
PrivateKey privateKey = crypto.generateSignatureKeyPair().getPrivate();
ForumPost post = forumPostFactory.createPseudonymousPost(groupId,
timestamp, parent, author, contentType, body, privateKey);
// Check the size of the serialised message // Check the size of the serialised message
int length = post.getMessage().getRaw().length; int length = post.getMessage().getRaw().length;
assertTrue(length > UniqueId.LENGTH + 8 + UniqueId.LENGTH assertTrue(length > UniqueId.LENGTH + 8 + UniqueId.LENGTH

View File

@@ -0,0 +1,838 @@
package org.briarproject;
import net.jodah.concurrentunit.Waiter;
import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.clients.ContactGroupFactory;
import org.briarproject.api.clients.MessageTracker.GroupCount;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.KeyPair;
import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.data.BdfList;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Transaction;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.MessageStateChangedEvent;
import org.briarproject.api.identity.AuthorFactory;
import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.privategroup.GroupMember;
import org.briarproject.api.privategroup.GroupMessage;
import org.briarproject.api.privategroup.GroupMessageFactory;
import org.briarproject.api.privategroup.GroupMessageHeader;
import org.briarproject.api.privategroup.JoinMessageHeader;
import org.briarproject.api.privategroup.PrivateGroup;
import org.briarproject.api.privategroup.PrivateGroupFactory;
import org.briarproject.api.privategroup.PrivateGroupManager;
import org.briarproject.api.privategroup.invitation.GroupInvitationFactory;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.MessageId;
import org.briarproject.api.sync.SyncSession;
import org.briarproject.api.sync.SyncSessionFactory;
import org.briarproject.api.system.Clock;
import org.briarproject.contact.ContactModule;
import org.briarproject.crypto.CryptoModule;
import org.briarproject.lifecycle.LifecycleModule;
import org.briarproject.privategroup.PrivateGroupModule;
import org.briarproject.properties.PropertiesModule;
import org.briarproject.sync.SyncModule;
import org.briarproject.transport.TransportModule;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
import javax.inject.Inject;
import static org.briarproject.TestPluginsModule.MAX_LATENCY;
import static org.briarproject.TestUtils.getRandomBytes;
import static org.briarproject.api.identity.Author.Status.VERIFIED;
import static org.briarproject.api.privategroup.Visibility.INVISIBLE;
import static org.briarproject.api.privategroup.Visibility.REVEALED_BY_CONTACT;
import static org.briarproject.api.privategroup.Visibility.REVEALED_BY_US;
import static org.briarproject.api.privategroup.Visibility.VISIBLE;
import static org.briarproject.api.privategroup.invitation.GroupInvitationFactory.SIGNING_LABEL_INVITE;
import static org.briarproject.api.sync.Group.Visibility.SHARED;
import static org.briarproject.api.sync.ValidationManager.State.DELIVERED;
import static org.briarproject.api.sync.ValidationManager.State.INVALID;
import static org.briarproject.api.sync.ValidationManager.State.PENDING;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class PrivateGroupManagerTest extends BriarIntegrationTest {
private LifecycleManager lifecycleManager0, lifecycleManager1,
lifecycleManager2;
private SyncSessionFactory sync0, sync1, sync2;
private PrivateGroupManager groupManager0, groupManager1, groupManager2;
private ContactManager contactManager0, contactManager1, contactManager2;
private ContactId contactId01, contactId02, contactId1, contactId2;
private IdentityManager identityManager0, identityManager1,
identityManager2;
private LocalAuthor author0, author1, author2;
private DatabaseComponent db0, db1, db2;
private PrivateGroup privateGroup0;
private GroupId groupId0;
@Inject
Clock clock;
@Inject
AuthorFactory authorFactory;
@Inject
ClientHelper clientHelper;
@Inject
CryptoComponent crypto;
@Inject
ContactGroupFactory contactGroupFactory;
@Inject
PrivateGroupFactory privateGroupFactory;
@Inject
GroupMessageFactory groupMessageFactory;
@Inject
GroupInvitationFactory groupInvitationFactory;
// objects accessed from background threads need to be volatile
private volatile Waiter validationWaiter;
private volatile Waiter deliveryWaiter;
private final File testDir = TestUtils.getTestDirectory();
private final SecretKey master = TestUtils.getSecretKey();
private final int TIMEOUT = 15000;
private final String AUTHOR0 = "Author 0";
private final String AUTHOR1 = "Author 1";
private final String AUTHOR2 = "Author 2";
private static final Logger LOG =
Logger.getLogger(PrivateGroupManagerTest.class.getName());
private PrivateGroupManagerTestComponent t0, t1, t2;
@Rule
public ExpectedException thrown = ExpectedException.none();
@Before
public void setUp() throws Exception {
PrivateGroupManagerTestComponent component =
DaggerPrivateGroupManagerTestComponent.builder().build();
component.inject(this);
assertTrue(testDir.mkdirs());
File t0Dir = new File(testDir, AUTHOR0);
t0 = DaggerPrivateGroupManagerTestComponent.builder()
.testDatabaseModule(new TestDatabaseModule(t0Dir)).build();
injectEagerSingletons(t0);
File t1Dir = new File(testDir, AUTHOR1);
t1 = DaggerPrivateGroupManagerTestComponent.builder()
.testDatabaseModule(new TestDatabaseModule(t1Dir)).build();
injectEagerSingletons(t1);
File t2Dir = new File(testDir, AUTHOR2);
t2 = DaggerPrivateGroupManagerTestComponent.builder()
.testDatabaseModule(new TestDatabaseModule(t2Dir)).build();
injectEagerSingletons(t2);
identityManager0 = t0.getIdentityManager();
identityManager1 = t1.getIdentityManager();
identityManager2 = t2.getIdentityManager();
contactManager0 = t0.getContactManager();
contactManager1 = t1.getContactManager();
contactManager2 = t2.getContactManager();
db0 = t0.getDatabaseComponent();
db1 = t1.getDatabaseComponent();
db2 = t2.getDatabaseComponent();
groupManager0 = t0.getPrivateGroupManager();
groupManager1 = t1.getPrivateGroupManager();
groupManager2 = t2.getPrivateGroupManager();
sync0 = t0.getSyncSessionFactory();
sync1 = t1.getSyncSessionFactory();
sync2 = t2.getSyncSessionFactory();
// initialize waiters fresh for each test
validationWaiter = new Waiter();
deliveryWaiter = new Waiter();
startLifecycles();
}
@Test
public void testSendingMessage() throws Exception {
defaultInit();
// create and add test message
long time = clock.currentTimeMillis();
String body = "This is a test message!";
MessageId previousMsgId =
groupManager0.getPreviousMsgId(groupId0);
GroupMessage msg = groupMessageFactory
.createGroupMessage(groupId0, time, null, author0, body,
previousMsgId);
groupManager0.addLocalMessage(msg);
assertEquals(msg.getMessage().getId(),
groupManager0.getPreviousMsgId(groupId0));
// sync test message
sync0To1();
deliveryWaiter.await(TIMEOUT, 1);
// assert that message arrived as expected
Collection<GroupMessageHeader> headers =
groupManager1.getHeaders(groupId0);
assertEquals(3, headers.size());
GroupMessageHeader header = null;
for (GroupMessageHeader h : headers) {
if (!(h instanceof JoinMessageHeader)) {
header = h;
}
}
assertTrue(header != null);
assertFalse(header.isRead());
assertEquals(author0, header.getAuthor());
assertEquals(time, header.getTimestamp());
assertEquals(VERIFIED, header.getAuthorStatus());
assertEquals(body, groupManager1.getMessageBody(header.getId()));
GroupCount count = groupManager1.getGroupCount(groupId0);
assertEquals(2, count.getUnreadCount());
assertEquals(time, count.getLatestMsgTime());
assertEquals(3, count.getMsgCount());
}
@Test
public void testMessageWithWrongPreviousMsgId() throws Exception {
defaultInit();
// create and add test message with no previousMsgId
@SuppressWarnings("ConstantConditions")
GroupMessage msg = groupMessageFactory
.createGroupMessage(groupId0, clock.currentTimeMillis(), null,
author0, "test", null);
groupManager0.addLocalMessage(msg);
// sync test message
sync0To1();
validationWaiter.await(TIMEOUT, 1);
// assert that message did not arrive
assertEquals(2, groupManager1.getHeaders(groupId0).size());
// create and add test message with random previousMsgId
MessageId previousMsgId = new MessageId(TestUtils.getRandomId());
msg = groupMessageFactory
.createGroupMessage(groupId0, clock.currentTimeMillis(), null,
author0, "test", previousMsgId);
groupManager0.addLocalMessage(msg);
// sync test message
sync0To1();
validationWaiter.await(TIMEOUT, 1);
// assert that message did not arrive
assertEquals(2, groupManager1.getHeaders(groupId0).size());
// create and add test message with wrong previousMsgId
previousMsgId = groupManager1.getPreviousMsgId(groupId0);
msg = groupMessageFactory
.createGroupMessage(groupId0, clock.currentTimeMillis(), null,
author0, "test", previousMsgId);
groupManager0.addLocalMessage(msg);
// sync test message
sync0To1();
validationWaiter.await(TIMEOUT, 1);
// assert that message did not arrive
assertEquals(2, groupManager1.getHeaders(groupId0).size());
}
@Test
public void testMessageWithWrongParentMsgId() throws Exception {
defaultInit();
// create and add test message with random parentMsgId
MessageId parentMsgId = new MessageId(TestUtils.getRandomId());
MessageId previousMsgId = groupManager0.getPreviousMsgId(groupId0);
GroupMessage msg = groupMessageFactory
.createGroupMessage(groupId0, clock.currentTimeMillis(),
parentMsgId, author0, "test", previousMsgId);
groupManager0.addLocalMessage(msg);
// sync test message
sync0To1();
validationWaiter.await(TIMEOUT, 1);
// assert that message did not arrive
assertEquals(2, groupManager1.getHeaders(groupId0).size());
// create and add test message with wrong parentMsgId
parentMsgId = previousMsgId;
msg = groupMessageFactory
.createGroupMessage(groupId0, clock.currentTimeMillis(),
parentMsgId, author0, "test", previousMsgId);
groupManager0.addLocalMessage(msg);
// sync test message
sync0To1();
validationWaiter.await(TIMEOUT, 1);
// assert that message did not arrive
assertEquals(2, groupManager1.getHeaders(groupId0).size());
}
@Test
public void testMessageWithWrongTimestamp() throws Exception {
defaultInit();
// create and add test message with wrong timestamp
MessageId previousMsgId = groupManager0.getPreviousMsgId(groupId0);
GroupMessage msg = groupMessageFactory
.createGroupMessage(groupId0, 42, null, author0, "test",
previousMsgId);
groupManager0.addLocalMessage(msg);
// sync test message
sync0To1();
validationWaiter.await(TIMEOUT, 1);
// assert that message did not arrive
assertEquals(2, groupManager1.getHeaders(groupId0).size());
// create and add test message with good timestamp
long time = clock.currentTimeMillis();
msg = groupMessageFactory
.createGroupMessage(groupId0, time, null, author0, "test",
previousMsgId);
groupManager0.addLocalMessage(msg);
// sync test message
sync0To1();
deliveryWaiter.await(TIMEOUT, 1);
assertEquals(3, groupManager1.getHeaders(groupId0).size());
// create and add test message with same timestamp as previous message
previousMsgId = msg.getMessage().getId();
msg = groupMessageFactory
.createGroupMessage(groupId0, time, previousMsgId, author0,
"test2", previousMsgId);
groupManager0.addLocalMessage(msg);
// sync test message
sync0To1();
validationWaiter.await(TIMEOUT, 1);
// assert that message did not arrive
assertEquals(3, groupManager1.getHeaders(groupId0).size());
}
@Test
public void testWrongJoinMessages1() throws Exception {
addDefaultIdentities();
addDefaultContacts();
listenToEvents();
// author0 joins privateGroup0 with wrong join message
long joinTime = clock.currentTimeMillis();
GroupMessage joinMsg0 = groupMessageFactory
.createJoinMessage(privateGroup0.getId(), joinTime, author0,
joinTime, getRandomBytes(12));
groupManager0.addPrivateGroup(privateGroup0, joinMsg0, true);
assertEquals(joinMsg0.getMessage().getId(),
groupManager0.getPreviousMsgId(groupId0));
// share the group with 1
Transaction txn0 = db0.startTransaction(false);
db0.setGroupVisibility(txn0, contactId1, privateGroup0.getId(), SHARED);
db0.commitTransaction(txn0);
db0.endTransaction(txn0);
// author1 joins privateGroup0 with wrong timestamp
joinTime = clock.currentTimeMillis();
long inviteTime = joinTime;
Contact c1 = contactManager0.getContact(contactId1);
byte[] creatorSignature = groupInvitationFactory
.signInvitation(c1, privateGroup0.getId(), inviteTime,
author0.getPrivateKey());
GroupMessage joinMsg1 = groupMessageFactory
.createJoinMessage(privateGroup0.getId(), joinTime, author1,
inviteTime, creatorSignature);
groupManager1.addPrivateGroup(privateGroup0, joinMsg1, false);
assertEquals(joinMsg1.getMessage().getId(),
groupManager1.getPreviousMsgId(groupId0));
// share the group with 0
Transaction txn1 = db1.startTransaction(false);
db1.setGroupVisibility(txn1, contactId01, privateGroup0.getId(),
SHARED);
db1.commitTransaction(txn1);
db1.endTransaction(txn1);
// sync join messages
sync0To1();
validationWaiter.await(TIMEOUT, 1);
// assert that 0 never joined the group from 1's perspective
assertEquals(1, groupManager1.getHeaders(groupId0).size());
sync1To0();
validationWaiter.await(TIMEOUT, 1);
// assert that 1 never joined the group from 0's perspective
assertEquals(1, groupManager0.getHeaders(groupId0).size());
}
@Test
public void testWrongJoinMessages2() throws Exception {
addDefaultIdentities();
addDefaultContacts();
listenToEvents();
// author0 joins privateGroup0 with wrong member's join message
long joinTime = clock.currentTimeMillis();
long inviteTime = joinTime - 1;
BdfList toSign = groupInvitationFactory
.createInviteToken(author0.getId(), author0.getId(),
privateGroup0.getId(), inviteTime);
byte[] creatorSignature = clientHelper
.sign(SIGNING_LABEL_INVITE, toSign, author0.getPrivateKey());
// join message should not include invite time and creator's signature
GroupMessage joinMsg0 = groupMessageFactory
.createJoinMessage(privateGroup0.getId(), joinTime, author0,
inviteTime, creatorSignature);
groupManager0.addPrivateGroup(privateGroup0, joinMsg0, true);
assertEquals(joinMsg0.getMessage().getId(),
groupManager0.getPreviousMsgId(groupId0));
// share the group with 1
Transaction txn0 = db0.startTransaction(false);
db0.setGroupVisibility(txn0, contactId1, privateGroup0.getId(), SHARED);
db0.commitTransaction(txn0);
db0.endTransaction(txn0);
// author1 joins privateGroup0 with wrong signature in join message
joinTime = clock.currentTimeMillis();
inviteTime = joinTime - 1;
// signature uses joiner's key, not creator's key
Contact c1 = contactManager0.getContact(contactId1);
creatorSignature = groupInvitationFactory
.signInvitation(c1, privateGroup0.getId(), inviteTime,
author1.getPrivateKey());
GroupMessage joinMsg1 = groupMessageFactory
.createJoinMessage(privateGroup0.getId(), joinTime, author1,
inviteTime, creatorSignature);
groupManager1.addPrivateGroup(privateGroup0, joinMsg1, false);
assertEquals(joinMsg1.getMessage().getId(),
groupManager1.getPreviousMsgId(groupId0));
// share the group with 0
Transaction txn1 = db1.startTransaction(false);
db1.setGroupVisibility(txn1, contactId01, privateGroup0.getId(), SHARED);
db1.commitTransaction(txn1);
db1.endTransaction(txn1);
// sync join messages
sync0To1();
validationWaiter.await(TIMEOUT, 1);
// assert that 0 never joined the group from 1's perspective
assertEquals(1, groupManager1.getHeaders(groupId0).size());
sync1To0();
validationWaiter.await(TIMEOUT, 1);
// assert that 1 never joined the group from 0's perspective
assertEquals(1, groupManager0.getHeaders(groupId0).size());
}
@Test
public void testGetMembers() throws Exception {
defaultInit();
Collection<GroupMember> members0 = groupManager0.getMembers(groupId0);
assertEquals(2, members0.size());
for (GroupMember m : members0) {
if (m.getAuthor().equals(author0)) {
assertEquals(VISIBLE, m.getVisibility());
} else {
assertEquals(author1, m.getAuthor());
assertEquals(VISIBLE, m.getVisibility());
}
}
Collection<GroupMember> members1 = groupManager1.getMembers(groupId0);
assertEquals(2, members1.size());
for (GroupMember m : members1) {
if (m.getAuthor().equals(author1)) {
assertEquals(VISIBLE, m.getVisibility());
} else {
assertEquals(author0, m.getAuthor());
assertEquals(VISIBLE, m.getVisibility());
}
}
}
@Test
public void testJoinMessages() throws Exception {
defaultInit();
Collection<GroupMessageHeader> headers0 =
groupManager0.getHeaders(groupId0);
for (GroupMessageHeader h : headers0) {
if (h instanceof JoinMessageHeader) {
JoinMessageHeader j = (JoinMessageHeader) h;
// all relationships of the creator are visible
assertEquals(VISIBLE, j.getVisibility());
}
}
Collection<GroupMessageHeader> headers1 =
groupManager1.getHeaders(groupId0);
for (GroupMessageHeader h : headers1) {
if (h instanceof JoinMessageHeader) {
JoinMessageHeader j = (JoinMessageHeader) h;
if (h.getAuthor().equals(author1))
// we are visible to ourselves
assertEquals(VISIBLE, j.getVisibility());
else
// our relationship to the creator is visible
assertEquals(VISIBLE, j.getVisibility());
}
}
}
@Test
public void testRevealingRelationships() throws Exception {
defaultInit();
// share the group with 2
Transaction txn0 = db0.startTransaction(false);
db0.setGroupVisibility(txn0, contactId2, privateGroup0.getId(), SHARED);
db0.commitTransaction(txn0);
db0.endTransaction(txn0);
// author2 joins privateGroup0
long joinTime = clock.currentTimeMillis();
long inviteTime = joinTime - 1;
Contact c2 = contactManager0.getContact(contactId2);
byte[] creatorSignature = groupInvitationFactory
.signInvitation(c2, privateGroup0.getId(), inviteTime,
author0.getPrivateKey());
GroupMessage joinMsg2 = groupMessageFactory
.createJoinMessage(privateGroup0.getId(), joinTime, author2,
inviteTime, creatorSignature);
Transaction txn2 = db2.startTransaction(false);
groupManager2.addPrivateGroup(txn2, privateGroup0, joinMsg2, false);
// share the group with 0
db2.setGroupVisibility(txn2, contactId01, privateGroup0.getId(),
SHARED);
db2.commitTransaction(txn2);
db2.endTransaction(txn2);
// sync join messages
deliverMessage(sync2, contactId2, sync0, contactId02, "2 to 0");
deliveryWaiter.await(TIMEOUT, 1);
deliverMessage(sync0, contactId02, sync2, contactId2, "0 to 2");
deliveryWaiter.await(TIMEOUT, 2);
sync0To1();
deliveryWaiter.await(TIMEOUT, 1);
// check that everybody sees everybody else as joined
Collection<GroupMember> members0 = groupManager0.getMembers(groupId0);
assertEquals(3, members0.size());
Collection<GroupMember> members1 = groupManager1.getMembers(groupId0);
assertEquals(3, members1.size());
Collection<GroupMember> members2 = groupManager2.getMembers(groupId0);
assertEquals(3, members2.size());
// assert that contact relationship is not revealed initially
for (GroupMember m : members1) {
if (m.getAuthor().equals(author2)) {
assertEquals(INVISIBLE, m.getVisibility());
}
}
for (GroupMember m : members2) {
if (m.getAuthor().equals(author1)) {
assertEquals(INVISIBLE, m.getVisibility());
}
}
// reveal contact relationship
Transaction txn1 = db1.startTransaction(false);
groupManager1
.relationshipRevealed(txn1, groupId0, author2.getId(), false);
db1.commitTransaction(txn1);
db1.endTransaction(txn1);
txn2 = db2.startTransaction(false);
groupManager2
.relationshipRevealed(txn2, groupId0, author1.getId(), true);
db2.commitTransaction(txn2);
db2.endTransaction(txn2);
// assert that contact relationship is now revealed properly
members1 = groupManager1.getMembers(groupId0);
for (GroupMember m : members1) {
if (m.getAuthor().equals(author2)) {
assertEquals(REVEALED_BY_US, m.getVisibility());
}
}
members2 = groupManager2.getMembers(groupId0);
for (GroupMember m : members2) {
if (m.getAuthor().equals(author1)) {
assertEquals(REVEALED_BY_CONTACT, m.getVisibility());
}
}
// assert that join messages reflect revealed relationship
Collection<GroupMessageHeader> headers1 =
groupManager1.getHeaders(groupId0);
for (GroupMessageHeader h : headers1) {
if (h instanceof JoinMessageHeader) {
JoinMessageHeader j = (JoinMessageHeader) h;
if (h.getAuthor().equals(author2))
// 1 revealed the relationship to 2
assertEquals(REVEALED_BY_US, j.getVisibility());
else
// 1's other relationship (to 1 and creator) are visible
assertEquals(VISIBLE, j.getVisibility());
}
}
Collection<GroupMessageHeader> headers2 =
groupManager2.getHeaders(groupId0);
for (GroupMessageHeader h : headers2) {
if (h instanceof JoinMessageHeader) {
JoinMessageHeader j = (JoinMessageHeader) h;
if (h.getAuthor().equals(author1))
// 2's relationship was revealed by 1
assertEquals(REVEALED_BY_CONTACT, j.getVisibility());
else
// 2's other relationship (to 2 and creator) are visible
assertEquals(VISIBLE, j.getVisibility());
}
}
}
@Test
public void testDissolveGroup() throws Exception {
defaultInit();
// group is not dissolved initially
assertFalse(groupManager1.isDissolved(groupId0));
// creator dissolves group
Transaction txn1 = db1.startTransaction(false);
groupManager1.markGroupDissolved(txn1, groupId0);
db1.commitTransaction(txn1);
db1.endTransaction(txn1);
// group is dissolved now
assertTrue(groupManager1.isDissolved(groupId0));
}
@After
public void tearDown() throws Exception {
stopLifecycles();
TestUtils.deleteTestDirectory(testDir);
}
private class Listener implements EventListener {
@Override
public void eventOccurred(Event e) {
if (e instanceof MessageStateChangedEvent) {
MessageStateChangedEvent event = (MessageStateChangedEvent) e;
if (!event.isLocal()) {
if (event.getState() == DELIVERED) {
LOG.info("Delivered new message");
deliveryWaiter.resume();
} else if (event.getState() == INVALID ||
event.getState() == PENDING) {
LOG.info("Validated new " + event.getState().name() +
" message");
validationWaiter.resume();
}
}
}
}
}
private void defaultInit() throws Exception {
addDefaultIdentities();
addDefaultContacts();
listenToEvents();
addGroup();
}
private void addDefaultIdentities() throws DbException {
KeyPair keyPair0 = crypto.generateSignatureKeyPair();
byte[] publicKey0 = keyPair0.getPublic().getEncoded();
byte[] privateKey0 = keyPair0.getPrivate().getEncoded();
author0 = authorFactory
.createLocalAuthor(AUTHOR0, publicKey0, privateKey0);
identityManager0.registerLocalAuthor(author0);
privateGroup0 =
privateGroupFactory.createPrivateGroup("Testgroup", author0);
groupId0 = privateGroup0.getId();
KeyPair keyPair1 = crypto.generateSignatureKeyPair();
byte[] publicKey1 = keyPair1.getPublic().getEncoded();
byte[] privateKey1 = keyPair1.getPrivate().getEncoded();
author1 = authorFactory
.createLocalAuthor(AUTHOR1, publicKey1, privateKey1);
identityManager1.registerLocalAuthor(author1);
KeyPair keyPair2 = crypto.generateSignatureKeyPair();
byte[] publicKey2 = keyPair2.getPublic().getEncoded();
byte[] privateKey2 = keyPair2.getPrivate().getEncoded();
author2 = authorFactory
.createLocalAuthor(AUTHOR2, publicKey2, privateKey2);
identityManager2.registerLocalAuthor(author2);
}
private void addDefaultContacts() throws DbException {
// creator adds invitee as contact
contactId1 = contactManager0
.addContact(author1, author0.getId(), master,
clock.currentTimeMillis(), true, true, true);
// invitee adds creator back
contactId01 = contactManager1
.addContact(author0, author1.getId(), master,
clock.currentTimeMillis(), true, true, true);
// creator adds invitee as contact
contactId2 = contactManager0
.addContact(author2, author0.getId(), master,
clock.currentTimeMillis(), true, true, true);
// invitee adds creator back
contactId02 = contactManager2
.addContact(author0, author2.getId(), master,
clock.currentTimeMillis(), true, true, true);
}
private void listenToEvents() {
Listener listener0 = new Listener();
t0.getEventBus().addListener(listener0);
Listener listener1 = new Listener();
t1.getEventBus().addListener(listener1);
Listener listener2 = new Listener();
t2.getEventBus().addListener(listener2);
}
private void addGroup() throws Exception {
// author0 joins privateGroup0
long joinTime = clock.currentTimeMillis();
GroupMessage joinMsg0 = groupMessageFactory
.createJoinMessage(privateGroup0.getId(), joinTime, author0);
groupManager0.addPrivateGroup(privateGroup0, joinMsg0, true);
assertEquals(joinMsg0.getMessage().getId(),
groupManager0.getPreviousMsgId(groupId0));
// share the group with 1
Transaction txn0 = db0.startTransaction(false);
db0.setGroupVisibility(txn0, contactId1, privateGroup0.getId(), SHARED);
db0.commitTransaction(txn0);
db0.endTransaction(txn0);
// author1 joins privateGroup0
joinTime = clock.currentTimeMillis();
long inviteTime = joinTime - 1;
Contact c1 = contactManager0.getContact(contactId1);
byte[] creatorSignature = groupInvitationFactory
.signInvitation(c1, privateGroup0.getId(), inviteTime,
author0.getPrivateKey());
GroupMessage joinMsg1 = groupMessageFactory
.createJoinMessage(privateGroup0.getId(), joinTime, author1,
inviteTime, creatorSignature);
groupManager1.addPrivateGroup(privateGroup0, joinMsg1, false);
// share the group with 0
Transaction txn1 = db1.startTransaction(false);
db1.setGroupVisibility(txn1, contactId01, privateGroup0.getId(),
SHARED);
db1.commitTransaction(txn1);
db1.endTransaction(txn1);
assertEquals(joinMsg1.getMessage().getId(),
groupManager1.getPreviousMsgId(groupId0));
// sync join messages
sync0To1();
deliveryWaiter.await(TIMEOUT, 1);
sync1To0();
deliveryWaiter.await(TIMEOUT, 1);
}
private void sync0To1() throws IOException, TimeoutException {
deliverMessage(sync0, contactId01, sync1, contactId1, "0 to 1");
}
private void sync1To0() throws IOException, TimeoutException {
deliverMessage(sync1, contactId1, sync0, contactId01, "1 to 0");
}
private void deliverMessage(SyncSessionFactory fromSync, ContactId fromId,
SyncSessionFactory toSync, ContactId toId, String debug)
throws IOException, TimeoutException {
if (debug != null) LOG.info("TEST: Sending message from " + debug);
ByteArrayOutputStream out = new ByteArrayOutputStream();
// Create an outgoing sync session
SyncSession sessionFrom =
fromSync.createSimplexOutgoingSession(toId, MAX_LATENCY, out);
// Write whatever needs to be written
sessionFrom.run();
out.close();
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
// Create an incoming sync session
SyncSession sessionTo = toSync.createIncomingSession(fromId, in);
// Read whatever needs to be read
sessionTo.run();
in.close();
}
private void startLifecycles() throws InterruptedException {
// Start the lifecycle manager and wait for it to finish
lifecycleManager0 = t0.getLifecycleManager();
lifecycleManager1 = t1.getLifecycleManager();
lifecycleManager2 = t2.getLifecycleManager();
lifecycleManager0.startServices(AUTHOR0);
lifecycleManager1.startServices(AUTHOR1);
lifecycleManager2.startServices(AUTHOR2);
lifecycleManager0.waitForStartup();
lifecycleManager1.waitForStartup();
lifecycleManager2.waitForStartup();
}
private void stopLifecycles() throws InterruptedException {
// Clean up
lifecycleManager0.stopServices();
lifecycleManager1.stopServices();
lifecycleManager2.stopServices();
lifecycleManager0.waitForShutdown();
lifecycleManager1.waitForShutdown();
lifecycleManager2.waitForShutdown();
}
private void injectEagerSingletons(
PrivateGroupManagerTestComponent component) {
component.inject(new LifecycleModule.EagerSingletons());
component.inject(new PrivateGroupModule.EagerSingletons());
component.inject(new CryptoModule.EagerSingletons());
component.inject(new ContactModule.EagerSingletons());
component.inject(new TransportModule.EagerSingletons());
component.inject(new SyncModule.EagerSingletons());
component.inject(new PropertiesModule.EagerSingletons());
}
}

View File

@@ -0,0 +1,85 @@
package org.briarproject;
import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.event.EventBus;
import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.lifecycle.LifecycleManager;
import org.briarproject.api.privategroup.PrivateGroupManager;
import org.briarproject.api.sync.SyncSessionFactory;
import org.briarproject.clients.ClientsModule;
import org.briarproject.contact.ContactModule;
import org.briarproject.crypto.CryptoModule;
import org.briarproject.data.DataModule;
import org.briarproject.db.DatabaseModule;
import org.briarproject.event.EventModule;
import org.briarproject.identity.IdentityModule;
import org.briarproject.lifecycle.LifecycleModule;
import org.briarproject.messaging.MessagingModule;
import org.briarproject.privategroup.PrivateGroupModule;
import org.briarproject.privategroup.invitation.GroupInvitationModule;
import org.briarproject.properties.PropertiesModule;
import org.briarproject.sharing.SharingModule;
import org.briarproject.sync.SyncModule;
import org.briarproject.system.SystemModule;
import org.briarproject.transport.TransportModule;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = {
TestDatabaseModule.class,
TestPluginsModule.class,
TestSeedProviderModule.class,
ClientsModule.class,
ContactModule.class,
CryptoModule.class,
DataModule.class,
DatabaseModule.class,
EventModule.class,
MessagingModule.class,
PrivateGroupModule.class,
GroupInvitationModule.class,
IdentityModule.class,
LifecycleModule.class,
PropertiesModule.class,
SharingModule.class,
SyncModule.class,
SystemModule.class,
TransportModule.class
})
interface PrivateGroupManagerTestComponent {
void inject(PrivateGroupManagerTest testCase);
void inject(ContactModule.EagerSingletons init);
void inject(CryptoModule.EagerSingletons init);
void inject(PrivateGroupModule.EagerSingletons init);
void inject(LifecycleModule.EagerSingletons init);
void inject(PropertiesModule.EagerSingletons init);
void inject(SyncModule.EagerSingletons init);
void inject(TransportModule.EagerSingletons init);
LifecycleManager getLifecycleManager();
EventBus getEventBus();
IdentityManager getIdentityManager();
ContactManager getContactManager();
PrivateGroupManager getPrivateGroupManager();
SyncSessionFactory getSyncSessionFactory();
DatabaseComponent getDatabaseComponent();
}

View File

@@ -43,6 +43,9 @@ import static org.junit.Assert.assertTrue;
public class SimplexMessagingIntegrationTest extends BriarTestCase { public class SimplexMessagingIntegrationTest extends BriarTestCase {
private final static String ALICE = "Alice";
private final static String BOB = "Bob";
private final File testDir = TestUtils.getTestDirectory(); private final File testDir = TestUtils.getTestDirectory();
private final File aliceDir = new File(testDir, "alice"); private final File aliceDir = new File(testDir, "alice");
private final File bobDir = new File(testDir, "bob"); private final File bobDir = new File(testDir, "bob");
@@ -69,6 +72,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
read(write()); read(write());
} }
private byte[] write() throws Exception { private byte[] write() throws Exception {
// Instantiate Alice's services // Instantiate Alice's services
LifecycleManager lifecycleManager = alice.getLifecycleManager(); LifecycleManager lifecycleManager = alice.getLifecycleManager();
@@ -83,23 +87,23 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
SyncSessionFactory syncSessionFactory = alice.getSyncSessionFactory(); SyncSessionFactory syncSessionFactory = alice.getSyncSessionFactory();
// Start the lifecycle manager // Start the lifecycle manager
lifecycleManager.startServices(); lifecycleManager.startServices(null);
lifecycleManager.waitForStartup(); lifecycleManager.waitForStartup();
// Add an identity for Alice // Add an identity for Alice
LocalAuthor aliceAuthor = new LocalAuthor(aliceId, "Alice", LocalAuthor aliceAuthor = new LocalAuthor(aliceId, "Alice",
new byte[MAX_PUBLIC_KEY_LENGTH], new byte[123], timestamp); new byte[MAX_PUBLIC_KEY_LENGTH], new byte[123], timestamp);
identityManager.addLocalAuthor(aliceAuthor); identityManager.registerLocalAuthor(aliceAuthor);
// Add Bob as a contact // Add Bob as a contact
Author bobAuthor = new Author(bobId, "Bob", Author bobAuthor = new Author(bobId, BOB,
new byte[MAX_PUBLIC_KEY_LENGTH]); new byte[MAX_PUBLIC_KEY_LENGTH]);
ContactId contactId = contactManager.addContact(bobAuthor, aliceId, ContactId contactId = contactManager.addContact(bobAuthor,
master, timestamp, true, true, true); aliceAuthor.getId(), master, timestamp, true, true, true);
// Send Bob a message // Send Bob a message
GroupId groupId = messagingManager.getConversationId(contactId); GroupId groupId = messagingManager.getConversationId(contactId);
byte[] body = "Hi Bob!".getBytes("UTF-8"); String body = "Hi Bob!";
PrivateMessage message = privateMessageFactory.createPrivateMessage( PrivateMessage message = privateMessageFactory.createPrivateMessage(
groupId, timestamp, null, "text/plain", body); groupId, timestamp, body);
messagingManager.addLocalMessage(message); messagingManager.addLocalMessage(message);
// Get a stream context // Get a stream context
StreamContext ctx = keyManager.getStreamContext(contactId, StreamContext ctx = keyManager.getStreamContext(contactId,
@@ -136,18 +140,17 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
bob.getMessagingManager(); bob.getMessagingManager();
// Start the lifecyle manager // Start the lifecyle manager
lifecycleManager.startServices(); lifecycleManager.startServices(null);
lifecycleManager.waitForStartup(); lifecycleManager.waitForStartup();
// Add an identity for Bob // Add an identity for Bob
LocalAuthor bobAuthor = new LocalAuthor(bobId, "Bob", LocalAuthor bobAuthor = new LocalAuthor(bobId, BOB,
new byte[MAX_PUBLIC_KEY_LENGTH], new byte[123], timestamp); new byte[MAX_PUBLIC_KEY_LENGTH], new byte[123], timestamp);
identityManager.addLocalAuthor(bobAuthor); identityManager.registerLocalAuthor(bobAuthor);
// Add Alice as a contact // Add Alice as a contact
Author aliceAuthor = new Author(aliceId, "Alice", Author aliceAuthor = new Author(aliceId, ALICE,
new byte[MAX_PUBLIC_KEY_LENGTH]); new byte[MAX_PUBLIC_KEY_LENGTH]);
ContactId contactId = contactManager.addContact(aliceAuthor, bobId, ContactId contactId = contactManager.addContact(aliceAuthor,
master, timestamp, false, true, true); bobAuthor.getId(), master, timestamp, false, true, true);
// Set up an event listener // Set up an event listener
MessageListener listener = new MessageListener(); MessageListener listener = new MessageListener();
bob.getEventBus().addListener(listener); bob.getEventBus().addListener(listener);

View File

@@ -74,7 +74,7 @@ public class SyncIntegrationTest extends BriarTestCase {
headerKey = TestUtils.getSecretKey(); headerKey = TestUtils.getSecretKey();
streamNumber = 123; streamNumber = 123;
// Create a group // Create a group
ClientId clientId = new ClientId(TestUtils.getRandomId()); ClientId clientId = new ClientId(TestUtils.getRandomString(5));
byte[] descriptor = new byte[0]; byte[] descriptor = new byte[0];
Group group = groupFactory.createGroup(clientId, descriptor); Group group = groupFactory.createGroup(clientId, descriptor);
// Add two messages to the group // Add two messages to the group
@@ -122,7 +122,7 @@ public class SyncIntegrationTest extends BriarTestCase {
// Create the readers // Create the readers
StreamContext ctx = new StreamContext(contactId, transportId, tagKey, StreamContext ctx = new StreamContext(contactId, transportId, tagKey,
headerKey, 0); headerKey, streamNumber);
InputStream streamReader = streamReaderFactory.createStreamReader(in, InputStream streamReader = streamReaderFactory.createStreamReader(in,
ctx); ctx);
PacketReader packetReader = packetReaderFactory.createPacketReader( PacketReader packetReader = packetReaderFactory.createPacketReader(

View File

@@ -1,6 +1,10 @@
package org.briarproject; package org.briarproject.introduction;
import org.briarproject.TestDatabaseModule;
import org.briarproject.TestPluginsModule;
import org.briarproject.TestSeedProviderModule;
import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.clients.MessageTracker;
import org.briarproject.api.contact.ContactManager; import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventBus;
@@ -16,10 +20,8 @@ import org.briarproject.data.DataModule;
import org.briarproject.db.DatabaseModule; import org.briarproject.db.DatabaseModule;
import org.briarproject.event.EventModule; import org.briarproject.event.EventModule;
import org.briarproject.identity.IdentityModule; import org.briarproject.identity.IdentityModule;
import org.briarproject.introduction.IntroductionGroupFactory;
import org.briarproject.introduction.IntroductionModule;
import org.briarproject.introduction.MessageSender;
import org.briarproject.lifecycle.LifecycleModule; import org.briarproject.lifecycle.LifecycleModule;
import org.briarproject.messaging.MessagingModule;
import org.briarproject.properties.PropertiesModule; import org.briarproject.properties.PropertiesModule;
import org.briarproject.sync.SyncModule; import org.briarproject.sync.SyncModule;
import org.briarproject.system.SystemModule; import org.briarproject.system.SystemModule;
@@ -46,9 +48,10 @@ import dagger.Component;
SyncModule.class, SyncModule.class,
SystemModule.class, SystemModule.class,
DataModule.class, DataModule.class,
PropertiesModule.class PropertiesModule.class,
MessagingModule.class
}) })
public interface IntroductionIntegrationTestComponent { interface IntroductionIntegrationTestComponent {
void inject(IntroductionIntegrationTest testCase); void inject(IntroductionIntegrationTest testCase);
@@ -80,6 +83,8 @@ public interface IntroductionIntegrationTestComponent {
TransportPropertyManager getTransportPropertyManager(); TransportPropertyManager getTransportPropertyManager();
MessageTracker getMessageTracker();
SyncSessionFactory getSyncSessionFactory(); SyncSessionFactory getSyncSessionFactory();
/* the following methods are only needed to manually construct messages */ /* the following methods are only needed to manually construct messages */

View File

@@ -1,6 +1,6 @@
[main] [main]
host = https://www.transifex.com host = https://www.transifex.com
lang_map = pt_BR: pt-rBR lang_map = pt_BR: pt-rBR, fr_FR: fr
[briar.stringsxml-5] [briar.stringsxml-5]
file_filter = res/values-<lang>/strings.xml file_filter = res/values-<lang>/strings.xml

View File

@@ -93,7 +93,7 @@
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/BriarThemeNoActionBar.Default" android:theme="@style/BriarThemeNoActionBar.Default"
android:parentActivityName=".android.NavDrawerActivity" android:parentActivityName=".android.NavDrawerActivity"
android:windowSoftInputMode="stateHidden"> android:windowSoftInputMode="stateHidden|adjustResize">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value=".android.NavDrawerActivity" android:value=".android.NavDrawerActivity"
@@ -101,7 +101,70 @@
</activity> </activity>
<activity <activity
android:name=".android.sharing.InvitationsForumActivity" android:name=".android.privategroup.creation.CreateGroupActivity"
android:label="@string/groups_create_group_title"
android:parentActivityName=".android.NavDrawerActivity"
android:windowSoftInputMode="adjustResize">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".android.NavDrawerActivity"
/>
</activity>
<activity
android:name=".android.privategroup.conversation.GroupActivity"
android:label="@string/app_name"
android:parentActivityName=".android.NavDrawerActivity"
android:windowSoftInputMode="adjustResize|stateHidden">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".android.NavDrawerActivity"
/>
</activity>
<activity
android:name=".android.privategroup.invitation.GroupInvitationActivity"
android:label="@string/groups_invitations_title"
android:parentActivityName=".android.NavDrawerActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".android.NavDrawerActivity"/>
</activity>
<activity
android:name=".android.privategroup.memberlist.GroupMemberListActivity"
android:label="@string/groups_member_list"
android:parentActivityName=".android.privategroup.conversation.GroupActivity"
android:windowSoftInputMode="adjustResize|stateHidden">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".android.privategroup.conversation.GroupActivity"
/>
</activity>
<activity
android:name=".android.privategroup.reveal.RevealContactsActivity"
android:label="@string/groups_reveal_contacts"
android:parentActivityName=".android.privategroup.conversation.GroupActivity"
android:windowSoftInputMode="adjustResize|stateAlwaysHidden">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".android.privategroup.conversation.GroupActivity"
/>
</activity>
<activity
android:name=".android.privategroup.creation.GroupInviteActivity"
android:label="@string/groups_invite_members"
android:parentActivityName=".android.privategroup.conversation.GroupActivity"
android:windowSoftInputMode="adjustResize|stateHidden">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".android.privategroup.conversation.GroupActivity"/>
</activity>
<activity
android:name=".android.sharing.ForumInvitationActivity"
android:label="@string/forum_invitations_title" android:label="@string/forum_invitations_title"
android:parentActivityName=".android.NavDrawerActivity"> android:parentActivityName=".android.NavDrawerActivity">
<meta-data <meta-data
@@ -111,7 +174,7 @@
</activity> </activity>
<activity <activity
android:name=".android.sharing.InvitationsBlogActivity" android:name=".android.sharing.BlogInvitationActivity"
android:label="@string/blogs_sharing_invitations_title" android:label="@string/blogs_sharing_invitations_title"
android:parentActivityName=".android.contact.ConversationActivity"> android:parentActivityName=".android.contact.ConversationActivity">
<meta-data <meta-data
@@ -134,7 +197,8 @@
<activity <activity
android:name=".android.forum.ForumActivity" android:name=".android.forum.ForumActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:parentActivityName=".android.NavDrawerActivity"> android:parentActivityName=".android.NavDrawerActivity"
android:windowSoftInputMode="adjustResize|stateHidden">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value=".android.NavDrawerActivity" android:value=".android.NavDrawerActivity"
@@ -144,7 +208,8 @@
<activity <activity
android:name=".android.sharing.ShareForumActivity" android:name=".android.sharing.ShareForumActivity"
android:label="@string/activity_share_toolbar_header" android:label="@string/activity_share_toolbar_header"
android:parentActivityName=".android.forum.ForumActivity"> android:parentActivityName=".android.forum.ForumActivity"
android:windowSoftInputMode="adjustResize|stateHidden">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value=".android.forum.ForumActivity" android:value=".android.forum.ForumActivity"
@@ -154,7 +219,8 @@
<activity <activity
android:name=".android.sharing.ShareBlogActivity" android:name=".android.sharing.ShareBlogActivity"
android:label="@string/activity_share_toolbar_header" android:label="@string/activity_share_toolbar_header"
android:parentActivityName=".android.blogs.BlogActivity"> android:parentActivityName=".android.blogs.BlogActivity"
android:windowSoftInputMode="adjustResize|stateHidden">
<meta-data <meta-data
android:name="android.support.PARENT_ACTIVITY" android:name="android.support.PARENT_ACTIVITY"
android:value=".android.blogs.BlogActivity" android:value=".android.blogs.BlogActivity"
@@ -162,7 +228,7 @@
</activity> </activity>
<activity <activity
android:name=".android.sharing.SharingStatusForumActivity" android:name=".android.sharing.ForumSharingStatusActivity"
android:label="@string/sharing_status" android:label="@string/sharing_status"
android:parentActivityName=".android.forum.ForumActivity"> android:parentActivityName=".android.forum.ForumActivity">
<meta-data <meta-data
@@ -172,7 +238,7 @@
</activity> </activity>
<activity <activity
android:name=".android.sharing.SharingStatusBlogActivity" android:name=".android.sharing.BlogSharingStatusActivity"
android:label="@string/sharing_status" android:label="@string/sharing_status"
android:parentActivityName=".android.blogs.BlogActivity"> android:parentActivityName=".android.blogs.BlogActivity">
<meta-data <meta-data
@@ -181,16 +247,6 @@
/> />
</activity> </activity>
<activity
android:name=".android.blogs.CreateBlogActivity"
android:label="@string/blogs_my_blogs_label"
android:parentActivityName=".android.NavDrawerActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".android.NavDrawerActivity"
/>
</activity>
<activity <activity
android:name=".android.blogs.BlogActivity" android:name=".android.blogs.BlogActivity"
android:parentActivityName=".android.NavDrawerActivity"> android:parentActivityName=".android.NavDrawerActivity">
@@ -243,12 +299,6 @@
/> />
</activity> </activity>
<activity
android:name=".android.identity.CreateIdentityActivity"
android:label="@string/new_identity_title"
android:windowSoftInputMode="stateVisible">
</activity>
<activity <activity
android:name=".android.invitation.AddContactActivity" android:name=".android.invitation.AddContactActivity"
android:label="@string/add_contact_title" android:label="@string/add_contact_title"

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
width="24"
height="24"
viewBox="0 0 24 24"
sodipodi:docname="ic_emoji_emoticons.svg">
<metadata
id="metadata8">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1021"
id="namedview4"
showgrid="false"
inkscape:zoom="4.6354778"
inkscape:cx="47.926788"
inkscape:cy="24.127496"
inkscape:window-x="1440"
inkscape:window-y="23"
inkscape:window-maximized="0"
inkscape:current-layer="svg2" />
<path
style="fill:#000000;fill-opacity:1"
d="m 15.483903,3.8556996 c -0.661546,0.040406 -0.536253,1.2125273 -0.08054,1.6240791 1.361771,1.4519837 1.747379,3.5080793 1.895646,5.4253553 0.109142,2.216286 -0.0846,4.555699 -1.171466,6.533591 -0.361828,0.731167 -1.339597,1.273078 -1.15283,2.195835 0.287109,1.037426 1.187031,0.242862 1.620751,-0.183708 1.991711,-1.742024 2.867744,-4.428018 2.93133,-7.013492 0.02009,-1.918049 -0.231841,-3.9213035 -1.212735,-5.6044037 -0.664187,-1.0906817 -1.39072,-2.2339438 -2.497355,-2.9193489 -0.127976,-0.045915 -0.238296,-0.06368 -0.332802,-0.057908 z M 5.9118212,7.6583077 A 1.3631614,1.3631614 0 0 0 4.54866,9.0214691 1.3631614,1.3631614 0 0 0 5.9118212,10.38463 1.3631614,1.3631614 0 0 0 7.2749824,9.0214691 1.3631614,1.3631614 0 0 0 5.9118212,7.6583077 Z m 3.0731032,3.0012183 0,2.044742 4.7710646,0 0,-2.044742 -4.7710646,0 z m -3.1496485,3.471136 a 1.3631614,1.3631614 0 0 0 -1.3631612,1.363161 1.3631614,1.3631614 0 0 0 1.3631612,1.363161 1.3631614,1.3631614 0 0 0 1.3631612,-1.363161 1.3631614,1.3631614 0 0 0 -1.3631612,-1.363161 z"
id="path4142"
inkscape:connector-curvature="0" />
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 901 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 KiB

View File

@@ -25,16 +25,20 @@ dependencies {
exclude module: 'recyclerview-v7' exclude module: 'recyclerview-v7'
} }
compile "com.android.support:cardview-v7:$supportVersion" compile "com.android.support:cardview-v7:$supportVersion"
compile 'com.android.support:support-annotations:23.4.0'
compile('ch.acra:acra:4.8.5') { compile('ch.acra:acra:4.8.5') {
exclude module: 'support-v4' exclude module: 'support-v4'
exclude module: 'support-annotations' exclude module: 'support-annotations'
} }
compile 'info.guardianproject.panic:panic:0.5' compile 'info.guardianproject.panic:panic:0.5'
compile 'info.guardianproject.trustedintents:trustedintents:0.2' compile 'info.guardianproject.trustedintents:trustedintents:0.2'
compile 'de.hdodenhof:circleimageview:2.0.0' compile 'de.hdodenhof:circleimageview:2.1.0'
compile 'com.google.zxing:core:3.2.1' compile 'com.google.zxing:core:3.2.1'
apt 'com.google.dagger:dagger-compiler:2.0.2' apt 'com.google.dagger:dagger-compiler:2.0.2'
provided 'javax.annotation:jsr250-api:1.0' provided 'javax.annotation:jsr250-api:1.0'
compile 'com.jpardogo.materialtabstrip:library:1.1.0'
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'uk.co.samuelwall:material-tap-target-prompt:1.3.0'
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
testCompile 'net.jodah:concurrentunit:0.4.2' testCompile 'net.jodah:concurrentunit:0.4.2'
@@ -49,17 +53,20 @@ dependencyVerification {
'ch.acra:acra:afd5b28934d5166b55f261c85685ad59e8a4ebe9ca1960906afaa8c76d8dc9eb', 'ch.acra:acra:afd5b28934d5166b55f261c85685ad59e8a4ebe9ca1960906afaa8c76d8dc9eb',
'info.guardianproject.panic:panic:a7ed9439826db2e9901649892cf9afbe76f00991b768d8f4c26332d7c9406cb2', 'info.guardianproject.panic:panic:a7ed9439826db2e9901649892cf9afbe76f00991b768d8f4c26332d7c9406cb2',
'info.guardianproject.trustedintents:trustedintents:6221456d8821a8d974c2acf86306900237cf6afaaa94a4c9c44e161350f80f3e', 'info.guardianproject.trustedintents:trustedintents:6221456d8821a8d974c2acf86306900237cf6afaaa94a4c9c44e161350f80f3e',
'de.hdodenhof:circleimageview:c76d936395b50705a3f98c9220c22d2599aeb9e609f559f6048975cfc1f686b8', 'de.hdodenhof:circleimageview:bcbc588e19e6dcf8c120b1957776bfe229efba5d2fbe5da7156372eeacf65503',
'com.google.zxing:core:b4d82452e7a6bf6ec2698904b332431717ed8f9a850224f295aec89de80f2259', 'com.google.zxing:core:b4d82452e7a6bf6ec2698904b332431717ed8f9a850224f295aec89de80f2259',
'com.android.support:support-v4:81ce890f26d35c75ad17d0f998a7e3230330c3b41e0b629566bc744bee89e448', 'com.android.support:support-v4:81ce890f26d35c75ad17d0f998a7e3230330c3b41e0b629566bc744bee89e448',
'com.android.support:appcompat-v7:00f9d93acacd6731f309724054bf51492814b4b2869f16d7d5c0038dcb8c9a0d', 'com.android.support:appcompat-v7:00f9d93acacd6731f309724054bf51492814b4b2869f16d7d5c0038dcb8c9a0d',
'com.android.support:preference-v14:44881bb46094e86d0bc2426f205419674a5b4eb514b44b5a4659b5de29f71eb7', 'com.android.support:preference-v14:44881bb46094e86d0bc2426f205419674a5b4eb514b44b5a4659b5de29f71eb7',
'com.android.support:design:003e0c0bea0a6891f8b2bc43f20ae7af2a49a17363e5bb10df5ee0bae12fa686', 'com.android.support:design:003e0c0bea0a6891f8b2bc43f20ae7af2a49a17363e5bb10df5ee0bae12fa686',
'com.android.support:support-annotations:786ab0d060774fb95cfdaf4878771e14b85733b1af9d72a4aae762dc7c1dff9f', 'com.android.support:support-annotations:e91a88dd0c5e99069b7f09d4a46b5e06f1e9c4c72fc0a8e987e25d86af480f01',
'com.android.support:animated-vector-drawable:06d1963b85aa917099d7757e6a7b3e4dc06889413dc747f625ae8683606db3a1', 'com.android.support:animated-vector-drawable:06d1963b85aa917099d7757e6a7b3e4dc06889413dc747f625ae8683606db3a1',
'com.android.support:support-vector-drawable:799bafe4c3de812386f0b291f744d5d6876452722dd40189b9ab87dbbf594ea1', 'com.android.support:support-vector-drawable:799bafe4c3de812386f0b291f744d5d6876452722dd40189b9ab87dbbf594ea1',
'com.android.support:recyclerview-v7:44040a888e23e0c93162a3377cfe06751080e3c22d369ab0d4301ef60d63b0fe', 'com.android.support:recyclerview-v7:44040a888e23e0c93162a3377cfe06751080e3c22d369ab0d4301ef60d63b0fe',
'com.android.support:cardview-v7:4595f1c4a28cfa083b6c0920ad4d49e1c2ca4b8302a955e548f68eb63b74931b', 'com.android.support:cardview-v7:4595f1c4a28cfa083b6c0920ad4d49e1c2ca4b8302a955e548f68eb63b74931b',
'com.jpardogo.materialtabstrip:library:24d19232b319f8c73e25793432357919a7ed972186f57a3b2c9093ea74ad8311',
'com.github.bumptech.glide:glide:76ef123957b5fbaebb05fcbe6606dd58c3bc3fcdadb257f99811d0ac9ea9b88b',
'uk.co.samuelwall:material-tap-target-prompt:f67e1caead12a914525b32cbf6da52a96b93ff89573f93cb41102ef3130fb64a',
] ]
} }
@@ -118,10 +125,6 @@ android {
warning 'MissingTranslation' warning 'MissingTranslation'
warning 'ImpliedQuantity' warning 'ImpliedQuantity'
} }
dexOptions {
incremental true
}
} }
task downloadTorGeoIp(type: Download) { task downloadTorGeoIp(type: Download) {

View File

@@ -54,9 +54,18 @@
# RSS libraries # RSS libraries
-keep class com.rometools.rome.feed.synd.impl.** { *;} -keep class com.rometools.rome.feed.synd.impl.** { *;}
-keep class com.rometools.rome.io.impl.** { *;} -keep class com.rometools.rome.io.impl.** { *;}
-keep class org.jsoup.safety.Whitelist
-dontnote com.rometools.rome.** -dontnote com.rometools.rome.**
-dontwarn javax.xml.stream.** -dontwarn javax.xml.stream.**
-dontwarn org.jaxen.** -dontwarn org.jaxen.**
-dontwarn java.nio.** -dontwarn java.nio.**
-dontwarn org.codehaus.mojo.animal_sniffer.** -dontwarn org.codehaus.mojo.animal_sniffer.**
-dontwarn org.slf4j.impl.** -dontwarn org.slf4j.impl.**
# Emoji
-keep class org.thoughtcrime.securesms.**
-keep class com.astuetz.PagerSlidingTabStrip$OnTabReselectedListener
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:alpha="0.54"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M22,3L7,3c-0.69,0 -1.23,0.35 -1.59,0.88L0,12l5.41,8.11c0.36,0.53 0.9,0.89 1.59,0.89h15c1.1,0 2,-0.9 2,-2L24,5c0,-1.1 -0.9,-2 -2,-2zM19,15.59L17.59,17 14,13.41 10.41,17 9,15.59 12.59,12 9,8.41 10.41,7 14,10.59 17.59,7 19,8.41 15.41,12 19,15.59z"/>
</vector>

View File

@@ -1,5 +1,10 @@
<vector android:alpha="0.56" android:height="48dp" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="48dp"
android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:height="48dp"
<path android:fillColor="#FF000000" android:pathData="M9.01,14L2,14v2h7.01v3L13,15l-3.99,-4v3zM14.99,13v-3L22,10L22,8h-7.01L14.99,5L11,9l3.99,4z"/> android:alpha="0.54"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M9.01,14L2,14v2h7.01v3L13,15l-3.99,-4v3zM14.99,13v-3L22,10L22,8h-7.01L14.99,5L11,9l3.99,4z"/>
</vector> </vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:alpha="0.54"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M20,0L4,0v2h16L20,0zM4,24h16v-2L4,22v2zM20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM12,6.75c1.24,0 2.25,1.01 2.25,2.25s-1.01,2.25 -2.25,2.25S9.75,10.24 9.75,9 10.76,6.75 12,6.75zM17,17L7,17v-1.5c0,-1.67 3.33,-2.5 5,-2.5s5,0.83 5,2.5L17,17z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#FF2D3E50"
android:pathData="M7.5,7.5C9.17,5.87 11.29,4.69 13.37,4.18C15.46,3.67 17.5,3.83 18.6,4C19.71,4.15 19.87,4.31 20.03,5.41C20.18,6.5 20.33,8.55 19.82,10.63C19.31,12.71 18.13,14.83 16.5,16.5C14.83,18.13 12.71,19.31 10.63,19.82C8.55,20.33 6.5,20.18 5.41,20.03C4.31,19.87 4.15,19.71 4,18.6C3.83,17.5 3.67,15.46 4.18,13.37C4.69,11.29 5.87,9.17 7.5,7.5M7.3,15.79L8.21,16.7L9.42,15.5L10.63,16.7L11.54,15.79L10.34,14.58L12,12.91L13.21,14.12L14.12,13.21L12.91,12L14.58,10.34L15.79,11.54L16.7,10.63L15.5,9.42L16.7,8.21L15.79,7.3L14.58,8.5L13.37,7.3L12.46,8.21L13.66,9.42L12,11.09L10.79,9.88L9.88,10.79L11.09,12L9.42,13.66L8.21,12.46L7.3,13.37L8.5,14.58L7.3,15.79Z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF2D3E50"
android:pathData="M18.7,12.4c-0.28,-0.16 -0.57,-0.29 -0.86,-0.4 0.29,-0.11 0.58,-0.24 0.86,-0.4 1.92,-1.11 2.99,-3.12 3,-5.19 -1.79,-1.03 -4.07,-1.11 -6,0 -0.28,0.16 -0.54,0.35 -0.78,0.54 0.05,-0.31 0.08,-0.63 0.08,-0.95 0,-2.22 -1.21,-4.15 -3,-5.19C10.21,1.85 9,3.78 9,6c0,0.32 0.03,0.64 0.08,0.95 -0.24,-0.2 -0.5,-0.39 -0.78,-0.55 -1.92,-1.11 -4.2,-1.03 -6,0 0,2.07 1.07,4.08 3,5.19 0.28,0.16 0.57,0.29 0.86,0.4 -0.29,0.11 -0.58,0.24 -0.86,0.4 -1.92,1.11 -2.99,3.12 -3,5.19 1.79,1.03 4.07,1.11 6,0 0.28,-0.16 0.54,-0.35 0.78,-0.54 -0.05,0.32 -0.08,0.64 -0.08,0.96 0,2.22 1.21,4.15 3,5.19 1.79,-1.04 3,-2.97 3,-5.19 0,-0.32 -0.03,-0.64 -0.08,-0.95 0.24,0.2 0.5,0.38 0.78,0.54 1.92,1.11 4.2,1.03 6,0 -0.01,-2.07 -1.08,-4.08 -3,-5.19zM12,16c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z"/>
</vector>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#FF2D3E50"
android:pathData="M15.4839,3.8557 C14.8224,3.89611,14.9476,5.06823,15.4034,5.47978
C16.7652,6.93176,17.1508,8.98786,17.299,10.9051
C17.4081,13.1214,17.2144,15.4608,16.1275,17.4387
C15.7657,18.1699,14.7879,18.7118,14.9747,19.6345
C15.2618,20.6719,16.1617,19.8774,16.5955,19.4508
C18.5872,17.7088,19.4632,15.0228,19.5268,12.4373
C19.5469,10.5193,19.295,8.516,18.3141,6.8329
C17.6499,5.74222,16.9234,4.59896,15.8167,3.91355
C15.6887,3.86763,15.5784,3.84987,15.4839,3.85564 Z M5.91182,7.65831
A1.3631614,1.3631614,0,0,0,4.54866,9.02147
A1.3631614,1.3631614,0,0,0,5.91182,10.3846
A1.3631614,1.3631614,0,0,0,7.27498,9.02147
A1.3631614,1.3631614,0,0,0,5.91182,7.65831 Z M8.98492,10.6595 L8.98492,12.7042
L13.756,12.7042 L13.756,10.6595 L8.98494,10.6595 Z M5.83527,14.1306
A1.3631614,1.3631614,0,0,0,4.47211,15.4938
A1.3631614,1.3631614,0,0,0,5.83527,16.857
A1.3631614,1.3631614,0,0,0,7.19843,15.4938
A1.3631614,1.3631614,0,0,0,5.83527,14.1306 Z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF2D3E50"
android:pathData="M14.4,6L14,4H5v17h2v-7h5.6l0.4,2h7V6z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF2D3E50"
android:pathData="M12,6c1.11,0 2,-0.9 2,-2 0,-0.38 -0.1,-0.73 -0.29,-1.03L12,0l-1.71,2.97c-0.19,0.3 -0.29,0.65 -0.29,1.03 0,1.1 0.9,2 2,2zM16.6,15.99l-1.07,-1.07 -1.08,1.07c-1.3,1.3 -3.58,1.31 -4.89,0l-1.07,-1.07 -1.09,1.07C6.75,16.64 5.88,17 4.96,17c-0.73,0 -1.4,-0.23 -1.96,-0.61L3,21c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1v-4.61c-0.56,0.38 -1.23,0.61 -1.96,0.61 -0.92,0 -1.79,-0.36 -2.44,-1.01zM18,9h-5L13,7h-2v2L6,9c-1.66,0 -3,1.34 -3,3v1.54c0,1.08 0.88,1.96 1.96,1.96 0.52,0 1.02,-0.2 1.38,-0.57l2.14,-2.13 2.13,2.13c0.74,0.74 2.03,0.74 2.77,0l2.14,-2.13 2.13,2.13c0.37,0.37 0.86,0.57 1.38,0.57 1.08,0 1.96,-0.88 1.96,-1.96L20.99,12C21,10.34 19.66,9 18,9z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#FF2D3E50"
android:pathData="M5,16L3,5L8.5,12L12,5L15.5,12L21,5L19,16H5M19,19A1,1 0 0,1 18,20H6A1,1 0 0,1 5,19V18H19V19Z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF2D3E50"
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF2D3E50"
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM15.5,11c0.83,0 1.5,-0.67 1.5,-1.5S16.33,8 15.5,8 14,8.67 14,9.5s0.67,1.5 1.5,1.5zM8.5,11c0.83,0 1.5,-0.67 1.5,-1.5S9.33,8 8.5,8 7,8.67 7,9.5 7.67,11 8.5,11zM12,17.5c2.33,0 4.31,-1.46 5.11,-3.5L6.89,14c0.8,2.04 2.78,3.5 5.11,3.5z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF2D3E50"
android:pathData="M12,7.77L18.39,18H5.61L12,7.77M12,4L2,20h20L12,4z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:alpha="0.54"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM15.5,11c0.83,0 1.5,-0.67 1.5,-1.5S16.33,8 15.5,8 14,8.67 14,9.5s0.67,1.5 1.5,1.5zM8.5,11c0.83,0 1.5,-0.67 1.5,-1.5S9.33,8 8.5,8 7,8.67 7,9.5 7.67,11 8.5,11zM12,17.5c2.33,0 4.31,-1.46 5.11,-3.5L6.89,14c0.8,2.04 2.78,3.5 5.11,3.5z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF2D3E50"
android:pathData="M18.92,6.01C18.72,5.42 18.16,5 17.5,5h-11c-0.66,0 -1.21,0.42 -1.42,1.01L3,12v8c0,0.55 0.45,1 1,1h1c0.55,0 1,-0.45 1,-1v-1h12v1c0,0.55 0.45,1 1,1h1c0.55,0 1,-0.45 1,-1v-8l-2.08,-5.99zM6.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,13 6.5,13s1.5,0.67 1.5,1.5S7.33,16 6.5,16zM17.5,16c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM5,11l1.5,-4.5h11L19,11L5,11z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M16,11c1.66,0 2.99,-1.34 2.99,-3S17.66,5 16,5c-1.66,0 -3,1.34 -3,3s1.34,3 3,3zM8,11c1.66,0 2.99,-1.34 2.99,-3S9.66,5 8,5C6.34,5 5,6.34 5,8s1.34,3 3,3zM8,13c-2.33,0 -7,1.17 -7,3.5L1,19h14v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5zM16,13c-0.29,0 -0.62,0.02 -0.97,0.05 1.16,0.84 1.97,1.97 1.97,3.45L17,19h6v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:alpha="0.54"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M20,5L4,5c-1.1,0 -1.99,0.9 -1.99,2L2,17c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,7c0,-1.1 -0.9,-2 -2,-2zM11,8h2v2h-2L11,8zM11,11h2v2h-2v-2zM8,8h2v2L8,10L8,8zM8,11h2v2L8,13v-2zM7,13L5,13v-2h2v2zM7,10L5,10L5,8h2v2zM16,17L8,17v-2h8v2zM16,13h-2v-2h2v2zM16,10h-2L14,8h2v2zM19,13h-2v-2h2v2zM19,10h-2L17,8h2v2z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF2D3E50"
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:alpha="0.54"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:alpha="0.53"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,7c2.76,0 5,2.24 5,5 0,0.65 -0.13,1.26 -0.36,1.83l2.92,2.92c1.51,-1.26 2.7,-2.89 3.43,-4.75 -1.73,-4.39 -6,-7.5 -11,-7.5 -1.4,0 -2.74,0.25 -3.98,0.7l2.16,2.16C10.74,7.13 11.35,7 12,7zM2,4.27l2.28,2.28 0.46,0.46C3.08,8.3 1.78,10.02 1,12c1.73,4.39 6,7.5 11,7.5 1.55,0 3.03,-0.3 4.38,-0.84l0.42,0.42L19.73,22 21,20.73 3.27,3 2,4.27zM7.53,9.8l1.55,1.55c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.66 1.34,3 3,3 0.22,0 0.44,-0.03 0.65,-0.08l1.55,1.55c-0.67,0.33 -1.41,0.53 -2.2,0.53 -2.76,0 -5,-2.24 -5,-5 0,-0.79 0.2,-1.53 0.53,-2.2zM11.84,9.02l3.15,3.15 0.02,-0.16c0,-1.66 -1.34,-3 -3,-3l-0.17,0.01z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -3,9 +3,9 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".android.contact.ConversationActivity"> tools:context=".android.contact.ConversationActivity">
<android.support.v7.widget.Toolbar <android.support.v7.widget.Toolbar
@@ -24,7 +24,7 @@
<include layout="@layout/contact_avatar_status"/> <include layout="@layout/contact_avatar_status"/>
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/contactName" android:id="@+id/contactName"
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse" style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@@ -38,17 +38,19 @@
</android.support.v7.widget.Toolbar> </android.support.v7.widget.Toolbar>
<org.briarproject.android.util.BriarRecyclerView <org.briarproject.android.view.BriarRecyclerView
android:id="@+id/conversationView" android:id="@+id/conversationView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1"/> android:layout_weight="1"
android:background="@color/window_background"/>
<View style="@style/Divider.Horizontal"/> <org.briarproject.android.view.TextInputView
android:id="@+id/text_input_container"
<include
layout="@layout/text_input_field"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"
android:background="@color/button_bar_background"
android:elevation="@dimen/margin_tiny"
app:hint="@string/message_hint"/>
</LinearLayout> </LinearLayout>

View File

@@ -1,69 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="@dimen/margin_activity_horizontal"
tools:context=".android.blogs.CreateBlogActivity">
<android.support.design.widget.TextInputLayout
android:id="@+id/titleLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:counterEnabled="true"
app:counterOverflowTextAppearance="@style/BriarTextCounter.Overflow">
<android.support.design.widget.TextInputEditText
android:id="@+id/titleInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/blogs_my_blogs_create_hint_title"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/descLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:counterEnabled="true"
app:counterOverflowTextAppearance="@style/BriarTextCounter.Overflow">
<android.support.design.widget.TextInputEditText
android:id="@+id/descInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/blogs_my_blogs_create_hint_desc"/>
</android.support.design.widget.TextInputLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/blogs_my_blogs_create_hint_desc_explanation"/>
<Button
android:id="@+id/createBlogButton"
style="@style/BriarButton"
android:layout_marginTop="@dimen/margin_activity_vertical"
android:enabled="false"
android:text="@string/blogs_my_blogs_create"/>
<ProgressBar
android:id="@+id/createBlogProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_activity_vertical"
android:indeterminate="true"
android:visibility="gone"/>
</LinearLayout>
</ScrollView>

View File

@@ -1,50 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="@dimen/margin_activity_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/choose_nickname"
android:textSize="@dimen/text_size_large"/>
<android.support.design.widget.TextInputLayout
android:id="@+id/nicknameInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:errorEnabled="true">
<EditText
android:id="@+id/nicknameEntry"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:ems="10"
android:inputType="textPersonName"
android:maxLines="1"/>
</android.support.design.widget.TextInputLayout>
<Button
android:id="@+id/createIdentityButton"
style="@style/BriarButton"
android:layout_gravity="center_horizontal"
android:enabled="false"
android:text="@string/create_identity_button"/>
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:indeterminate="true"
android:visibility="gone"/>
</LinearLayout>

View File

@@ -6,16 +6,20 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<org.briarproject.android.util.BriarRecyclerView <org.briarproject.android.view.BriarRecyclerView
android:id="@+id/forum_discussion_list" android:id="@+id/list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" android:layout_weight="1"
app:emptyText="@string/no_forum_posts"
app:scrollToEnd="false"/> app:scrollToEnd="false"/>
<include <org.briarproject.android.view.TextInputView
layout="@layout/text_input_field" android:id="@+id/text_input_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"
android:background="@color/button_bar_background"
android:elevation="@dimen/margin_tiny"
app:hint="@string/forum_new_message_hint"/>
</LinearLayout> </LinearLayout>

View File

@@ -3,14 +3,4 @@
android:id="@+id/fragmentContainer" android:id="@+id/fragmentContainer"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"/>
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="invisible"/>
</FrameLayout>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<org.briarproject.android.util.BriarRecyclerView
android:id="@+id/invitationsView"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
style="@style/BriarToolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/content_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/window_background"/>
</FrameLayout>
</LinearLayout>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".android.privategroup.reveal.RevealContactsActivity">
<FrameLayout
android:id="@+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<Button
android:id="@+id/revealButton"
style="@style/BriarButton"
android:layout_marginEnd="@dimen/margin_small"
android:layout_marginLeft="@dimen/margin_small"
android:layout_marginRight="@dimen/margin_small"
android:layout_marginStart="@dimen/margin_small"
android:text="@string/groups_reveal_contacts"/>
</LinearLayout>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<org.briarproject.android.util.BriarRecyclerView <org.briarproject.android.view.BriarRecyclerView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
android:id="@+id/shareContainer"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

View File

@@ -19,7 +19,7 @@
<View style="@style/Divider.ForumList"/> <View style="@style/Divider.ForumList"/>
<org.briarproject.android.util.BriarRecyclerView <org.briarproject.android.view.BriarRecyclerView
android:id="@+id/sharedByView" android:id="@+id/sharedByView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -36,7 +36,7 @@
<View style="@style/Divider.ForumList"/> <View style="@style/Divider.ForumList"/>
<org.briarproject.android.util.BriarRecyclerView <org.briarproject.android.view.BriarRecyclerView
android:id="@+id/sharedWithView" android:id="@+id/sharedWithView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@@ -1,56 +1,27 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"
android:padding="@dimen/margin_small"
tools:context=".android.blogs.WriteBlogPostActivity"> tools:context=".android.blogs.WriteBlogPostActivity">
<android.support.design.widget.TextInputLayout <org.briarproject.android.view.LargeTextInputView
android:id="@+id/titleLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
app:counterEnabled="true"
app:counterOverflowTextAppearance="@style/BriarTextCounter.Overflow">
<android.support.design.widget.TextInputEditText
android:id="@+id/titleInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/blogs_write_blog_post_title_hint"
android:inputType="textCapWords|textCapSentences|textAutoCorrect"/>
</android.support.design.widget.TextInputLayout>
<EditText
android:id="@+id/bodyInput" android:id="@+id/bodyInput"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="bottom" android:gravity="bottom"
android:hint="@string/blogs_write_blog_post_body_hint" app:buttonText="@string/blogs_publish_blog_post"
android:inputType="textMultiLine|textLongMessage|textCapSentences|textAutoCorrect"> app:hint="@string/blogs_write_blog_post_body_hint"
app:fillHeight="true"/>
<requestFocus/>
</EditText>
<Button
android:id="@+id/publishButton"
style="@style/BriarButton"
android:enabled="false"
android:text="@string/blogs_publish_blog_post"/>
<ProgressBar <ProgressBar
android:id="@+id/progressBar" android:id="@+id/progressBar"
style="?android:attr/progressBarStyle" style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:visibility="gone"/> android:visibility="invisible"/>
</LinearLayout> </FrameLayout>

View File

@@ -9,7 +9,7 @@
style="@style/BriarAvatar" style="@style/BriarAvatar"
android:layout_width="@dimen/blogs_avatar_normal_size" android:layout_width="@dimen/blogs_avatar_normal_size"
android:layout_height="@dimen/blogs_avatar_normal_size" android:layout_height="@dimen/blogs_avatar_normal_size"
android:layout_centerVertical="true" android:layout_alignTop="@+id/authorName"
android:layout_marginRight="@dimen/margin_medium" android:layout_marginRight="@dimen/margin_medium"
tools:src="@drawable/ic_launcher"/> tools:src="@drawable/ic_launcher"/>
@@ -26,18 +26,17 @@
android:visibility="invisible" android:visibility="invisible"
tools:ignore="ContentDescription"/> tools:ignore="ContentDescription"/>
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/authorName" android:id="@+id/authorName"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignTop="@+id/avatar"
android:layout_toEndOf="@+id/avatar" android:layout_toEndOf="@+id/avatar"
android:layout_toRightOf="@+id/avatar" android:layout_toRightOf="@+id/avatar"
android:textColor="@color/briar_text_primary" android:textColor="@color/briar_text_primary"
android:textSize="@dimen/text_size_small" android:textSize="@dimen/text_size_small"
tools:text="Author Name"/> tools:text="Author Name"/>
<org.briarproject.android.util.TrustIndicatorView <org.briarproject.android.view.TrustIndicatorView
android:id="@+id/trustIndicator" android:id="@+id/trustIndicator"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<View
style="@style/Divider.Horizontal"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@color/emoji_pager_background"
android:orientation="horizontal">
<com.astuetz.PagerSlidingTabStrip
android:id="@+id/tabs"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
app:pstsIndicatorColor="@color/briar_accent"
app:pstsIndicatorHeight="@dimen/emoji_drawer_indicator_height"
app:pstsShouldExpand="true"
app:pstsTabPaddingLeftRight="@dimen/emoji_drawer_left_right_padding"/>
<View
android:layout_width="@dimen/margin_separator"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:background="@color/divider"/>
<org.thoughtcrime.securesms.components.RepeatableImageKey
android:id="@+id/backspace"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@color/emoji_pager_background"
android:paddingLeft="@dimen/margin_medium"
android:paddingRight="@dimen/margin_medium"
android:src="@drawable/ic_backspace_black"/>
</LinearLayout>
<View
style="@style/Divider.Horizontal"/>
<android.support.v4.view.ViewPager
android:id="@+id/emoji_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/window_background"
android:visibility="visible"/>
</merge>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<GridView
android:id="@+id/emoji"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:columnWidth="@dimen/emoji_drawer_size"
android:gravity="center"
android:horizontalSpacing="0dp"
android:numColumns="auto_fit"
android:stretchMode="columnWidth"
android:verticalSpacing="0dp"
android:visibility="visible"/>
</FrameLayout>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<org.briarproject.android.util.BriarRecyclerView <org.briarproject.android.view.BriarRecyclerView
android:id="@+id/postList" android:id="@+id/postList"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This is just a placeholder to be replaced by the real My Blogs list -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/num"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:padding="@dimen/margin_activity_horizontal"
android:textSize="128sp"
tools:text="1"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/margin_activity_horizontal"
android:text="There is nothing for you to see here.\n\nMove along and come back later."
android:textSize="@dimen/text_size_large"/>
</LinearLayout>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<org.briarproject.android.util.BriarRecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/contactList"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="@dimen/margin_medium">
<EditText
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="bottom"
android:maxLines="1"
android:inputType="text|textCapSentences"
android:hint="@string/groups_create_group_hint"/>
<Button
android:id="@+id/button"
style="@style/BriarButton"
android:enabled="false"
android:text="@string/groups_create_group_button"/>
</LinearLayout>

View File

@@ -5,11 +5,11 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<org.briarproject.android.util.BriarRecyclerView <org.briarproject.android.view.BriarRecyclerView
android:id="@+id/forumList" android:id="@+id/forumList"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:layout_behavior="org.briarproject.android.util.BriarRecyclerViewBehavior"/> app:layout_behavior="org.briarproject.android.view.BriarRecyclerViewBehavior"/>
</android.support.design.widget.CoordinatorLayout> </android.support.design.widget.CoordinatorLayout>

View File

@@ -21,7 +21,6 @@
android:id="@+id/imageView" android:id="@+id/imageView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_xlarge"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:scaleType="fitCenter" android:scaleType="fitCenter"
android:src="@drawable/qr_code_intro" android:src="@drawable/qr_code_intro"
@@ -42,7 +41,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:padding="@dimen/margin_medium" android:padding="@dimen/margin_medium"
android:src="@drawable/qr_code_explanation"/> android:src="@drawable/qr_code_explanation"
android:contentDescription="@string/face_to_face"/>
<TextView <TextView
style="@style/BriarTextBody" style="@style/BriarTextBody"

View File

@@ -5,15 +5,17 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<org.briarproject.android.util.CameraView <org.briarproject.android.view.CameraView
android:id="@+id/camera_view" android:id="@+id/camera_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"/> android:layout_height="match_parent"/>
<LinearLayout <LinearLayout
android:id="@+id/camera_overlay"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical"
android:weightSum="2">
<FrameLayout <FrameLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -31,9 +33,9 @@
android:visibility="invisible"> android:visibility="invisible">
<ProgressBar <ProgressBar
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"/>
android:paddingTop="@dimen/margin_large"/>
<TextView <TextView
android:id="@+id/connect_status" android:id="@+id/connect_status"
@@ -45,23 +47,50 @@
</LinearLayout> </LinearLayout>
</FrameLayout> </FrameLayout>
<RelativeLayout <FrameLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" android:layout_weight="1"
android:background="@android:color/white"> android:background="@android:color/white">
<ProgressBar <ProgressBar
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerInParent="true" android:layout_gravity="center"/>
android:paddingTop="@dimen/margin_large"/>
<ImageView <ImageView
android:id="@+id/qr_code" android:id="@+id/qr_code"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:scaleType="fitCenter"/> android:scaleType="fitCenter"
</RelativeLayout> android:layout_gravity="center"/>
</LinearLayout> </FrameLayout>
</LinearLayout>
<RelativeLayout
android:id="@+id/container_progress"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:visibility="invisible">
<ProgressBar
android:id="@+id/progress_bar"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/title_progress_bar"
android:layout_centerHorizontal="true"/>
<TextView
android:id="@+id/title_progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:paddingTop="@dimen/margin_large"
tools:text="@string/waiting_for_contact_to_scan"/>
</RelativeLayout>
</FrameLayout> </FrameLayout>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<org.briarproject.android.view.LargeTextInputView
android:id="@+id/messageView"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:buttonText="@string/forum_share_button"
app:fillHeight="true"
app:hint="@string/forum_share_message"/>

View File

@@ -1,21 +1,28 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView <ScrollView
android:id="@+id/scrollView" android:id="@+id/scrollView"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="0dp"
android:layout_weight="1"
android:background="@color/window_background"> android:background="@color/window_background">
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content">
android:padding="@dimen/margin_small">
<include <include
android:id="@+id/postLayout" android:id="@+id/postLayout"
layout="@layout/list_item_blog_post" layout="@layout/list_item_blog_post"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_small"/>
<ProgressBar <ProgressBar
android:id="@+id/progressBar" android:id="@+id/progressBar"
@@ -24,23 +31,17 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerInParent="true"/> android:layout_centerInParent="true"/>
<EditText
android:id="@+id/inputText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/postLayout"
android:layout_margin="@dimen/listitem_vertical_margin"
android:gravity="bottom"
android:hint="@string/blogs_reblog_comment_hint"
android:inputType="textShortMessage|textMultiLine|textCapSentences|textAutoCorrect"/>
<Button
android:id="@+id/publishButton"
style="@style/BriarButton"
android:layout_below="@+id/inputText"
android:enabled="false"
android:text="@string/blogs_reblog_button"/>
</RelativeLayout> </RelativeLayout>
</ScrollView> </ScrollView>
<org.briarproject.android.view.LargeTextInputView
android:id="@+id/inputText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom"
app:buttonText="@string/blogs_reblog_button"
app:maxLines="5"
app:hint="@string/blogs_reblog_comment_hint"/>
</LinearLayout>

View File

@@ -1,41 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/margin_activity_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/introductionText"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="@dimen/margin_medium"
android:layout_weight="1"
android:gravity="top"
android:textSize="@dimen/text_size_medium"
android:textColor="@color/briar_text_primary"
android:text="@string/forum_share_message"/>
<EditText
android:id="@+id/invitationMessageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_medium"
android:gravity="bottom"
android:hint="@string/introduction_message_hint"
android:inputType="text|textMultiLine|textCapSentences"/>
<Button
android:id="@+id/shareForumButton"
style="@style/BriarButton"
android:text="@string/forum_share_button"/>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>

View File

@@ -1,16 +1,22 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fillViewport="true"> android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:orientation="vertical" android:layout_margin="@dimen/margin_activity_horizontal"
android:padding="@dimen/margin_activity_horizontal"> android:orientation="vertical">
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -34,7 +40,7 @@
android:layout_marginStart="@dimen/listitem_horizontal_margin" android:layout_marginStart="@dimen/listitem_horizontal_margin"
tools:src="@drawable/ic_launcher"/> tools:src="@drawable/ic_launcher"/>
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/nameContact1" android:id="@+id/nameContact1"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -74,7 +80,7 @@
android:transitionName="avatar" android:transitionName="avatar"
tools:src="@drawable/ic_launcher"/> tools:src="@drawable/ic_launcher"/>
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/nameContact2" android:id="@+id/nameContact2"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -96,33 +102,25 @@
android:layout_gravity="center" android:layout_gravity="center"
tools:visibility="gone"/> tools:visibility="gone"/>
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/introductionText" android:id="@+id/introductionText"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_medium" android:layout_marginTop="@dimen/margin_activity_horizontal"
android:layout_weight="1"
android:gravity="top"
android:textColor="@color/briar_text_secondary" android:textColor="@color/briar_text_secondary"
android:textSize="@dimen/text_size_medium" android:textSize="@dimen/text_size_medium"
tools:text="@string/introduction_message_text"/> tools:text="@string/introduction_message_text"/>
<EditText </LinearLayout>
</ScrollView>
<org.briarproject.android.view.LargeTextInputView
android:id="@+id/introductionMessageView" android:id="@+id/introductionMessageView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_medium" app:buttonText="@string/introduction_button"
android:gravity="bottom" app:hint="@string/introduction_message_hint"
android:hint="@string/introduction_message_hint" app:maxLines="5"/>
android:inputType="text|textMultiLine|textCapSentences"
android:textColor="@color/briar_text_primary"
android:textColorHint="@color/briar_text_tertiary"/>
<Button
android:id="@+id/makeIntroductionButton"
style="@style/BriarButton"
android:text="@string/introduction_button"/>
</LinearLayout> </LinearLayout>
</android.support.v4.widget.NestedScrollView>

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<org.briarproject.android.util.BriarRecyclerView <org.briarproject.android.view.BriarRecyclerView
android:id="@+id/list"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/contactList"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:listitem="@layout/list_item_contact"/> app:scrollToEnd="false"/>

View File

@@ -8,7 +8,7 @@
android:layout_marginStart="@dimen/listitem_horizontal_margin" android:layout_marginStart="@dimen/listitem_horizontal_margin"
android:background="?attr/selectableItemBackground"> android:background="?attr/selectableItemBackground">
<org.briarproject.android.util.TextAvatarView <org.briarproject.android.view.TextAvatarView
android:id="@+id/avatarView" android:id="@+id/avatarView"
android:layout_width="@dimen/listitem_picture_frame_size" android:layout_width="@dimen/listitem_picture_frame_size"
android:layout_height="@dimen/listitem_picture_frame_size" android:layout_height="@dimen/listitem_picture_frame_size"
@@ -18,7 +18,7 @@
android:layout_marginRight="@dimen/listitem_horizontal_margin" android:layout_marginRight="@dimen/listitem_horizontal_margin"
android:layout_marginTop="@dimen/margin_medium"/> android:layout_marginTop="@dimen/margin_medium"/>
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/nameView" android:id="@+id/nameView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@@ -11,7 +11,7 @@
android:id="@+id/inputDivider" android:id="@+id/inputDivider"
style="@style/Divider.Horizontal"/> style="@style/Divider.Horizontal"/>
<org.briarproject.android.util.AuthorView <org.briarproject.android.view.AuthorView
android:id="@+id/authorView" android:id="@+id/authorView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -20,7 +20,7 @@
android:padding="@dimen/listitem_vertical_margin" android:padding="@dimen/listitem_vertical_margin"
app:persona="commenter"/> app:persona="commenter"/>
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/bodyView" android:id="@+id/bodyView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@@ -19,7 +19,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="@dimen/listitem_vertical_margin"> android:padding="@dimen/listitem_vertical_margin">
<org.briarproject.android.util.AuthorView <org.briarproject.android.view.AuthorView
android:id="@+id/rebloggerView" android:id="@+id/rebloggerView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -29,7 +29,7 @@
android:layout_toLeftOf="@+id/commentView" android:layout_toLeftOf="@+id/commentView"
app:persona="reblogger"/> app:persona="reblogger"/>
<org.briarproject.android.util.AuthorView <org.briarproject.android.view.AuthorView
android:id="@+id/authorView" android:id="@+id/authorView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -50,7 +50,7 @@
android:padding="@dimen/margin_small" android:padding="@dimen/margin_small"
android:src="@drawable/ic_repeat"/> android:src="@drawable/ic_repeat"/>
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/bodyView" android:id="@+id/bodyView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -12,8 +11,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground" android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/listitem_horizontal_margin" android:paddingBottom="@dimen/listitem_horizontal_margin"
android:paddingTop="@dimen/listitem_horizontal_margin" android:paddingTop="@dimen/listitem_horizontal_margin">
>
<FrameLayout <FrameLayout
android:id="@+id/avatarFrameView" android:id="@+id/avatarFrameView"
@@ -59,7 +57,7 @@
android:layout_toRightOf="@+id/avatarFrameView" android:layout_toRightOf="@+id/avatarFrameView"
android:orientation="vertical"> android:orientation="vertical">
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/nameView" android:id="@+id/nameView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -76,15 +74,6 @@
android:textSize="@dimen/text_size_small" android:textSize="@dimen/text_size_small"
tools:text="Dec 24"/> tools:text="Dec 24"/>
<TextView
android:id="@+id/identityView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/tertiary_text_light"
android:textSize="@dimen/text_size_tiny"
android:visibility="gone"
tools:text="My Identity"/>
</LinearLayout> </LinearLayout>
<ImageView <ImageView

View File

@@ -17,7 +17,7 @@
android:layout_marginStart="@dimen/listitem_horizontal_margin" android:layout_marginStart="@dimen/listitem_horizontal_margin"
tools:src="@drawable/ic_launcher"/> tools:src="@drawable/ic_launcher"/>
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/nameView" android:id="@+id/nameView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout
android:id="@+id/msgLayout" android:id="@+id/layout"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@@ -10,8 +10,8 @@
android:background="@drawable/msg_in" android:background="@drawable/msg_in"
android:orientation="vertical"> android:orientation="vertical">
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/msgBody" android:id="@+id/text"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textColor="@color/briar_text_primary" android:textColor="@color/briar_text_primary"
@@ -20,7 +20,7 @@
tools:text="Short message"/> tools:text="Short message"/>
<TextView <TextView
android:id="@+id/msgTime" android:id="@+id/time"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="right|end" android:layout_gravity="right|end"

View File

@@ -7,7 +7,7 @@
android:orientation="vertical"> android:orientation="vertical">
<RelativeLayout <RelativeLayout
android:id="@+id/msgLayout" android:id="@+id/layout"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="right|end" android:layout_gravity="right|end"
@@ -15,8 +15,8 @@
android:layout_marginRight="@dimen/message_bubble_margin_tail" android:layout_marginRight="@dimen/message_bubble_margin_tail"
android:background="@drawable/msg_out"> android:background="@drawable/msg_out">
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/msgBody" android:id="@+id/text"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textColor="@color/briar_text_primary_inverse" android:textColor="@color/briar_text_primary_inverse"
@@ -25,12 +25,12 @@
tools:text="This is a long long long message that spans over several lines.\n\nIt ends here."/> tools:text="This is a long long long message that spans over several lines.\n\nIt ends here."/>
<TextView <TextView
android:id="@+id/msgTime" android:id="@+id/time"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentLeft="true" android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:layout_below="@+id/msgBody" android:layout_below="@+id/text"
android:layout_marginTop="@dimen/message_bubble_timestamp_margin" android:layout_marginTop="@dimen/message_bubble_timestamp_margin"
android:maxLines="1" android:maxLines="1"
android:textColor="@color/private_message_date_inverse" android:textColor="@color/private_message_date_inverse"
@@ -38,13 +38,13 @@
tools:text="Dec 24, 13:37"/> tools:text="Dec 24, 13:37"/>
<ImageView <ImageView
android:id="@+id/msgStatus" android:id="@+id/status"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignBottom="@+id/msgTime" android:layout_alignBottom="@+id/time"
android:layout_marginLeft="@dimen/margin_medium" android:layout_marginLeft="@dimen/margin_medium"
android:layout_toEndOf="@+id/msgTime" android:layout_toEndOf="@+id/time"
android:layout_toRightOf="@+id/msgTime" android:layout_toRightOf="@+id/time"
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
tools:src="@drawable/message_delivered_white"/> tools:src="@drawable/message_delivered_white"/>

View File

@@ -6,8 +6,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/msgBody" android:id="@+id/msgText"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="left|start" android:layout_gravity="left|start"
@@ -20,15 +20,15 @@
tools:text="Short message"/> tools:text="Short message"/>
<RelativeLayout <RelativeLayout
android:id="@+id/noticeLayout" android:id="@+id/layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/message_bubble_margin_tail" android:layout_marginLeft="@dimen/message_bubble_margin_tail"
android:layout_marginRight="@dimen/message_bubble_margin_non_tail" android:layout_marginRight="@dimen/message_bubble_margin_non_tail"
android:background="@drawable/notice_in_bottom"> android:background="@drawable/notice_in_bottom">
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/introductionText" android:id="@+id/text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minWidth="80dp" android:minWidth="80dp"
@@ -39,28 +39,17 @@
tools:text="@string/forum_invitation_received"/> tools:text="@string/forum_invitation_received"/>
<TextView <TextView
android:id="@+id/introductionTime" android:id="@+id/time"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignEnd="@+id/introductionText" android:layout_alignEnd="@+id/text"
android:layout_alignRight="@+id/introductionText" android:layout_alignRight="@+id/text"
android:layout_below="@+id/showInvitationsButton" android:layout_below="@+id/text"
android:layout_marginTop="@dimen/message_bubble_timestamp_margin" android:layout_marginTop="@dimen/message_bubble_timestamp_margin"
android:textColor="@color/private_message_date" android:textColor="@color/private_message_date"
android:textSize="@dimen/text_size_tiny" android:textSize="@dimen/text_size_tiny"
tools:text="Dec 24, 13:37"/> tools:text="Dec 24, 13:37"/>
<Button
android:id="@+id/showInvitationsButton"
style="@style/BriarButtonFlat.Positive"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignEnd="@+id/introductionText"
android:layout_alignRight="@+id/introductionText"
android:layout_below="@+id/introductionText"
android:layout_marginBottom="-15dp"
tools:text="@string/forum_show_invitations"/>
</RelativeLayout> </RelativeLayout>
</LinearLayout> </LinearLayout>

View File

@@ -6,8 +6,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/msgBody" android:id="@+id/msgText"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/message_bubble_margin_non_tail" android:layout_marginLeft="@dimen/message_bubble_margin_non_tail"
@@ -19,15 +19,15 @@
tools:text="This is a long long long message that spans over several lines.\n\nIt ends here."/> tools:text="This is a long long long message that spans over several lines.\n\nIt ends here."/>
<RelativeLayout <RelativeLayout
android:id="@+id/noticeLayout" android:id="@+id/layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/message_bubble_margin_non_tail" android:layout_marginLeft="@dimen/message_bubble_margin_non_tail"
android:layout_marginRight="@dimen/message_bubble_margin_tail" android:layout_marginRight="@dimen/message_bubble_margin_tail"
android:background="@drawable/notice_out_bottom"> android:background="@drawable/notice_out_bottom">
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/introductionText" android:id="@+id/text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textColor="@color/briar_text_secondary" android:textColor="@color/briar_text_secondary"
@@ -37,25 +37,25 @@
tools:text="@string/introduction_request_received"/> tools:text="@string/introduction_request_received"/>
<TextView <TextView
android:id="@+id/introductionTime" android:id="@+id/time"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentLeft="true" android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:layout_below="@+id/introductionText" android:layout_below="@+id/text"
android:layout_marginTop="@dimen/message_bubble_timestamp_margin" android:layout_marginTop="@dimen/message_bubble_timestamp_margin"
android:textColor="@color/private_message_date" android:textColor="@color/private_message_date"
android:textSize="@dimen/text_size_tiny" android:textSize="@dimen/text_size_tiny"
tools:text="Dec 24, 13:37"/> tools:text="Dec 24, 13:37"/>
<ImageView <ImageView
android:id="@+id/introductionStatus" android:id="@+id/status"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignBottom="@+id/introductionTime" android:layout_alignBottom="@+id/time"
android:layout_marginLeft="@dimen/margin_medium" android:layout_marginLeft="@dimen/margin_medium"
android:layout_toEndOf="@+id/introductionTime" android:layout_toEndOf="@+id/time"
android:layout_toRightOf="@+id/introductionTime" android:layout_toRightOf="@+id/time"
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
tools:src="@drawable/message_delivered"/> tools:src="@drawable/message_delivered"/>

View File

@@ -6,8 +6,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/msgBody" android:id="@+id/msgText"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/message_bubble_margin_tail" android:layout_marginLeft="@dimen/message_bubble_margin_tail"
@@ -19,15 +19,15 @@
tools:text="Short message"/> tools:text="Short message"/>
<RelativeLayout <RelativeLayout
android:id="@+id/noticeLayout" android:id="@+id/layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/message_bubble_margin_tail" android:layout_marginLeft="@dimen/message_bubble_margin_tail"
android:layout_marginRight="@dimen/message_bubble_margin_non_tail" android:layout_marginRight="@dimen/message_bubble_margin_non_tail"
android:background="@drawable/notice_in_bottom"> android:background="@drawable/notice_in_bottom">
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/introductionText" android:id="@+id/text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minWidth="80dp" android:minWidth="80dp"
@@ -38,11 +38,11 @@
tools:text="@string/introduction_request_received"/> tools:text="@string/introduction_request_received"/>
<TextView <TextView
android:id="@+id/introductionTime" android:id="@+id/time"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignEnd="@+id/introductionText" android:layout_alignEnd="@+id/text"
android:layout_alignRight="@+id/introductionText" android:layout_alignRight="@+id/text"
android:layout_below="@+id/declineButton" android:layout_below="@+id/declineButton"
android:layout_marginTop="@dimen/message_bubble_timestamp_margin" android:layout_marginTop="@dimen/message_bubble_timestamp_margin"
android:textColor="@color/private_message_date" android:textColor="@color/private_message_date"
@@ -54,9 +54,9 @@
style="@style/BriarButtonFlat.Positive" style="@style/BriarButtonFlat.Positive"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignEnd="@+id/introductionText" android:layout_alignEnd="@+id/text"
android:layout_alignRight="@+id/introductionText" android:layout_alignRight="@+id/text"
android:layout_below="@+id/introductionText" android:layout_below="@+id/text"
android:text="@string/accept"/> android:text="@string/accept"/>
<Button <Button
@@ -64,7 +64,7 @@
style="@style/BriarButtonFlat.Negative" style="@style/BriarButtonFlat.Negative"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/introductionText" android:layout_below="@+id/text"
android:layout_marginBottom="-15dp" android:layout_marginBottom="-15dp"
android:layout_toLeftOf="@+id/acceptButton" android:layout_toLeftOf="@+id/acceptButton"
android:layout_toStartOf="@+id/acceptButton" android:layout_toStartOf="@+id/acceptButton"

View File

@@ -8,16 +8,17 @@
android:layout_marginStart="@dimen/listitem_horizontal_margin" android:layout_marginStart="@dimen/listitem_horizontal_margin"
android:background="?attr/selectableItemBackground"> android:background="?attr/selectableItemBackground">
<org.briarproject.android.util.TextAvatarView <org.briarproject.android.view.TextAvatarView
android:id="@+id/avatarView" android:id="@+id/avatarView"
android:layout_width="@dimen/listitem_picture_frame_size" android:layout_width="@dimen/listitem_picture_frame_size"
android:layout_height="@dimen/listitem_picture_frame_size" android:layout_height="@dimen/listitem_picture_frame_size"
android:layout_alignParentLeft="true" android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginRight="@dimen/listitem_horizontal_margin"/> android:layout_marginRight="@dimen/listitem_horizontal_margin"
android:layout_marginTop="@dimen/listitem_horizontal_margin"/>
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/forumNameView" android:id="@+id/forumNameView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/listitem_horizontal_margin"
android:layout_marginStart="@dimen/listitem_horizontal_margin"
android:background="?attr/selectableItemBackground">
<org.briarproject.android.view.TextAvatarView
android:id="@+id/avatarView"
android:layout_width="@dimen/listitem_picture_frame_size"
android:layout_height="@dimen/listitem_picture_frame_size"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginEnd="@dimen/listitem_horizontal_margin"
android:layout_marginRight="@dimen/listitem_horizontal_margin"
android:layout_marginTop="@dimen/listitem_horizontal_margin"/>
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/nameView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginTop="@dimen/listitem_horizontal_margin"
android:layout_toEndOf="@+id/avatarView"
android:layout_toRightOf="@+id/avatarView"
android:maxLines="2"
android:textColor="@color/briar_text_primary"
android:textSize="@dimen/text_size_medium"
tools:text="This is a name of a Private Group"/>
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/creatorView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/nameView"
android:layout_marginBottom="@dimen/margin_small"
android:layout_toEndOf="@+id/avatarView"
android:layout_toRightOf="@+id/avatarView"
android:paddingTop="@dimen/margin_small"
android:textColor="@color/briar_text_secondary"
android:textSize="@dimen/text_size_small"
tools:text="Created by Santa Claus"/>
<TextView
android:id="@+id/messageCountView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/creatorView"
android:layout_marginBottom="@dimen/margin_small"
android:layout_toEndOf="@+id/avatarView"
android:layout_toRightOf="@+id/avatarView"
android:paddingTop="@dimen/margin_small"
android:textColor="@color/briar_text_secondary"
android:textSize="@dimen/text_size_small"
tools:text="1337 messages"
tools:visibility="visible"/>
<TextView
android:id="@+id/dateView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_below="@+id/creatorView"
android:layout_marginEnd="@dimen/listitem_horizontal_margin"
android:layout_marginRight="@dimen/listitem_horizontal_margin"
android:paddingTop="@dimen/margin_small"
android:textColor="@color/briar_text_secondary"
android:textSize="@dimen/text_size_small"
tools:text="3 weeks ago, 12:00"
tools:visibility="visible"/>
<TextView
android:id="@+id/statusView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/messageCountView"
android:layout_toEndOf="@+id/avatarView"
android:layout_toRightOf="@+id/avatarView"
android:layout_toLeftOf="@+id/removeButton"
android:paddingTop="@dimen/margin_small"
android:textColor="@color/briar_text_tertiary"
tools:text="@string/groups_group_is_empty"/>
<Button
android:id="@+id/removeButton"
style="@style/BriarButtonFlat.Negative"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/divider"
android:layout_alignParentRight="true"
android:text="@string/groups_remove"
tools:visibility="gone"/>
<View
android:id="@+id/divider"
style="@style/Divider.ForumList"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/statusView"
android:layout_marginTop="@dimen/listitem_horizontal_margin"/>
</RelativeLayout>

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_medium"
android:baselineAligned="false"
android:orientation="vertical">
<View
android:id="@+id/top_divider"
style="@style/Divider.ForumList"
android:layout_alignParentTop="true"/>
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/top_divider"
android:layout_marginBottom="@dimen/margin_small"
android:layout_marginRight="@dimen/margin_medium"
android:layout_marginTop="@dimen/margin_medium"
android:textColor="@color/briar_text_secondary"
android:textSize="@dimen/text_size_medium"
android:textStyle="italic"
tools:text="@string/groups_member_joined"/>
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/text"
android:layout_below="@+id/text"
android:layout_marginRight="@dimen/margin_small"
tools:ignore="ContentDescription"
tools:src="@drawable/ic_visibility"/>
<TextView
android:id="@+id/info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignEnd="@+id/text"
android:layout_alignRight="@+id/text"
android:layout_below="@+id/text"
android:layout_toRightOf="@+id/icon"
android:gravity="center_vertical"
android:minHeight="24dp"
android:textColor="@color/briar_text_secondary"
android:textIsSelectable="true"
android:textSize="@dimen/text_size_tiny"
android:textStyle="italic"
tools:text="@string/groups_reveal_visible_revealed_by_contact"/>
<org.briarproject.android.view.AuthorView
android:id="@+id/author"
android:layout_width="wrap_content"
android:layout_height="@dimen/button_size"
android:layout_alignLeft="@+id/text"
android:layout_below="@+id/info"
android:gravity="center"
app:persona="commenter"/>
<Button
android:id="@+id/optionsButton"
style="@style/BriarButtonFlat.Positive.Tiny"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignEnd="@+id/text"
android:layout_alignRight="@+id/text"
android:layout_alignTop="@+id/author"
android:layout_toRightOf="@+id/author"
android:gravity="right|center_vertical"
android:text="@string/options"/>
</RelativeLayout>

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/listitem_horizontal_margin"
android:layout_marginStart="@dimen/listitem_horizontal_margin"
android:paddingTop="@dimen/margin_medium">
<org.briarproject.android.view.AuthorView
android:id="@+id/authorView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginBottom="@dimen/margin_small"
android:layout_marginEnd="@dimen/listitem_horizontal_margin"
android:layout_marginRight="@dimen/listitem_horizontal_margin"
app:persona="list"/>
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/authorView"
android:layout_marginLeft="@dimen/listitem_group_member_indentation"
android:layout_marginRight="@dimen/margin_small"
android:contentDescription="@string/forum_invitation_already_sharing"
android:src="@drawable/ic_visibility"/>
<TextView
android:id="@+id/info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/authorView"
android:layout_marginEnd="@dimen/listitem_horizontal_margin"
android:layout_marginRight="@dimen/listitem_horizontal_margin"
android:layout_toRightOf="@+id/icon"
android:gravity="center_vertical"
android:minHeight="24dp"
android:textColor="@color/briar_text_secondary"
android:textIsSelectable="true"
android:textSize="@dimen/text_size_tiny"
android:textStyle="italic"
tools:text="@string/groups_reveal_visible_revealed_by_us"/>
<View
android:id="@+id/divider"
style="@style/Divider.ContactList"
android:layout_below="@+id/info"
android:layout_marginLeft="@dimen/listitem_group_member_indentation"
android:layout_marginTop="@dimen/margin_medium"/>
</RelativeLayout>

View File

@@ -9,7 +9,7 @@
android:background="?attr/selectableItemBackground" android:background="?attr/selectableItemBackground"
android:paddingTop="@dimen/listitem_horizontal_margin"> android:paddingTop="@dimen/listitem_horizontal_margin">
<org.briarproject.android.util.TextAvatarView <org.briarproject.android.view.TextAvatarView
android:id="@+id/avatarView" android:id="@+id/avatarView"
android:layout_width="@dimen/listitem_picture_frame_size" android:layout_width="@dimen/listitem_picture_frame_size"
android:layout_height="@dimen/listitem_picture_frame_size" android:layout_height="@dimen/listitem_picture_frame_size"
@@ -18,7 +18,7 @@
android:layout_marginRight="@dimen/listitem_horizontal_margin" android:layout_marginRight="@dimen/listitem_horizontal_margin"
/> />
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/forumNameView" android:id="@+id/forumNameView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -31,7 +31,7 @@
android:textSize="@dimen/text_size_medium" android:textSize="@dimen/text_size_medium"
tools:text="This is a name of a forum that is available"/> tools:text="This is a name of a forum that is available"/>
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/sharedByView" android:id="@+id/sharedByView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/notice_in"
android:orientation="vertical"
android:layout_marginLeft="@dimen/message_bubble_margin_tail"
android:layout_marginRight="@dimen/message_bubble_margin_non_tail">
<TextView
android:id="@+id/noticeText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textIsSelectable="true"
android:textSize="@dimen/text_size_medium"
android:textStyle="italic"
android:textColor="@color/briar_text_secondary"
tools:text="@string/introduction_response_accepted_received"/>
<TextView
android:id="@+id/noticeTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|end"
android:layout_marginTop="@dimen/message_bubble_timestamp_margin"
android:maxLines="1"
android:textColor="@color/private_message_date"
android:textSize="@dimen/text_size_tiny"
tools:text="Dec 24, 13:37"/>
</LinearLayout>

View File

@@ -1,52 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|end"
android:background="@drawable/notice_out"
android:layout_marginLeft="@dimen/message_bubble_margin_non_tail"
android:layout_marginRight="@dimen/message_bubble_margin_tail">
<TextView
android:id="@+id/noticeText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textIsSelectable="true"
android:textSize="@dimen/text_size_medium"
android:textStyle="italic"
android:textColor="@color/briar_text_secondary"
tools:text="@string/introduction_response_accepted_sent"/>
<TextView
android:id="@+id/noticeTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/message_bubble_timestamp_margin"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/noticeText"
android:textColor="@color/private_message_date"
android:textSize="@dimen/text_size_tiny"
tools:text="Dec 24, 13:37"/>
<ImageView
android:id="@+id/noticeStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/noticeTime"
android:layout_marginLeft="@dimen/margin_medium"
android:layout_toEndOf="@+id/noticeTime"
android:layout_toRightOf="@+id/noticeTime"
tools:ignore="ContentDescription"
tools:src="@drawable/message_delivered"/>
</RelativeLayout>
</LinearLayout>

View File

@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:orientation="vertical"
android:padding="@dimen/listitem_horizontal_margin">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/avatarView"
style="@style/BriarAvatar"
android:layout_width="@dimen/listitem_selectable_picture_size"
android:layout_height="@dimen/listitem_selectable_picture_size"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginEnd="@dimen/listitem_horizontal_margin"
android:layout_marginRight="@dimen/listitem_horizontal_margin"
android:transitionName="avatar"
tools:src="@drawable/ic_launcher"/>
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/nameView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/avatarView"
android:textColor="@color/briar_text_primary"
android:textSize="@dimen/text_size_large"
tools:text="Revealable Contact"/>
<ImageView
android:id="@+id/visibilityView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/nameView"
android:layout_marginRight="@dimen/margin_small"
android:layout_toRightOf="@+id/avatarView"
android:src="@drawable/ic_visibility"
tools:ignore="ContentDescription"/>
<TextView
android:id="@+id/infoView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/nameView"
android:layout_toLeftOf="@+id/checkBox"
android:layout_toRightOf="@+id/visibilityView"
android:gravity="center_vertical"
android:text="@string/groups_reveal_visible"
android:textColor="@color/briar_text_tertiary"
android:textSize="@dimen/text_size_small"
tools:visibility="visible"/>
<CheckBox
android:id="@+id/checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:clickable="false"/>
</RelativeLayout>
<View style="@style/Divider.ContactList"/>
</LinearLayout>

View File

@@ -9,7 +9,7 @@
android:layout_marginTop="@dimen/listitem_horizontal_margin" android:layout_marginTop="@dimen/listitem_horizontal_margin"
android:background="?attr/selectableItemBackground"> android:background="?attr/selectableItemBackground">
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/titleView" android:id="@+id/titleView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -41,7 +41,7 @@
android:textColor="@color/briar_text_secondary" android:textColor="@color/briar_text_secondary"
android:textSize="@dimen/text_size_small"/> android:textSize="@dimen/text_size_small"/>
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/authorView" android:id="@+id/authorView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -100,7 +100,7 @@
android:textSize="@dimen/text_size_small" android:textSize="@dimen/text_size_small"
tools:text="5 min. ago"/> tools:text="5 min. ago"/>
<TextView <org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/descriptionView" android:id="@+id/descriptionView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"

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