Compare commits

...

750 Commits

Author SHA1 Message Date
Alan Evans
68aa97a676 Bump version to 5.7.5 2021-04-09 17:01:16 -03:00
Alan Evans
20bb07e829 Updated language translations. 2021-04-09 16:59:21 -03:00
Alan Evans
53b6cc21b1 Make call to desugared classes from ApplicationContext indirect for API19.
Fixes #11185
2021-04-09 16:48:49 -03:00
Alan Evans
96a80f0ed2 Bump version to 5.7.4 2021-04-09 15:34:19 -03:00
Alan Evans
9ebb150b68 Updated language translations. 2021-04-09 15:19:02 -03:00
Alan Evans
4ae7312c7f Use correct currency position for all locales. 2021-04-09 12:33:16 -03:00
Alan Evans
113393de8f Enforce upper bound on MobileCoin/fiat entry. 2021-04-09 11:17:50 -03:00
Greyson Parrelli
5daa027c10 Disallow SMS/MMS sends to UUID-only recipients. 2021-04-09 10:13:00 -04:00
Alan Evans
7394b4ac27 Bump version to 5.7.3 2021-04-08 19:58:30 -03:00
Alan Evans
1259da01a5 Updated language translations. 2021-04-08 19:27:38 -03:00
Alex Hart
86a8cd29e5 Fix issue preventing user from entering fiat value. 2021-04-08 12:00:41 -03:00
Alex Hart
bfc84d50dd Always show scrollbar on create payment screen if there is scrollable content. 2021-04-08 11:39:31 -03:00
Alan Evans
af060f52e1 Place fee after estimated fiat. 2021-04-08 09:45:29 -03:00
Alex Hart
f87fc1d639 Fix activate getting cut off in activation dialog. 2021-04-08 09:13:09 -03:00
Alan Evans
6ddfbcb945 Bump version to 5.7.2 2021-04-07 19:33:39 -03:00
Alan Evans
d4f11867a8 Updated language translations. 2021-04-07 19:31:28 -03:00
Alan Evans
759f30244a Remove unnecessary sorts. 2021-04-07 18:02:55 -03:00
Greyson Parrelli
fcc49ae7b6 Limit the directory refresh in response to system contact changes.
Previously, we would do a full directory/CDS refresh in response to any
change in system contacts. That can be expensive.

This changes the behavior to look at how many new contacts there after
being notified of a contact change.

- If there aren't any, we just sync names and stuff.
- If we just have a few new contacts, we'll sync just those specifically.
- If we have a lot, we'll do a full sync.
2021-04-07 17:45:51 -03:00
Alex Hart
1aa8e9753d Fix aspect ratio with info icon on API 21 devices. 2021-04-07 17:45:51 -03:00
Alex Hart
f400504898 Fix issue where formatted mnemonic with newlines would fail even though it looks correct. 2021-04-07 15:32:38 -03:00
Alex Hart
41e6097ac5 Fix issue resulting in crash when re-entering Recovery Phrase screen. 2021-04-07 15:10:50 -03:00
Alex Hart
8e4b08b493 Do not modify amount immediately after toggle. 2021-04-07 14:59:07 -03:00
Alex Hart
df948179d8 Wrap add_money layout in ScrollView. 2021-04-07 14:00:22 -03:00
Greyson Parrelli
7b3aa43217 Fix issue with GV1 deprecation and rotate feature flag. 2021-04-07 10:29:36 -04:00
Alex Hart
e42fe5349b Add proper payments icon in AttachmentKeyboard 2021-04-07 09:43:45 -03:00
Alan Evans
1f578ebd2c Bump version to 5.7.1 2021-04-06 20:21:56 -03:00
Alan Evans
b80875773f Updated language translations. 2021-04-06 20:17:22 -03:00
Alan Evans
3caebb8613 Enable Java8 core library desugaring. 2021-04-06 19:54:18 -03:00
Alan Evans
24ac705fe8 Bump version to 5.7.0 2021-04-06 17:09:00 -03:00
Alan Evans
57acdd4b21 Updated language translations. 2021-04-06 17:07:19 -03:00
Android Team
fddba2906a Payments.
Co-authored-by: Alan Evans <alan@signal.org>
Co-authored-by: Alex Hart <alex@signal.org>
Co-authored-by: Cody Henthorne <cody@signal.org>
2021-04-06 17:07:19 -03:00
Android Team
c42023855b Service support for Payments.
Co-authored-by: Alan Evans <alan@signal.org>
Co-authored-by: Alex Hart <alex@signal.org>
Co-authored-by: Cody Henthorne <cody@signal.org>
2021-04-06 15:27:23 -03:00
Hugo Kiehl
dd38dd9cae Fixing notification image preview. 2021-04-06 15:27:23 -03:00
Cody Henthorne
5f0341cd53 Fix calling PIP stuck when calls ends on device lock screen.
Fixes #11090
2021-04-06 11:34:20 -04:00
Cody Henthorne
e3d3129e6d Bump version to 5.6.3 2021-04-05 16:11:03 -04:00
Cody Henthorne
ed8b6c6bc9 Updated language translations. 2021-04-05 16:09:10 -04:00
Cody Henthorne
2218fc0d41 Start call service as foreground for notification actions. 2021-04-05 16:09:04 -04:00
Greyson Parrelli
b8cbcfe986 Prevent crash when reading cursor in DirectoryHelper.
The cause of the crash is very unclear. Our best guess at present is
that the cursor is unable to fit a single row within the 2mb allocation
window, and therefore can't read anything. In this case, the best we can
do is catch the exception and develop some future fallback. Logging the
exception will also mean that maybe we'll be able to get the actual
exception message.
2021-04-05 15:52:30 -04:00
Cody Henthorne
dbc5f5bfcc Fix bluetooth ringing for outgoing calls. 2021-04-05 15:44:58 -04:00
Greyson Parrelli
33cb02b9e4 Disallow GV1 group edits when GV1 is disabled. 2021-04-05 15:25:41 -04:00
Cody Henthorne
8783d150e8 Fix potential OOM when updating shortcuts. 2021-04-05 14:21:32 -04:00
Cody Henthorne
449ea9375e Fix old device locked dialog crash. 2021-04-05 14:10:54 -04:00
Cody Henthorne
d5a73a3380 Bump version to 5.6.2 2021-04-02 15:29:01 -04:00
Cody Henthorne
173dd180d9 Updated language translations. 2021-04-02 15:29:01 -04:00
Cody Henthorne
f332cbf1bc Fix state exception by always starting call service in foreground. 2021-04-02 15:29:01 -04:00
Cody Henthorne
c4d317b33e Fix crash when bluetooth is unavailable for calling. 2021-04-02 13:09:06 -04:00
Cody Henthorne
9c59d6a69b Use english help categories for email filter. 2021-04-02 12:42:10 -04:00
Alex Hart
61bdd4e027 Bump version to 5.6.1 2021-04-01 16:58:59 -03:00
Alex Hart
ab2efe78b1 Updated language translations. 2021-04-01 16:58:59 -03:00
Cody Henthorne
c3af3e4740 Fix rounded corners for messages with a quote and small link preview. 2021-04-01 16:58:59 -03:00
Alex Hart
6418eac658 Prevent crash in forwarding captioned audio message to multiple recipients. 2021-04-01 10:33:40 -03:00
Alex Hart
d74e9f7410 Bump version to 5.6.0 2021-03-31 16:02:32 -03:00
Alex Hart
569c83d90e Updated language translations. 2021-03-31 16:02:32 -03:00
Cody Henthorne
1dc3cf7824 Move calling management out of service. 2021-03-31 16:02:32 -03:00
Cody Henthorne
d8dead82b6 Improve Call Notification UX when things don't go as planned. 2021-03-31 16:02:32 -03:00
Greyson Parrelli
b053fbc4a7 Use Log.tag where appropriate. 2021-03-31 16:02:32 -03:00
Cody Henthorne
2144dc3b67 Fix call ringtone not playing on some custom ROMs and Samsung Android 11 devices. 2021-03-31 16:02:32 -03:00
Alex Hart
243b4b9414 Refactor ContactsCursorLoader to implement factory pattern.
Utilization of the factory pattern will enable us to more easily change what contacts we present to the user for a specific screen in the future instead of continuing to modify and potentially introduce bugs to this screen.
2021-03-31 16:02:32 -03:00
Greyson Parrelli
e068fde8f2 Improve efficiency of bulk receipt processing.
If there were N receipts for a single thread, we were previously
updating that thread N times.

This change bundles updates together so we will only update each thread
once after all receipts in a bundle are processed.
2021-03-31 16:02:32 -03:00
Greyson Parrelli
3162f04937 Update mute options.
2 hours -> 8 hours
1 year -> Always

These options should make way more sense, and existing mute settings
will continue to be respected.
2021-03-31 16:02:32 -03:00
Greyson Parrelli
58a32c11ec Disable inline message processing for internal users. 2021-03-31 16:02:32 -03:00
Fumiaki Yoshimatsu
f06817f00d Account for grapheme cluster when trimming to fit a specific length.
Fixes #10076
2021-03-31 16:02:32 -03:00
Greyson Parrelli
da4be5c1cf Allow recipient cache to refresh inline while in a transaction. 2021-03-31 16:02:32 -03:00
Cody Henthorne
a59f5d953a Fix bug during registration when self exists already without an e164. 2021-03-31 16:02:32 -03:00
Cody Henthorne
815a988587 Prevent crash when trying to save conversation viewing position. 2021-03-31 16:02:32 -03:00
Cody Henthorne
b65d9ffaed Fix KitKat crash when showing cell service warning during registration. 2021-03-31 16:02:32 -03:00
Cody Henthorne
0fc73c3a6f Remove Group Calling feature flag. 2021-03-31 16:02:31 -03:00
Cody Henthorne
57fdc1b223 Include pin reminder preference in settings backup. 2021-03-23 10:34:56 -04:00
Fumiaki Yoshimatsu
22d5fc6cba Fix shape of message bubbles in RTL langauges.
Fixes #9894
2021-03-23 08:58:33 -04:00
Sgn-32
c36f9646f9 Fix bugs with RTL languages and showing/entering backup code.
Fixes #10193
Fixes #10195
2021-03-22 15:52:05 -04:00
Fumiaki Yoshimatsu
45e11f6291 Fix continue arrow icon for RTL.
Fixes #10914.
2021-03-22 15:50:43 -04:00
Fumiaki Yoshimatsu
2893c3dc0e Fix RTL bug in lockscreen timeout dialog.
Fixes #9892
2021-03-22 15:50:09 -04:00
Cody Henthorne
116022b01d Install gradle as part of docker image build. 2021-03-22 15:49:46 -04:00
Chris Eager
09cba8774d Add support for verification codes without an internal hyphen 2021-03-19 14:38:30 -05:00
Greyson Parrelli
41129f7c50 Add tracing to a few critical jobs. 2021-03-19 09:28:04 -04:00
Greyson Parrelli
44d014c445 Bump version to 5.5.5 2021-03-18 11:24:29 -04:00
Greyson Parrelli
51e086b20e Updated language translations. 2021-03-18 11:24:09 -04:00
Greyson Parrelli
d71a5c99f4 Fix crash in migration job retries. 2021-03-18 11:18:08 -04:00
Greyson Parrelli
fb0243a029 Fix issue with websocket connection after reregistering.
Big shoutout to @jonahbeckford for the investigation here. Thanks!

Fixes #10939
Fixes #11095
2021-03-18 11:07:34 -04:00
Greyson Parrelli
713441d9cb Bump version to 5.5.4 2021-03-17 19:11:15 -04:00
Greyson Parrelli
451f0fd12b Updated language translations. 2021-03-17 19:10:53 -04:00
Cody Henthorne
5a84fa5a80 Fix device transfer stall if screen is locked during transfer. 2021-03-17 16:46:25 -04:00
Greyson Parrelli
751ba8d1c2 Bump version to 5.5.3 2021-03-17 14:12:40 -04:00
Greyson Parrelli
974ed439a4 Updated language translations. 2021-03-17 14:12:40 -04:00
Greyson Parrelli
0172c1e385 Prevent crashing on duplicate gv1 storage records. 2021-03-17 14:12:40 -04:00
Cody Henthorne
faa19acf81 Include additional settings in backup. 2021-03-17 14:12:40 -04:00
Cody Henthorne
1f9afb6c6e Use new Signal logo for more notifications. 2021-03-17 14:12:40 -04:00
Cody Henthorne
5d96bc2d3a Allow choose backup restore flow to work on pre-API29 devices. 2021-03-17 14:12:40 -04:00
Cody Henthorne
9366596f5f Fix discrepancy in message counting between export and import backups. 2021-03-17 14:12:40 -04:00
Cody Henthorne
cb6e3ade15 Fix bug where transfer continues when stopped from new device. 2021-03-17 14:12:40 -04:00
Cody Henthorne
45178b3eb3 Keep old device inactive after a successful transfer. 2021-03-17 14:12:40 -04:00
Greyson Parrelli
31e3e37c9b Improve logging for remapped recipients. 2021-03-16 15:57:14 -04:00
Alan Evans
e1489bb407 Exclude junit brought in by spongycastle. 2021-03-16 14:25:09 -03:00
Greyson Parrelli
8b50d8645a Add back private PlayStoreUtil constructor.
It was taken out in a public PR, thought I added it back in, but
apparently didn't.
2021-03-16 11:35:18 -04:00
Greyson Parrelli
796fdb1cf6 Bump version to 5.5.2 2021-03-16 10:52:56 -04:00
Greyson Parrelli
5203d40804 Updated language translations. 2021-03-16 10:45:43 -04:00
Yannick Verdie
21252aad0f Request storage permission when adding additional media. 2021-03-16 10:45:31 -04:00
Alex Hart
0c535904fc Restart activity in onNewIntent if activity is not yet initialized. 2021-03-16 11:37:40 -03:00
Cody Henthorne
490944a02a Improve UI/UX around device transfer. 2021-03-16 10:18:02 -04:00
Greyson Parrelli
ace85df9b7 Use US locale for log dates. 2021-03-16 10:00:04 -04:00
Alex Hart
9e56441d4a Fix several issues with contact name syncing. 2021-03-16 10:52:59 -03:00
Alan Evans
d83c3d35eb Ensure Job factories pass the parameters to their created Jobs. 2021-03-16 10:07:21 -03:00
Alan Evans
8f26d63d6f System name split migration. 2021-03-16 09:55:57 -03:00
Alan Evans
75c520097a Gradle witness checksums. 2021-03-15 19:54:12 -03:00
Leptopoda
38375982dd Don't ask for Play Store rating in website builds. 2021-03-15 12:35:57 -04:00
Greyson Parrelli
d24a71bbd2 Bump version to 5.5.1 2021-03-13 11:56:33 -05:00
Greyson Parrelli
7964c9fca7 Updated language translations. 2021-03-13 11:55:57 -05:00
Greyson Parrelli
ec07e4b233 Avoid possibility of walking outside a contact cursor. 2021-03-13 11:50:10 -05:00
Greyson Parrelli
b4266b8575 Fix contact sync issues where structured names are absent. 2021-03-13 11:29:57 -05:00
Greyson Parrelli
07201203b2 Add a category dropdown in the help fragment. 2021-03-12 22:56:56 -05:00
Greyson Parrelli
e7c5eb93dd Default OkHttp feature flag to 'true'. 2021-03-12 19:22:18 -05:00
Greyson Parrelli
e70229c672 Bump version to 5.5.0 2021-03-12 16:08:22 -05:00
Greyson Parrelli
86c5b28562 Updated language translations. 2021-03-12 16:08:22 -05:00
Cody Henthorne
a9149c5dc0 Stop backup jobs from continuing to run if backups become disabled.
Fixes #10819
2021-03-12 16:08:22 -05:00
Alan Evans
a64430c65f Make the foreground delay configurable. Remove short initial delay. 2021-03-12 16:08:22 -05:00
Cody Henthorne
75aab4c031 Add Device to Device Transfer UI. 2021-03-12 16:08:22 -05:00
Greyson Parrelli
6f8be3260c Do not mark dirty when updating profile key during storage sync. 2021-03-12 10:30:05 -05:00
Cody Henthorne
e74460bd91 Enable TLS connection and SAS verification between device transfer server and client. 2021-03-12 10:30:05 -05:00
Greyson Parrelli
c25250cb05 Include background restriction status in the logs. 2021-03-12 10:30:05 -05:00
Alan Evans
42c3cc5296 Do not insert empty group updates for non-internal users. 2021-03-12 10:30:05 -05:00
Greyson Parrelli
e4b3f90457 Log total time for conversation to render. 2021-03-12 10:30:05 -05:00
Greyson Parrelli
992b04f8c5 Add more logging around threads in message sends. 2021-03-12 10:30:05 -05:00
Alan Evans
d1e0f3646a Remove unused gradle file. 2021-03-08 13:50:34 -04:00
Fumiaki Yoshimatsu
b4ba565923 Purge view cache when layout direction is changed. 2021-03-08 12:13:32 -05:00
Fumiaki Yoshimatsu
006e7dc736 Fix reply and forward icons in RTL.
These vector drawables are `autoMirrored=true` but the attribute does
not work correctly due to [a known Android bug](https://issuetracker.google.com/issues/37138973).
This fix is to work around the bug.

Fixes #11006.
2021-03-08 12:12:48 -05:00
Greyson Parrelli
5ed6407ea3 No longer use a lock for RecipientCache.getSelf()
First, the only lock we can use for the time being is the database lock,
because if we use some other lock we could deadlock.

That said, it seems like we could avoid using a lock at all. The purpose
of the lock was to eliminate double-lookups, but if we have to acquire
the database lock to check if we need to do the lookup, we've lost the
advantage of doing so at all.

We *could* just do a traditional check-lock-check pattern to get the
lock far less often, but given that we're likely going to acquire it
during startup, even a single access has the possibility of really
gumming up the works.
2021-03-08 09:48:28 -05:00
Jon Chambers
faf6b5a4e4 Use a new serviceID for the re-deployed KBS setup in staging. 2021-03-05 14:11:50 -05:00
Greyson Parrelli
f92891895e Add foundation for automated performance tests. 2021-03-05 13:54:57 -05:00
Jonah Beckford
d8cc3c86b4 Correct check for null test. 2021-03-04 10:54:33 -04:00
Cody Henthorne
e7f233db5b Add Device Transfer via WiFi Direct groundwork. 2021-03-03 16:03:49 -05:00
Alex Hart
fd9c420dc8 Split system names into first / last. 2021-03-03 09:37:30 -04:00
Jim Gustafson
dc9fceb8cf Update to RingRTC v2.9.4 2021-03-02 11:09:55 -08:00
Cody Henthorne
dc9b8169c0 Make thread related utility methods available for use in all modules. 2021-03-02 11:07:04 -05:00
Greyson Parrelli
38caf1e2b7 Update ShortcutBadger to 1.1.22 2021-03-02 11:07:04 -05:00
Greyson Parrelli
4b3e7c8858 Remove SELF_LOCK from LiveRecipientCache.
Had the potential to deadlock if accessed inside of a database
transaction.
2021-03-02 11:07:04 -05:00
Alan Evans
2be3068675 Bump version to 5.4.12 2021-03-02 11:29:35 -04:00
Alan Evans
682e47c7b3 Updated language translations. 2021-03-02 11:29:07 -04:00
Greyson Parrelli
8c90c3ad81 Update notification megaphone behavior.
Detect when they've blocked the channel group, and also don't snooze the
megaphone unless they hit 'not now'.
2021-03-02 10:08:02 -05:00
Alan Evans
d5afcc4aec Bump version to 5.4.11 2021-03-01 10:54:29 -04:00
Alan Evans
14ed4201c0 Updated language translations. 2021-03-01 10:54:29 -04:00
Greyson Parrelli
1b9efeb049 Go back to using a reentrant lock for store operations. 2021-03-01 09:38:33 -05:00
Greyson Parrelli
4b862cf4c7 Bump version to 5.4.10 2021-02-26 15:24:41 -05:00
Greyson Parrelli
4e7683961e Updated language translations. 2021-02-26 15:24:04 -05:00
Greyson Parrelli
ce9d44d010 Move back to async message processing. 2021-02-26 15:24:04 -05:00
Greyson Parrelli
32d052259f Fix MessageContentProcessor logging. 2021-02-26 15:24:04 -05:00
Greyson Parrelli
fb98874948 Fix initialization of BlobProvider. 2021-02-26 15:24:04 -05:00
Cody Henthorne
55a62ead05 Avoid API 10 issues with androidx.biometric usage. 2021-02-26 15:24:03 -05:00
Alan Evans
f81f50646e Add share hint for sharing group link. 2021-02-25 18:09:36 -04:00
Alan Evans
f707c1d02c Bump version to 5.4.9 2021-02-25 16:03:26 -04:00
Alan Evans
417c04bf1c Updated language translations. 2021-02-25 16:02:16 -04:00
Greyson Parrelli
8f7f836598 Add logging around the message processing lock. 2021-02-25 15:56:16 -04:00
Surith Thekkiam
32aea8d154 Recommend Docker have 5GB memory available.
Co-authored-by: Alan Evans <alan@signal.org>
2021-02-25 14:16:59 -04:00
Alan Evans
3f6c8cb622 Prevent showing notification megaphone if not translated. 2021-02-25 14:16:59 -04:00
Greyson Parrelli
8f6ff215aa Show a megaphone when notifications are disabled. 2021-02-25 12:54:23 -05:00
Greyson Parrelli
4f01bacb49 Add recipient protections and logging to media send flow. 2021-02-25 12:19:58 -05:00
Alan Evans
e6f4b0976f Prevent double tap send on camera first flow.
Defensive array list copies where used in builders and Intent#putParcelableArrayListExtra.

Spelling.
2021-02-25 12:33:39 -04:00
Cody Henthorne
e0d9c3f149 Fix duplicate showing of new biometric lock dialog. 2021-02-25 11:25:52 -05:00
Greyson Parrelli
9d3cebf430 Fix possible NPE in ConversationListAdapter. 2021-02-25 09:29:29 -05:00
Greyson Parrelli
5e106bf510 Prevent possible NPE when handling early message content. 2021-02-25 09:29:29 -05:00
Angelo Trevisiol
fc617fb7a9 Fixes sharing empty messages via Invite Friends.
Fixes #10817
2021-02-25 09:17:18 -05:00
Alan Evans
b88ecb6370 Add "Enter your phone number" string for translation. 2021-02-25 10:06:46 -04:00
Greyson Parrelli
9b21001953 Remove research megaphone feature flag. 2021-02-24 20:23:36 -05:00
Greyson Parrelli
cb0e10c7ab Inline group migration job feature flag. 2021-02-24 20:18:10 -05:00
Greyson Parrelli
69884935f3 Inline manual group migration feature flag. 2021-02-24 20:17:01 -05:00
Greyson Parrelli
b809008291 Bump version to 5.4.8 2021-02-24 16:36:41 -05:00
Greyson Parrelli
79e77f871e Updated language translations. 2021-02-24 16:36:15 -05:00
Greyson Parrelli
32ac6e3429 Ensure blobs from old sessions are deleted before creating new ones.
There was a race condition where if you created a blob super-early in
the application lifecycle, you could create it *before* we deleted the
blobs from the previous session, leading you to lose the blob you just
created immediately.

In an effort to protect our cold start time, I just made a little
initialization flow where read/write calls to BlobProvider will block
until it's deleted blobs from the old session.
2021-02-24 16:04:58 -05:00
Alan Evans
da56c2790f Ensure no typing indicators can be sent to self or blocked recipients. 2021-02-24 16:04:29 -05:00
Fumiaki Yoshimatsu
687192f071 Fix crash when draft text is null.
Fixes #10913
2021-02-24 15:29:39 -05:00
Fumiaki Yoshimatsu
2e82ee0aaf Fix leaking cursor in Contact Selection list. 2021-02-24 15:28:53 -05:00
Fumiaki Yoshimatsu
4dacf4e342 Fix reaction overlay not showing on first try in RTL mode.
The view needs to request a call to `fitsSystemWindows`; otherwise it
cannot determine where to layout itself within the parent that uses
fitsSystemWindows method to determine the boundary of it.

This fixes the issue reported in [the beta 5.3 forum](https://community.signalusers.org/t/beta-feedback-for-the-upcoming-android-5-3-release/25088/315).
2021-02-24 15:09:31 -05:00
Cody Henthorne
b91f04316a Fix lint errors and add submodules to qa checks. 2021-02-24 15:07:56 -05:00
Fumiaki Yoshimatsu
3c4252a933 Enable lock screen fallback when biometric authentications may not work.
Fixes #9407
Fixes #10166
2021-02-24 08:54:25 -05:00
Alan Evans
be4b687e48 Always delete all messages when deleting a conversation. 2021-02-23 23:59:53 -04:00
Greyson Parrelli
8950100bd7 Decrypt and process messages all in one transaction.
Giddy up
2021-02-23 18:34:18 -05:00
Alan Evans
d651716d99 Remove two AsyncTasks. 2021-02-23 12:48:20 -04:00
Sgn-32
270606699b Do not send typing indicators in Note to Self.
Fixes #10988
2021-02-22 18:07:56 -04:00
Greyson Parrelli
cc7617a302 Throttle conversation list update frequency.
Reduces the load on the database (and UI jankiness) while processing a
large message backlog.
2021-02-22 11:48:41 -05:00
Cody Henthorne
c04b5f2085 Fix tint for bubbled conversation up icon. 2021-02-20 14:59:48 -05:00
Greyson Parrelli
28f3ded4bd Perform individual decryptions inside a database transaction.
Required a lot of random locking work to prevent deadlocking, but
overall this results in about a 2x speed increase for decryptions.
2021-02-20 14:45:36 -05:00
Greyson Parrelli
d56607a686 Log when screen lock toggle changes. 2021-02-20 14:45:36 -05:00
Greyson Parrelli
f8dde57133 Add notification settings to debuglogs. 2021-02-20 14:45:36 -05:00
Greyson Parrelli
f2ea13a142 Bump libsignal-client to 0.1.6 2021-02-20 14:45:36 -05:00
Greyson Parrelli
69a1fa0d3c Remove database transaction protections for job manager interactions.
Now that the JobDatabase is a separate physical database, we no longer
have to worry about people enqueuing jobs while in a transaction.
2021-02-20 14:45:36 -05:00
Greyson Parrelli
5cb54b9ad7 Only sync contact names in contact syncs. 2021-02-20 14:45:36 -05:00
Cody Henthorne
ee610cadd3 Bump version to 5.4.7 2021-02-19 13:29:31 -05:00
Cody Henthorne
acf131308b Updated language translations. 2021-02-19 13:29:31 -05:00
Cody Henthorne
c591ec3185 Fix bug with dropped ice candidates when receiving a call. 2021-02-19 13:07:20 -05:00
Cody Henthorne
264a245d27 Bump version to 5.4.6 2021-02-17 15:08:16 -05:00
Cody Henthorne
f6c25d2a8b Updated language translations. 2021-02-17 15:08:16 -05:00
Greyson Parrelli
d069d9331c Perform additional URI validation in ShareRepository.
Thanks to Shivasurya <s5sankar@uwaterloo.ca> for reporting this issue!
2021-02-17 15:07:37 -05:00
Greyson Parrelli
ba14031945 Revert "Perform additional URI validation in ShareRepository."
This reverts commit 04b7cb15cc.
2021-02-17 15:07:37 -05:00
Cody Henthorne
0b639e0169 Attempt to calculate orientation without magnetic field sensor data when it's missing. 2021-02-17 12:48:47 -05:00
Greyson Parrelli
afee8631e1 Do not compress stickers. 2021-02-17 12:33:38 -05:00
Cody Henthorne
214cb25d1b Fix crash when receiving call with no corresponding identity key. 2021-02-17 10:26:45 -05:00
Greyson Parrelli
a1457d22d6 Do not show recipient tooltip for the share flow. 2021-02-17 08:31:59 -05:00
Greyson Parrelli
82107e2938 Do not show GV1 manual migration if you don't have the capability. 2021-02-17 08:29:58 -05:00
Greyson Parrelli
e2f5fa6962 Bump version to 5.4.5 2021-02-16 17:45:06 -05:00
Greyson Parrelli
74336041ea Updated language translations. 2021-02-16 17:45:06 -05:00
Greyson Parrelli
0dea5eb779 Log both current and original priority for FCM messages. 2021-02-16 17:45:06 -05:00
Greyson Parrelli
267f759452 Fix possible crash during NotificationChannels initialization. 2021-02-16 17:45:06 -05:00
Greyson Parrelli
2779d7efc5 Target the middle of the screen when jumping to a message. 2021-02-16 17:45:06 -05:00
Greyson Parrelli
04b7cb15cc Perform additional URI validation in ShareRepository. 2021-02-16 17:38:05 -05:00
Cody Henthorne
eba04eb75b Revert "Fix reaction overlay not showing on first try in RTL mode."
This reverts commit 424979d91f.
2021-02-13 19:50:32 -05:00
Greyson Parrelli
d924fc92ab Improve accuracy of decryption drained constraint. 2021-02-12 22:42:01 -05:00
Greyson Parrelli
69de830a10 Fix conversation search bar tint. 2021-02-12 20:09:24 -05:00
Alan Evans
60b9811e08 Bump version to 5.4.4 2021-02-12 17:56:01 -04:00
Alan Evans
01418c0e36 Upgrade notification channels earlier. 2021-02-12 17:38:39 -04:00
Cody Henthorne
3f374eebc2 Bump version to 5.4.3 2021-02-12 15:48:45 -05:00
Cody Henthorne
502a2ead00 Updated language translations. 2021-02-12 15:47:56 -05:00
Alan Evans
0d9490e1fb Force disabling of foreground notification vibration. 2021-02-12 16:33:06 -04:00
Cody Henthorne
4afb459b30 Revert "Bump libsignal-client to 0.2.3"
This reverts commit 8b7506ed2d.
2021-02-12 15:03:37 -05:00
Greyson Parrelli
37f4557fef Fix status bar color on Android 5.x. 2021-02-12 14:53:40 -05:00
Fumiaki Yoshimatsu
424979d91f Fix reaction overlay not showing on first try in RTL mode.
Moved the code that does some layouts according to the view's layout direction to the place where we can safely use the value from getLayoutDirection().

This fixes the issue reported in [the beta 5.3 forum](https://community.signalusers.org/t/beta-feedback-for-the-upcoming-android-5-3-release/25088/315).
2021-02-12 14:53:14 -05:00
Greyson Parrelli
527fbee41e Improve experience of populating migration dialog. 2021-02-12 11:42:20 -05:00
Cody Henthorne
1935b0ebdd Do not show message notifications if disabled in settings. 2021-02-12 11:09:51 -05:00
Alan Evans
f6aaef1434 Ensure MessageProcessReceiver pending result finished is called timely. 2021-02-12 11:24:12 -04:00
Alan Evans
050b59f09d Increase maximum zoom level for small images. 2021-02-12 10:36:03 -04:00
Greyson Parrelli
db8dcf6073 Fix conversation banner layout issues. 2021-02-11 21:48:23 -05:00
Cody Henthorne
c45002d5b6 Bump version to 5.4.2 2021-02-11 16:19:28 -05:00
Cody Henthorne
3cd9f0ffef Updated language translations. 2021-02-11 16:18:44 -05:00
Greyson Parrelli
d065a6f563 Make max image dimensions a round number. 2021-02-11 13:59:02 -05:00
Greyson Parrelli
49d7a032fb Improve network reliability. 2021-02-11 13:53:48 -05:00
Greyson Parrelli
80f3504098 Move BlobProvider storage out of cache and into internal storage. 2021-02-11 13:26:12 -05:00
Greyson Parrelli
37d971859b Bump Lottie version to 3.6.0
Should hopefully fix an NPE we're seeing.
2021-02-11 12:35:16 -05:00
Greyson Parrelli
2a5bed1d21 Update chat wallpaper preview toolbar colors. 2021-02-11 11:59:47 -05:00
Cody Henthorne
0927914c57 Fix RTL padding issue for conversation items. 2021-02-11 11:47:37 -05:00
Greyson Parrelli
dda0e0393e Ensure a job has a context before we fail it. 2021-02-11 11:43:21 -05:00
Greyson Parrelli
cc9be7b61e Update long message activity toolbar color. 2021-02-11 11:37:50 -05:00
Greyson Parrelli
2751076089 Archive sessions on 409/410 instead of deleting them. 2021-02-11 10:43:04 -05:00
Greyson Parrelli
2a3f85008b Do not use View.getLayoutDirection().
This value doesn't populate until after the first layout pass. Instead,
it appears to be safer to just read it from the Configuration.
2021-02-11 10:41:40 -05:00
Alan Evans
432a732e7c Shorten message processor foreground service delay to resolve ANR. 2021-02-11 11:36:32 -04:00
Cody Henthorne
dc6045ca8b Fix crash when running shortcut update job on older APIs. 2021-02-11 10:36:02 -05:00
Greyson Parrelli
b58b0fd7a8 Fix boundaries of conversation banners in landscape. 2021-02-11 09:53:05 -05:00
Greyson Parrelli
5e122353e1 Fix landscape boundaries of conversation activity. 2021-02-11 00:58:49 -05:00
Greyson Parrelli
fc41fb5014 Bump version to 5.4.1 2021-02-11 00:09:33 -05:00
Greyson Parrelli
99477c8eef Updated language translations. 2021-02-11 00:05:58 -05:00
Greyson Parrelli
f50466f779 Fix NPE in AppForegroundObserver. 2021-02-11 00:05:58 -05:00
Greyson Parrelli
eb79300fe2 Lighten and unify toolbar shadows. 2021-02-10 22:05:09 -05:00
Greyson Parrelli
b35c96b0b6 Fix banner position issues. 2021-02-10 18:25:35 -05:00
Cody Henthorne
2282cd12d7 Bump version to 5.4.0 2021-02-10 15:30:47 -05:00
Cody Henthorne
0cbe992912 Updated language translations. 2021-02-10 15:26:29 -05:00
Alan Evans
98cb6b457c Periodic alarm to check for messages. 2021-02-10 15:21:04 -05:00
Greyson Parrelli
29d66f2b92 Remove unused signaling key code. 2021-02-10 15:21:04 -05:00
Greyson Parrelli
763a12dbc6 Ensure we only have one IncomingMessageObserver.
We saw a worrisome log that implied there may be a situation where
there's two IncomingMessageObservers. I can't see how that would happen,
but this is a failsafe to prevent that from happening.
2021-02-10 15:21:04 -05:00
Greyson Parrelli
158f3d898f Fail an enqueued job if its dependencies already failed.
This was a bug that was most notable during the attachment pre-upload
process: if an attachment failed to upload, the subsequently-enqueued
PushMediaSendJob would still send. This is because the attachment jobs
were enqueued first and failed *before* we enqueued the PushMediaSendJob
as a dependency.

This will use the JobTracker to determine if a dependency already failed
at the time of enqueueing a job like this. This isn't perfect, because
the JobTracker is memory-only and has a limited buffer (currently 1000),
but in practice this should be sufficient for our use cases. I imagine
it'd only fall apart if we somehow  enqueued a dependent job *much*
later, or somehow enqueued it based on a job ID that we persisted on
disk through an app restart. We don't do any of these things, currently,
and probably never should.

Also took the opportunity to patch a case where we weren't failing
dependent jobs when canceling a job, since I was giving the failure
stuff a look-over.
2021-02-10 15:21:03 -05:00
Cody Henthorne
b935999548 Fix timestamp and size for attachment saves. 2021-02-10 15:21:03 -05:00
Fumiaki Yoshimatsu
2cca6a5afb Check if the content uri already exists and rename the file until it's valid to insert.
Fixes #10159
2021-02-10 15:21:03 -05:00
Greyson Parrelli
2954c31b5f Fix issue where group sent transcripts were not put in proper processing queue. 2021-02-10 15:21:03 -05:00
Alan Evans
6c2d21125e Fix missing UUID crash, get group recipients direct from V2 group record. 2021-02-10 15:21:03 -05:00
Greyson Parrelli
59d69192c6 Disable conversation shortcuts when screen lock is enabled. 2021-02-10 15:21:03 -05:00
Greyson Parrelli
937a288cee Switch to a standard toolbar color.
* Switch to a standard toolbar color.

* T r a n s p a r e n c y

* Add back a toolbar shadow.

* Some more theming

* Also fix verify identity screen.

* Hide shadow on empty conversations.

* Slightly less transparent.
2021-02-10 15:21:03 -05:00
Greyson Parrelli
236e1ba885 Updated image compression parameters. 2021-02-10 09:16:42 -05:00
Greyson Parrelli
3bdf2e7e2c Add a system to improve app foreground observation.
There was previously a crash that occurred when multiple threads tried to use ProcessLifecycleOwner, and this will hopefully resolve that.
2021-02-08 15:37:45 -05:00
Fumiaki Yoshimatsu
a160af2d11 Adds some breathing space in the button caption.
Fix to a bug reported in the [beta forum](https://community.signalusers.org/t/beta-feedback-for-the-upcoming-android-5-3-release/25088/353)
2021-02-08 14:28:37 -05:00
AsamK
341a31da00 Fix crash from incoming call without contacts permission.
When the device is in Do Not Disturb mode and a call comes in from a
system contact, the app crashes if the user has revoked the contacts
permission.
The crash occurs because in Do Not Disturb mode Signal tries to check if
the contact is starred.
2021-02-08 14:28:19 -05:00
AsamK
e0128e7e31 Fix crash when changing contact color without contacts permission.
On mulit-device app, after the contact color is changed, a multi-device
contact update job is triggered, which tries to access the system
avatar.
This causes a crash if the user has revoked the contacts permission.
2021-02-08 14:27:49 -05:00
AsamK
8f51bdcb78 Adapt maxInstancesForQueue to only consider instances of the same job.
Currently the maxInstancesForQueue limit checks the count of all jobs in a
given queue. If there are already too many jobs, the new job is discarded.

However this is not the expected behavior for the two jobs where it's used:
GroupCallPeekWorkerJob and AutomaticSessionResetJob
For both the expected behavior is that there aren't too many jobs of them
started, but that there will be at least one instance of them started.
Both of them use the same queue as the PushProcessMessageJob and the MarkerJob.
Those two jobs are often in the queue at the same time, effectively preventing
the GroupCallPeekWorkerJob and AutomaticSessionResetJob from being enqueued.
2021-02-08 14:26:59 -05:00
Greyson Parrelli
53dc5bab43 Fix text overlapping on edit proxy screen. 2021-02-08 11:34:35 -05:00
Greyson Parrelli
8f86de1764 Add transparency to the compose bar when wallpaper is present. 2021-02-05 16:18:21 -05:00
Alex Hart
133a7d2576 Dismiss reactions when read on linked devices.
Also sends out read receipts for read reactions.

At present, only iPad is sending these -- desktop still needs to add send support.
2021-02-05 16:15:05 -05:00
Jack Lloyd
8b7506ed2d Bump libsignal-client to 0.2.3 2021-02-05 15:18:56 -05:00
Greyson Parrelli
c378e4413e Include git hash in debuglog. 2021-02-05 15:18:11 -05:00
Greyson Parrelli
f3182ddbc6 Fix success dialog in proxy edit screen. 2021-02-05 11:51:17 -05:00
Greyson Parrelli
951d4ad06f Prevent narrow race condition when resetting network components. 2021-02-05 11:40:58 -05:00
Alex Hart
2678a00781 Apply proper rotation to buttons and video in landscape. 2021-02-05 11:40:03 -05:00
Greyson Parrelli
e6e8786d86 Bump version to 5.3.12 2021-02-03 17:57:26 -05:00
Greyson Parrelli
1ec3782f64 Updated language translations. 2021-02-03 17:57:03 -05:00
Greyson Parrelli
a4ec31eebe Increase thread string length to 5 in logs. 2021-02-03 17:17:14 -05:00
Greyson Parrelli
94b631ccfe Add some description to the proxy settings screen. 2021-02-03 16:40:21 -05:00
Greyson Parrelli
26d8df5ea9 Change migration prompt from 'update' to 'upgrade'. 2021-02-03 16:04:01 -05:00
Greyson Parrelli
0569d0555f Improve proxy link parsing. 2021-02-03 16:04:01 -05:00
Alan Evans
3e2349c4ff Use matching color for read conversation sender names. 2021-02-03 16:04:01 -05:00
Greyson Parrelli
af7e736de9 Use a simple check to verify proxies during registration. 2021-02-03 16:04:01 -05:00
Greyson Parrelli
51879a9c46 Allow proxy deep links during registration. 2021-02-03 16:04:01 -05:00
Greyson Parrelli
524f3d6d08 Add support for sgnl:// proxy deep links. 2021-02-03 16:04:01 -05:00
Greyson Parrelli
64fe78ff9a Clean up several UX interactions with proxy entry. 2021-02-03 16:04:01 -05:00
Greyson Parrelli
e798f3f276 Add additional debug info for internal users. 2021-02-03 13:06:11 -05:00
Alan Evans
ddb04c6ea3 Do not linkify message body if recipient is not message request accepted.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2021-02-03 11:45:44 -05:00
Greyson Parrelli
213ffdab62 Bump version to 5.3.11 2021-02-02 20:35:14 -05:00
Greyson Parrelli
60354b2f1f Updated language translations. 2021-02-02 20:35:14 -05:00
AsamK
4bb214cb2a Configure keep alive duration for okhttp connection pool to 1 minute.
The signal http server supports http keep alive, but closes idle
connections after 1 minute.
The default OkHttp connection pool will keep idle connections in the pool
for 5 minutes and doesn't notice it when the server closes connections.
As currently the automatic okhttp retries are disabled, reusing such a
stale connection will be fatal.

Issue is especially severe for incoming calls, which fail because the request
to retrieve the turn servers fails and isn't retried: #10787
2021-02-02 20:35:14 -05:00
Greyson Parrelli
cfd4399685 Remove conversation update min width. 2021-02-02 20:32:52 -05:00
Greyson Parrelli
30563ed3e5 Allow using a proxy during registration. 2021-02-02 20:32:52 -05:00
Greyson Parrelli
46344776a4 Add UI support for configuring a proxy. 2021-02-02 16:42:47 -05:00
Cody Henthorne
0d215d609b Fix empty conversation update item text.
For some reason, if an EmojiTextView has a wrap content width and some other set of conditions occur, the view will not request a relayout when text changes.
This change inelegantly calls request layout more often to prevent that from happening.
2021-02-02 14:50:08 -05:00
Alan Evans
c15ea8c0b4 Skip automigration of nameless groups. 2021-02-02 15:30:20 -04:00
Alan Evans
d6061fb699 Fix migration of null titled group. 2021-02-02 15:19:06 -04:00
Moxie Marlinspike
7f2b6178d5 Add support for configuring a signal proxy. 2021-02-01 21:52:01 -05:00
Greyson Parrelli
53177bf40e Clean up unnecessary GCM stuff, improve FCM logging. 2021-02-01 20:56:25 -05:00
Greyson Parrelli
857b945410 Fix storage sync issue related to duplicate remote contacts.
The theory is that if multiple remote keys map to the *same* local
entry, then when we go to update the local contact the second time, we
won't find the entry by StorageID, because we changed it during the
*first*  update, which will then lead to a crash.

This change makes it so dupes are considered invalid, so we'll delete
them and upload our own local copy.
2021-02-01 18:06:33 -05:00
Alan Evans
904593c103 Add additional logging for conflict resolution. 2021-02-01 13:01:34 -04:00
Cody Henthorne
dcfa7e3b36 Allow contact support from registration lock and screen lock screens. 2021-02-01 11:58:33 -05:00
Alan Evans
589f345825 Fix unnecessary zeros padding. 2021-02-01 12:47:31 -04:00
Greyson Parrelli
0b7c22886d Fix issue where reaction shade is offset in chat bubbles.
Fixes #10843
2021-02-01 10:23:41 -05:00
Greyson Parrelli
e9e2846532 Force custom emojis for about views. 2021-02-01 09:44:12 -05:00
Greyson Parrelli
e0fc191883 Bump version to 5.3.10 2021-01-30 11:29:44 -05:00
Greyson Parrelli
b2ecd89a71 Updated language translations. 2021-01-30 11:29:44 -05:00
Greyson Parrelli
9ed95a6081 Revert "Fix wallpaper in landscape mode with notched devices."
This reverts commit 0b62bb8168.
2021-01-30 11:29:44 -05:00
Greyson Parrelli
3f51f89d86 Update libphonenumber to v8.12.17 2021-01-30 11:04:54 -05:00
Greyson Parrelli
01778f718a Bump version to 5.3.9 2021-01-29 18:35:44 -05:00
Greyson Parrelli
7d5ddd8eac Updated language translations. 2021-01-29 18:35:44 -05:00
Alan Evans
2447601219 Use stable ids on conversation list.
Fixes #10853
2021-01-29 18:35:44 -05:00
Greyson Parrelli
701e43c13d Do a normal message fetch in FcmReceiveService#onDeleteMessages() 2021-01-29 18:35:44 -05:00
Alex Hart
bbbccccf47 Fix crash when READ_PHONE_STATE is denied. 2021-01-29 18:22:32 -05:00
Alex Hart
1e9ca0a9bf Fix bad navigation for icon in ConversationActivity toolbar. 2021-01-29 18:22:32 -05:00
Alex Hart
0b62bb8168 Fix wallpaper in landscape mode with notched devices. 2021-01-29 18:22:32 -05:00
Greyson Parrelli
4f9f62992f Bump version to 5.3.8 2021-01-28 18:58:45 -05:00
Greyson Parrelli
1938d6cae0 Updated language translations. 2021-01-28 18:57:17 -05:00
Greyson Parrelli
13e8c55781 Delete duplicated internal preference. 2021-01-28 18:51:42 -05:00
Greyson Parrelli
6264f9b585 Have a much longer backoff maximum for 5xx errors. 2021-01-28 18:51:42 -05:00
Greyson Parrelli
4482bfcabb Ensure NonSuccessfulReponseCodeException knows the response code. 2021-01-28 18:51:42 -05:00
Alan Evans
015088a53f Fix registration issue where pin box is left disabled. 2021-01-28 18:51:42 -05:00
Alan Evans
ef7d707432 Fix wallpaper preview layout for longer text. 2021-01-28 18:44:04 -05:00
Alan Evans
d1f6a924fb Allow block of any recipient except MMS groups still. 2021-01-28 18:44:04 -05:00
Alan Evans
f312757daf Fix potential Base64 < 4 characters crash on group invite. 2021-01-28 18:44:04 -05:00
Greyson Parrelli
1d83729e6c Move backoff calculation into jobs. 2021-01-28 18:44:04 -05:00
Alan Evans
6a45858b4a Replace Firebase ML vision with built in face detection. 2021-01-28 18:44:04 -05:00
Alex Hart
1b448c2bdf Move reaction overlay UI into a stub. 2021-01-27 16:34:59 -04:00
Alan Evans
f6cd190245 Prevent warnings about multiple substitutions in non-positional format. 2021-01-27 12:32:10 -04:00
Alan Evans
23303e5407 Show name of message sender for groups in conversation list. 2021-01-27 11:53:31 -04:00
Alan Evans
b5237848e9 Restore pinned chats on archive undo. 2021-01-27 11:52:32 -04:00
Alan Evans
7cac0c9a7c UUID is now returned always. 2021-01-27 11:52:32 -04:00
Jim Gustafson
9dbbe4675f Update to RingRTC v2.9.0
Co-authored-by: Alex Hart <alex@signal.org>
2021-01-27 11:52:32 -04:00
Greyson Parrelli
95978f16e9 Possible fix to getting thrown to the bottom while reading unreads.
Shoutout to @fumiakiy for the excellent research here!

Sometimes we get thrown to the bottom of the list (or other list
locations) when reading content in the middle of the list. Most often,
this happens when you have a lot of unread messages and you open the
conversation.

FixedSizePagingController#onDataNeededAroundIndex() can be called very
fast in rapid succession, and we use the DataStatus class for
bookkeeping to know which requests are in-flight. We then make those
requests in LIFO order in order to make sure that the data visible on
screen now gets the highest priority.

...But in practice, that LIFO ordering can make things a little screwy.
Imagine we called onDataNeedAroundIndex() 50 times in rapid succession
(1, 2..., 50). Each time it's called, we generate a range and mark that
range as being fetched in DataStatus. That could mean that the latest
request for index 50 might only have, like, 1 item in it, because a
previously-enqueued fetch already got assigned most of it's data.

BUT we execute the nearly-empty request for index 50 first because of the
LIFO ordering. We give that data to RecyclerView first, and it doesn't like
that at all, and it jumps to weird places because we gave it mostly
null values, which are rendered as placeholder values (which are smaller
than real cells). So then, when we give it the real data right after,
its position is all off.

I switched to a serial executor. That prevents us from giving back weird
lists. The consequence is that if you scroll super fast, you run the
risk of the executor getting 'backed up' fetching data that's offscreen.
However, in practice, I couldn't trigger this. We'll see how it goes. I
think the true solution is a smarter way of fetching and ordering
requests, but that gets to be really tricky from a threading
perspective, and I'd rather keep things simple.
2021-01-27 11:52:32 -04:00
Alan Evans
d055bba452 Lint to prevent glide log usage. 2021-01-27 11:52:32 -04:00
Greyson Parrelli
8ef809a02b Only cluster updates of the same type together. 2021-01-27 11:52:32 -04:00
Alex Hart
458941f952 Enable dither on the gradient painter. 2021-01-27 11:52:32 -04:00
Greyson Parrelli
5852a508aa Bump version to 5.3.7 2021-01-27 10:17:53 -05:00
Greyson Parrelli
e2b4995fbb Updated language translations. 2021-01-27 10:17:20 -05:00
Greyson Parrelli
a3556d9f68 Ensure passphrases are disabled for all but the oldest users. 2021-01-27 10:10:26 -05:00
Greyson Parrelli
fe890a1a41 Added some additional logging around About. 2021-01-27 10:09:07 -05:00
Greyson Parrelli
c06bb18249 Fix navigation bar theming issue.
Fixes #10772
2021-01-27 09:09:56 -05:00
Greyson Parrelli
9099969b41 Bump version to 5.3.6 2021-01-25 18:14:14 -05:00
Greyson Parrelli
6358f59f67 Updated language translations. 2021-01-25 18:13:49 -05:00
Greyson Parrelli
073034dd3c Update logic on deciding whether to bulk animate stickers. 2021-01-25 13:57:24 -05:00
Alan Evans
17fb815805 Prevent duplicate member UUIDs in groups.
Fixes #10702
2021-01-25 13:06:15 -04:00
Alan Evans
409e7c41b4 Restore group update message "Loading" text. 2021-01-25 12:58:24 -04:00
Alan Evans
b9a1a5027c Fix rotation locked after voice record cancel and allow rotation when recording locked. 2021-01-25 12:46:49 -04:00
Alan Evans
49535f6378 Fix initial LiveData value for recipients. 2021-01-25 12:30:21 -04:00
Greyson Parrelli
c058452605 Bump version to 5.3.5 2021-01-24 17:50:40 -05:00
Greyson Parrelli
b3511dba77 Updated language translations. 2021-01-24 17:40:44 -05:00
Greyson Parrelli
afbe27c55f Revert "Bump libsignal-client to 0.2.2"
This reverts commit ce156c3450.
2021-01-24 17:40:44 -05:00
Greyson Parrelli
41d227207d Fix author title on remote deleted group messages. 2021-01-24 17:40:44 -05:00
Greyson Parrelli
92b586c061 Disable mass APNG animation on low-memory devices. 2021-01-24 17:40:44 -05:00
Greyson Parrelli
acbc17c909 Bump version to 5.3.4 2021-01-24 03:35:56 -05:00
Greyson Parrelli
15f17747ee Updated language translations. 2021-01-24 03:35:56 -05:00
Greyson Parrelli
781054fc9d Switch dark theme bubbles with wallpaper to grey_95 instead of black. 2021-01-24 03:35:56 -05:00
Greyson Parrelli
b59769a30a Do not allow saving pending media. 2021-01-24 03:10:03 -05:00
Greyson Parrelli
26e0e09e24 Update padding and margins on conversation updates. 2021-01-24 03:07:49 -05:00
Greyson Parrelli
3a2990a911 Fix crash when sharing stickers you don't have installed. 2021-01-24 02:33:24 -05:00
Greyson Parrelli
d8060b3041 Fix inset issues in landscape. 2021-01-24 02:22:09 -05:00
Greyson Parrelli
f42ec5318f Bump version to 5.3.3 2021-01-23 18:58:48 -05:00
Greyson Parrelli
bd0d425cbf Updated language translations. 2021-01-23 18:58:48 -05:00
Greyson Parrelli
b3d5d7c33e Move cursor to end of text field after select About preset. 2021-01-23 18:58:48 -05:00
Greyson Parrelli
1746869dc3 Fix issue with rendering of group update timestamps.
TIL SimpleDateFormat is not thread safe.
Across instances.

God forgive them, for they know not what they did.
2021-01-23 18:48:14 -05:00
Greyson Parrelli
633f4cbbe5 Disable 'loading' update message. 2021-01-23 18:48:14 -05:00
Greyson Parrelli
0944e2f758 Apply contact list SMS filter to 'recents' section. 2021-01-23 18:48:14 -05:00
Alex Hart
b49e4004ab Restrict SMS in multishare. 2021-01-23 18:48:14 -05:00
Greyson Parrelli
68381f8b64 Fix text color of recent conversations in share activity. 2021-01-23 18:48:14 -05:00
Greyson Parrelli
f180066058 Disallow link previews in multi-forward when sending to SMS. 2021-01-23 15:31:48 -05:00
Greyson Parrelli
6b7de2e85e Make voice note play button visible in wallpaper mode. 2021-01-23 15:20:58 -05:00
Greyson Parrelli
c650a978e9 Update styling of last seen divider. 2021-01-23 15:02:11 -05:00
Greyson Parrelli
e05cadafe6 Collapse adjacent conversation updates. 2021-01-23 14:55:19 -05:00
Greyson Parrelli
c6008a4f90 Disable forwarding of pending media. 2021-01-23 13:39:13 -05:00
Greyson Parrelli
5624855eba Make ManageProfileActivity work with screen lock. 2021-01-23 13:27:37 -05:00
Greyson Parrelli
799ff86fc0 Fixed tinting of wallpaper bubble previews. 2021-01-23 13:18:53 -05:00
Greyson Parrelli
798fc84e82 Fix issue where empty about could be rendered in contact list. 2021-01-23 12:56:00 -05:00
Greyson Parrelli
cc363a3c88 Fix wallpaper sizing issues in landscape. 2021-01-23 12:41:29 -05:00
Greyson Parrelli
6fdaef1f58 Bump version to 5.3.2 2021-01-22 23:44:10 -05:00
Greyson Parrelli
6db6c93295 Updated language translations. 2021-01-22 23:43:45 -05:00
Greyson Parrelli
4fb0f30d32 Add bubbles around additional elements in wallpaper mode. 2021-01-22 23:36:42 -05:00
Greyson Parrelli
7fa4eb079b Improve responsiveness of conversation update rendering. 2021-01-22 23:36:42 -05:00
Greyson Parrelli
c5392b8844 Fix highlighted bounds of conversation items. 2021-01-22 23:36:42 -05:00
Greyson Parrelli
e460973957 Various wallpaper UX fixes. 2021-01-22 23:36:42 -05:00
Greyson Parrelli
e1c6311a18 Fix bug where dates weren't rendered properly after wallpaper change. 2021-01-22 23:36:42 -05:00
Greyson Parrelli
ed11e2f05a Center-align About text in recipient settings. 2021-01-22 23:36:42 -05:00
Greyson Parrelli
3182e5af88 Fix spacing bug when About is set to only text or only emoji. 2021-01-22 23:36:42 -05:00
Greyson Parrelli
5cfdf626fe Reduce the font size of all update messages. 2021-01-22 23:36:42 -05:00
Alex Hart
e55834d523 Prevent NPE in PhoneNumberFormatter. 2021-01-22 23:36:42 -05:00
Greyson Parrelli
9d5a52a980 Made setting a profile photo a synchronous operation. 2021-01-22 23:36:42 -05:00
Alan Evans
5649c906a5 Do not bump group threads on leave. 2021-01-22 23:36:42 -05:00
Greyson Parrelli
ee548d27e5 Made setting profile name and About synchronous operations. 2021-01-22 23:36:42 -05:00
Greyson Parrelli
1dc737b5e5 Increase max About glyphs to 140. 2021-01-22 23:36:42 -05:00
Greyson Parrelli
427869d4ca Various improvements to About UI/UX. 2021-01-22 23:36:42 -05:00
Greyson Parrelli
36395ced89 Add About presets. 2021-01-22 23:36:42 -05:00
Greyson Parrelli
52a9f2c893 Add the ability to clear about and emoji. 2021-01-22 10:29:52 -05:00
Greyson Parrelli
bd88be2513 Auto-open keyboard on About screen. 2021-01-22 10:17:06 -05:00
Alan Evans
7107c1d6b2 Add Taqbaylit language support. 2021-01-22 10:59:42 -04:00
Alan Evans
51f4a343c9 Add Odia ଓଡ଼ିଆ language support. 2021-01-22 10:54:21 -04:00
Alex Hart
a12ee1b78b Update copy for reset all wallpapers dialog. 2021-01-22 09:42:24 -04:00
Alex Hart
4bf59a55da Distinguish clear copy between global and single recipient wallpapers. 2021-01-22 09:40:05 -04:00
Alex Hart
dbac9bf9f6 Enable 'dim in dark theme' by default. 2021-01-22 09:13:12 -04:00
Alex Hart
b95083fe92 Fix sticker support in multishare. 2021-01-22 09:01:38 -04:00
Alan Evans
e2d297eb8a Skip native LibSignal tests on unsupported and non-unix OS. 2021-01-22 00:34:41 -04:00
Greyson Parrelli
a3176bbb67 Bump version to 5.3.1 2021-01-21 22:52:31 -05:00
Greyson Parrelli
4203dde151 Updated language translations. 2021-01-21 22:52:08 -05:00
Greyson Parrelli
880661710f Fix possible NPE in group list item. 2021-01-21 22:47:30 -05:00
Greyson Parrelli
d844fa0fb5 Fix possible NPE on wallpaper change. 2021-01-21 22:47:30 -05:00
Greyson Parrelli
18ede2e900 Bump version to 5.3.0 2021-01-21 18:29:56 -05:00
Greyson Parrelli
06cc96bee7 Updated language translations. 2021-01-21 18:29:15 -05:00
Greyson Parrelli
43a12d2a81 Refine incognito keyboard setting string. 2021-01-21 18:22:05 -05:00
Michael Crenshaw
0a29ffcf4c Update incognito keyboard copy. 2021-01-21 18:17:35 -05:00
Thore Goebel
9c88532c21 Add ripple to review storage button. 2021-01-21 18:04:56 -05:00
Martin d'Allens
f3450b8f10 Center the terms link on the welcome fragment for long translations. 2021-01-21 18:02:20 -05:00
Alan Evans
a4d56e376f Allow clicking on typer avatar to bring up their bottom sheet details. 2021-01-21 18:02:20 -05:00
ascendingSun
24b5bac589 Fix camera crash when mic permission is granted.
Fixes #10642
2021-01-21 18:02:19 -05:00
Greyson Parrelli
762f17f1c1 Install a new animated sticker pack. 2021-01-21 18:02:19 -05:00
Greyson Parrelli
105c8c9745 Fix issue where forwarded link previews weren't marked uploaded. 2021-01-21 18:02:19 -05:00
Alan Evans
93d99287eb Wallpaper preview size respects device aspect ratio. 2021-01-21 18:02:19 -05:00
Jack Lloyd
ce156c3450 Bump libsignal-client to 0.2.2 2021-01-21 18:02:19 -05:00
Greyson Parrelli
7db16e6156 Add support for an 'About' field on your profile. 2021-01-21 18:02:19 -05:00
Alex Hart
e80033c287 Fix several issues with local expandable pip. 2021-01-21 18:02:19 -05:00
Alex Hart
1553f9b75d Upgrade libphonenumber to v8.12.16 2021-01-21 18:02:19 -05:00
Alex Hart
c244a98962 Finalize wallpaper UX.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
Co-authored-by: Alan Evans <alan@signal.org>
2021-01-21 18:02:19 -05:00
Alan Evans
a8ad1e718e Wallpaper image selection and cropping. 2021-01-21 18:02:19 -05:00
Alex Hart
b5712f4bd1 Improve wallpaper settings screen, conversation rendering.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2021-01-21 18:02:19 -05:00
Greyson Parrelli
6bcb0de43d Add support for persisting wallpaper selection. 2021-01-21 18:02:19 -05:00
Alex Hart
80651d2425 Initial wallpaper settings screens. 2021-01-21 18:02:19 -05:00
Martin d'Allens
46492b8238 Remove ~200 unused English strings. 2021-01-21 18:02:19 -05:00
Alan Evans
1be561543c Fix API19 drawable. 2021-01-21 18:02:19 -05:00
PockelHockel
e430a46e20 Prevent screen rotation during voice record.
Fixes #8276
2021-01-21 18:02:19 -05:00
Alex Hart
8d187c8ba1 Add the ability to forward content to multiple chats at once. 2021-01-21 18:02:19 -05:00
Sicco van Sas
eacf03768f Create FUNDING.yml
This will add a 'sponsor' button at the top of the repository which links to Signals donate page https://signal.org/donate/
2021-01-19 17:09:42 -04:00
Alan Evans
b077c9b4f3 Only schedule one job per constraint set. 2021-01-19 17:07:32 -04:00
Alan Evans
893749fcab Prevent stripping of leading zeros in national numbers. 2021-01-19 17:06:49 -04:00
Alan Evans
848ead5e78 Include an English filter line in the support email body. 2021-01-19 17:06:23 -04:00
Jim Gustafson
9c47acb004 Update to RingRTC v2.8.10 2021-01-19 16:03:37 -05:00
Greyson Parrelli
8ca54bcc7b Create a new manage profile screen. 2021-01-19 10:39:49 -05:00
Greyson Parrelli
7e64d57ba8 Bump version to 5.2.3 2021-01-17 00:17:47 -05:00
Greyson Parrelli
a517fc4e15 Fix NPE in RecipientDatabase. 2021-01-17 00:17:26 -05:00
Greyson Parrelli
4f4aea22ce Bump version to 5.2.2 2021-01-16 21:27:38 -05:00
Greyson Parrelli
e0ea2bdde4 Updated language translations. 2021-01-16 21:27:14 -05:00
Greyson Parrelli
d40dc1d90b Bump signal-client-java version to 0.1.5 2021-01-16 21:11:42 -05:00
Greyson Parrelli
4571151e3c Revert "Remove reset session button."
This reverts commit f24020e7b7.
2021-01-16 21:11:42 -05:00
Greyson Parrelli
3e43963f67 Put receipts in the recipient's queue. 2021-01-16 21:11:42 -05:00
Greyson Parrelli
fe71d6ac41 Make outage banner color less aggressive. 2021-01-16 21:11:42 -05:00
Greyson Parrelli
0514950333 Feature flag OkHttp automatic network retry. 2021-01-16 21:11:42 -05:00
Greyson Parrelli
a2dc781840 Add an automatic session reset interval. 2021-01-16 21:11:42 -05:00
Greyson Parrelli
2c1c6fab35 Bump version to 5.2.1 2021-01-16 03:41:29 -05:00
Greyson Parrelli
3c2e428c54 Updated language translations. 2021-01-16 03:41:29 -05:00
Greyson Parrelli
8f7fe5c3ee Add jitter to job exponential backoff. 2021-01-16 03:41:29 -05:00
Greyson Parrelli
93e9dd6425 Feature flag the default max backoff interval. 2021-01-16 03:06:54 -05:00
Greyson Parrelli
c95f0fce6e Handle ServerRejectedException.
Handle an exception that indicates we should halt retries.
2021-01-16 02:32:09 -05:00
Greyson Parrelli
a3c7e7e552 Feature flag automatic session reset. 2021-01-16 02:05:43 -05:00
Greyson Parrelli
1e2590af49 Lock the threadId during message send.
Fixes #10659
2021-01-15 12:15:07 -05:00
Greyson Parrelli
562e608e1f Fix issue with previously-enqueued bad encrypted messages. 2021-01-15 11:50:50 -05:00
Greyson Parrelli
417d5a2804 Be extra safe when posting a notification during a migration. 2021-01-15 11:22:15 -05:00
Ewout ter Hoeven
c0c8d2caa7 Update issue template.
Fixes #10626

Co-authored-by: Greyson Parrelli <greyson@signal.org>
2021-01-15 11:17:38 -05:00
Greyson Parrelli
727175e4f4 Add 'constraints' and 'key preferences' sections to logs. 2021-01-15 11:17:38 -05:00
Ewout ter Hoeven
577d2b13ca CI: Update to checkout v2, remove install NDK
- Updates to action/checkout v2, which is faster
 - Remove install NDK step, since it's installed by default and speeds up the build
2021-01-14 12:44:08 -04:00
Greyson Parrelli
6ac2f922e2 Fix capitalization in some strings. 2021-01-14 10:47:42 -05:00
Greyson Parrelli
98297e55c1 Don't show menu actions for chat refresh messages. 2021-01-14 10:46:09 -05:00
Alan Evans
aa2094a2cc Fix group recipient showing in verify safety number change "learn more". 2021-01-14 10:19:50 -04:00
Alex Hart
f8c053cc96 Add 'on another device' to participants description 2021-01-14 07:03:19 -04:00
Alex Hart
790f8426ac Fix issue when single user leaves ParticipantCollection. 2021-01-14 06:53:18 -04:00
Greyson Parrelli
ff11609a82 Bump version to 5.2.0 2021-01-13 19:57:58 -05:00
Greyson Parrelli
94346033a8 Updated language translations. 2021-01-13 19:57:35 -05:00
Alan Evans
cb1401f556 Prompt to confirm number before SMS or call. 2021-01-13 19:43:35 -05:00
Alan Evans
ae676d7486 Fast job sorting. 2021-01-13 19:43:35 -05:00
Alan Evans
2d39e43677 Restrict group names to 32 graphemes.
Uses some code from #10132 hence co-author:

Co-authored-by: Fumiaki Yoshimatsu <fumiakiy@gmail.com>
2021-01-13 19:43:35 -05:00
Alex Hart
0ccc7e3c06 Distinguish between primary and secondary devices in participants list. 2021-01-13 19:43:23 -05:00
Alex Hart
2d20ceea01 Show contact profile photo instead of system contact. 2021-01-13 19:43:23 -05:00
Alex Hart
cee2702fdf Add expandable video pip to 1:1 conversations. 2021-01-13 19:43:23 -05:00
Greyson Parrelli
6c94be70dc Update safety number UI. 2021-01-13 19:43:23 -05:00
Greyson Parrelli
f24020e7b7 Remove reset session button. 2021-01-13 19:43:23 -05:00
Greyson Parrelli
728f1707b6 Automatically recover from bad encrypted messages. 2021-01-13 19:43:23 -05:00
Alan Evans
adea15df10 Recover from CDN 416 Range error on attachment download. 2021-01-13 19:43:23 -05:00
Alex Hart
be91f2396c Add toggle to control call bandwidth. 2021-01-13 19:43:23 -05:00
Alex Hart
8724d904b7 Add NotInCallConstraint, restrict auto-download of media and documents when on an active voice or video call. 2021-01-13 19:43:23 -05:00
Greyson Parrelli
ef95479157 Increase versionCode postFixSize from 10 to 100. 2021-01-13 19:43:23 -05:00
Greyson Parrelli
710cd23537 Fix typo in log. 2021-01-13 19:43:23 -05:00
Alex Hart
0af313a81f Add correct margin to in-call menu item. 2021-01-13 19:43:23 -05:00
Alex Hart
71be388989 Order grid by latest speakers and prevent any unnecessary shifts. 2021-01-13 19:43:23 -05:00
Alex Hart
db3098f633 Add immersive mode for calling. 2021-01-13 19:43:23 -05:00
Greyson Parrelli
ac197f42f2 Bump version to 5.1.9 2021-01-13 17:39:05 -05:00
Greyson Parrelli
d82882ba28 Updated language translations. 2021-01-13 17:38:35 -05:00
Greyson Parrelli
957a12875d Fix situations where we might not have detected first-ever-launch. 2021-01-13 17:33:14 -05:00
Greyson Parrelli
796eb5043c Bump version to 5.1.8 2021-01-12 12:47:57 -05:00
Greyson Parrelli
4f8d86828f Updated language translations. 2021-01-12 12:47:57 -05:00
Greyson Parrelli
5370605815 Control CDS refresh interval with a feature flag. 2021-01-12 12:47:57 -05:00
Greyson Parrelli
d5fb71b63f Prevent creating threads for remapped users.
Fixes #10538
2021-01-12 11:41:13 -05:00
Greyson Parrelli
2455c291d8 Bump version to 5.1.7 2021-01-12 02:06:59 -05:00
Greyson Parrelli
80ad28e9cc Updated language translations. 2021-01-12 02:06:00 -05:00
Greyson Parrelli
74552ba545 Fix possible crash with ProcessLifecycleOwner. 2021-01-12 02:06:00 -05:00
Greyson Parrelli
141cab1105 Perfom a migration to notify users of new contacts. 2021-01-11 23:22:01 -05:00
Greyson Parrelli
f012a41345 Fix issue with Signal join notifications. 2021-01-11 23:21:54 -05:00
Alan Evans
1f95df60d4 Fix style of approve new member switch in light bottom sheet. 2021-01-11 19:07:27 -04:00
Alan Evans
560c8c8cac Bump version to 5.1.6 2021-01-11 17:27:32 -04:00
Alan Evans
7cd79f8a94 Updated language translations. 2021-01-11 17:27:32 -04:00
Greyson Parrelli
667304c81e Cause LiveRecipient.refresh() to force a LiveData change. 2021-01-11 17:18:46 -04:00
Greyson Parrelli
2dd95c6ef6 Increase profile timeouts. 2021-01-11 17:18:46 -04:00
Greyson Parrelli
29e66e1d47 Fix the invite share button. 2021-01-11 17:18:46 -04:00
Alan Evans
5eb5af2f87 Bump version to 5.1.5 2021-01-11 14:13:02 -04:00
Alan Evans
e47b62805b Updated language translations. 2021-01-11 14:13:02 -04:00
Alan Evans
57adc73e95 Revert "Fast job sorting."
This reverts commit 373972f5dc.
2021-01-11 13:59:01 -04:00
Greyson Parrelli
8f4d64d37a Update link preview user agent. 2021-01-11 13:46:35 -04:00
Alan Evans
9ce3813044 Add "Enter your phone number" string for translation. 2021-01-11 13:46:35 -04:00
Alan Evans
6436e2836d No cell service hint during registration. 2021-01-11 13:46:35 -04:00
Alan Evans
77c83019d0 Smaller titles on small screen registration. 2021-01-11 13:46:35 -04:00
Greyson Parrelli
e6dfe96569 Add a gradient and background to the onboarding megaphone. 2021-01-11 13:46:35 -04:00
Alan Evans
5d515198e6 Fix initial state for update button. 2021-01-10 11:47:59 -04:00
Greyson Parrelli
1d912c0db2 Fix issue where conversation hero avatars didn't show up. 2021-01-10 10:01:31 -05:00
Greyson Parrelli
bac04dea8d Bump version to 5.1.4 2021-01-09 23:45:05 -05:00
Greyson Parrelli
3b39d13412 Fix possible crash with ProcessLifecycleObserver. 2021-01-09 23:41:31 -05:00
Greyson Parrelli
9838b2cf0a Fix crash in ContactSelectionListFragment. 2021-01-09 23:36:57 -05:00
Greyson Parrelli
0ac56ca571 Fix crash with ExpiringMessageManager. 2021-01-09 23:36:09 -05:00
Greyson Parrelli
12321bc2f0 Bump version to 5.1.3 2021-01-09 23:22:10 -05:00
Greyson Parrelli
3a55dfa32f Updated language translations. 2021-01-09 23:21:50 -05:00
Alan Evans
373972f5dc Fast job sorting. 2021-01-09 23:16:46 -05:00
Alan Evans
60a701f84f Fix missing dialog message on single user add confirm. 2021-01-09 20:12:10 -04:00
Greyson Parrelli
14f7c01fcb Only notify for actual recipient changes. 2021-01-09 18:45:22 -05:00
Greyson Parrelli
caf4f1a7ba Bump version to 5.1.2 2021-01-08 23:08:31 -05:00
Greyson Parrelli
eb55ac9a97 Updated language translations. 2021-01-08 23:07:17 -05:00
Greyson Parrelli
b9d8868aab Added a new onboarding megaphone. 2021-01-08 23:00:41 -05:00
Alex Hart
bec03534ef Animated skip button. 2021-01-08 21:10:40 -04:00
Alan Evans
565eab9dc1 Fix jumping "0 members". 2021-01-08 21:10:40 -04:00
Alan Evans
4d229862b6 Invite Friends bottom sheet. 2021-01-08 21:10:40 -04:00
Greyson Parrelli
3739eb7731 Add extra conditions for the SMS banner. 2021-01-08 21:01:13 -04:00
Alex Hart
ae5f9fb8ac Add empty state for members list in AddGroupDetailsFragment. 2021-01-08 21:01:13 -04:00
Alex Hart
4320a81846 Add invite friends action button and text. 2021-01-08 21:01:13 -04:00
Alan Evans
9fcf40fdc4 Allow empty group creation. 2021-01-08 12:53:23 -04:00
Greyson Parrelli
79d6ac100c Fix issue where megaphone display may be delayed. 2021-01-08 11:31:35 -05:00
Greyson Parrelli
a3e3153ee3 Add the Honor Play to the CameraX blacklist. 2021-01-08 10:13:50 -05:00
Alan Evans
0f525d2b07 Bump version to 5.1.1 2021-01-07 16:08:02 -04:00
Alan Evans
8de3f5045b Updated language translations. 2021-01-07 16:07:21 -04:00
Greyson Parrelli
fba4ae91e3 Fix issue where recipient observing could show stale data. 2021-01-07 16:07:21 -04:00
Alan Evans
dda68d6c95 Revert "Bump libsignal-client to 0.2.0"
This reverts commit e845fba8b3.
2021-01-07 16:07:04 -04:00
Greyson Parrelli
25af25cd19 Fix issue where button to go to archive was missing. 2021-01-07 16:07:04 -04:00
Alan Evans
dfd5b2c225 Ensure consistency and completeness of feature flag remote capable designation.
Make CustomVideoMuxer flag remote capable.
2021-01-07 16:07:04 -04:00
Greyson Parrelli
e850d8e917 Fix badge overlap in archive screen. 2021-01-07 09:54:02 -05:00
Alex Hart
677cf725a1 Fix bad screen lock behaviour. 2021-01-07 10:37:55 -04:00
Alan Evans
e95bb9cb0f Bump version to 5.1.0 2021-01-06 17:05:30 -04:00
Alan Evans
2c223a5826 Updated language translations. 2021-01-06 17:03:38 -04:00
Greyson Parrelli
bbc346bd7a Create a system for scheduling work post-initial-render. 2021-01-06 17:03:38 -04:00
Cody Henthorne
cf32b93269 Better error handling for group calls. 2021-01-06 17:03:38 -04:00
Cody Henthorne
84f1da76ad Fix bug where missing media keys would not always be shown on time. 2021-01-06 17:03:21 -04:00
Jack Lloyd
e845fba8b3 Bump libsignal-client to 0.2.0 2021-01-06 17:03:21 -04:00
Greyson Parrelli
01152ead61 Move the JobDatabase to a separate physical database.
Also removes maxInstancesPerFactory from DB, which was only used during job submission and had no need to be persisted.
2021-01-06 17:03:21 -04:00
Alex Hart
198281aa47 Show 'return to call' if local user is in the call group. 2021-01-06 17:03:21 -04:00
Jim Gustafson
8e8d86606b Update to RingRTC v2.8.9 2021-01-06 17:03:21 -04:00
Alan Evans
b4c2e21415 Custom streaming video muxer. 2021-01-06 17:03:21 -04:00
Alan Evans
6080e1f338 Ensure ProfileKeyCredentials match ProfileKey.
Fixes #10344
2021-01-06 17:03:20 -04:00
Alan Evans
6dd3fdaa55 Remove usages of deprecated Handler constructor. 2021-01-06 17:03:20 -04:00
Alan Evans
64312f9c7f Fix non-rendered previews when differ by trailing slash. 2021-01-06 17:03:20 -04:00
Greyson Parrelli
86542febf9 Move the MegaphoneDatabase to a separate physical database. 2021-01-06 17:03:20 -04:00
Alex Hart
9da49f9f8a Load correct recipient from thread record. 2021-01-06 17:03:20 -04:00
Alex Hart
ce3872ce1a Fix ACTION_OPEN_DOCUMENT_TREE crash when no file picker available.
Fixes #10131
2021-01-06 17:03:20 -04:00
Greyson Parrelli
c466dba8c4 Move the KeyValueDatabase to a separate physical database. 2021-01-06 17:03:20 -04:00
Alex Hart
46d412a6c3 UX update and slight stability fix. 2021-01-06 17:03:20 -04:00
Alex Hart
e2872d9af8 Add emdash instead of 0 if no callers are present and we haven't connected / loaded the group state. 2021-01-06 17:03:20 -04:00
Greyson Parrelli
3474b26f61 Don't include archived threads in recent conversation query. 2021-01-06 17:03:20 -04:00
Greyson Parrelli
740e934e5d Speed up the recipient warm-up phase. 2021-01-06 17:03:20 -04:00
Greyson Parrelli
61c5fc1057 Add shake-to-report for internal users. 2021-01-06 17:03:20 -04:00
Greyson Parrelli
7ef77bf16c Remove unbounded conversation list query. 2021-01-06 17:03:20 -04:00
Greyson Parrelli
aa3eb78956 Clean up and speed up conversation list item view. 2021-01-06 17:03:20 -04:00
Greyson Parrelli
cdd7b2deb9 Improve and streamline Application#onCreate. 2021-01-06 17:03:20 -04:00
Greyson Parrelli
c27300c19d Add a perf buildType for testing performance improvements. 2021-01-06 17:03:20 -04:00
Greyson Parrelli
8927971a19 Replace non-essential conversation list views with stubs. 2021-01-06 17:03:20 -04:00
Greyson Parrelli
1ced115b54 Only force a conversation list re-query for non-cold-starts. 2021-01-06 17:03:20 -04:00
Greyson Parrelli
fcbd594def Add a system to easily trace jobs. 2021-01-06 17:03:20 -04:00
Greyson Parrelli
4b8d02fdba Move Tracer to core-util. 2021-01-06 17:03:20 -04:00
Greyson Parrelli
e10284bd13 Remove Trace annotation. 2021-01-06 17:03:20 -04:00
Greyson Parrelli
4b5f1d64e6 Switch the conversation list to our own paging library. 2021-01-06 17:03:20 -04:00
Alex Hart
b7477d287b Reopen properly when we select launcher icon.
* Reopen properly when we select launcher icon.

* Reduce noise
2021-01-06 17:03:20 -04:00
Greyson Parrelli
6bab6c2454 Increase prekey archive age to 30 days. 2021-01-06 17:03:20 -04:00
Alex Hart
586c45616c Utilize ACTION_GET_CONTENT for one-time-access to backup.
Fixes #10312
2021-01-06 17:03:20 -04:00
Greyson Parrelli
ccd405fdce Don't double-isolate-bidi on phone numbers.
Fixes #10257
2021-01-06 17:03:20 -04:00
henry
dbf78d1b69 Show correct fragment layout preview. 2020-12-18 10:41:14 -04:00
Alex Hart
5f947ea2d6 Remove a few more instances of AsyncTask. 2020-12-18 10:41:14 -04:00
Alex Hart
73afa82147 Remove ViewUtil deprecated methods. 2020-12-18 10:41:14 -04:00
Alex Hart
744b79419b Swap out AsyncTask usage in notification action receivers with bounded threadpool. 2020-12-18 10:41:14 -04:00
Alex Hart
ce20dd97ff Fix bad compose input height. 2020-12-18 10:41:14 -04:00
Greyson Parrelli
3983d5aca4 Log the threadId of a log. 2020-12-18 10:41:14 -04:00
Greyson Parrelli
7b0de2d2a9 Force a feature flag refresh after a version change. 2020-12-18 10:41:14 -04:00
Cody Henthorne
2b65482abd Fix KitKat OOM when rendering rounded material buttons. 2020-12-18 10:41:14 -04:00
Cody Henthorne
fe01e80af5 Fix bug with mute states not dynamically updating in participants list. 2020-12-18 10:41:14 -04:00
Greyson Parrelli
fc43a0d8e9 Put log tag in brackets. 2020-12-18 10:41:14 -04:00
Alex Hart
e709cdc9d5 Remember the last position of emoji and sticker picker as you swap between them. 2020-12-18 10:41:14 -04:00
Jack Lloyd
d2d698f64e Don't rely on the SessionState protobuf.
Instead use the convenient deserialization constructor
2020-12-18 10:41:14 -04:00
Alan Evans
7f1e33be32 Fix not deselecting item that is too large to send. 2020-12-18 10:41:14 -04:00
Greyson Parrelli
443f1a1554 Bump version to 5.0.8 2020-12-17 17:55:40 -05:00
Greyson Parrelli
ebb025c40a Updated language translations. 2020-12-17 17:55:40 -05:00
Greyson Parrelli
f3ce582fa5 Inline GV1 auto-migration flag. 2020-12-17 17:55:33 -05:00
Greyson Parrelli
372744178e Bump version to 5.0.7 2020-12-15 20:24:51 -05:00
Greyson Parrelli
fc3aa96b5a Updated language translations. 2020-12-15 20:24:22 -05:00
Greyson Parrelli
f4c723cc60 Refactor how we handle GV1->GV2 migration suggestions. 2020-12-15 20:18:47 -05:00
Alan Evans
7864c8ceb4 Fix translations in group call screen when using in-app language. 2020-12-15 12:34:34 -04:00
Alan Evans
4c80aac4d6 Drop sync messages with bad GV1 lengths. 2020-12-15 12:10:42 -04:00
Greyson Parrelli
e2b6e85431 Bump version to 5.0.6 2020-12-14 22:48:57 -05:00
Greyson Parrelli
8587153ddd Updated language translations. 2020-12-14 22:48:18 -05:00
Greyson Parrelli
21956e400f Use a new DatabaseObserver system. 2020-12-14 22:43:34 -05:00
Alex Hart
fa7346f79b Add group calling tooltip and megaphone. 2020-12-14 22:43:34 -05:00
Alan Evans
7227b43bbe Remove conversation list datasource throttler. 2020-12-14 12:47:26 -04:00
Greyson Parrelli
e8c75249f1 Bump version to 5.0.5 2020-12-14 01:13:41 -05:00
Greyson Parrelli
cc5628cbce Updated language translations. 2020-12-14 01:12:46 -05:00
Greyson Parrelli
441808b1df Fix issue where client deprecation sometimes wasn't cleared. 2020-12-13 14:44:19 -05:00
Greyson Parrelli
42b0fe7853 Bump version to 5.0.4 2020-12-10 12:36:38 -05:00
Greyson Parrelli
7877f5db2f Updated language translations. 2020-12-10 12:36:38 -05:00
Alex Hart
b972e05660 Auto focus national number field after valid country code in delete fragment. 2020-12-10 12:36:38 -05:00
Greyson Parrelli
23579a9b1d Do not unnecessarily refresh known-unregistered users during migration. 2020-12-10 12:36:38 -05:00
Greyson Parrelli
af99753d47 Trace Application and Activity creates. 2020-12-10 11:45:15 -05:00
Greyson Parrelli
4b2366e537 Bump version to 5.0.3 2020-12-09 17:42:44 -05:00
Greyson Parrelli
bea72c2ee3 Updated language translations. 2020-12-09 17:42:44 -05:00
Greyson Parrelli
32a50fcfad Disable group calling for API 19. 2020-12-09 17:42:44 -05:00
Greyson Parrelli
30fa741365 Make group calling flag hot-swappable. 2020-12-09 17:39:02 -05:00
Greyson Parrelli
bed2544ff4 Don't try to update contacts if you have no permission.
Fixes #10271
2020-12-09 17:07:54 -05:00
Cody Henthorne
5a773de3b1 Handle group call update sync messages. 2020-12-09 16:33:47 -05:00
Alan Evans
924405c8ba Increase uncompressed video attachment size to 500 Mb. 2020-12-09 16:30:42 -04:00
Alan Evans
93e9de3932 Increase stream copy buffer size to 64K. 2020-12-09 16:29:08 -04:00
Alan Evans
a8dd81eace Return optional for telephone number region name for the unknown case to be localized. 2020-12-09 15:47:44 -04:00
Greyson Parrelli
ec8793c6fe Fix rendering issue when deleting the last message in a conversation. 2020-12-09 14:39:22 -05:00
Alex Hart
ffc0a230be Fix country code width on account deletion screen. 2020-12-09 14:09:21 -04:00
Cody Henthorne
5d4922ed8d Show accurate current group call participants in lobby header. 2020-12-09 11:53:59 -05:00
Alan Evans
974c33fe37 Directly reference activity for remove avatar confirmation prompt. 2020-12-09 11:15:48 -04:00
Alex Hart
3f2b4d60fd Fix voice note saves on API 28 and lower. 2020-12-09 10:22:31 -04:00
Greyson Parrelli
ca633b13af Bump version to 5.0.2 2020-12-08 18:23:07 -05:00
Greyson Parrelli
a671e152bd Updated language translations. 2020-12-08 18:22:44 -05:00
Cody Henthorne
a564aae80a Do not show speaker hint in pip. 2020-12-08 18:10:04 -05:00
Greyson Parrelli
9f8e31db78 Change WebsocketDrainedConstraint to DecryptionsDrainedConstraint. 2020-12-08 18:10:04 -05:00
Cody Henthorne
84e9282f87 Attempt to reduce number of peek jobs run after being offline. 2020-12-08 18:10:04 -05:00
Alan Evans
3949f4fd45 Hide join group call for inactive groups. 2020-12-08 18:10:04 -05:00
Greyson Parrelli
944a180b68 Ensure GV1->GV2 migrations work via group links. 2020-12-08 18:10:04 -05:00
Greyson Parrelli
9cd1a12b6a Fix NPE in FastJobStorage#getJobCountForQueue(). 2020-12-08 18:10:04 -05:00
Greyson Parrelli
a4a2d2fc0d Log out exception when a backup fails. 2020-12-08 18:10:04 -05:00
Artem Varaksa
6df839612d Fix "Advanced PIN settings" pushing wrong fragment. 2020-12-08 18:10:04 -05:00
Greyson Parrelli
dd630abd0e Fix issue where scrolling could get stuck.
The number of off-screen pages was too small, resulting in the
possibility of you still being offscreen after the pages loaded,
which could lead to loading more data, which could lead to you still
being offscreen, ad infinitum.

Simply increasing the number of buffer
pages resolves it.

Tested by adding an artificial 1 second delay to
loading a page.
2020-12-08 18:10:04 -05:00
Greyson Parrelli
6826c0ded5 Fix another scenario where search position was off. 2020-12-08 18:10:04 -05:00
Alex Hart
f1d0d4f81b Fix account deletion UI bugs. 2020-12-08 18:10:04 -05:00
Alex Hart
bfa56f771d Do not show join banner in pip mode. 2020-12-08 09:20:51 -04:00
Greyson Parrelli
167b9c13e5 Bump version to 5.0.1 2020-12-07 22:52:26 -05:00
Greyson Parrelli
4b7d9a3b9d Updated language translations. 2020-12-07 22:52:10 -05:00
Greyson Parrelli
c7585c5594 Fix issues with jumpToMessage behavior. 2020-12-07 22:40:43 -05:00
Greyson Parrelli
c3d7b88cf6 Add support for setting max instances per job queue. 2020-12-07 17:30:05 -05:00
Cody Henthorne
dc4ce234b7 Ensure proper group call history in chat after being offline.
Co-authored-by: Alan Evans <alan@signal.org>
2020-12-07 17:27:35 -05:00
Cody Henthorne
12330b0aff Bump RingRTC to 2.8.7 2020-12-07 16:43:47 -05:00
Alex Hart
edb2a17bcb Add ability to delete your Signal account from within the app. 2020-12-07 17:39:16 -04:00
Alan Evans
00b6416583 Prevent surplus notification sound when entering group. 2020-12-07 17:36:21 -04:00
Alex Hart
62297f1f98 Stabilize bluetooth a bit. 2020-12-07 16:33:14 -05:00
Cody Henthorne
c00b0727e3 Show call full UI when group call is full. 2020-12-07 16:17:39 -05:00
Greyson Parrelli
13616b9820 Fix preview of link previews with no thumbnails. 2020-12-07 15:54:16 -05:00
Greyson Parrelli
6530e1d937 Update CameraX blacklist. 2020-12-07 14:34:52 -05:00
Alex Hart
aff00615cb Fix bad theming on audio device selection popup. 2020-12-07 15:32:43 -04:00
Alex Hart
be53bfa88f Hide members list when user enters pip. 2020-12-07 14:50:11 -04:00
Alex Hart
5de50f1a8b Fix overflow presentation when active speaker changes. 2020-12-07 14:11:35 -04:00
Alex Hart
61886ea10a Display speaker in PiP. 2020-12-07 13:16:02 -04:00
Sgn-32
ea94f6bc91 Pretty print your phone number in advanced settings. 2020-12-07 11:15:13 -05:00
Greyson Parrelli
6080c18c90 Fix RTL display of formatted phone numbers.
Fixes #10261

Thank you to @Sgn-32 for finding that it can be solved with
StringUtil#isolateBidi()
2020-12-07 11:02:46 -05:00
Cody Henthorne
595d5dddbe Add Group Call speaker view hint. 2020-12-07 10:46:36 -05:00
Bastian Köcher
9b81e7f71b Removes deprecated Samsung multi-window support
This removes the deprecated Samsung multi-window support. Actually this
breaks multi-window support on newer Samsung devices. Android supports
multi-window since Android 7.0 and AFAIK Samsung switched to this as
well. There isn't even any reference anymore that mentions these lines
of code as required.
2020-12-07 10:39:54 -05:00
Cody Henthorne
bdc6c8c65a Fix a few minor group call UI issues. 2020-12-07 10:05:35 -05:00
Cody Henthorne
2dcc7d284f Update group membership for a group call when it changes. 2020-12-05 20:55:52 -05:00
Greyson Parrelli
234e4be924 Bump version to 5.0.0 2020-12-05 14:11:46 -05:00
Greyson Parrelli
1083e022cc Updated language translations. 2020-12-05 14:11:46 -05:00
Greyson Parrelli
cb1b4ec0b9 Rotate the GV1->GV2 auto migration flag. 2020-12-05 14:11:46 -05:00
Greyson Parrelli
40c46351e6 Update MMS description string. 2020-12-05 13:44:13 -05:00
Greyson Parrelli
3f75e4aeb3 Fix GV1->GV2 migration bug where users were incorrectly marked as dropped. 2020-12-05 13:44:13 -05:00
Greyson Parrelli
4321fabf0b Rotate the group calling feature flag. 2020-12-05 13:44:13 -05:00
Greyson Parrelli
8e93bf9075 Create a core-util module with some common utilities. 2020-12-05 13:44:13 -05:00
Greyson Parrelli
831cd2f297 Trace database methods. 2020-12-05 13:44:13 -05:00
Cody Henthorne
42d61518b3 Handle safety number changes in a group call context. 2020-12-05 13:44:13 -05:00
Alex Hart
112782ccaf Add join/leave banner for group calls. 2020-12-05 13:44:13 -05:00
Alan Evans
67a3a30d4c Run witness checksums in task and only when compiling. 2020-12-05 13:44:13 -05:00
Greyson Parrelli
898d92ba54 Fix issue where remote deletes screwed up jump positions.
Fixes #10171
2020-12-05 13:44:13 -05:00
Greyson Parrelli
323a405004 Don't format numbers unnecessarily.
Util.getFirstNonEmpty() requires calculating all input strings first,
but that's unnecessary and could result in lots of warning logs in the
case of calling PhoneNumberFormatter#prettyPrint with nulls or other
stuff.

Fixes #10246
2020-12-05 13:44:13 -05:00
Alex Hart
3f25609561 Add equals/hashcode to Key implementation. 2020-12-05 13:44:13 -05:00
Greyson Parrelli
97047bccde Remove job adds from database transactions. 2020-12-05 13:44:13 -05:00
Greyson Parrelli
31960b53a0 Use our own homemade paging library for conversation paging.
I made the lib, and Alan made the build actually work.

Co-authored-by: Alan Evans <alan@signal.org>
2020-12-05 13:44:13 -05:00
Cody Henthorne
ac41f3d662 Fix deadlock between group calling jobs. 2020-12-05 13:44:13 -05:00
Cody Henthorne
82eebbc3b0 Fix incorrect string resource usage for some activities. 2020-12-05 13:44:13 -05:00
Cody Henthorne
b1d74e21e2 Improve handling of 1:1 calls during group calls. 2020-12-05 13:44:13 -05:00
Greyson Parrelli
7868c3094b Make FastJobStorage synchronous again. 2020-12-05 13:44:13 -05:00
Sgn-32
ebaa4cee65 Pretty print phone numbers in recent chats on share screen.
Fixes #10204
2020-12-05 13:44:09 -05:00
Greyson Parrelli
141b22765e Pretty print your phone number in settings. 2020-12-05 13:43:25 -05:00
Cody Henthorne
050fad3114 Handle blocked users in group calls. 2020-12-05 13:43:25 -05:00
Cody Henthorne
01f143667f Add Group Call peeking in the Conversation view. 2020-12-05 13:43:25 -05:00
Alan Evans
2729eb9f5f Bump version to 4.79.3 2020-12-02 21:17:11 -04:00
Alan Evans
0a8e0d7889 Updated language translations. 2020-12-02 21:16:35 -04:00
Cody Henthorne
25bffa6d56 Put send viewed receipts behind a feature flag. 2020-12-02 20:15:26 -05:00
Greyson Parrelli
cf7fb7e1a2 Bump version to 4.79.2 2020-12-02 13:55:44 -05:00
Greyson Parrelli
4b7017580c Updated language translations. 2020-12-02 13:33:28 -05:00
Greyson Parrelli
90852b5715 Ensure we refresh our own profile after refreshing attributes. 2020-12-02 13:33:28 -05:00
Alex Hart
2103fd016b Return sane value if player is out of sync with data adapter. 2020-12-02 13:40:46 -04:00
Cody Henthorne
973ad55dfe Fix various UI issues with group calling PIPs. 2020-12-02 11:37:20 -05:00
Cody Henthorne
c3dea97857 Clear view cache properly after configuration change. 2020-12-02 10:27:20 -05:00
Cody Henthorne
0e37381179 Bump RingRTC to 2.8.5 2020-12-02 09:01:31 -05:00
Alex Hart
f7bc975534 Utilize left margin in drawing mask. 2020-12-02 09:44:51 -04:00
Greyson Parrelli
fab24bcd1e Bump version to 4.79.1 2020-12-01 17:11:12 -05:00
Greyson Parrelli
9be2e6b815 Updated language translations. 2020-12-01 17:11:12 -05:00
Greyson Parrelli
4037170b4a Rotate GV1 auto-migration feature flag. 2020-12-01 17:11:12 -05:00
Greyson Parrelli
b1974f31a9 Reduce number of optimistic migrations enqueued at once. 2020-12-01 16:52:19 -05:00
Greyson Parrelli
e6bf8f078d Use proper Recipient method in group sync job. 2020-12-01 16:52:19 -05:00
Alex Hart
cea4ee4ea9 Utilize GeneratedContactPhoto for named folk. 2020-12-01 16:17:36 -05:00
Alex Hart
283ff44da9 Cache conversation icon shortcuts. 2020-12-01 16:17:36 -05:00
Cody Henthorne
adee104899 Stop camera from turning on when returning to a group call. 2020-12-01 16:17:36 -05:00
Greyson Parrelli
1a844abcec Fix perf issues around shortcut updates. 2020-12-01 16:17:36 -05:00
Alan Evans
5f30745908 Reduce layout depth of conversation items. 2020-12-01 16:20:53 -04:00
Alex Hart
4ae0f3999c Apply better strategy for dependency init. 2020-12-01 16:01:47 -04:00
Alex Hart
dcb16378c8 Display PiP in Group Calls even if local video is disabled. 2020-12-01 14:53:34 -04:00
Alex Hart
b59a5c8609 Revert "Don't show members button if there are no remote people."
This reverts commit d4748efd42.
2020-12-01 12:19:03 -04:00
Cody Henthorne
55c9124c54 Prevent multiple taps from starting multiple calls. 2020-12-01 10:56:47 -05:00
henry
1376b4c0b8 Fix crash when enter long phone number on registration. 2020-12-01 10:13:12 -05:00
Sgn-32
9333e4fb68 Fix notification text for view-once videos.
Fixes #10141
2020-12-01 09:49:05 -05:00
Alan Evans
04d3faf057 Update rust lib to 0.1.5 to fix missing method log messages. 2020-12-01 10:43:58 -04:00
Greyson Parrelli
bcfbed9b3f Prevent error when user has no email client.
Fixes #10212

Thanks to @ali-khannakhjavani

Co-authored-by: ali-khannakhjavani
2020-11-30 18:59:42 -05:00
Jonah Beckford
dda51bf367 Complete update of reproducible build instructions 2020-11-30 18:14:35 -05:00
Greyson Parrelli
a324288d97 Bump version to 4.79.0 2020-11-30 15:32:27 -05:00
Greyson Parrelli
f21d2a2187 Updated language translations. 2020-11-30 15:31:56 -05:00
Cody Henthorne
5272fec948 Change group calling feature flag to boolean. 2020-11-30 15:13:56 -05:00
Alan Evans
fe11ebce55 Inline Group Invite Link feature flags. 2020-11-30 14:50:11 -04:00
Alan Evans
221cf56ddc Enqueue cached layout inflation on background thread. 2020-11-30 13:21:20 -04:00
Greyson Parrelli
7efd8be238 Inline max envelope size feature flag. 2020-11-30 11:47:54 -05:00
Greyson Parrelli
105862b524 Chunk read sync messages.
Same thing we do with read receipts we send to other people. Just missed
this part.
2020-11-30 11:36:04 -05:00
Alan Evans
cce8cdc7bf fixup! Clean up any invalid group V1 ids in database. 2020-11-30 12:32:01 -04:00
Cody Henthorne
834c2c2495 Bump RingRTC to 2.8.4 2020-11-30 11:02:54 -05:00
Greyson Parrelli
59f7ee6682 Remove aspectj for now. 2020-11-27 20:08:10 -05:00
Alan Evans
6cbd68fe9f Clean up any invalid group V1 ids in database. 2020-11-25 15:53:58 -04:00
Alex Hart
e1bf23251f Add support for Android 11 Conversation Bubbles. 2020-11-25 14:11:17 -04:00
Alan Evans
3aebadd90d Use protobuf's reserved keyword. 2020-11-25 13:58:06 -04:00
Alex Hart
e57a35ab3e Localize Conversation Intent creation. 2020-11-25 11:40:05 -04:00
Jack Lloyd
13c014215d Move to Signal Protocol written in Rust.
Co-authored-by: Alex Hart <alex@signal.org>
2020-11-25 11:40:05 -04:00
Alex Hart
02931f1826 Clear voice note media queues within synchronized block. 2020-11-25 11:40:05 -04:00
Cody Henthorne
a640d9e298 Improve group update copy and implement speaker indexing. 2020-11-25 11:40:05 -04:00
Alan Evans
ce68da1613 Reserve service field 20. 2020-11-25 11:40:05 -04:00
Greyson Parrelli
3599122ca6 Delete unnecessary artwork directory. 2020-11-25 11:40:05 -04:00
Greyson Parrelli
0003830a42 Cycle the GV1->GV2 auto migration flag. 2020-11-25 11:40:05 -04:00
Greyson Parrelli
3804a89619 Improve handling of membership changes during a GV1->GV2 migration. 2020-11-25 11:40:05 -04:00
Alex Hart
d4748efd42 Don't show members button if there are no remote people. 2020-11-25 11:40:05 -04:00
Alan Evans
0bda1d46a2 Allow setting local group names and avatars for MMS groups. 2020-11-25 11:40:05 -04:00
Greyson Parrelli
43e3ef2bee Refactor Message Request logic to fix some GV1->GV2 bugs. 2020-11-25 11:40:05 -04:00
Alex Hart
ce44e3949c Add new VIEWED item in RecieptMessage enumeration.
Also includes necessary Database changes for supporting this as well as View-Once receipt support.
2020-11-25 11:37:13 -04:00
Greyson Parrelli
7bb1262571 Upload trace file as separate debuglogs item. 2020-11-25 11:37:13 -04:00
Alex Hart
39f1aea8e3 Bump version to 4.78.5 2020-11-24 14:05:57 -04:00
Alex Hart
bda19d01ed Updated language translations. 2020-11-24 13:39:59 -04:00
Alex Hart
1f5364f01d Do not crash if RECIPIENT_EXTRA is null. 2020-11-24 13:22:41 -04:00
Alex Hart
65e88d2d1c Bump version to 4.78.4 2020-11-23 10:48:48 -04:00
Alex Hart
cef8aa67dd Updated language translations. 2020-11-23 10:43:51 -04:00
Alex Hart
5941b22eb6 Revert "Move to Signal Protocol written in Rust."
This reverts commit 907e8d93a3.
2020-11-23 10:22:53 -04:00
Alex Hart
9e7c55847e Bump version to 4.78.3 2020-11-20 16:54:53 -04:00
Alex Hart
5209b74605 Updated language translations. 2020-11-20 16:51:57 -04:00
Cody Henthorne
b90a74d26a Add additional Group Calling features. 2020-11-20 15:42:46 -05:00
Alan Evans
8c1737e597 Increase uncompressed video attachment size to 300 Mb. 2020-11-20 15:15:42 -04:00
Greyson Parrelli
2ea5bd2d44 Convert GV1->GV2 migration flags to booleans. 2020-11-20 13:50:14 -05:00
Greyson Parrelli
4166e7931e Fix membership diffs that occur during a GV1->GV2 migration.
Co-authored-by: Alan Evans <alan@signal.org>
2020-11-20 13:26:17 -05:00
Alan Evans
89f2c25d73 Display video file output size and duration during clipping.
Prevent video upscale, i.e. use input bit rate if lower than our normal target rates.
Do not time limit videos that are under the send file size.
Increase time limit to 10 minutes to match our lowest acceptable bitrate.
2020-11-20 13:27:58 -04:00
Alan Evans
abb1ca2afe Increase in-app recording duration to 60 seconds. 2020-11-20 13:11:48 -04:00
Greyson Parrelli
f7befd1593 Block GV1 creation if forced migrations are enabled. 2020-11-20 11:49:18 -05:00
Greyson Parrelli
28511de23c Ensure we properly detect update messages for migrations. 2020-11-20 11:39:55 -05:00
Greyson Parrelli
2ff3d1b7c5 Update phrasing on donate megaphone dismiss button. 2020-11-19 13:46:35 -05:00
Greyson Parrelli
fe6ae7e142 Don't show donate or research megaphones on new app installs. 2020-11-19 08:42:35 -05:00
2211 changed files with 131842 additions and 37607 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
custom: https://signal.org/donate/

View File

@@ -1,3 +1,12 @@
---
name: 🛠️ Bug report
about: Let us know that something isn't working as intended
title: ''
labels: ''
assignees: ''
---
<!-- This is a bug report template. By following the instructions below and filling out the sections with your information, you will help the developers get all the necessary data to fix your issue.
You can also preview your report before submitting it. You may remove sections that aren't relevant to your particular case.

20
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
blank_issues_enabled: false
contact_links:
- name: 📃Support Center
url: https://support.signal.org/
about: Find answers to many common questions.
- name: ✨ Feature request
url: https://community.signalusers.org/c/feature-requests/
about: Missing something in Signal? Let us know.
- name: 💬 Community support
url: https://community.signalusers.org/c/support/
about: Feel free to ask anything.
- name: 📖 Developer documentation
url: https://signal.org/docs/
about: Official Signal developer documentation.
- name: 📚 Translation feedback.
url: https://community.signalusers.org/c/translation-feedback/
about: Share feedback on translations.
- name: ❓ Other issue?
url: https://community.signalusers.org/
about: Search on the community forums.

View File

@@ -14,18 +14,22 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Install NDK
run: echo "y" | sudo /usr/local/lib/android/sdk/tools/bin/sdkmanager --install "ndk;21.0.6113669" --sdk_root=${ANDROID_SDK_ROOT}
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
- name: Build with Gradle
run: ./gradlew qa
- name: Archive reports for failed build
if: ${{ failure() }}
uses: actions/upload-artifact@v2
with:
name: reports
path: '*/build/reports'

View File

@@ -2,47 +2,13 @@ import org.signal.signing.ApkSignerUtil
import java.security.MessageDigest
buildscript {
repositories {
google()
maven {
url "https://repo1.maven.org/maven2"
}
jcenter {
content {
includeVersion 'org.jetbrains.trove4j', 'trove4j', '20160824'
includeGroupByRegex "com\\.archinamon.*"
}
}
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.2'
classpath 'androidx.navigation:navigation-safe-args-gradle-plugin:2.1.0'
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.10'
classpath 'com.archinamon:android-gradle-aspectj:4.2.0'
}
}
apply plugin: 'com.android.application'
apply plugin: 'com.google.protobuf'
apply plugin: 'androidx.navigation.safeargs'
apply plugin: 'witness'
apply plugin: 'com.archinamon.aspectj-ext'
apply from: 'translations.gradle'
apply from: 'witness-verifications.gradle'
if (getGradle().getStartParameter().getTaskRequests().toString().contains("Internal")) {
aspectj {
includeJar 'sqlcipher'
includeAspectsFromJar 'Signal-Android'
java = JavaVersion.VERSION_1_8
}
} else if (getGradle().getStartParameter().getTaskRequests().toString().contains("Test")) {
aspectj {
compileTests = false
}
}
repositories {
maven {
url "https://raw.github.com/signalapp/maven/master/photoview/releases/"
@@ -50,12 +16,6 @@ repositories {
includeGroupByRegex "com\\.github\\.chrisbanes.*"
}
}
maven {
url "https://raw.github.com/signalapp/maven/master/shortcutbadger/releases/"
content {
includeGroupByRegex "me\\.leolin.*"
}
}
maven {
url "https://raw.github.com/signalapp/maven/master/circular-progress-button/releases/"
content {
@@ -78,6 +38,9 @@ repositories {
mavenCentral()
jcenter()
mavenLocal()
maven {
url "https://dl.cloudsmith.io/qxAgwaeEE1vN8aLU/mobilecoin/mobilecoin/maven/"
}
}
protobuf {
@@ -95,10 +58,10 @@ protobuf {
}
}
def canonicalVersionCode = 743
def canonicalVersionName = "4.78.2"
def canonicalVersionCode = 814
def canonicalVersionName = "5.7.5"
def postFixSize = 10
def postFixSize = 100
def abiPostFix = ['universal' : 0,
'armeabi-v7a' : 1,
'arm64-v8a' : 2,
@@ -108,9 +71,10 @@ def abiPostFix = ['universal' : 0,
def keystores = [ 'debug' : loadKeystoreProperties('keystore.debug.properties') ]
android {
buildToolsVersion BUILD_TOOL_VERSION
compileSdkVersion COMPILE_SDK
flavorDimensions 'distribution', 'environment'
compileSdkVersion 30
buildToolsVersion '30.0.2'
useLibrary 'org.apache.http.legacy'
dexOptions {
@@ -132,14 +96,16 @@ android {
versionCode canonicalVersionCode * postFixSize
versionName canonicalVersionName
minSdkVersion 19
targetSdkVersion 30
minSdkVersion MINIMUM_SDK
targetSdkVersion TARGET_SDK
multiDexEnabled true
vectorDrawables.useSupportLibrary = true
project.ext.set("archivesBaseName", "Signal");
buildConfigField "long", "BUILD_TIMESTAMP", getLastCommitTimestamp() + "L"
buildConfigField "String", "GIT_HASH", "\"${getGitHash()}\""
buildConfigField "String", "SIGNAL_URL", "\"https://textsecure-service.whispersystems.org\""
buildConfigField "String", "STORAGE_URL", "\"https://storage.signal.org\""
buildConfigField "String", "SIGNAL_CDN_URL", "\"https://cdn.signal.org\""
@@ -147,6 +113,7 @@ android {
buildConfigField "String", "SIGNAL_CONTACT_DISCOVERY_URL", "\"https://api.directory.signal.org\""
buildConfigField "String", "SIGNAL_SERVICE_STATUS_URL", "\"uptime.signal.org\""
buildConfigField "String", "SIGNAL_KEY_BACKUP_URL", "\"https://api.backup.signal.org\""
buildConfigField "String", "SIGNAL_SFU_URL", "\"https://sfu.voip.signal.org\""
buildConfigField "String", "CONTENT_PROXY_HOST", "\"contentproxy.signal.org\""
buildConfigField "int", "CONTENT_PROXY_PORT", "443"
buildConfigField "String", "SIGNAL_AGENT", "\"OWA\""
@@ -159,7 +126,8 @@ android {
buildConfigField "String", "ZKGROUP_SERVER_PUBLIC_PARAMS", "\"AMhf5ywVwITZMsff/eCyudZx9JDmkkkbV6PInzG4p8x3VqVJSFiMvnvlEKWuRob/1eaIetR31IYeAbm0NdOuHH8Qi+Rexi1wLlpzIo1gstHWBfZzy1+qHRV5A4TqPp15YzBPm0WSggW6PbSn+F4lf57VCnHF7p8SvzAA2ZZJPYJURt8X7bbg+H3i+PEjH9DXItNEqs2sNcug37xZQDLm7X0=\""
buildConfigField "String[]", "LANGUAGES", "new String[]{\"" + autoResConfig().collect { s -> s.replace('-r', '_') }.join('", "') + '"}'
buildConfigField "int", "CANONICAL_VERSION_CODE", "$canonicalVersionCode"
buildConfigField "int", "TRACE_EVENT_MAX", "2000"
buildConfigField "String", "DEFAULT_CURRENCIES", "\"EUR,AUD,GBP,CAD,CNY\""
buildConfigField "int[]", "MOBILE_COIN_REGIONS", "new int[]{44}"
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
@@ -180,8 +148,9 @@ android {
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
coreLibraryDesugaringEnabled true
sourceCompatibility JAVA_VERSION
targetCompatibility JAVA_VERSION
}
packagingOptions {
@@ -192,10 +161,8 @@ android {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
exclude 'META-INF/proguard/androidx-annotations.pro'
}
aaptOptions {
ignoreAssetsPattern '!contours.tfl:!LMprec_600.emd:!blazeface.tfl'
exclude '/org/spongycastle/x509/CertPathReviewerMessages.properties'
exclude '/org/spongycastle/x509/CertPathReviewerMessages_de.properties'
}
buildTypes {
@@ -231,11 +198,24 @@ android {
initWith debug
isDefault false
minifyEnabled false
matchingFallbacks = ['debug']
}
release {
minifyEnabled true
proguardFiles = buildTypes.debug.proguardFiles
}
perf {
initWith debug
isDefault false
debuggable false
matchingFallbacks = ['debug']
}
mock {
initWith debug
isDefault false
minifyEnabled false
matchingFallbacks = ['debug']
}
}
productFlavors {
@@ -259,13 +239,23 @@ android {
ext.websiteUpdateUrl = "null"
buildConfigField "boolean", "PLAY_STORE_DISABLED", "false"
buildConfigField "String", "NOPLAY_UPDATE_URL", "$ext.websiteUpdateUrl"
buildConfigField "int", "TRACE_EVENT_MAX", "30_000"
}
study {
dimension 'distribution'
applicationIdSuffix ".study"
ext.websiteUpdateUrl = "null"
buildConfigField "boolean", "PLAY_STORE_DISABLED", "false"
buildConfigField "String", "NOPLAY_UPDATE_URL", "$ext.websiteUpdateUrl"
}
prod {
dimension 'environment'
isDefault true
buildConfigField "String", "MOBILE_COIN_ENVIRONMENT", "\"mainnet\""
}
staging {
@@ -281,11 +271,12 @@ android {
buildConfigField "String", "SIGNAL_KEY_BACKUP_URL", "\"https://api-staging.backup.signal.org\""
buildConfigField "String", "CDS_MRENCLAVE", "\"c98e00a4e3ff977a56afefe7362a27e4961e4f19e211febfbb19b897e6b80b15\""
buildConfigField "KbsEnclave", "KBS_ENCLAVE", "new KbsEnclave(\"823a3b2c037ff0cbe305cc48928cfcc97c9ed4a8ca6d49af6f7d6981fb60a4e9\", " +
"\"038c40bbbacdc873caa81ac793bb75afde6dfe436a99ab1f15e3f0cbb7434ced\", " +
"\"51a56084c0b21c6b8f62b1bc792ec9bedac4c7c3964bb08ddcab868158c09982\", " +
"\"a3baab19ef6ce6f34ab9ebb25ba722725ae44a8872dc0ff08ad6d83a9489de87\")"
buildConfigField "KbsEnclave[]", "KBS_FALLBACKS", "new KbsEnclave[0]"
buildConfigField "String", "UNIDENTIFIED_SENDER_TRUST_ROOT", "\"BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx\""
buildConfigField "String", "ZKGROUP_SERVER_PUBLIC_PARAMS", "\"ABSY21VckQcbSXVNCGRYJcfWHiAMZmpTtTELcDmxgdFbtp/bWsSxZdMKzfCp8rvIs8ocCU3B37fT3r4Mi5qAemeGeR2X+/YmOGR5ofui7tD5mDQfstAI9i+4WpMtIe8KC3wU5w3Inq3uNWVmoGtpKndsNfwJrCg0Hd9zmObhypUnSkfYn2ooMOOnBpfdanRtrvetZUayDMSC5iSRcXKpdls=\""
buildConfigField "String", "MOBILE_COIN_ENVIRONMENT", "\"testnet\""
}
}
@@ -301,6 +292,18 @@ android {
}
}
android.variantFilter { variant ->
def distribution = variant.getFlavors().get(0).name
def environment = variant.getFlavors().get(1).name
def buildType = variant.buildType.name
if (distribution == 'study' && buildType != 'perf' && buildType != 'mock') {
variant.setIgnore(true)
} else if (distribution != 'study' && buildType == 'mock') {
variant.setIgnore(true)
}
}
lintOptions {
abortOnError true
baseline file("lint-baseline.xml")
@@ -317,6 +320,8 @@ android {
dependencies {
lintChecks project(':lintchecks')
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
implementation ('androidx.appcompat:appcompat:1.2.0') {
force = true
}
@@ -341,10 +346,7 @@ dependencies {
implementation "androidx.camera:camera-view:1.0.0-alpha18"
implementation "androidx.concurrent:concurrent-futures:1.0.0"
implementation "androidx.autofill:autofill:1.0.0"
implementation "androidx.paging:paging-common:2.1.2"
implementation "androidx.paging:paging-runtime:2.1.2"
implementation 'com.google.firebase:firebase-ml-vision:24.0.3'
implementation 'com.google.firebase:firebase-ml-vision-face-model:20.0.1'
implementation "androidx.biometric:biometric:1.1.0"
implementation ('com.google.firebase:firebase-messaging:20.2.0') {
exclude group: 'com.google.firebase', module: 'firebase-core'
@@ -363,14 +365,24 @@ dependencies {
implementation 'org.signal:aesgcmprovider:0.0.3'
implementation project(':libsignal-service')
implementation project(':paging')
implementation project(':core-util')
implementation project(':video')
implementation project(':device-transfer')
implementation 'org.signal:zkgroup-android:0.7.0'
implementation 'org.whispersystems:signal-client-android:0.1.3'
implementation 'org.whispersystems:signal-client-android:0.1.7'
implementation 'com.google.protobuf:protobuf-javalite:3.10.0'
implementation('com.mobilecoin:android-sdk:1.0.0') {
exclude group: 'com.google.protobuf'
}
implementation 'org.signal:argon2:13.1@aar'
implementation 'org.signal:ringrtc-android:2.8.0'
implementation 'org.signal:ringrtc-android:2.9.4'
implementation "me.leolin:ShortcutBadger:1.1.16"
implementation "me.leolin:ShortcutBadger:1.1.22"
implementation 'se.emilsjolander:stickylistheaders:2.7.0'
implementation 'com.jpardogo.materialtabstrip:library:1.0.9'
implementation 'org.apache.httpcomponents:httpclient-android:4.3.5'
@@ -406,7 +418,7 @@ dependencies {
exclude group: 'com.android.support', module: 'recyclerview-v7'
}
implementation 'com.airbnb.android:lottie:3.0.7'
implementation 'com.airbnb.android:lottie:3.6.0'
implementation 'com.codewaves.stickyheadergrid:stickyheadergrid:0.9.4'
implementation 'com.github.dmytrodanylyk.circular-progress-button:library:1.1.3-S2'
@@ -516,6 +528,15 @@ def getLastCommitTimestamp() {
}
}
def getGitHash() {
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'rev-parse', '--short', 'HEAD'
standardOutput = stdout
}
return stdout.toString().trim()
}
tasks.withType(Test) {
testLogging {
events "failed"

View File

@@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.database;
import android.app.Application;
import android.content.Context;
import android.database.Cursor;
import android.text.TextUtils;
@@ -14,8 +15,8 @@ import net.sqlcipher.DatabaseUtils;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteStatement;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.logging.Log;
import java.lang.reflect.Field;
import java.util.ArrayList;
@@ -24,6 +25,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* A lot of this code is taken from {@link com.facebook.flipper.plugins.databases.impl.SqliteDatabaseDriver}
@@ -42,8 +44,16 @@ public class FlipperSqlCipherAdapter extends DatabaseDriver<FlipperSqlCipherAdap
try {
Field databaseHelperField = DatabaseFactory.class.getDeclaredField("databaseHelper");
databaseHelperField.setAccessible(true);
SQLCipherOpenHelper sqlCipherOpenHelper = (SQLCipherOpenHelper) databaseHelperField.get(DatabaseFactory.getInstance(getContext()));
return Collections.singletonList(new Descriptor(sqlCipherOpenHelper));
SignalDatabase mainOpenHelper = Objects.requireNonNull((SQLCipherOpenHelper) databaseHelperField.get(DatabaseFactory.getInstance(getContext())));
SignalDatabase keyValueOpenHelper = KeyValueDatabase.getInstance((Application) getContext());
SignalDatabase megaphoneOpenHelper = MegaphoneDatabase.getInstance((Application) getContext());
SignalDatabase jobManagerOpenHelper = JobDatabase.getInstance((Application) getContext());
return Arrays.asList(new Descriptor(mainOpenHelper),
new Descriptor(keyValueOpenHelper),
new Descriptor(megaphoneOpenHelper),
new Descriptor(jobManagerOpenHelper));
} catch (Exception e) {
Log.i(TAG, "Unable to use reflection to access raw database.", e);
}
@@ -235,9 +245,9 @@ public class FlipperSqlCipherAdapter extends DatabaseDriver<FlipperSqlCipherAdap
}
static class Descriptor implements DatabaseDescriptor {
private final SQLCipherOpenHelper sqlCipherOpenHelper;
private final SignalDatabase sqlCipherOpenHelper;
Descriptor(@NonNull SQLCipherOpenHelper sqlCipherOpenHelper) {
Descriptor(@NonNull SignalDatabase sqlCipherOpenHelper) {
this.sqlCipherOpenHelper = sqlCipherOpenHelper;
}
@@ -247,11 +257,11 @@ public class FlipperSqlCipherAdapter extends DatabaseDriver<FlipperSqlCipherAdap
}
public @NonNull SQLiteDatabase getReadable() {
return sqlCipherOpenHelper.getReadableDatabase();
return sqlCipherOpenHelper.getSqlCipherDatabase();
}
public @NonNull SQLiteDatabase getWritable() {
return sqlCipherOpenHelper.getWritableDatabase();
return sqlCipherOpenHelper.getSqlCipherDatabase();
}
}
}

View File

@@ -1,103 +0,0 @@
package org.thoughtcrime.securesms.tracing;
import androidx.annotation.NonNull;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.thoughtcrime.securesms.logging.Log;
/**
* Uses AspectJ to augment relevant methods to be traced with the {@link TracerImpl}.
*/
@Aspect
public class TraceAspect {
@Pointcut("within(@org.thoughtcrime.securesms.tracing.Trace *)")
public void withinAnnotatedClass() {}
@Pointcut("execution(!synthetic * *(..)) && withinAnnotatedClass()")
public void methodInsideAnnotatedType() {}
@Pointcut("execution(!synthetic *.new(..)) && withinAnnotatedClass()")
public void constructorInsideAnnotatedType() {}
@Pointcut("execution(@org.thoughtcrime.securesms.tracing.Trace * *(..)) || methodInsideAnnotatedType()")
public void annotatedMethod() {}
@Pointcut("execution(@org.thoughtcrime.securesms.tracing.Trace *.new(..)) || constructorInsideAnnotatedType()")
public void annotatedConstructor() {}
@Pointcut("execution(* *(..)) && within(net.sqlcipher.database.*)")
public void sqlcipher() {}
@Pointcut("execution(* net.sqlcipher.database.SQLiteDatabase.rawQuery(..)) || " +
"execution(* net.sqlcipher.database.SQLiteDatabase.query(..)) || " +
"execution(* net.sqlcipher.database.SQLiteDatabase.insert(..)) || " +
"execution(* net.sqlcipher.database.SQLiteDatabase.insertOrThrow(..)) || " +
"execution(* net.sqlcipher.database.SQLiteDatabase.insertWithOnConflict(..)) || " +
"execution(* net.sqlcipher.database.SQLiteDatabase.delete(..)) || " +
"execution(* net.sqlcipher.database.SQLiteDatabase.update(..))")
public void sqlcipherQuery() {}
@Around("annotatedMethod() || annotatedConstructor() || (sqlcipher() && !sqlcipherQuery())")
public @NonNull Object profile(@NonNull ProceedingJoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().toShortString();
Tracer.getInstance().start(methodName);
Object result = joinPoint.proceed();
Tracer.getInstance().end(methodName);
return result;
}
@Around("sqlcipherQuery()")
public @NonNull Object profileQuery(@NonNull ProceedingJoinPoint joinPoint) throws Throwable {
String table;
String query;
if (joinPoint.getSignature().getName().equals("query")) {
if (joinPoint.getArgs().length == 9) {
table = (String) joinPoint.getArgs()[1];
query = (String) joinPoint.getArgs()[3];
} else if (joinPoint.getArgs().length == 7 || joinPoint.getArgs().length == 8) {
table = (String) joinPoint.getArgs()[0];
query = (String) joinPoint.getArgs()[2];
} else {
table = "N/A";
query = "N/A";
}
} else if (joinPoint.getSignature().getName().equals("rawQuery")) {
table = "";
query = (String) joinPoint.getArgs()[0];
} else if (joinPoint.getSignature().getName().equals("insert")) {
table = (String) joinPoint.getArgs()[0];
query = "";
} else if (joinPoint.getSignature().getName().equals("insertOrThrow")) {
table = (String) joinPoint.getArgs()[0];
query = "";
} else if (joinPoint.getSignature().getName().equals("insertWithOnConflict")) {
table = (String) joinPoint.getArgs()[0];
query = "";
} else if (joinPoint.getSignature().getName().equals("delete")) {
table = (String) joinPoint.getArgs()[0];
query = (String) joinPoint.getArgs()[1];
} else if (joinPoint.getSignature().getName().equals("update")) {
table = (String) joinPoint.getArgs()[0];
query = (String) joinPoint.getArgs()[2];
} else {
table = "N/A";
query = "N/A";
}
query = query == null ? "null" : query;
query = "[" + table + "] " + query;
String methodName = joinPoint.getSignature().toShortString();
Tracer.getInstance().start(methodName, "query", query);
Object result = joinPoint.proceed();
Tracer.getInstance().end(methodName);
return result;
}
}

View File

@@ -64,7 +64,6 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- So we can add a TextSecure 'Account' -->
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
@@ -116,7 +115,7 @@
<meta-data android:name="firebase_messaging_auto_init_enabled" android:value="false" />
<activity android:name=".WebRtcCallActivity"
android:theme="@style/TextSecure.LightTheme.WebRTCCall"
android:theme="@style/TextSecure.DarkTheme.WebRTCCall"
android:excludeFromRecents="true"
android:screenOrientation="portrait"
android:supportsPictureInPicture="true"
@@ -159,12 +158,15 @@
<activity android:name=".preferences.MmsPreferencesActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".sharing.interstitial.ShareInterstitialActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:windowSoftInputMode="adjustResize" />
<activity android:name=".sharing.ShareActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:excludeFromRecents="true"
android:launchMode="singleTask"
android:taskAffinity=""
android:noHistory="true"
android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
<intent-filter>
@@ -225,6 +227,17 @@
<category android:name="android.intent.category.MULTIWINDOW_LAUNCHER" />
</intent-filter>
<meta-data android:name="com.sec.minimode.icon.portrait.normal"
android:resource="@mipmap/ic_launcher" />
<meta-data android:name="com.sec.minimode.icon.landscape.normal"
android:resource="@mipmap/ic_launcher" />
</activity-alias>
<activity android:name=".deeplinks.DeepLinkEntryActivity"
android:noHistory="true"
android:theme="@style/Signal.Transparent">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
@@ -242,12 +255,16 @@
android:host="signal.group"/>
</intent-filter>
<meta-data android:name="com.sec.minimode.icon.portrait.normal"
android:resource="@mipmap/ic_launcher" />
<meta-data android:name="com.sec.minimode.icon.landscape.normal"
android:resource="@mipmap/ic_launcher" />
</activity-alias>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https"
android:host="signal.tube" />
<data android:scheme="sgnl"
android:host="signal.tube" />
</intent-filter>
</activity>
<activity android:name=".conversation.ConversationActivity"
android:windowSoftInputMode="stateUnchanged"
@@ -259,6 +276,11 @@
android:value="org.thoughtcrime.securesms.MainActivity" />
</activity>
<activity android:name=".conversation.BubbleConversationActivity"
android:theme="@style/Signal.DayNight"
android:allowEmbedded="true"
android:resizeableActivity="true" />
<activity android:name=".longmessage.LongMessageActivity" />
<activity android:name=".conversation.ConversationPopupActivity"
@@ -270,15 +292,10 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" />
<activity android:name=".messagedetails.MessageDetailsActivity"
android:label="@string/AndroidManifest__message_details"
android:windowSoftInputMode="stateHidden"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".groups.ui.pendingmemberinvites.PendingMemberInvitesActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:theme="@style/Theme.Signal.DayNight.NoActionBar" />
<activity android:name=".groups.ui.invitesandrequests.ManagePendingAndRequestingMembersActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"
android:theme="@style/Theme.Signal.DayNight.NoActionBar" />
@@ -342,13 +359,34 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".ApplicationPreferencesActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.NOTIFICATION_PREFERENCES" />
</intent-filter>
</activity>
<activity android:name=".wallpaper.ChatWallpaperActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:windowSoftInputMode="stateAlwaysHidden">
</activity>
<activity android:name=".wallpaper.ChatWallpaperPreviewActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:windowSoftInputMode="stateAlwaysHidden">
</activity>
<activity android:name=".devicetransfer.olddevice.OldDeviceTransferActivity"
android:theme="@style/TextSecure.LightRegistrationTheme"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".devicetransfer.olddevice.OldDeviceExitActivity"
android:noHistory="true"
android:excludeFromRecents="true"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".registration.RegistrationNavigationActivity"
android:launchMode="singleTask"
android:theme="@style/TextSecure.LightRegistrationTheme"
@@ -373,7 +411,6 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".logsubmit.SubmitDebugLogActivity"
android:label="@string/AndroidManifest__log_submit"
android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
@@ -456,6 +493,14 @@
android:theme="@style/TextSecure.LightRegistrationTheme"
android:windowSoftInputMode="stateVisible|adjustResize" />
<activity android:name=".profiles.manage.ManageProfileActivity"
android:theme="@style/TextSecure.LightTheme"
android:windowSoftInputMode="stateVisible|adjustResize" />
<activity android:name=".payments.preferences.PaymentsActivity"
android:theme="@style/TextSecure.LightRegistrationTheme"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".lock.v2.CreateKbsPinActivity"
android:theme="@style/TextSecure.LightRegistrationTheme"
android:windowSoftInputMode="adjustResize"
@@ -466,17 +511,11 @@
android:windowSoftInputMode="adjustResize"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".ClearProfileAvatarActivity"
android:theme="@style/Theme.AppCompat.Dialog.Alert"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:icon="@drawable/clear_profile_avatar"
android:label="@string/AndroidManifest_remove_photo">
<intent-filter>
<action android:name="org.thoughtcrime.securesms.action.CLEAR_PROFILE_PHOTO"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name=".ClearAvatarPromptActivity"
android:theme="@style/Theme.AppCompat.Dialog.Alert"
android:icon="@drawable/clear_profile_avatar"
android:label="@string/AndroidManifest_remove_photo"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".contacts.TurnOffContactJoinedNotificationsActivity"
android:theme="@style/Theme.AppCompat.Dialog.Alert" />
@@ -511,7 +550,6 @@
<activity android:name=".MainActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" />
<activity android:name=".pin.PinRestoreActivity"
@@ -538,7 +576,16 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"
android:launchMode="singleTask" />
<service android:enabled="true" android:name=".service.WebRtcCallService"/>
<activity android:name=".wallpaper.crop.WallpaperImageSelectionActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:theme="@style/TextSecure.FullScreenMedia" />
<activity android:name=".wallpaper.crop.WallpaperCropActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:screenOrientation="portrait"
android:theme="@style/Theme.Signal.WallpaperCropper" />
<service android:enabled="true" android:name=".service.webrtc.WebRtcCallService"/>
<service android:enabled="true" android:name=".service.ApplicationMigrationService"/>
<service android:enabled="true" android:exported="false" android:name=".service.KeyCachingService"/>
<service android:enabled="true" android:name=".messages.IncomingMessageObserver$ForegroundService"/>
@@ -669,6 +716,8 @@
<receiver android:name=".service.TrimThreadsByDateManager$TrimThreadsByDateAlarm" />
<receiver android:name=".payments.backup.phrase.ClearClipboardAlarmReceiver" />
<provider android:name=".providers.PartProvider"
android:grantUriPermissions="true"
android:exported="false"
@@ -738,6 +787,13 @@
</intent-filter>
</receiver>
<receiver android:name=".messageprocessingalarm.MessageProcessReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="org.thoughtcrime.securesms.action.PROCESS_MESSAGES" />
</intent-filter>
</receiver>
<receiver android:name=".service.LocalBackupListener">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
@@ -803,12 +859,5 @@
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
<uses-library android:name="com.sec.android.app.multiwindow" android:required="false"/>
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" />
<meta-data android:name="com.sec.android.multiwindow.DEFAULT_SIZE_W" android:value="632.0dip" />
<meta-data android:name="com.sec.android.multiwindow.DEFAULT_SIZE_H" android:value="598.0dip" />
<meta-data android:name="com.sec.android.multiwindow.MINIMUM_SIZE_W" android:value="632.0dip" />
<meta-data android:name="com.sec.android.multiwindow.MINIMUM_SIZE_H" android:value="598.0dip" />
</application>
</manifest>

View File

@@ -65,6 +65,8 @@ import androidx.lifecycle.LiveData;
import com.google.common.util.concurrent.ListenableFuture;
import org.signal.core.util.logging.Log;
import java.io.File;
import java.util.concurrent.Executor;
@@ -82,7 +84,7 @@ import java.util.concurrent.Executor;
@RequiresApi(21)
@SuppressLint("RestrictedApi")
public final class SignalCameraView extends FrameLayout {
static final String TAG = SignalCameraView.class.getSimpleName();
static final String TAG = Log.tag(SignalCameraView.class);
static final int INDEFINITE_VIDEO_DURATION = -1;
static final int INDEFINITE_VIDEO_SIZE = -1;

View File

@@ -16,8 +16,6 @@
package androidx.camera.view;
import static androidx.camera.core.ImageCapture.FLASH_MODE_OFF;
import android.Manifest.permission;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -29,7 +27,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RequiresPermission;
import androidx.camera.core.AspectRatio;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraInfoUnavailableException;
import androidx.camera.core.CameraSelector;
@@ -70,6 +67,8 @@ import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import static androidx.camera.core.ImageCapture.FLASH_MODE_OFF;
/** CameraX use case operation built on @{link androidx.camera.core}. */
@RequiresApi(21)
@SuppressLint("RestrictedApi")

View File

@@ -24,7 +24,7 @@ public final class Log {
}
public static void e(@NonNull String tag, @NonNull String message) {
e(tag, message, null);
SignalGlideCodecs.getLogProvider().e(tag, message, null);
}
public static void e(@NonNull String tag, @NonNull String message, @Nullable Throwable throwable) {

View File

@@ -7,8 +7,8 @@ package org.signal.glide.apng;
import android.content.Context;
import org.signal.glide.common.FrameAnimationDrawable;
import org.signal.glide.apng.decode.APNGDecoder;
import org.signal.glide.common.FrameAnimationDrawable;
import org.signal.glide.common.decode.FrameSeqDecoder;
import org.signal.glide.common.loader.AssetStreamLoader;
import org.signal.glide.common.loader.FileLoader;

View File

@@ -12,7 +12,7 @@ import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import org.signal.glide.Log;
import org.signal.core.util.logging.Log;
import org.signal.glide.apng.io.APNGReader;
import org.signal.glide.apng.io.APNGWriter;
import org.signal.glide.common.decode.Frame;
@@ -32,7 +32,7 @@ import java.util.List;
*/
public class APNGDecoder extends FrameSeqDecoder<APNGReader, APNGWriter> {
private static final String TAG = APNGDecoder.class.getSimpleName();
private static final String TAG = Log.tag(APNGDecoder.class);
private APNGWriter apngWriter;
private int mLoopCount;

View File

@@ -21,7 +21,7 @@ import android.os.Message;
import androidx.annotation.NonNull;
import androidx.vectordrawable.graphics.drawable.Animatable2Compat;
import org.signal.glide.Log;
import org.signal.core.util.logging.Log;
import org.signal.glide.common.decode.FrameSeqDecoder;
import org.signal.glide.common.loader.Loader;
@@ -35,7 +35,7 @@ import java.util.Set;
* @CreateDate: 2019/3/27
*/
public abstract class FrameAnimationDrawable<Decoder extends FrameSeqDecoder> extends Drawable implements Animatable2Compat, FrameSeqDecoder.RenderListener {
private static final String TAG = FrameAnimationDrawable.class.getSimpleName();
private static final String TAG = Log.tag(FrameAnimationDrawable.class);
private final Paint paint = new Paint();
private final Decoder frameSeqDecoder;
private DrawFilter drawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);

View File

@@ -15,7 +15,7 @@ import android.os.Looper;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import org.signal.glide.Log;
import org.signal.core.util.logging.Log;
import org.signal.glide.common.executor.FrameDecoderExecutor;
import org.signal.glide.common.io.Reader;
import org.signal.glide.common.io.Writer;
@@ -39,7 +39,7 @@ import java.util.concurrent.locks.LockSupport;
* @CreateDate: 2019/3/27
*/
public abstract class FrameSeqDecoder<R extends Reader, W extends Writer> {
private static final String TAG = FrameSeqDecoder.class.getSimpleName();
private static final String TAG = Log.tag(FrameSeqDecoder.class);
private final int taskId;
private final Loader mLoader;

View File

@@ -8,14 +8,15 @@ public final class AppCapabilities {
private AppCapabilities() {
}
private static final boolean UUID_CAPABLE = false;
private static final boolean GV2_CAPABLE = true;
private static final boolean UUID_CAPABLE = false;
private static final boolean GV2_CAPABLE = true;
private static final boolean GV1_MIGRATION = true;
/**
* @param storageCapable Whether or not the user can use storage service. This is another way of
* asking if the user has set a Signal PIN or not.
*/
public static AccountAttributes.Capabilities getCapabilities(boolean storageCapable) {
return new AccountAttributes.Capabilities(UUID_CAPABLE, GV2_CAPABLE, storageCapable, FeatureFlags.groupsV1AutoMigration());
return new AccountAttributes.Capabilities(UUID_CAPABLE, GV2_CAPABLE, storageCapable, GV1_MIGRATION);
}
}

View File

@@ -4,12 +4,12 @@ import android.content.Context;
import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.insights.InsightsOptOut;
import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.migrations.ApplicationMigrations;
import org.thoughtcrime.securesms.stickers.BlessedPacks;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@@ -43,6 +43,7 @@ public final class AppInitialization {
SignalStore.onFirstEverAppLaunch();
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.ZOZO.getPackId(), BlessedPacks.ZOZO.getPackKey(), false));
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.BANDIT.getPackId(), BlessedPacks.BANDIT.getPackKey(), false));
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.DAY_BY_DAY.getPackId(), BlessedPacks.DAY_BY_DAY.getPackKey(), false));
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forReference(BlessedPacks.SWOON_HANDS.getPackId(), BlessedPacks.SWOON_HANDS.getPackKey()));
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forReference(BlessedPacks.SWOON_FACES.getPackId(), BlessedPacks.SWOON_FACES.getPackKey()));
}
@@ -52,8 +53,33 @@ public final class AppInitialization {
ApplicationDependencies.getMegaphoneRepository().onFirstEverAppLaunch();
SignalStore.onFirstEverAppLaunch();
SignalStore.onboarding().clearAll();
TextSecurePreferences.onPostBackupRestore(context);
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.ZOZO.getPackId(), BlessedPacks.ZOZO.getPackKey(), false));
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.BANDIT.getPackId(), BlessedPacks.BANDIT.getPackKey(), false));
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.DAY_BY_DAY.getPackId(), BlessedPacks.DAY_BY_DAY.getPackKey(), false));
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forReference(BlessedPacks.SWOON_HANDS.getPackId(), BlessedPacks.SWOON_HANDS.getPackKey()));
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forReference(BlessedPacks.SWOON_FACES.getPackId(), BlessedPacks.SWOON_FACES.getPackKey()));
}
/**
* Temporary migration method that does the safest bits of {@link #onFirstEverAppLaunch(Context)}
*/
public static void onRepairFirstEverAppLaunch(@NonNull Context context) {
Log.w(TAG, "onRepairFirstEverAppLaunch()");
InsightsOptOut.userRequestedOptOut(context);
TextSecurePreferences.setAppMigrationVersion(context, ApplicationMigrations.CURRENT_VERSION);
TextSecurePreferences.setJobManagerVersion(context, JobManager.CURRENT_VERSION);
TextSecurePreferences.setLastExperienceVersionCode(context, Util.getCanonicalVersionCode());
TextSecurePreferences.setHasSeenStickerIntroTooltip(context, true);
TextSecurePreferences.setPasswordDisabled(context, true);
TextSecurePreferences.setLastExperienceVersionCode(context, Util.getCanonicalVersionCode());
ApplicationDependencies.getMegaphoneRepository().onFirstEverAppLaunch();
SignalStore.onFirstEverAppLaunch();
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.ZOZO.getPackId(), BlessedPacks.ZOZO.getPackKey(), false));
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.BANDIT.getPackId(), BlessedPacks.BANDIT.getPackKey(), false));
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.DAY_BY_DAY.getPackId(), BlessedPacks.DAY_BY_DAY.getPackKey(), false));
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forReference(BlessedPacks.SWOON_HANDS.getPackId(), BlessedPacks.SWOON_HANDS.getPackKey()));
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forReference(BlessedPacks.SWOON_FACES.getPackId(), BlessedPacks.SWOON_FACES.getPackKey()));
}

View File

@@ -16,23 +16,24 @@
*/
package org.thoughtcrime.securesms;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ProcessLifecycleOwner;
import androidx.multidex.MultiDexApplication;
import com.google.android.gms.security.ProviderInstaller;
import org.conscrypt.Conscrypt;
import org.signal.aesgcmprovider.AesGcmProvider;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.AndroidLogger;
import org.signal.core.util.logging.Log;
import org.signal.core.util.logging.PersistentLogger;
import org.signal.core.util.tracing.Tracer;
import org.signal.glide.SignalGlideCodecs;
import org.signal.ringrtc.CallManager;
import org.thoughtcrime.securesms.database.DatabaseFactory;
@@ -48,11 +49,9 @@ import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob;
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.logging.AndroidLogger;
import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.logging.PersistentLogger;
import org.thoughtcrime.securesms.logging.SignalUncaughtExceptionHandler;
import org.thoughtcrime.securesms.logging.LogSecretProvider;
import org.thoughtcrime.securesms.messageprocessingalarm.MessageProcessReceiver;
import org.thoughtcrime.securesms.migrations.ApplicationMigrations;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.providers.BlobProvider;
@@ -68,20 +67,20 @@ import org.thoughtcrime.securesms.service.RotateSenderCertificateListener;
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
import org.thoughtcrime.securesms.service.UpdateApkRefreshListener;
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
import org.thoughtcrime.securesms.tracing.Trace;
import org.thoughtcrime.securesms.util.AppForegroundObserver;
import org.thoughtcrime.securesms.util.AppStartup;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.SignalUncaughtExceptionHandler;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.util.VersionTracker;
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper;
import org.webrtc.voiceengine.WebRtcAudioManager;
import org.webrtc.voiceengine.WebRtcAudioUtils;
import org.whispersystems.libsignal.logging.SignalProtocolLoggerProvider;
import java.security.Security;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
@@ -92,88 +91,113 @@ import java.util.concurrent.TimeUnit;
*
* @author Moxie Marlinspike
*/
@Trace
public class ApplicationContext extends MultiDexApplication implements DefaultLifecycleObserver {
public class ApplicationContext extends MultiDexApplication implements AppForegroundObserver.Listener {
private static final String TAG = ApplicationContext.class.getSimpleName();
private static final String TAG = Log.tag(ApplicationContext.class);
private ExpiringMessageManager expiringMessageManager;
private ViewOnceMessageManager viewOnceMessageManager;
private PersistentLogger persistentLogger;
private volatile boolean isAppVisible;
public static ApplicationContext getInstance(Context context) {
return (ApplicationContext)context.getApplicationContext();
}
@Override
public void onCreate() {
Tracer.getInstance().start("Application#onCreate()");
AppStartup.getInstance().onApplicationCreate();
long startTime = System.currentTimeMillis();
super.onCreate();
initializeSecurityProvider();
initializeLogging();
Log.i(TAG, "onCreate()");
initializeCrashHandling();
initializeAppDependencies();
initializeFirstEverAppLaunch();
initializeApplicationMigrations();
initializeMessageRetrieval();
initializeExpiringMessageManager();
initializeRevealableMessageManager();
initializeGcmCheck();
initializeSignedPreKeyCheck();
initializePeriodicTasks();
initializeCircumvention();
initializeRingRtc();
initializePendingMessages();
initializeBlobProvider();
initializeCleanup();
initializeGlideCodecs();
FeatureFlags.init();
NotificationChannels.create(this);
RefreshPreKeysJob.scheduleIfNecessary();
StorageSyncHelper.scheduleRoutineSync();
RegistrationUtil.maybeMarkRegistrationComplete(this);
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
if (Build.VERSION.SDK_INT < 21) {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
if (FeatureFlags.internalUser()) {
Tracer.getInstance().setMaxBufferSize(35_000);
}
ApplicationDependencies.getJobManager().beginJobLoop();
super.onCreate();
DynamicTheme.setDefaultDayNightMode(this);
AppStartup.getInstance().addBlocking("security-provider", this::initializeSecurityProvider)
.addBlocking("logging", () -> {
initializeLogging();
Log.i(TAG, "onCreate()");
})
.addBlocking("crash-handling", this::initializeCrashHandling)
.addBlocking("eat-db", () -> DatabaseFactory.getInstance(this))
.addBlocking("app-dependencies", this::initializeAppDependencies)
.addBlocking("notification-channels", () -> NotificationChannels.create(this))
.addBlocking("first-launch", this::initializeFirstEverAppLaunch)
.addBlocking("app-migrations", this::initializeApplicationMigrations)
.addBlocking("ring-rtc", this::initializeRingRtc)
.addBlocking("mark-registration", () -> RegistrationUtil.maybeMarkRegistrationComplete(this))
.addBlocking("lifecycle-observer", () -> ApplicationDependencies.getAppForegroundObserver().addListener(this))
.addBlocking("message-retriever", this::initializeMessageRetrieval)
.addBlocking("dynamic-theme", () -> DynamicTheme.setDefaultDayNightMode(this))
.addBlocking("vector-compat", () -> {
if (Build.VERSION.SDK_INT < 21) {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
})
.addBlocking("proxy-init", () -> {
if (SignalStore.proxy().isProxyEnabled()) {
Log.w(TAG, "Proxy detected. Enabling Conscrypt.setUseEngineSocketByDefault()");
Conscrypt.setUseEngineSocketByDefault(true);
}
})
.addBlocking("blob-provider", this::initializeBlobProvider)
.addNonBlocking(this::initializeRevealableMessageManager)
.addNonBlocking(this::initializeGcmCheck)
.addNonBlocking(this::initializeSignedPreKeyCheck)
.addNonBlocking(this::initializePeriodicTasks)
.addNonBlocking(this::initializeCircumvention)
.addNonBlocking(this::initializePendingMessages)
.addNonBlocking(this::initializeCleanup)
.addNonBlocking(this::initializeGlideCodecs)
.addNonBlocking(FeatureFlags::init)
.addNonBlocking(RefreshPreKeysJob::scheduleIfNecessary)
.addNonBlocking(StorageSyncHelper::scheduleRoutineSync)
.addNonBlocking(() -> ApplicationDependencies.getJobManager().beginJobLoop())
.addPostRender(this::initializeExpiringMessageManager)
.execute();
Log.d(TAG, "onCreate() took " + (System.currentTimeMillis() - startTime) + " ms");
Tracer.getInstance().end("Application#onCreate()");
}
@Override
public void onStart(@NonNull LifecycleOwner owner) {
isAppVisible = true;
public void onForeground() {
long startTime = System.currentTimeMillis();
Log.i(TAG, "App is now visible.");
FeatureFlags.refreshIfNecessary();
ApplicationDependencies.getRecipientCache().warmUp();
RetrieveProfileJob.enqueueRoutineFetchIfNecessary(this);
GroupV1MigrationJob.enqueueRoutineMigrationsIfNecessary(this);
executePendingContactSync();
KeyCachingService.onAppForegrounded(this);
ApplicationDependencies.getFrameRateTracker().begin();
ApplicationDependencies.getMegaphoneRepository().onAppForegrounded();
checkBuildExpiration();
SignalExecutors.BOUNDED.execute(() -> {
FeatureFlags.refreshIfNecessary();
ApplicationDependencies.getRecipientCache().warmUp();
RetrieveProfileJob.enqueueRoutineFetchIfNecessary(this);
GroupV1MigrationJob.enqueueRoutineMigrationsIfNecessary(this);
executePendingContactSync();
KeyCachingService.onAppForegrounded(this);
ApplicationDependencies.getShakeToReport().enable();
checkBuildExpiration();
});
Log.d(TAG, "onStart() took " + (System.currentTimeMillis() - startTime) + " ms");
}
@Override
public void onStop(@NonNull LifecycleOwner owner) {
isAppVisible = false;
public void onBackground() {
Log.i(TAG, "App is no longer visible.");
KeyCachingService.onAppBackgrounded(this);
ApplicationDependencies.getMessageNotifier().clearVisibleThread();
ApplicationDependencies.getFrameRateTracker().end();
ApplicationDependencies.getShakeToReport().disable();
}
public ExpiringMessageManager getExpiringMessageManager() {
if (expiringMessageManager == null) {
initializeExpiringMessageManager();
}
return expiringMessageManager;
}
@@ -181,10 +205,6 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
return viewOnceMessageManager;
}
public boolean isAppVisible() {
return isAppVisible;
}
public PersistentLogger getPersistentLogger() {
return persistentLogger;
}
@@ -221,8 +241,8 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
}
private void initializeLogging() {
persistentLogger = new PersistentLogger(this);
org.thoughtcrime.securesms.logging.Log.initialize(new AndroidLogger(), persistentLogger);
persistentLogger = new PersistentLogger(this, LogSecretProvider.getOrCreateAttachmentSecret(this), BuildConfig.VERSION_NAME);
org.signal.core.util.logging.Log.initialize(new AndroidLogger(), persistentLogger);
SignalProtocolLoggerProvider.setProvider(new CustomSignalProtocolLogger());
}
@@ -241,18 +261,24 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
}
private void initializeAppDependencies() {
ApplicationDependencies.init(this, new ApplicationDependencyProvider(this, new SignalServiceNetworkAccess(this)));
ApplicationDependencies.init(this, new ApplicationDependencyProvider(this));
}
private void initializeFirstEverAppLaunch() {
if (TextSecurePreferences.getFirstInstallVersion(this) == -1) {
if (!SQLCipherOpenHelper.databaseFileExists(this)) {
if (!SQLCipherOpenHelper.databaseFileExists(this) || VersionTracker.getDaysSinceFirstInstalled(this) < 365) {
Log.i(TAG, "First ever app launch!");
AppInitialization.onFirstEverAppLaunch(this);
}
Log.i(TAG, "Setting first install version to " + BuildConfig.CANONICAL_VERSION_CODE);
TextSecurePreferences.setFirstInstallVersion(this, BuildConfig.CANONICAL_VERSION_CODE);
} else if (!TextSecurePreferences.isPasswordDisabled(this) && VersionTracker.getDaysSinceFirstInstalled(this) < 90) {
Log.i(TAG, "Detected a new install that doesn't have passphrases disabled -- assuming bad initialization.");
AppInitialization.onRepairFirstEverAppLaunch(this);
} else if (!TextSecurePreferences.isPasswordDisabled(this) && VersionTracker.getDaysSinceFirstInstalled(this) < 912) {
Log.i(TAG, "Detected a not-recent install that doesn't have passphrases disabled -- disabling now.");
TextSecurePreferences.setPasswordDisabled(this, true);
}
}
@@ -285,6 +311,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
DirectoryRefreshListener.schedule(this);
LocalBackupListener.schedule(this);
RotateSenderCertificateListener.schedule(this);
MessageProcessReceiver.startOrUpdateAlarm(this);
if (BuildConfig.PLAY_STORE_DISABLED) {
UpdateApkRefreshListener.schedule(this);
@@ -293,31 +320,11 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
private void initializeRingRtc() {
try {
Set<String> HARDWARE_AEC_BLACKLIST = new HashSet<String>() {{
add("Pixel");
add("Pixel XL");
add("Moto G5");
add("Moto G (5S) Plus");
add("Moto G4");
add("TA-1053");
add("Mi A1");
add("Mi A2");
add("E5823"); // Sony z5 compact
add("Redmi Note 5");
add("FP2"); // Fairphone FP2
add("MI 5");
}};
Set<String> OPEN_SL_ES_WHITELIST = new HashSet<String>() {{
add("Pixel");
add("Pixel XL");
}};
if (HARDWARE_AEC_BLACKLIST.contains(Build.MODEL)) {
if (RtcDeviceLists.hardwareAECBlocked()) {
WebRtcAudioUtils.setWebRtcBasedAcousticEchoCanceler(true);
}
if (!OPEN_SL_ES_WHITELIST.contains(Build.MODEL)) {
if (!RtcDeviceLists.openSLESAllowed()) {
WebRtcAudioManager.setBlacklistDeviceForOpenSLESUsage(true);
}
@@ -327,23 +334,15 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
}
}
@SuppressLint("StaticFieldLeak")
@WorkerThread
private void initializeCircumvention() {
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
if (new SignalServiceNetworkAccess(ApplicationContext.this).isCensored(ApplicationContext.this)) {
try {
ProviderInstaller.installIfNeeded(ApplicationContext.this);
} catch (Throwable t) {
Log.w(TAG, t);
}
}
return null;
if (new SignalServiceNetworkAccess(ApplicationContext.this).isCensored(ApplicationContext.this)) {
try {
ProviderInstaller.installIfNeeded(ApplicationContext.this);
} catch (Throwable t) {
Log.w(TAG, t);
}
};
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
private void executePendingContactSync() {
@@ -358,23 +357,21 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
if (Build.VERSION.SDK_INT >= 26) {
FcmJobService.schedule(this);
} else {
ApplicationDependencies.getJobManager().add(new PushNotificationReceiveJob(this));
ApplicationDependencies.getJobManager().add(new PushNotificationReceiveJob());
}
TextSecurePreferences.setNeedsMessagePull(this, false);
}
}
@WorkerThread
private void initializeBlobProvider() {
SignalExecutors.BOUNDED.execute(() -> {
BlobProvider.getInstance().onSessionStart(this);
});
BlobProvider.getInstance().initialize(this);
}
@WorkerThread
private void initializeCleanup() {
SignalExecutors.BOUNDED.execute(() -> {
int deleted = DatabaseFactory.getAttachmentDatabase(this).deleteAbandonedPreuploadedAttachments();
Log.i(TAG, "Deleted " + deleted + " abandoned attachments.");
});
int deleted = DatabaseFactory.getAttachmentDatabase(this).deleteAbandonedPreuploadedAttachments();
Log.i(TAG, "Deleted " + deleted + " abandoned attachments.");
}
private void initializeGlideCodecs() {

View File

@@ -23,6 +23,7 @@ import android.content.SharedPreferences;
import android.graphics.PorterDuff;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -31,28 +32,34 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.preference.Preference;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.conversationlist.model.UnreadPayments;
import org.thoughtcrime.securesms.conversationlist.model.UnreadPaymentsLiveData;
import org.thoughtcrime.securesms.help.HelpFragment;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.payments.preferences.PaymentsActivity;
import org.thoughtcrime.securesms.preferences.AdvancedPreferenceFragment;
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
import org.thoughtcrime.securesms.preferences.AppearancePreferenceFragment;
import org.thoughtcrime.securesms.preferences.BackupsPreferenceFragment;
import org.thoughtcrime.securesms.preferences.ChatsPreferenceFragment;
import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment;
import org.thoughtcrime.securesms.preferences.DataAndStoragePreferenceFragment;
import org.thoughtcrime.securesms.preferences.EditProxyFragment;
import org.thoughtcrime.securesms.preferences.NotificationsPreferenceFragment;
import org.thoughtcrime.securesms.preferences.SmsMmsPreferenceFragment;
import org.thoughtcrime.securesms.preferences.StoragePreferenceFragment;
import org.thoughtcrime.securesms.preferences.widgets.PaymentsPreference;
import org.thoughtcrime.securesms.preferences.widgets.ProfilePreference;
import org.thoughtcrime.securesms.preferences.widgets.UsernamePreference;
import org.thoughtcrime.securesms.profiles.edit.EditProfileActivity;
import org.thoughtcrime.securesms.profiles.manage.ManageProfileActivity;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.CachedInflater;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ThemeUtil;
/**
* The Activity for application preference display and management.
@@ -64,10 +71,13 @@ import org.thoughtcrime.securesms.util.ThemeUtil;
public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
implements SharedPreferences.OnSharedPreferenceChangeListener
{
public static final String LAUNCH_TO_BACKUPS_FRAGMENT = "launch.to.backups.fragment";
public static final String LAUNCH_TO_BACKUPS_FRAGMENT = "launch.to.backups.fragment";
public static final String LAUNCH_TO_HELP_FRAGMENT = "launch.to.help.fragment";
public static final String LAUNCH_TO_PROXY_FRAGMENT = "launch.to.proxy.fragment";
public static final String LAUNCH_TO_NOTIFICATIONS_FRAGMENT = "launch.to.notifications.fragment";
@SuppressWarnings("unused")
private static final String TAG = ApplicationPreferencesActivity.class.getSimpleName();
private static final String TAG = Log.tag(ApplicationPreferencesActivity.class);
private static final String PREFERENCE_CATEGORY_PROFILE = "preference_category_profile";
private static final String PREFERENCE_CATEGORY_USERNAME = "preference_category_username";
@@ -81,6 +91,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
private static final String PREFERENCE_CATEGORY_HELP = "preference_category_help";
private static final String PREFERENCE_CATEGORY_ADVANCED = "preference_category_advanced";
private static final String PREFERENCE_CATEGORY_DONATE = "preference_category_donate";
private static final String PREFERENCE_CATEGORY_PAYMENTS = "preference_category_payments";
private static final String WAS_CONFIGURATION_UPDATED = "was_configuration_updated";
@@ -104,6 +115,15 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
initFragment(android.R.id.content, new NotificationsPreferenceFragment());
} else if (getIntent() != null && getIntent().getBooleanExtra(LAUNCH_TO_BACKUPS_FRAGMENT, false)) {
initFragment(android.R.id.content, new BackupsPreferenceFragment());
} else if (getIntent() != null && getIntent().getBooleanExtra(LAUNCH_TO_HELP_FRAGMENT, false)) {
Bundle bundle = new Bundle();
bundle.putInt(HelpFragment.START_CATEGORY_INDEX, getIntent().getIntExtra(HelpFragment.START_CATEGORY_INDEX, 0));
initFragment(android.R.id.content, new HelpFragment(), null, bundle);
} else if (getIntent() != null && getIntent().getBooleanExtra(LAUNCH_TO_PROXY_FRAGMENT, false)) {
initFragment(android.R.id.content, EditProxyFragment.newInstance());
} else if (getIntent() != null && getIntent().getBooleanExtra(LAUNCH_TO_NOTIFICATIONS_FRAGMENT, false)) {
initFragment(android.R.id.content, new NotificationsPreferenceFragment());
} else if (icicle == null) {
initFragment(android.R.id.content, new ApplicationPreferenceFragment());
} else {
@@ -159,6 +179,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
DynamicTheme.setDefaultDayNightMode(this);
recreate();
} else if (key.equals(TextSecurePreferences.LANGUAGE_PREF)) {
CachedInflater.from(this).clear();
wasConfigurationUpdated = true;
recreate();
@@ -178,6 +199,8 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
public static class ApplicationPreferenceFragment extends CorrectedPreferenceFragment {
private final UnreadPaymentsLiveData unreadPaymentsLiveData = new UnreadPaymentsLiveData();
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -207,9 +230,29 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
this.findPreference(PREFERENCE_CATEGORY_DONATE)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_DONATE));
Preference paymentsPreference = this.findPreference(PREFERENCE_CATEGORY_PAYMENTS);
if (SignalStore.paymentsValues().getPaymentsAvailability().showPaymentsMenu()) {
paymentsPreference.setVisible(true);
paymentsPreference.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_PAYMENTS));
} else {
paymentsPreference.setVisible(false);
}
tintIcons();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (SignalStore.paymentsValues().getPaymentsAvailability().showPaymentsMenu()) {
PaymentsPreference paymentsPreference = (PaymentsPreference) this.findPreference(PREFERENCE_CATEGORY_PAYMENTS);
unreadPaymentsLiveData.observe(getViewLifecycleOwner(), unreadPayments -> paymentsPreference.setUnreadCount(unreadPayments.transform(UnreadPayments::getUnreadCount).or(-1)));
}
}
private void tintIcons() {
if (Build.VERSION.SDK_INT >= 21) return;
@@ -308,7 +351,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
fragment = new ChatsPreferenceFragment();
break;
case PREFERENCE_CATEGORY_STORAGE:
fragment = new StoragePreferenceFragment();
fragment = new DataAndStoragePreferenceFragment();
break;
case PREFERENCE_CATEGORY_DEVICES:
Intent intent = new Intent(getActivity(), DeviceActivity.class);
@@ -323,6 +366,9 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
case PREFERENCE_CATEGORY_DONATE:
CommunicationActions.openBrowserLink(requireContext(), getString(R.string.donate_url));
break;
case PREFERENCE_CATEGORY_PAYMENTS:
startActivity(new Intent(requireContext(), PaymentsActivity.class));
break;
default:
throw new AssertionError();
}
@@ -341,7 +387,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
private class ProfileClickListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
requireActivity().startActivity(EditProfileActivity.getIntentForUserProfileEdit(preference.getContext()));
requireActivity().startActivity(ManageProfileActivity.getIntent(requireActivity()));
return true;
}
}
@@ -349,7 +395,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
private class UsernameClickListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
requireActivity().startActivity(EditProfileActivity.getIntentForUsernameEdit(preference.getContext()));
requireActivity().startActivity(ManageProfileActivity.getIntentForUsernameEdit(preference.getContext()));
return true;
}
}

View File

@@ -26,11 +26,11 @@ import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.request.transition.Transition;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;

View File

@@ -1,10 +1,8 @@
package org.thoughtcrime.securesms;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
@@ -16,11 +14,11 @@ import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.app.ActivityCompat;
import androidx.core.app.ActivityOptionsCompat;
import org.thoughtcrime.securesms.logging.Log;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.util.AppStartup;
import org.thoughtcrime.securesms.util.ConfigurationUtil;
import org.thoughtcrime.securesms.util.ContextUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.WindowUtil;
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper;
import java.util.Objects;
@@ -35,8 +33,10 @@ public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
AppStartup.getInstance().onCriticalRenderEventStart();
logEvent("onCreate()");
super.onCreate(savedInstanceState);
AppStartup.getInstance().onCriticalRenderEventEnd();
}
@Override
@@ -48,6 +48,7 @@ public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onStart() {
logEvent("onStart()");
ApplicationDependencies.getShakeToReport().registerActivity(this);
super.onStart();
}

View File

@@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.conversation.ConversationMessage;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient;
@@ -35,7 +36,9 @@ public interface BindableConversationItem extends Unbindable {
@NonNull Set<ConversationMessage> batchSelected,
@NonNull Recipient recipients,
@Nullable String searchQuery,
boolean pulseMention);
boolean pulseMention,
boolean hasWallpaper,
boolean isMessageRequestAccepted);
ConversationMessage getConversationMessage();
@@ -59,7 +62,12 @@ public interface BindableConversationItem extends Unbindable {
void onVoiceNotePause(@NonNull Uri uri);
void onVoiceNotePlay(@NonNull Uri uri, long messageId, double position);
void onVoiceNoteSeekTo(@NonNull Uri uri, double position);
void onGroupMigrationLearnMoreClicked(@NonNull List<RecipientId> pendingRecipients);
void onGroupMigrationLearnMoreClicked(@NonNull GroupMigrationMembershipChange membershipChange);
void onDecryptionFailedLearnMoreClicked();
void onSafetyNumberLearnMoreClicked(@NonNull Recipient recipient);
void onJoinGroupCallClicked();
void onInviteFriendsToGroupClicked(@NonNull GroupId.V2 groupId);
void onEnableCallNotificationsClicked();
/** @return true if handled, false if you want to let the normal url handling continue */
boolean onUrlClicked(@NonNull String url);

View File

@@ -11,9 +11,6 @@ import androidx.lifecycle.Lifecycle;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
/**

View File

@@ -3,26 +3,25 @@ package org.thoughtcrime.securesms;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.ContextThemeWrapper;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.ThemeUtil;
public class ClearProfileAvatarActivity extends Activity {
public final class ClearAvatarPromptActivity extends Activity {
private static final String ARG_TITLE = "arg_title";
public static Intent createForUserProfilePhoto() {
return new Intent("org.thoughtcrime.securesms.action.CLEAR_PROFILE_PHOTO");
Intent intent = new Intent(ApplicationDependencies.getApplication(), ClearAvatarPromptActivity.class);
intent.putExtra(ARG_TITLE, R.string.ClearProfileActivity_remove_profile_photo);
return intent;
}
public static Intent createForGroupProfilePhoto() {
Intent intent = new Intent("org.thoughtcrime.securesms.action.CLEAR_PROFILE_PHOTO");
Intent intent = new Intent(ApplicationDependencies.getApplication(), ClearAvatarPromptActivity.class);
intent.putExtra(ARG_TITLE, R.string.ClearProfileActivity_remove_group_photo);
return intent;
}
@@ -31,10 +30,10 @@ public class ClearProfileAvatarActivity extends Activity {
public void onResume() {
super.onResume();
int titleId = getIntent().getIntExtra(ARG_TITLE, R.string.ClearProfileActivity_remove_profile_photo);
int message = getIntent().getIntExtra(ARG_TITLE, 0);
new AlertDialog.Builder(new ContextThemeWrapper(this, DynamicTheme.isDarkTheme(this) ? R.style.TextSecure_DarkTheme : R.style.TextSecure_LightTheme))
.setMessage(titleId)
.setMessage(message)
.setNegativeButton(android.R.string.cancel, (dialog, which) -> finish())
.setPositiveButton(R.string.ClearProfileActivity_remove, (dialog, which) -> {
Intent result = new Intent();

View File

@@ -11,12 +11,12 @@ import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessageDatabase;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.PushDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
@@ -29,17 +29,16 @@ import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.VerifySpan;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalSessionLock;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
import java.io.IOException;
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
public class ConfirmIdentityDialog extends AlertDialog {
@SuppressWarnings("unused")
private static final String TAG = ConfirmIdentityDialog.class.getSimpleName();
private static final String TAG = Log.tag(ConfirmIdentityDialog.class);
private OnClickListener callback;
@@ -96,7 +95,7 @@ public class ConfirmIdentityDialog extends AlertDialog {
{
@Override
protected Void doInBackground(Void... params) {
synchronized (SESSION_LOCK) {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(Recipient.resolved(recipientId).requireServiceId(), 1);
TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(getContext());
@@ -138,7 +137,6 @@ public class ConfirmIdentityDialog extends AlertDialog {
private void processIncomingMessageRecord(MessageRecord messageRecord) {
try {
PushDatabase pushDatabase = DatabaseFactory.getPushDatabase(getContext());
MessageDatabase smsDatabase = DatabaseFactory.getSmsDatabase(getContext());
smsDatabase.removeMismatchedIdentity(messageRecord.getId(),
@@ -157,9 +155,7 @@ public class ConfirmIdentityDialog extends AlertDialog {
0,
null);
long pushId = pushDatabase.insert(envelope);
ApplicationDependencies.getJobManager().add(new PushDecryptMessageJob(getContext(), pushId, messageRecord.getId()));
ApplicationDependencies.getJobManager().add(new PushDecryptMessageJob(getContext(), envelope, messageRecord.getId()));
} catch (IOException e) {
throw new AssertionError(e);
}

View File

@@ -22,10 +22,10 @@ import android.os.Bundle;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.components.ContactFilterToolbar;
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
@@ -47,7 +47,7 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActivit
ContactSelectionListFragment.OnContactSelectedListener,
ContactSelectionListFragment.ScrollCallback
{
private static final String TAG = ContactSelectionActivity.class.getSimpleName();
private static final String TAG = Log.tag(ContactSelectionActivity.class);
public static final String EXTRA_LAYOUT_RES_ID = "layout_res_id";
@@ -99,7 +99,6 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActivit
private void initializeResources() {
contactsFragment = (ContactSelectionListFragment) getSupportFragmentManager().findFragmentById(R.id.contact_selection_list_fragment);
contactsFragment.setOnContactSelectedListener(this);
contactsFragment.setOnRefreshListener(this);
}

View File

@@ -55,8 +55,10 @@ import com.annimon.stream.Stream;
import com.google.android.material.chip.ChipGroup;
import com.pnikosis.materialishprogress.ProgressWheel;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.components.RecyclerViewFastScroller;
import org.thoughtcrime.securesms.components.emoji.WarningTextView;
import org.thoughtcrime.securesms.contacts.AbstractContactsCursorLoader;
import org.thoughtcrime.securesms.contacts.ContactChip;
import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter;
import org.thoughtcrime.securesms.contacts.ContactSelectionListItem;
@@ -66,7 +68,6 @@ import org.thoughtcrime.securesms.contacts.SelectedContact;
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
import org.thoughtcrime.securesms.groups.SelectionLimits;
import org.thoughtcrime.securesms.groups.ui.GroupLimitDialog;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.permissions.Permissions;
@@ -76,6 +77,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.UsernameUtil;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.adapter.FixedViewsAdapter;
import org.thoughtcrime.securesms.util.adapter.RecyclerViewConcatenateAdapterStickyHeader;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
@@ -110,22 +112,27 @@ public final class ContactSelectionListFragment extends LoggingFragment
public static final String SELECTION_LIMITS = "selection_limits";
public static final String CURRENT_SELECTION = "current_selection";
public static final String HIDE_COUNT = "hide_count";
public static final String CAN_SELECT_SELF = "can_select_self";
public static final String DISPLAY_CHIPS = "display_chips";
private ConstraintLayout constraintLayout;
private TextView emptyText;
private OnContactSelectedListener onContactSelectedListener;
private SwipeRefreshLayout swipeRefresh;
private View showContactsLayout;
private Button showContactsButton;
private TextView showContactsDescription;
private ProgressWheel showContactsProgress;
private String cursorFilter;
private RecyclerView recyclerView;
private RecyclerViewFastScroller fastScroller;
private ContactSelectionListAdapter cursorRecyclerViewAdapter;
private ChipGroup chipGroup;
private HorizontalScrollView chipGroupScrollContainer;
private WarningTextView groupLimit;
private OnSelectionLimitReachedListener onSelectionLimitReachedListener;
private AbstractContactsCursorLoaderFactoryProvider cursorFactoryProvider;
private ConstraintLayout constraintLayout;
private TextView emptyText;
private OnContactSelectedListener onContactSelectedListener;
private SwipeRefreshLayout swipeRefresh;
private View showContactsLayout;
private Button showContactsButton;
private TextView showContactsDescription;
private ProgressWheel showContactsProgress;
private String cursorFilter;
private RecyclerView recyclerView;
private RecyclerViewFastScroller fastScroller;
private ContactSelectionListAdapter cursorRecyclerViewAdapter;
private ChipGroup chipGroup;
private HorizontalScrollView chipGroupScrollContainer;
private WarningTextView groupLimit;
@Nullable private FixedViewsAdapter headerAdapter;
@Nullable private FixedViewsAdapter footerAdapter;
@@ -136,6 +143,7 @@ public final class ContactSelectionListFragment extends LoggingFragment
private Set<RecipientId> currentSelection;
private boolean isMulti;
private boolean hideCount;
private boolean canSelectSelf;
@Override
public void onAttach(@NonNull Context context) {
@@ -145,9 +153,33 @@ public final class ContactSelectionListFragment extends LoggingFragment
listCallback = (ListCallback) context;
}
if (getParentFragment() instanceof ScrollCallback) {
scrollCallback = (ScrollCallback) getParentFragment();
}
if (context instanceof ScrollCallback) {
scrollCallback = (ScrollCallback) context;
}
if (getParentFragment() instanceof OnContactSelectedListener) {
onContactSelectedListener = (OnContactSelectedListener) getParentFragment();
}
if (context instanceof OnContactSelectedListener) {
onContactSelectedListener = (OnContactSelectedListener) context;
}
if (context instanceof OnSelectionLimitReachedListener) {
onSelectionLimitReachedListener = (OnSelectionLimitReachedListener) context;
}
if (context instanceof AbstractContactsCursorLoaderFactoryProvider) {
cursorFactoryProvider = (AbstractContactsCursorLoaderFactoryProvider) context;
}
if (getParentFragment() instanceof AbstractContactsCursorLoaderFactoryProvider) {
cursorFactoryProvider = (AbstractContactsCursorLoaderFactoryProvider) context;
}
}
@Override
@@ -176,7 +208,7 @@ public final class ContactSelectionListFragment extends LoggingFragment
activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
if (activity.getIntent().getBooleanExtra(RECENTS, false)) {
if (safeArguments().getBoolean(RECENTS, activity.getIntent().getBooleanExtra(RECENTS, false))) {
LoaderManager.getInstance(this).initLoader(0, null, ContactSelectionListFragment.this);
} else {
initializeNoContactsPermission();
@@ -210,13 +242,18 @@ public final class ContactSelectionListFragment extends LoggingFragment
}
});
Intent intent = requireActivity().getIntent();
Intent intent = requireActivity().getIntent();
Bundle arguments = safeArguments();
swipeRefresh.setEnabled(intent.getBooleanExtra(REFRESHABLE, true));
swipeRefresh.setEnabled(arguments.getBoolean(REFRESHABLE, intent.getBooleanExtra(REFRESHABLE, true)));
hideCount = intent.getBooleanExtra(HIDE_COUNT, false);
selectionLimit = intent.getParcelableExtra(SELECTION_LIMITS);
isMulti = selectionLimit != null;
hideCount = arguments.getBoolean(HIDE_COUNT, intent.getBooleanExtra(HIDE_COUNT, false));
selectionLimit = arguments.getParcelable(SELECTION_LIMITS);
if (selectionLimit == null) {
selectionLimit = intent.getParcelableExtra(SELECTION_LIMITS);
}
isMulti = selectionLimit != null;
canSelectSelf = arguments.getBoolean(CAN_SELECT_SELF, intent.getBooleanExtra(CAN_SELECT_SELF, !isMulti));
if (!isMulti) {
selectionLimit = SelectionLimits.NO_LIMITS;
@@ -229,6 +266,10 @@ public final class ContactSelectionListFragment extends LoggingFragment
return view;
}
private @NonNull Bundle safeArguments() {
return getArguments() != null ? getArguments() : new Bundle();
}
private void updateGroupLimit(int chipCount) {
int members = currentSelection.size() + chipCount;
groupLimit.setText(getResources().getQuantityString(R.plurals.ContactSelectionListFragment_d_members, members, members));
@@ -258,7 +299,10 @@ public final class ContactSelectionListFragment extends LoggingFragment
}
private Set<RecipientId> getCurrentSelection() {
List<RecipientId> currentSelection = requireActivity().getIntent().getParcelableArrayListExtra(CURRENT_SELECTION);
List<RecipientId> currentSelection = safeArguments().getParcelableArrayList(CURRENT_SELECTION);
if (currentSelection == null) {
currentSelection = requireActivity().getIntent().getParcelableArrayListExtra(CURRENT_SELECTION);
}
return currentSelection == null ? Collections.emptySet()
: Collections.unmodifiableSet(Stream.of(currentSelection).collect(Collectors.toSet()));
@@ -295,7 +339,7 @@ public final class ContactSelectionListFragment extends LoggingFragment
}
recyclerView.setAdapter(concatenateAdapter);
recyclerView.addItemDecoration(new StickyHeaderDecoration(concatenateAdapter, true, true));
recyclerView.addItemDecoration(new StickyHeaderDecoration(concatenateAdapter, true, true, 0));
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
@@ -372,10 +416,15 @@ public final class ContactSelectionListFragment extends LoggingFragment
@Override
public @NonNull Loader<Cursor> onCreateLoader(int id, Bundle args) {
FragmentActivity activity = requireActivity();
return new ContactsCursorLoader(activity,
activity.getIntent().getIntExtra(DISPLAY_MODE, DisplayMode.FLAG_ALL),
cursorFilter, activity.getIntent().getBooleanExtra(RECENTS, false));
FragmentActivity activity = requireActivity();
int displayMode = safeArguments().getInt(DISPLAY_MODE, activity.getIntent().getIntExtra(DISPLAY_MODE, DisplayMode.FLAG_ALL));
boolean displayRecents = safeArguments().getBoolean(RECENTS, activity.getIntent().getBooleanExtra(RECENTS, false));
if (cursorFactoryProvider != null) {
return cursorFactoryProvider.get().create();
} else {
return new ContactsCursorLoader.Factory(activity, displayMode, cursorFilter, displayRecents).create();
}
}
@Override
@@ -448,8 +497,11 @@ public final class ContactSelectionListFragment extends LoggingFragment
swipeRefresh.setVisibility(View.VISIBLE);
reset();
} else {
Toast.makeText(getContext(), R.string.ContactSelectionListFragment_error_retrieving_contacts_check_your_network_connection, Toast.LENGTH_LONG).show();
initializeNoContactsPermission();
Context context = getContext();
if (context != null) {
Toast.makeText(getContext(), R.string.ContactSelectionListFragment_error_retrieving_contacts_check_your_network_connection, Toast.LENGTH_LONG).show();
initializeNoContactsPermission();
}
}
}
}.execute();
@@ -461,14 +513,18 @@ public final class ContactSelectionListFragment extends LoggingFragment
SelectedContact selectedContact = contact.isUsernameType() ? SelectedContact.forUsername(contact.getRecipientId().orNull(), contact.getNumber())
: SelectedContact.forPhone(contact.getRecipientId().orNull(), contact.getNumber());
if (isMulti && Recipient.self().getId().equals(selectedContact.getOrCreateRecipientId(requireContext()))) {
if (!canSelectSelf && Recipient.self().getId().equals(selectedContact.getOrCreateRecipientId(requireContext()))) {
Toast.makeText(requireContext(), R.string.ContactSelectionListFragment_you_do_not_need_to_add_yourself_to_the_group, Toast.LENGTH_SHORT).show();
return;
}
if (!isMulti || !cursorRecyclerViewAdapter.isSelectedContact(selectedContact)) {
if (selectionHardLimitReached()) {
GroupLimitDialog.showHardLimitMessage(requireContext());
if (onSelectionLimitReachedListener != null) {
onSelectionLimitReachedListener.onHardLimitReached(selectionLimit.getHardLimit());
} else {
GroupLimitDialog.showHardLimitMessage(requireContext());
}
return;
}
@@ -486,11 +542,11 @@ public final class ContactSelectionListFragment extends LoggingFragment
if (onContactSelectedListener != null) {
if (onContactSelectedListener.onBeforeContactSelected(Optional.of(recipient.getId()), null)) {
markContactSelected(selected);
cursorRecyclerViewAdapter.notifyItemChanged(recyclerView.getChildAdapterPosition(contact), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
cursorRecyclerViewAdapter.notifyItemRangeChanged(0, cursorRecyclerViewAdapter.getItemCount(), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
}
} else {
markContactSelected(selected);
cursorRecyclerViewAdapter.notifyItemChanged(recyclerView.getChildAdapterPosition(contact), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
cursorRecyclerViewAdapter.notifyItemRangeChanged(0, cursorRecyclerViewAdapter.getItemCount(), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
}
} else {
new AlertDialog.Builder(requireContext())
@@ -504,16 +560,16 @@ public final class ContactSelectionListFragment extends LoggingFragment
if (onContactSelectedListener != null) {
if (onContactSelectedListener.onBeforeContactSelected(contact.getRecipientId(), contact.getNumber())) {
markContactSelected(selectedContact);
cursorRecyclerViewAdapter.notifyItemChanged(recyclerView.getChildAdapterPosition(contact), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
cursorRecyclerViewAdapter.notifyItemRangeChanged(0, cursorRecyclerViewAdapter.getItemCount(), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
}
} else {
markContactSelected(selectedContact);
cursorRecyclerViewAdapter.notifyItemChanged(recyclerView.getChildAdapterPosition(contact), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
cursorRecyclerViewAdapter.notifyItemRangeChanged(0, cursorRecyclerViewAdapter.getItemCount(), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
}
}
} else {
markContactUnselected(selectedContact);
cursorRecyclerViewAdapter.notifyItemChanged(recyclerView.getChildAdapterPosition(contact), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
cursorRecyclerViewAdapter.notifyItemRangeChanged(0, cursorRecyclerViewAdapter.getItemCount(), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
if (onContactSelectedListener != null) {
onContactSelectedListener.onContactDeselected(contact.getRecipientId(), contact.getNumber());
@@ -608,7 +664,11 @@ public final class ContactSelectionListFragment extends LoggingFragment
chipGroup.addView(chip);
updateGroupLimit(getChipCount());
if (selectionWarningLimitReachedExactly()) {
GroupLimitDialog.showRecommendedLimitMessage(requireContext());
if (onSelectionLimitReachedListener != null) {
onSelectionLimitReachedListener.onSuggestedLimitReached(selectionLimit.getRecommendedLimit());
} else {
GroupLimitDialog.showRecommendedLimitMessage(requireContext());
}
}
}
@@ -630,6 +690,10 @@ public final class ContactSelectionListFragment extends LoggingFragment
}
private void setChipGroupVisibility(int visibility) {
if (!safeArguments().getBoolean(DISPLAY_CHIPS, requireActivity().getIntent().getBooleanExtra(DISPLAY_CHIPS, true))) {
return;
}
TransitionManager.beginDelayedTransition(constraintLayout, new AutoTransition().setDuration(CHIP_GROUP_REVEAL_DURATION_MS));
ConstraintSet constraintSet = new ConstraintSet();
@@ -638,16 +702,12 @@ public final class ContactSelectionListFragment extends LoggingFragment
constraintSet.applyTo(constraintLayout);
}
public void setOnContactSelectedListener(OnContactSelectedListener onContactSelectedListener) {
this.onContactSelectedListener = onContactSelectedListener;
}
public void setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener onRefreshListener) {
this.swipeRefresh.setOnRefreshListener(onRefreshListener);
}
private void smoothScrollChipsToEnd() {
int x = chipGroupScrollContainer.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR ? chipGroup.getWidth() : 0;
int x = ViewUtil.isLtr(chipGroupScrollContainer) ? chipGroup.getWidth() : 0;
chipGroupScrollContainer.smoothScrollTo(x, 0);
}
@@ -657,6 +717,11 @@ public final class ContactSelectionListFragment extends LoggingFragment
void onContactDeselected(Optional<RecipientId> recipientId, String number);
}
public interface OnSelectionLimitReachedListener {
void onSuggestedLimitReached(int limit);
void onHardLimitReached(int limit);
}
public interface ListCallback {
void onInvite();
void onNewGroup(boolean forceV1);
@@ -665,4 +730,8 @@ public final class ContactSelectionListFragment extends LoggingFragment
public interface ScrollCallback {
void onBeginScroll();
}
public interface AbstractContactsCursorLoaderFactoryProvider {
@NonNull AbstractContactsCursorLoader.Factory get();
}
}

View File

@@ -9,6 +9,7 @@ import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Parcelable;
import android.view.View;
@@ -150,7 +151,7 @@ public class DatabaseMigrationActivity extends PassphraseRequiredActivity {
startActivity((Intent)getIntent().getParcelableExtra("next_intent"));
} else {
// TODO [greyson] Navigation
startActivity(new Intent(this, MainActivity.class));
startActivity(MainActivity.clearTop(this));
}
}
@@ -158,6 +159,11 @@ public class DatabaseMigrationActivity extends PassphraseRequiredActivity {
}
private class ImportStateHandler extends Handler {
public ImportStateHandler() {
super(Looper.getMainLooper());
}
@Override
public void handleMessage(Message message) {
switch (message.what) {

View File

@@ -18,17 +18,17 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import org.signal.core.util.ThreadUtil;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.qr.ScanListener;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.InvalidKeyException;
@@ -45,7 +45,7 @@ public class DeviceActivity extends PassphraseRequiredActivity
implements Button.OnClickListener, ScanListener, DeviceLinkFragment.LinkClickedListener
{
private static final String TAG = DeviceActivity.class.getSimpleName();
private static final String TAG = Log.tag(DeviceActivity.class);
private final DynamicTheme dynamicTheme = new DynamicTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
@@ -123,7 +123,7 @@ public class DeviceActivity extends PassphraseRequiredActivity
@Override
public void onQrDataFound(final String data) {
Util.runOnMain(() -> {
ThreadUtil.runOnMain(() -> {
((Vibrator)getSystemService(Context.VIBRATOR_SERVICE)).vibrate(50);
Uri uri = Uri.parse(data);
deviceLinkFragment.setLinkClickedListener(uri, DeviceActivity.this);

View File

@@ -5,8 +5,6 @@ import android.annotation.TargetApi;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewAnimationUtils;
@@ -15,6 +13,8 @@ import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.components.camera.CameraView;
import org.thoughtcrime.securesms.qr.ScanListener;
import org.thoughtcrime.securesms.qr.ScanningThread;
@@ -32,9 +32,9 @@ public class DeviceAddFragment extends LoggingFragment {
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup viewGroup, Bundle bundle) {
this.container = ViewUtil.inflate(inflater, viewGroup, R.layout.device_add_fragment);
this.overlay = ViewUtil.findById(this.container, R.id.overlay);
this.scannerView = ViewUtil.findById(this.container, R.id.scanner);
this.devicesImage = ViewUtil.findById(this.container, R.id.devices);
this.overlay = this.container.findViewById(R.id.overlay);
this.scannerView = this.container.findViewById(R.id.scanner);
this.devicesImage = this.container.findViewById(R.id.devices);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
this.overlay.setOrientation(LinearLayout.HORIZONTAL);

View File

@@ -3,13 +3,14 @@ package org.thoughtcrime.securesms;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
public class DeviceLinkFragment extends Fragment implements View.OnClickListener {
private LinearLayout container;

View File

@@ -6,15 +6,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.ListFragment;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
import androidx.appcompat.app.AlertDialog;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.devicelist.Device;
import org.thoughtcrime.securesms.logging.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -24,12 +15,20 @@ import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.ListFragment;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
import com.melnykov.fab.FloatingActionButton;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.loaders.DeviceListLoader;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.devicelist.Device;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import java.io.IOException;
@@ -41,7 +40,7 @@ public class DeviceListFragment extends ListFragment
ListView.OnItemClickListener, Button.OnClickListener
{
private static final String TAG = DeviceListFragment.class.getSimpleName();
private static final String TAG = Log.tag(DeviceListFragment.class);
private SignalServiceAccountManager accountManager;
private Locale locale;
@@ -68,7 +67,7 @@ public class DeviceListFragment extends ListFragment
this.empty = view.findViewById(R.id.empty);
this.progressContainer = view.findViewById(R.id.progress_container);
this.addDeviceButton = ViewUtil.findById(view, R.id.add_device);
this.addDeviceButton = view.findViewById(R.id.add_device);
this.addDeviceButton.setOnClickListener(this);
return view;

View File

@@ -2,13 +2,16 @@ package org.thoughtcrime.securesms;
import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AlertDialog;
import android.view.Window;
import androidx.appcompat.app.AlertDialog;
import org.signal.core.util.logging.Log;
public class DeviceProvisioningActivity extends PassphraseRequiredActivity {
@SuppressWarnings("unused")
private static final String TAG = DeviceProvisioningActivity.class.getSimpleName();
private static final String TAG = Log.tag(DeviceProvisioningActivity.class);
@Override
protected void onPreCreate() {

View File

@@ -7,6 +7,8 @@ import android.graphics.PorterDuff;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -35,10 +37,12 @@ import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.DynamicNoActionBarInviteTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.WindowUtil;
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture.Listener;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
import org.thoughtcrime.securesms.util.text.AfterTextChanged;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.concurrent.ExecutionException;
@@ -93,26 +97,40 @@ public class InviteActivity extends PassphraseRequiredActivity implements Contac
slideInAnimation = loadAnimation(R.anim.slide_from_bottom);
slideOutAnimation = loadAnimation(R.anim.slide_to_bottom);
View shareButton = ViewUtil.findById(this, R.id.share_button);
View smsButton = ViewUtil.findById(this, R.id.sms_button);
Button smsCancelButton = ViewUtil.findById(this, R.id.cancel_sms_button);
ContactFilterToolbar contactFilter = ViewUtil.findById(this, R.id.contact_filter);
View shareButton = findViewById(R.id.share_button);
Button smsButton = findViewById(R.id.sms_button);
Button smsCancelButton = findViewById(R.id.cancel_sms_button);
ContactFilterToolbar contactFilter = findViewById(R.id.contact_filter);
inviteText = ViewUtil.findById(this, R.id.invite_text);
smsSendFrame = ViewUtil.findById(this, R.id.sms_send_frame);
smsSendButton = ViewUtil.findById(this, R.id.send_sms_button);
inviteText = findViewById(R.id.invite_text);
smsSendFrame = findViewById(R.id.sms_send_frame);
smsSendButton = findViewById(R.id.send_sms_button);
contactsFragment = (ContactSelectionListFragment)getSupportFragmentManager().findFragmentById(R.id.contact_selection_list_fragment);
inviteText.setText(getString(R.string.InviteActivity_lets_switch_to_signal, getString(R.string.install_url)));
inviteText.addTextChangedListener(new AfterTextChanged(editable -> {
boolean isEnabled = editable.length() > 0;
smsButton.setEnabled(isEnabled);
shareButton.setEnabled(isEnabled);
smsButton.animate().alpha(isEnabled ? 1f : 0.5f);
shareButton.animate().alpha(isEnabled ? 1f : 0.5f);
}));
updateSmsButtonText(contactsFragment.getSelectedContacts().size());
contactsFragment.setOnContactSelectedListener(this);
shareButton.setOnClickListener(new ShareClickListener());
smsButton.setOnClickListener(new SmsClickListener());
smsCancelButton.setOnClickListener(new SmsCancelClickListener());
smsSendButton.setOnClickListener(new SmsSendClickListener());
contactFilter.setOnFilterChangedListener(new ContactFilterChangedListener());
contactFilter.setNavigationIcon(R.drawable.ic_search_conversation_24);
if (Util.isDefaultSmsProvider(this)) {
shareButton.setOnClickListener(new ShareClickListener());
smsButton.setOnClickListener(new SmsClickListener());
} else {
shareButton.setVisibility(View.GONE);
smsButton.setOnClickListener(new ShareClickListener());
smsButton.setText(R.string.InviteActivity_share);
}
}
private Animation loadAnimation(@AnimRes int animResId) {

View File

@@ -2,11 +2,12 @@ package org.thoughtcrime.securesms;
import android.os.Bundle;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import org.thoughtcrime.securesms.logging.Log;
import org.signal.core.util.logging.Log;
/**
* Simply logs out lifecycle events.
@@ -15,6 +16,12 @@ public abstract class LoggingFragment extends Fragment {
private static final String TAG = Log.tag(LoggingFragment.class);
public LoggingFragment() { }
public LoggingFragment(@LayoutRes int contentLayoutId) {
super(contentLayoutId);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
logEvent("onCreate()");

View File

@@ -1,6 +1,7 @@
package org.thoughtcrime.securesms;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
@@ -8,12 +9,14 @@ import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.tracing.Trace;
import org.thoughtcrime.securesms.devicetransfer.olddevice.OldDeviceTransferLockedDialog;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.util.AppStartup;
import org.thoughtcrime.securesms.util.CachedInflater;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
@Trace
public class MainActivity extends PassphraseRequiredActivity {
public static final int RESULT_CONFIG_CHANGED = Activity.RESULT_FIRST_USER + 901;
@@ -21,20 +24,42 @@ public class MainActivity extends PassphraseRequiredActivity {
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
private final MainNavigator navigator = new MainNavigator(this);
public static @NonNull Intent clearTop(@NonNull Context context) {
Intent intent = new Intent(context, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
return intent;
}
@Override
protected void onCreate(Bundle savedInstanceState, boolean ready) {
AppStartup.getInstance().onCriticalRenderEventStart();
super.onCreate(savedInstanceState, ready);
setContentView(R.layout.main_activity);
navigator.onCreate(savedInstanceState);
handleGroupLinkInIntent(getIntent());
handleProxyInIntent(getIntent());
CachedInflater.from(this).clear();
}
@Override
public Intent getIntent() {
return super.getIntent().setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
handleGroupLinkInIntent(intent);
handleProxyInIntent(intent);
}
@Override
@@ -47,6 +72,9 @@ public class MainActivity extends PassphraseRequiredActivity {
protected void onResume() {
super.onResume();
dynamicTheme.onResume(this);
if (SignalStore.misc().isOldDeviceTransferLocked()) {
OldDeviceTransferLockedDialog.show(getSupportFragmentManager());
}
}
@Override
@@ -74,4 +102,11 @@ public class MainActivity extends PassphraseRequiredActivity {
CommunicationActions.handlePotentialGroupLinkUrl(this, data.toString());
}
}
private void handleProxyInIntent(Intent intent) {
Uri data = intent.getData();
if (data != null) {
CommunicationActions.handlePotentialProxyLinkUrl(this, data.toString());
}
}
}

View File

@@ -9,7 +9,7 @@ import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import org.thoughtcrime.securesms.conversation.ConversationActivity;
import org.thoughtcrime.securesms.conversation.ConversationIntents;
import org.thoughtcrime.securesms.conversationlist.ConversationListArchiveFragment;
import org.thoughtcrime.securesms.conversationlist.ConversationListFragment;
import org.thoughtcrime.securesms.groups.ui.creategroup.CreateGroupActivity;
@@ -59,7 +59,10 @@ public class MainNavigator {
}
public void goToConversation(@NonNull RecipientId recipientId, long threadId, int distributionType, int startingPosition) {
Intent intent = ConversationActivity.buildIntent(activity, recipientId, threadId, distributionType, startingPosition);
Intent intent = ConversationIntents.createBuilder(activity, recipientId, threadId)
.withDistributionType(distributionType)
.withStartingPosition(startingPosition)
.build();
activity.startActivity(intent);
activity.overridePendingTransition(R.anim.slide_from_end, R.anim.fade_scale_out);

View File

@@ -53,13 +53,13 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.ViewPager;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.animation.DepthPageTransformer;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.components.viewpager.ExtendedOnPageChangedListener;
import org.thoughtcrime.securesms.database.MediaDatabase;
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
import org.thoughtcrime.securesms.database.loaders.PagingMediaLoader;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity;
import org.thoughtcrime.securesms.mediapreview.MediaPreviewFragment;
import org.thoughtcrime.securesms.mediapreview.MediaPreviewViewModel;
@@ -91,7 +91,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
MediaPreviewFragment.Events
{
private final static String TAG = MediaPreviewActivity.class.getSimpleName();
private final static String TAG = Log.tag(MediaPreviewActivity.class);
private static final int NOT_IN_A_THREAD = -2;

View File

@@ -1,8 +1,8 @@
package org.thoughtcrime.securesms;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
@@ -38,10 +38,10 @@ public class MuteDialog extends AlertDialog {
switch (which) {
case 0: muteUntil = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(1); break;
case 1: muteUntil = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(2); break;
case 1: muteUntil = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(8); break;
case 2: muteUntil = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1); break;
case 3: muteUntil = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(7); break;
case 4: muteUntil = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(365); break;
case 4: muteUntil = Long.MAX_VALUE; break;
default: muteUntil = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(1); break;
}

View File

@@ -23,16 +23,14 @@ import android.view.MenuItem;
import androidx.appcompat.app.AlertDialog;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
import org.thoughtcrime.securesms.conversation.ConversationActivity;
import org.thoughtcrime.securesms.conversation.ConversationIntents;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.groups.ui.creategroup.CreateGroupActivity;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
@@ -51,7 +49,7 @@ public class NewConversationActivity extends ContactSelectionActivity
{
@SuppressWarnings("unused")
private static final String TAG = NewConversationActivity.class.getSimpleName();
private static final String TAG = Log.tag(NewConversationActivity.class);
@Override
public void onCreate(Bundle bundle, boolean ready) {
@@ -99,15 +97,13 @@ public class NewConversationActivity extends ContactSelectionActivity
}
private void launch(Recipient recipient) {
Intent intent = new Intent(this, ConversationActivity.class);
intent.putExtra(ConversationActivity.RECIPIENT_EXTRA, recipient.getId().serialize());
intent.putExtra(ConversationActivity.TEXT_EXTRA, getIntent().getStringExtra(ConversationActivity.TEXT_EXTRA));
intent.setDataAndType(getIntent().getData(), getIntent().getType());
long existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient.getId());
Intent intent = ConversationIntents.createBuilder(this, recipient.getId(), existingThread)
.withDraftText(getIntent().getStringExtra(Intent.EXTRA_TEXT))
.withDataUri(getIntent().getData())
.withDataType(getIntent().getType())
.build();
long existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient.getId());
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, existingThread);
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
startActivity(intent);
finish();
}

View File

@@ -21,8 +21,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import org.thoughtcrime.securesms.logging.Log;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.service.KeyCachingService;
@@ -34,7 +34,7 @@ import org.thoughtcrime.securesms.service.KeyCachingService;
*/
public abstract class PassphraseActivity extends BaseActivity {
private static final String TAG = PassphraseActivity.class.getSimpleName();
private static final String TAG = Log.tag(PassphraseActivity.class);
private KeyCachingService keyCachingService;
private MasterSecret masterSecret;

View File

@@ -20,12 +20,12 @@ import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
import org.thoughtcrime.securesms.logging.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.InvalidPassphraseException;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;

View File

@@ -22,8 +22,6 @@ import android.os.Bundle;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.VersionTracker;
/**

View File

@@ -17,23 +17,18 @@
package org.thoughtcrime.securesms;
import android.animation.Animator;
import android.annotation.SuppressLint;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.PorterDuff;
import android.os.Build;
import android.os.Bundle;
import androidx.core.hardware.fingerprint.FingerprintManagerCompat;
import androidx.core.os.CancellationSignal;
import androidx.appcompat.widget.Toolbar;
import android.text.Editable;
import android.text.InputType;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.RelativeSizeSpan;
import android.text.style.TypefaceSpan;
import org.thoughtcrime.securesms.logging.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
@@ -50,14 +45,23 @@ import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.biometric.BiometricManager;
import androidx.biometric.BiometricManager.Authenticators;
import androidx.biometric.BiometricPrompt;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.animation.AnimationCompleteListener;
import org.thoughtcrime.securesms.components.AnimatingToggle;
import org.thoughtcrime.securesms.crypto.InvalidPassphraseException;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.logsubmit.SubmitDebugLogActivity;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.DynamicIntroTheme;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.SupportEmailUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
/**
@@ -67,7 +71,12 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences;
*/
public class PassphrasePromptActivity extends PassphraseActivity {
private static final String TAG = PassphrasePromptActivity.class.getSimpleName();
private static final String TAG = Log.tag(PassphrasePromptActivity.class);
private static final int BIOMETRIC_AUTHENTICATORS = Authenticators.BIOMETRIC_STRONG | Authenticators.BIOMETRIC_WEAK;
private static final int ALLOWED_AUTHENTICATORS = BIOMETRIC_AUTHENTICATORS | Authenticators.DEVICE_CREDENTIAL;
private static final short AUTHENTICATE_REQUEST_CODE = 1007;
private static final String BUNDLE_ALREADY_SHOWN = "bundle_already_shown";
public static final String FROM_FOREGROUND = "from_foreground";
private DynamicIntroTheme dynamicTheme = new DynamicIntroTheme();
private DynamicLanguage dynamicLanguage = new DynamicLanguage();
@@ -81,12 +90,13 @@ public class PassphrasePromptActivity extends PassphraseActivity {
private ImageButton hideButton;
private AnimatingToggle visibilityToggle;
private FingerprintManagerCompat fingerprintManager;
private CancellationSignal fingerprintCancellationSignal;
private FingerprintListener fingerprintListener;
private BiometricManager biometricManager;
private BiometricPrompt biometricPrompt;
private BiometricPrompt.PromptInfo biometricPromptInfo;
private boolean authenticated;
private boolean failure;
private boolean hadFailure;
private boolean alreadyShown;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -99,6 +109,15 @@ public class PassphrasePromptActivity extends PassphraseActivity {
setContentView(R.layout.prompt_passphrase_activity);
initializeResources();
alreadyShown = (savedInstanceState != null && savedInstanceState.getBoolean(BUNDLE_ALREADY_SHOWN)) ||
getIntent().getBooleanExtra(FROM_FOREGROUND, false);
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(BUNDLE_ALREADY_SHOWN, alreadyShown);
}
@Override
@@ -109,20 +128,12 @@ public class PassphrasePromptActivity extends PassphraseActivity {
setLockTypeVisibility();
if (TextSecurePreferences.isScreenLockEnabled(this) && !authenticated && !failure) {
resumeScreenLock();
if (TextSecurePreferences.isScreenLockEnabled(this) && !authenticated && !hadFailure) {
resumeScreenLock(!alreadyShown);
alreadyShown = true;
}
failure = false;
}
@Override
public void onPause() {
super.onPause();
if (TextSecurePreferences.isScreenLockEnabled(this)) {
pauseScreenLock();
}
hadFailure = false;
}
@Override
@@ -136,7 +147,7 @@ public class PassphrasePromptActivity extends PassphraseActivity {
MenuInflater inflater = this.getMenuInflater();
menu.clear();
inflater.inflate(R.menu.log_submit, menu);
inflater.inflate(R.menu.passphrase_prompt, menu);
super.onCreateOptionsMenu(menu);
return true;
@@ -145,23 +156,28 @@ public class PassphrasePromptActivity extends PassphraseActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case R.id.menu_submit_debug_logs: handleLogSubmit(); return true;
if (item.getItemId() == R.id.menu_submit_debug_logs) {
handleLogSubmit();
return true;
} else if (item.getItemId() == R.id.menu_contact_support) {
sendEmailToSupport();
return true;
}
return false;
}
@Override
@SuppressLint("MissingSuperCall") // no fragments to dispatch to
public void onActivityResult(int requestCode, int resultcode, Intent data) {
if (requestCode != 1) return;
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultcode == RESULT_OK) {
if (requestCode != AUTHENTICATE_REQUEST_CODE) return;
if (resultCode == RESULT_OK) {
handleAuthenticated();
} else {
Log.w(TAG, "Authentication failed");
failure = true;
hadFailure = true;
}
}
@@ -212,16 +228,20 @@ public class PassphrasePromptActivity extends PassphraseActivity {
ImageButton okButton = findViewById(R.id.ok_button);
Toolbar toolbar = findViewById(R.id.toolbar);
showButton = findViewById(R.id.passphrase_visibility);
hideButton = findViewById(R.id.passphrase_visibility_off);
visibilityToggle = findViewById(R.id.button_toggle);
passphraseText = findViewById(R.id.passphrase_edit);
passphraseAuthContainer = findViewById(R.id.password_auth_container);
fingerprintPrompt = findViewById(R.id.fingerprint_auth_container);
lockScreenButton = findViewById(R.id.lock_screen_auth_container);
fingerprintManager = FingerprintManagerCompat.from(this);
fingerprintCancellationSignal = new CancellationSignal();
fingerprintListener = new FingerprintListener();
showButton = findViewById(R.id.passphrase_visibility);
hideButton = findViewById(R.id.passphrase_visibility_off);
visibilityToggle = findViewById(R.id.button_toggle);
passphraseText = findViewById(R.id.passphrase_edit);
passphraseAuthContainer = findViewById(R.id.password_auth_container);
fingerprintPrompt = findViewById(R.id.fingerprint_auth_container);
lockScreenButton = findViewById(R.id.lock_screen_auth_container);
biometricManager = BiometricManager.from(this);
biometricPrompt = new BiometricPrompt(this, new BiometricAuthenticationListener());
biometricPromptInfo = new BiometricPrompt.PromptInfo
.Builder()
.setAllowedAuthenticators(ALLOWED_AUTHENTICATORS)
.setTitle(getString(R.string.PassphrasePromptActivity_unlock_signal))
.build();
setSupportActionBar(toolbar);
getSupportActionBar().setTitle("");
@@ -241,20 +261,15 @@ public class PassphrasePromptActivity extends PassphraseActivity {
fingerprintPrompt.setImageResource(R.drawable.ic_fingerprint_white_48dp);
fingerprintPrompt.getBackground().setColorFilter(getResources().getColor(R.color.core_ultramarine), PorterDuff.Mode.SRC_IN);
lockScreenButton.setOnClickListener(v -> resumeScreenLock());
lockScreenButton.setOnClickListener(v -> resumeScreenLock(true));
}
private void setLockTypeVisibility() {
if (TextSecurePreferences.isScreenLockEnabled(this)) {
passphraseAuthContainer.setVisibility(View.GONE);
if (fingerprintManager.isHardwareDetected() && fingerprintManager.hasEnrolledFingerprints()) {
fingerprintPrompt.setVisibility(View.VISIBLE);
lockScreenButton.setVisibility(View.GONE);
} else {
fingerprintPrompt.setVisibility(View.GONE);
lockScreenButton.setVisibility(View.VISIBLE);
}
fingerprintPrompt.setVisibility(biometricManager.canAuthenticate(BIOMETRIC_AUTHENTICATORS) == BiometricManager.BIOMETRIC_SUCCESS ? View.VISIBLE
: View.GONE);
lockScreenButton.setVisibility(View.VISIBLE);
} else {
passphraseAuthContainer.setVisibility(View.VISIBLE);
fingerprintPrompt.setVisibility(View.GONE);
@@ -262,7 +277,7 @@ public class PassphrasePromptActivity extends PassphraseActivity {
}
}
private void resumeScreenLock() {
private void resumeScreenLock(boolean force) {
KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
assert keyguardManager != null;
@@ -273,24 +288,36 @@ public class PassphrasePromptActivity extends PassphraseActivity {
return;
}
if (fingerprintManager.isHardwareDetected() && fingerprintManager.hasEnrolledFingerprints()) {
Log.i(TAG, "Listening for fingerprints...");
fingerprintCancellationSignal = new CancellationSignal();
fingerprintManager.authenticate(null, 0, fingerprintCancellationSignal, fingerprintListener, null);
} else if (Build.VERSION.SDK_INT >= 21){
Log.i(TAG, "firing intent...");
Intent intent = keyguardManager.createConfirmDeviceCredentialIntent(getString(R.string.PassphrasePromptActivity_unlock_signal), "");
startActivityForResult(intent, 1);
if (Build.VERSION.SDK_INT != 29 && biometricManager.canAuthenticate(ALLOWED_AUTHENTICATORS) == BiometricManager.BIOMETRIC_SUCCESS) {
if (force) {
Log.i(TAG, "Listening for biometric authentication...");
biometricPrompt.authenticate(biometricPromptInfo);
} else {
Log.i(TAG, "Skipping show system biometric dialog unless forced");
}
} else if (Build.VERSION.SDK_INT >= 21) {
if (force) {
Log.i(TAG, "firing intent...");
Intent intent = keyguardManager.createConfirmDeviceCredentialIntent(getString(R.string.PassphrasePromptActivity_unlock_signal), "");
startActivityForResult(intent, AUTHENTICATE_REQUEST_CODE);
} else {
Log.i(TAG, "Skipping firing intent unless forced");
}
} else {
Log.w(TAG, "Not compatible...");
handleAuthenticated();
}
}
private void pauseScreenLock() {
if (fingerprintCancellationSignal != null) {
fingerprintCancellationSignal.cancel();
}
private void sendEmailToSupport() {
String body = SupportEmailUtil.generateSupportEmailBody(this,
R.string.PassphrasePromptActivity_signal_android_lock_screen,
null,
null);
CommunicationActions.openEmail(this,
SupportEmailUtil.getSupportEmailAddress(this),
getString(R.string.PassphrasePromptActivity_signal_android_lock_screen),
body);
}
private class PassphraseActionListener implements TextView.OnEditorActionListener {
@@ -341,15 +368,19 @@ public class PassphrasePromptActivity extends PassphraseActivity {
System.gc();
}
private class FingerprintListener extends FingerprintManagerCompat.AuthenticationCallback {
private class BiometricAuthenticationListener extends BiometricPrompt.AuthenticationCallback {
@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) {
Log.w(TAG, "Authentication error: " + errMsgId + " " + errString);
onAuthenticationFailed();
public void onAuthenticationError(int errorCode, @NonNull CharSequence errorString) {
Log.w(TAG, "Authentication error: " + errorCode);
hadFailure = true;
if (errorCode != BiometricPrompt.ERROR_CANCELED && errorCode != BiometricPrompt.ERROR_USER_CANCELED) {
onAuthenticationFailed();
}
}
@Override
public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
Log.i(TAG, "onAuthenticationSucceeded");
fingerprintPrompt.setImageResource(R.drawable.ic_check_white_48dp);
fingerprintPrompt.getBackground().setColorFilter(getResources().getColor(R.color.green_500), PorterDuff.Mode.SRC_IN);
@@ -366,8 +397,7 @@ public class PassphrasePromptActivity extends PassphraseActivity {
@Override
public void onAuthenticationFailed() {
Log.w(TAG, "onAuthenticatoinFailed()");
FingerprintManagerCompat.AuthenticationCallback callback = this;
Log.w(TAG, "onAuthenticationFailed()");
fingerprintPrompt.setImageResource(R.drawable.ic_close_white_48dp);
fingerprintPrompt.getBackground().setColorFilter(getResources().getColor(R.color.red_500), PorterDuff.Mode.SRC_IN);
@@ -391,6 +421,5 @@ public class PassphrasePromptActivity extends PassphraseActivity {
fingerprintPrompt.startAnimation(shake);
}
}
}

View File

@@ -11,12 +11,16 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import org.greenrobot.eventbus.EventBus;
import org.signal.core.util.logging.Log;
import org.signal.core.util.tracing.Tracer;
import org.signal.devicetransfer.TransferStatus;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.devicetransfer.olddevice.OldDeviceTransferActivity;
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.migrations.ApplicationMigrationActivity;
import org.thoughtcrime.securesms.migrations.ApplicationMigrations;
import org.thoughtcrime.securesms.pin.PinRestoreActivity;
@@ -25,12 +29,13 @@ import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.AppStartup;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.util.Locale;
public abstract class PassphraseRequiredActivity extends BaseActivity implements MasterSecretListener {
private static final String TAG = PassphraseRequiredActivity.class.getSimpleName();
private static final String TAG = Log.tag(PassphraseRequiredActivity.class);
public static final String LOCALE_EXTRA = "locale_extra";
public static final String NEXT_INTENT_EXTRA = "next_intent";
@@ -43,12 +48,16 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
private static final int STATE_ENTER_SIGNAL_PIN = 5;
private static final int STATE_CREATE_PROFILE_NAME = 6;
private static final int STATE_CREATE_SIGNAL_PIN = 7;
private static final int STATE_TRANSFER_ONGOING = 8;
private static final int STATE_TRANSFER_LOCKED = 9;
private SignalServiceNetworkAccess networkAccess;
private BroadcastReceiver clearKeyReceiver;
@Override
protected final void onCreate(Bundle savedInstanceState) {
Tracer.getInstance().start(Log.tag(getClass()) + "#onCreate()");
AppStartup.getInstance().onCriticalRenderEventStart();
this.networkAccess = new SignalServiceNetworkAccess(this);
onPreCreate();
@@ -61,6 +70,9 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
initializeClearKeyReceiver();
onCreate(savedInstanceState, true);
}
AppStartup.getInstance().onCriticalRenderEventEnd();
Tracer.getInstance().end(Log.tag(getClass()) + "#onCreate()");
}
protected void onPreCreate() {}
@@ -71,7 +83,7 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
super.onResume();
if (networkAccess.isCensored(this)) {
ApplicationDependencies.getJobManager().add(new PushNotificationReceiveJob(this));
ApplicationDependencies.getJobManager().add(new PushNotificationReceiveJob());
}
}
@@ -84,8 +96,8 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
@Override
public void onMasterSecretCleared() {
Log.d(TAG, "onMasterSecretCleared()");
if (ApplicationContext.getInstance(this).isAppVisible()) routeApplicationState(true);
else finish();
if (ApplicationDependencies.getAppForegroundObserver().isForegrounded()) routeApplicationState(true);
else finish();
}
protected <T extends Fragment> T initFragment(@IdRes int target,
@@ -139,6 +151,8 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
case STATE_ENTER_SIGNAL_PIN: return getEnterSignalPinIntent();
case STATE_CREATE_SIGNAL_PIN: return getCreateSignalPinIntent();
case STATE_CREATE_PROFILE_NAME: return getCreateProfileNameIntent();
case STATE_TRANSFER_ONGOING: return getOldDeviceTransferIntent();
case STATE_TRANSFER_LOCKED: return getOldDeviceTransferLockedIntent();
default: return null;
}
}
@@ -158,6 +172,10 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
return STATE_CREATE_PROFILE_NAME;
} else if (userMustCreateSignalPin()) {
return STATE_CREATE_SIGNAL_PIN;
} else if (EventBus.getDefault().getStickyEvent(TransferStatus.class) != null && getClass() != OldDeviceTransferActivity.class) {
return STATE_TRANSFER_ONGOING;
} else if (SignalStore.misc().isOldDeviceTransferLocked()) {
return STATE_TRANSFER_LOCKED;
} else {
return STATE_NORMAL;
}
@@ -176,7 +194,9 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
}
private Intent getPromptPassphraseIntent() {
return getRoutedIntent(PassphrasePromptActivity.class, getIntent());
Intent intent = getRoutedIntent(PassphrasePromptActivity.class, getIntent());
intent.putExtra(PassphrasePromptActivity.FROM_FOREGROUND, ApplicationDependencies.getAppForegroundObserver().isForegrounded());
return intent;
}
private Intent getUiBlockingUpgradeIntent() {
@@ -187,7 +207,7 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
}
private Intent getPushRegistrationIntent() {
return RegistrationNavigationActivity.newIntentForNewRegistration(this);
return RegistrationNavigationActivity.newIntentForNewRegistration(this, getIntent());
}
private Intent getEnterSignalPinIntent() {
@@ -210,6 +230,19 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
return getRoutedIntent(EditProfileActivity.class, getIntent());
}
private Intent getOldDeviceTransferIntent() {
Intent intent = new Intent(this, OldDeviceTransferActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
return intent;
}
private @Nullable Intent getOldDeviceTransferLockedIntent() {
if (getClass() == MainActivity.class) {
return null;
}
return MainActivity.clearTop(this);
}
private Intent getRoutedIntent(Class<?> destination, @Nullable Intent nextIntent) {
final Intent intent = new Intent(this, destination);
if (nextIntent != null) intent.putExtra("next_intent", nextIntent);
@@ -218,15 +251,17 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
private Intent getConversationListIntent() {
// TODO [greyson] Navigation
return new Intent(this, MainActivity.class);
return MainActivity.clearTop(this);
}
private void initializeClearKeyReceiver() {
this.clearKeyReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "onReceive() for clear key event");
onMasterSecretCleared();
Log.i(TAG, "onReceive() for clear key event. PasswordDisabled: " + TextSecurePreferences.isPasswordDisabled(context) + ", ScreenLock: " + TextSecurePreferences.isScreenLockEnabled(context));
if (TextSecurePreferences.isScreenLockEnabled(context) || !TextSecurePreferences.isPasswordDisabled(context)) {
onMasterSecretCleared();
}
}
};

View File

@@ -17,6 +17,7 @@
package org.thoughtcrime.securesms;
import android.os.Bundle;
import androidx.fragment.app.FragmentActivity;
public class PlayServicesProblemActivity extends FragmentActivity {

View File

@@ -21,10 +21,11 @@ import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import com.google.android.gms.common.GoogleApiAvailability;

View File

@@ -21,6 +21,7 @@ import android.os.Bundle;
import com.annimon.stream.Stream;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.contacts.SelectedContact;
import org.thoughtcrime.securesms.recipients.RecipientId;
@@ -38,7 +39,7 @@ public class PushContactSelectionActivity extends ContactSelectionActivity {
public static final String KEY_SELECTED_RECIPIENTS = "recipients";
@SuppressWarnings("unused")
private final static String TAG = PushContactSelectionActivity.class.getSimpleName();
private final static String TAG = Log.tag(PushContactSelectionActivity.class);
@Override
protected void onCreate(Bundle icicle, boolean ready) {

View File

@@ -0,0 +1,48 @@
package org.thoughtcrime.securesms;
import android.os.Build;
import java.util.HashSet;
import java.util.Set;
/**
* Device hardware capability lists.
* <p>
* Moved outside of ApplicationContext as the indirection was important for API19 support with desugaring: https://issuetracker.google.com/issues/183419297
*/
final class RtcDeviceLists {
private RtcDeviceLists() {}
static Set<String> hardwareAECBlockList() {
return new HashSet<String>() {{
add("Pixel");
add("Pixel XL");
add("Moto G5");
add("Moto G (5S) Plus");
add("Moto G4");
add("TA-1053");
add("Mi A1");
add("Mi A2");
add("E5823"); // Sony z5 compact
add("Redmi Note 5");
add("FP2"); // Fairphone FP2
add("MI 5");
}};
}
static Set<String> openSlEsAllowList() {
return new HashSet<String>() {{
add("Pixel");
add("Pixel XL");
}};
}
static boolean hardwareAECBlocked() {
return hardwareAECBlockList().contains(Build.MODEL);
}
static boolean openSLESAllowed() {
return openSlEsAllowList().contains(Build.MODEL);
}
}

View File

@@ -3,11 +3,12 @@ package org.thoughtcrime.securesms;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.TaskStackBuilder;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.Toast;
import androidx.core.app.TaskStackBuilder;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
@@ -34,7 +35,7 @@ public class ShortcutLauncherActivity extends AppCompatActivity {
if (rawId == null) {
Toast.makeText(this, R.string.ShortcutLauncherActivity_invalid_shortcut, Toast.LENGTH_SHORT).show();
// TODO [greyson] Navigation
startActivity(new Intent(this, MainActivity.class));
startActivity(MainActivity.clearTop(this));
finish();
return;
}
@@ -42,7 +43,7 @@ public class ShortcutLauncherActivity extends AppCompatActivity {
Recipient recipient = Recipient.live(RecipientId.from(rawId)).get();
// TODO [greyson] Navigation
TaskStackBuilder backStack = TaskStackBuilder.create(this)
.addNextIntent(new Intent(this, MainActivity.class));
.addNextIntent(MainActivity.clearTop(this));
CommunicationActions.startConversation(this, recipient, null, backStack);
finish();

View File

@@ -5,13 +5,13 @@ import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import androidx.annotation.NonNull;
import android.text.TextUtils;
import org.thoughtcrime.securesms.conversation.ConversationActivity;
import org.thoughtcrime.securesms.logging.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.conversation.ConversationIntents;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.Rfc5724Uri;
@@ -20,7 +20,7 @@ import java.net.URISyntaxException;
public class SmsSendtoActivity extends Activity {
private static final String TAG = SmsSendtoActivity.class.getSimpleName();
private static final String TAG = Log.tag(SmsSendtoActivity.class);
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -44,16 +44,15 @@ public class SmsSendtoActivity extends Activity {
if (TextUtils.isEmpty(destination.destination)) {
nextIntent = new Intent(this, NewConversationActivity.class);
nextIntent.putExtra(ConversationActivity.TEXT_EXTRA, destination.getBody());
nextIntent.putExtra(Intent.EXTRA_TEXT, destination.getBody());
Toast.makeText(this, R.string.ConversationActivity_specify_recipient, Toast.LENGTH_LONG).show();
} else {
Recipient recipient = Recipient.external(this, destination.getDestination());
long threadId = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient.getId());
nextIntent = new Intent(this, ConversationActivity.class);
nextIntent.putExtra(ConversationActivity.TEXT_EXTRA, destination.getBody());
nextIntent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
nextIntent.putExtra(ConversationActivity.RECIPIENT_EXTRA, recipient.getId().serialize());
nextIntent = ConversationIntents.createBuilder(this, recipient.getId(), threadId)
.withDraftText(destination.getBody())
.build();
}
return nextIntent;
}

View File

@@ -2,9 +2,10 @@ package org.thoughtcrime.securesms;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import android.text.TextUtils;
import org.thoughtcrime.securesms.util.CharacterCalculator;
import org.thoughtcrime.securesms.util.CharacterCalculator.CharacterState;

View File

@@ -2,9 +2,11 @@ package org.thoughtcrime.securesms;
import android.Manifest;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.util.CharacterCalculator;
import org.thoughtcrime.securesms.util.MmsCharacterCalculator;
@@ -24,7 +26,7 @@ import static org.thoughtcrime.securesms.TransportOption.Type;
public class TransportOptions {
private static final String TAG = TransportOptions.class.getSimpleName();
private static final String TAG = Log.tag(TransportOptions.class);
private final List<OnTransportChangedListener> listeners = new LinkedList<>();
private final Context context;

View File

@@ -2,7 +2,6 @@ package org.thoughtcrime.securesms;
import android.content.Context;
import android.graphics.PorterDuff.Mode;
import androidx.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -10,7 +9,7 @@ import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import org.thoughtcrime.securesms.util.ViewUtil;
import androidx.annotation.NonNull;
import java.util.List;
@@ -54,9 +53,9 @@ public class TransportOptionsAdapter extends BaseAdapter {
}
TransportOption transport = (TransportOption) getItem(position);
ImageView imageView = ViewUtil.findById(convertView, R.id.icon);
TextView textView = ViewUtil.findById(convertView, R.id.text);
TextView subtextView = ViewUtil.findById(convertView, R.id.subtext);
ImageView imageView = convertView.findViewById(R.id.icon);
TextView textView = convertView.findViewById(R.id.text);
TextView subtextView = convertView.findViewById(R.id.subtext);
imageView.getBackground().setColorFilter(transport.getBackgroundColor(), Mode.MULTIPLY);
imageView.setImageResource(transport.getDrawable());

View File

@@ -1,12 +1,13 @@
package org.thoughtcrime.securesms;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.ListPopupWindow;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.ListPopupWindow;
import java.util.LinkedList;
import java.util.List;

View File

@@ -22,7 +22,6 @@ import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
@@ -32,7 +31,6 @@ import android.graphics.PorterDuff;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Vibrator;
import android.text.Html;
@@ -62,8 +60,12 @@ import androidx.appcompat.widget.SwitchCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import org.signal.core.util.ThreadUtil;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.components.camera.CameraView;
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.database.DatabaseFactory;
@@ -71,7 +73,6 @@ import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobs.MultiDeviceVerifiedUpdateJob;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.qr.QrCode;
import org.thoughtcrime.securesms.qr.ScanListener;
@@ -80,7 +81,6 @@ import org.thoughtcrime.securesms.recipients.LiveRecipient;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
import org.thoughtcrime.securesms.util.DynamicDarkActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.IdentityUtil;
@@ -93,15 +93,12 @@ import org.whispersystems.libsignal.fingerprint.Fingerprint;
import org.whispersystems.libsignal.fingerprint.FingerprintParsingException;
import org.whispersystems.libsignal.fingerprint.FingerprintVersionMismatchException;
import org.whispersystems.libsignal.fingerprint.NumericFingerprintGenerator;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalSessionLock;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.Locale;
import java.util.UUID;
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
/**
* Activity for verifying identity keys.
@@ -117,7 +114,7 @@ public class VerifyIdentityActivity extends PassphraseRequiredActivity implement
private static final String IDENTITY_EXTRA = "recipient_identity";
private static final String VERIFIED_EXTRA = "verified_state";
private final DynamicTheme dynamicTheme = new DynamicDarkActionBarTheme();
private final DynamicTheme dynamicTheme = new DynamicTheme();
private final VerifyDisplayFragment displayFragment = new VerifyDisplayFragment();
private final VerifyScanFragment scanFragment = new VerifyScanFragment();
@@ -165,11 +162,6 @@ public class VerifyIdentityActivity extends PassphraseRequiredActivity implement
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(R.string.AndroidManifest__verify_safety_number);
LiveRecipient recipient = Recipient.live(getIntent().getParcelableExtra(RECIPIENT_EXTRA));
recipient.observe(this, r -> setActionBarNotificationBarColor(r.getColor()));
setActionBarNotificationBarColor(recipient.get().getColor());
Bundle extras = new Bundle();
extras.putParcelable(VerifyDisplayFragment.RECIPIENT_ID, getIntent().getParcelableExtra(RECIPIENT_EXTRA));
extras.putParcelable(VerifyDisplayFragment.REMOTE_IDENTITY, getIntent().getParcelableExtra(IDENTITY_EXTRA));
@@ -194,7 +186,7 @@ public class VerifyIdentityActivity extends PassphraseRequiredActivity implement
@Override
public void onQrDataFound(final String data) {
Util.runOnMain(() -> {
ThreadUtil.runOnMain(() -> {
((Vibrator)getSystemService(Context.VIBRATOR_SERVICE)).vibrate(50);
getSupportFragmentManager().popBackStack();
@@ -262,24 +254,24 @@ public class VerifyIdentityActivity extends PassphraseRequiredActivity implement
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup viewGroup, Bundle bundle) {
this.container = ViewUtil.inflate(inflater, viewGroup, R.layout.verify_display_fragment);
this.numbersContainer = ViewUtil.findById(container, R.id.number_table);
this.qrCode = ViewUtil.findById(container, R.id.qr_code);
this.verified = ViewUtil.findById(container, R.id.verified_switch);
this.qrVerified = ViewUtil.findById(container, R.id.qr_verified);
this.description = ViewUtil.findById(container, R.id.description);
this.tapLabel = ViewUtil.findById(container, R.id.tap_label);
this.codes[0] = ViewUtil.findById(container, R.id.code_first);
this.codes[1] = ViewUtil.findById(container, R.id.code_second);
this.codes[2] = ViewUtil.findById(container, R.id.code_third);
this.codes[3] = ViewUtil.findById(container, R.id.code_fourth);
this.codes[4] = ViewUtil.findById(container, R.id.code_fifth);
this.codes[5] = ViewUtil.findById(container, R.id.code_sixth);
this.codes[6] = ViewUtil.findById(container, R.id.code_seventh);
this.codes[7] = ViewUtil.findById(container, R.id.code_eighth);
this.codes[8] = ViewUtil.findById(container, R.id.code_ninth);
this.codes[9] = ViewUtil.findById(container, R.id.code_tenth);
this.codes[10] = ViewUtil.findById(container, R.id.code_eleventh);
this.codes[11] = ViewUtil.findById(container, R.id.code_twelth);
this.numbersContainer = container.findViewById(R.id.number_table);
this.qrCode = container.findViewById(R.id.qr_code);
this.verified = container.findViewById(R.id.verified_switch);
this.qrVerified = container.findViewById(R.id.qr_verified);
this.description = container.findViewById(R.id.description);
this.tapLabel = container.findViewById(R.id.tap_label);
this.codes[0] = container.findViewById(R.id.code_first);
this.codes[1] = container.findViewById(R.id.code_second);
this.codes[2] = container.findViewById(R.id.code_third);
this.codes[3] = container.findViewById(R.id.code_fourth);
this.codes[4] = container.findViewById(R.id.code_fifth);
this.codes[5] = container.findViewById(R.id.code_sixth);
this.codes[6] = container.findViewById(R.id.code_seventh);
this.codes[7] = container.findViewById(R.id.code_eighth);
this.codes[8] = container.findViewById(R.id.code_ninth);
this.codes[9] = container.findViewById(R.id.code_tenth);
this.codes[10] = container.findViewById(R.id.code_eleventh);
this.codes[11] = container.findViewById(R.id.code_twelth);
this.qrCode.setOnClickListener(clickListener);
this.registerForContextMenu(numbersContainer);
@@ -310,6 +302,7 @@ public class VerifyIdentityActivity extends PassphraseRequiredActivity implement
byte[] localId;
byte[] remoteId;
//noinspection WrongThread
Recipient resolved = recipient.resolve();
if (FeatureFlags.verifyV2() && resolved.getUuid().isPresent()) {
@@ -626,36 +619,35 @@ public class VerifyIdentityActivity extends PassphraseRequiredActivity implement
@Override
public void onCheckedChanged(CompoundButton buttonView, final boolean isChecked) {
new AsyncTask<Recipient, Void, Void>() {
@Override
protected Void doInBackground(Recipient... params) {
synchronized (SESSION_LOCK) {
if (isChecked) {
Log.i(TAG, "Saving identity: " + params[0].getId());
DatabaseFactory.getIdentityDatabase(getActivity())
.saveIdentity(params[0].getId(),
remoteIdentity,
VerifiedStatus.VERIFIED, false,
System.currentTimeMillis(), true);
} else {
DatabaseFactory.getIdentityDatabase(getActivity())
.setVerified(params[0].getId(),
remoteIdentity,
VerifiedStatus.DEFAULT);
}
final Recipient recipient = this.recipient.get();
final RecipientId recipientId = recipient.getId();
ApplicationDependencies.getJobManager()
.add(new MultiDeviceVerifiedUpdateJob(recipient.getId(),
remoteIdentity,
isChecked ? VerifiedStatus.VERIFIED :
VerifiedStatus.DEFAULT));
StorageSyncHelper.scheduleSyncForDataChange();
IdentityUtil.markIdentityVerified(getActivity(), recipient.get(), isChecked, false);
SignalExecutors.BOUNDED.execute(() -> {
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
if (isChecked) {
Log.i(TAG, "Saving identity: " + recipientId);
DatabaseFactory.getIdentityDatabase(getActivity())
.saveIdentity(recipientId,
remoteIdentity,
VerifiedStatus.VERIFIED, false,
System.currentTimeMillis(), true);
} else {
DatabaseFactory.getIdentityDatabase(getActivity())
.setVerified(recipientId,
remoteIdentity,
VerifiedStatus.DEFAULT);
}
return null;
ApplicationDependencies.getJobManager()
.add(new MultiDeviceVerifiedUpdateJob(recipientId,
remoteIdentity,
isChecked ? VerifiedStatus.VERIFIED
: VerifiedStatus.DEFAULT));
StorageSyncHelper.scheduleSyncForDataChange();
IdentityUtil.markIdentityVerified(getActivity(), recipient, isChecked, false);
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, recipient.get());
});
}
}
@@ -668,7 +660,7 @@ public class VerifyIdentityActivity extends PassphraseRequiredActivity implement
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup viewGroup, Bundle bundle) {
this.container = ViewUtil.inflate(inflater, viewGroup, R.layout.verify_scan_fragment);
this.cameraView = ViewUtil.findById(container, R.id.scanner);
this.cameraView = container.findViewById(R.id.scanner);
return container;
}

View File

@@ -19,6 +19,7 @@ package org.thoughtcrime.securesms;
import android.Manifest;
import android.app.PictureInPictureParams;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
@@ -31,40 +32,46 @@ import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProviders;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.components.TooltipPopup;
import org.thoughtcrime.securesms.components.sensors.DeviceOrientationMonitor;
import org.thoughtcrime.securesms.components.webrtc.CallParticipantsListUpdatePopupWindow;
import org.thoughtcrime.securesms.components.webrtc.CallParticipantsState;
import org.thoughtcrime.securesms.components.webrtc.GroupCallSafetyNumberChangeNotificationUtil;
import org.thoughtcrime.securesms.components.webrtc.WebRtcAudioOutput;
import org.thoughtcrime.securesms.components.webrtc.WebRtcCallView;
import org.thoughtcrime.securesms.components.webrtc.WebRtcCallViewModel;
import org.thoughtcrime.securesms.components.webrtc.participantslist.CallParticipantsListDialog;
import org.thoughtcrime.securesms.conversation.ui.error.SafetyNumberChangeDialog;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.events.WebRtcViewModel;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.messagerequests.CalleeMustAcceptMessageRequestActivity;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
import org.thoughtcrime.securesms.service.WebRtcCallService;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.service.webrtc.SignalCallManager;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.EllapsedTimeFormatter;
import org.thoughtcrime.securesms.util.FullscreenHelper;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumberChangeDialog.Callback {
import java.util.List;
public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChangeDialog.Callback {
private static final String TAG = WebRtcCallActivity.class.getSimpleName();
private static final String TAG = Log.tag(WebRtcCallActivity.class);
private static final int STANDARD_DELAY_FINISH = 1000;
private static final int STANDARD_DELAY_FINISH = 1000;
public static final String ANSWER_ACTION = WebRtcCallActivity.class.getCanonicalName() + ".ANSWER_ACTION";
public static final String DENY_ACTION = WebRtcCallActivity.class.getCanonicalName() + ".DENY_ACTION";
@@ -72,11 +79,21 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
public static final String EXTRA_ENABLE_VIDEO_IF_AVAILABLE = WebRtcCallActivity.class.getCanonicalName() + ".ENABLE_VIDEO_IF_AVAILABLE";
private CallParticipantsListUpdatePopupWindow participantUpdateWindow;
private DeviceOrientationMonitor deviceOrientationMonitor;
private FullscreenHelper fullscreenHelper;
private WebRtcCallView callScreen;
private TooltipPopup videoTooltip;
private WebRtcCallViewModel viewModel;
private boolean enableVideoIfAvailable;
@Override
protected void attachBaseContext(@NonNull Context newBase) {
getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);
super.attachBaseContext(newBase);
}
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate()");
@@ -86,8 +103,8 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.webrtc_call_activity);
//noinspection ConstantConditions
getSupportActionBar().hide();
fullscreenHelper = new FullscreenHelper(this);
setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
@@ -112,7 +129,7 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
}
@Override
public void onNewIntent(Intent intent){
public void onNewIntent(Intent intent) {
Log.i(TAG, "onNewIntent");
super.onNewIntent(intent);
processIntent(intent);
@@ -123,13 +140,15 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
Log.i(TAG, "onPause");
super.onPause();
if (!isInPipMode()) {
if (!isInPipMode() || isFinishing()) {
EventBus.getDefault().unregister(this);
}
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
if (state != null && state.getCallState() == WebRtcViewModel.State.CALL_PRE_JOIN) {
finish();
if (!viewModel.isCallStarting()) {
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
if (state != null && state.getCallState().isPreJoinOrNetworkUnavailable()) {
finish();
}
}
}
@@ -138,14 +157,22 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
Log.i(TAG, "onStop");
super.onStop();
EventBus.getDefault().unregister(this);
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
if (state != null && state.getCallState() == WebRtcViewModel.State.CALL_PRE_JOIN) {
Intent intent = new Intent(this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_CANCEL_PRE_JOIN_CALL);
startService(intent);
if (!isInPipMode() || isFinishing()) {
EventBus.getDefault().unregister(this);
}
if (!viewModel.isCallStarting()) {
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
if (state != null && state.getCallState().isPreJoinOrNetworkUnavailable()) {
ApplicationDependencies.getSignalCallManager().cancelPreJoin();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
@Override
@@ -168,6 +195,7 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {
viewModel.setIsInPipMode(isInPictureInPictureMode);
participantUpdateWindow.setEnabled(!isInPictureInPictureMode);
}
private boolean enterPipModeIfPossible() {
@@ -176,6 +204,8 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
.setAspectRatio(new Rational(9, 16))
.build();
enterPictureInPictureMode(params);
CallParticipantsListDialog.dismiss(getSupportFragmentManager());
return true;
}
return false;
@@ -207,44 +237,83 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
private void initializeResources() {
callScreen = findViewById(R.id.callScreen);
callScreen.setControlsListener(new ControlsListener());
callScreen.setEventListener(new EventListener());
participantUpdateWindow = new CallParticipantsListUpdatePopupWindow(callScreen);
}
private void initializeViewModel() {
viewModel = ViewModelProviders.of(this).get(WebRtcCallViewModel.class);
deviceOrientationMonitor = new DeviceOrientationMonitor(this);
getLifecycle().addObserver(deviceOrientationMonitor);
WebRtcCallViewModel.Factory factory = new WebRtcCallViewModel.Factory(deviceOrientationMonitor);
viewModel = ViewModelProviders.of(this, factory).get(WebRtcCallViewModel.class);
viewModel.setIsInPipMode(isInPipMode());
viewModel.getMicrophoneEnabled().observe(this, callScreen::setMicEnabled);
viewModel.getWebRtcControls().observe(this, callScreen::setWebRtcControls);
viewModel.getEvents().observe(this, this::handleViewModelEvent);
viewModel.getCallTime().observe(this, this::handleCallTime);
viewModel.getCallParticipantsState().observe(this, callScreen::updateCallParticipants);
viewModel.getCallParticipantListUpdate().observe(this, participantUpdateWindow::addCallParticipantListUpdate);
viewModel.getSafetyNumberChangeEvent().observe(this, this::handleSafetyNumberChangeEvent);
viewModel.getGroupMembers().observe(this, unused -> updateGroupMembersForGroupCall());
viewModel.shouldShowSpeakerHint().observe(this, this::updateSpeakerHint);
callScreen.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
if (state != null) {
if (state.needsNewRequestSizes()) {
ApplicationDependencies.getSignalCallManager().updateRenderedResolutions();
}
}
});
viewModel.getOrientation().observe(this, orientation -> {
ApplicationDependencies.getSignalCallManager().orientationChanged(orientation.getDegrees());
switch (orientation) {
case LANDSCAPE_LEFT_EDGE:
callScreen.rotateControls(90);
break;
case LANDSCAPE_RIGHT_EDGE:
callScreen.rotateControls(-90);
break;
case PORTRAIT_BOTTOM_EDGE:
callScreen.rotateControls(0);
}
});
}
private void handleViewModelEvent(@NonNull WebRtcCallViewModel.Event event) {
if (event instanceof WebRtcCallViewModel.Event.StartCall) {
startCall(((WebRtcCallViewModel.Event.StartCall)event).isVideoCall());
return;
} else if (event instanceof WebRtcCallViewModel.Event.ShowGroupCallSafetyNumberChange) {
SafetyNumberChangeDialog.showForGroupCall(getSupportFragmentManager(), ((WebRtcCallViewModel.Event.ShowGroupCallSafetyNumberChange) event).getIdentityRecords());
return;
}
if (isInPipMode()) {
return;
}
switch (event) {
case SHOW_VIDEO_TOOLTIP:
if (videoTooltip == null) {
videoTooltip = TooltipPopup.forTarget(callScreen.getVideoTooltipTarget())
.setBackgroundTint(ContextCompat.getColor(this, R.color.core_ultramarine))
.setTextColor(ContextCompat.getColor(this, R.color.core_white))
.setText(R.string.WebRtcCallActivity__tap_here_to_turn_on_your_video)
.setOnDismissListener(() -> viewModel.onDismissedVideoTooltip())
.show(TooltipPopup.POSITION_ABOVE);
return;
}
break;
case DISMISS_VIDEO_TOOLTIP:
if (videoTooltip != null) {
videoTooltip.dismiss();
videoTooltip = null;
}
break;
default:
throw new IllegalArgumentException("Unknown event: " + event);
if (event instanceof WebRtcCallViewModel.Event.ShowVideoTooltip) {
if (videoTooltip == null) {
videoTooltip = TooltipPopup.forTarget(callScreen.getVideoTooltipTarget())
.setBackgroundTint(ContextCompat.getColor(this, R.color.core_ultramarine))
.setTextColor(ContextCompat.getColor(this, R.color.core_white))
.setText(R.string.WebRtcCallActivity__tap_here_to_turn_on_your_video)
.setOnDismissListener(() -> viewModel.onDismissedVideoTooltip())
.show(TooltipPopup.POSITION_ABOVE);
return;
}
} else if (event instanceof WebRtcCallViewModel.Event.DismissVideoTooltip) {
if (videoTooltip != null) {
videoTooltip.dismiss();
videoTooltip = null;
}
} else {
throw new IllegalArgumentException("Unknown event: " + event);
}
}
@@ -259,30 +328,19 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
}
private void handleSetAudioHandset() {
Intent intent = new Intent(this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_SET_AUDIO_SPEAKER);
startService(intent);
ApplicationDependencies.getSignalCallManager().setAudioSpeaker(false);
}
private void handleSetAudioSpeaker() {
Intent intent = new Intent(this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_SET_AUDIO_SPEAKER);
intent.putExtra(WebRtcCallService.EXTRA_SPEAKER, true);
startService(intent);
ApplicationDependencies.getSignalCallManager().setAudioSpeaker(true);
}
private void handleSetAudioBluetooth() {
Intent intent = new Intent(this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_SET_AUDIO_BLUETOOTH);
intent.putExtra(WebRtcCallService.EXTRA_BLUETOOTH, true);
startService(intent);
ApplicationDependencies.getSignalCallManager().setAudioBluetooth(true);
}
private void handleSetMuteAudio(boolean enabled) {
Intent intent = new Intent(this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_SET_MUTE_AUDIO);
intent.putExtra(WebRtcCallService.EXTRA_MUTE, enabled);
startService(intent);
ApplicationDependencies.getSignalCallManager().setMuteAudio(enabled);
}
private void handleSetMuteVideo(boolean muted) {
@@ -296,20 +354,13 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
.ifNecessary()
.withRationaleDialog(getString(R.string.WebRtcCallActivity__to_call_s_signal_needs_access_to_your_camera, recipientDisplayName), R.drawable.ic_video_solid_24_tinted)
.withPermanentDenialDialog(getString(R.string.WebRtcCallActivity__to_call_s_signal_needs_access_to_your_camera, recipientDisplayName))
.onAllGranted(() -> {
Intent intent = new Intent(this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_SET_ENABLE_VIDEO);
intent.putExtra(WebRtcCallService.EXTRA_ENABLE, !muted);
startService(intent);
})
.onAllGranted(() -> ApplicationDependencies.getSignalCallManager().setMuteVideo(!muted))
.execute();
}
}
private void handleFlipCamera() {
Intent intent = new Intent(this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_FLIP_CAMERA);
startService(intent);
ApplicationDependencies.getSignalCallManager().flipCamera();
}
private void handleAnswerWithAudio() {
@@ -326,9 +377,7 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
callScreen.setRecipient(recipient);
callScreen.setStatus(getString(R.string.RedPhone_answering));
Intent intent = new Intent(this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_ACCEPT_CALL);
startService(intent);
ApplicationDependencies.getSignalCallManager().acceptCall(false);
})
.onAnyDenied(this::handleDenyCall)
.execute();
@@ -349,10 +398,7 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
callScreen.setRecipient(recipient);
callScreen.setStatus(getString(R.string.RedPhone_answering));
Intent intent = new Intent(this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_ACCEPT_CALL);
intent.putExtra(WebRtcCallService.EXTRA_ANSWER_WITH_VIDEO, true);
startService(intent);
ApplicationDependencies.getSignalCallManager().acceptCall(true);
handleSetMuteVideo(false);
})
@@ -365,9 +411,7 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
Recipient recipient = viewModel.getRecipient().get();
if (!recipient.equals(Recipient.UNKNOWN)) {
Intent intent = new Intent(this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_DENY_CALL);
startService(intent);
ApplicationDependencies.getSignalCallManager().denyCall();
callScreen.setRecipient(recipient);
callScreen.setStatus(getString(R.string.RedPhone_ending_call));
@@ -377,9 +421,7 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
private void handleEndCall() {
Log.i(TAG, "Hangup pressed, handling termination now...");
Intent intent = new Intent(WebRtcCallActivity.this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_LOCAL_HANGUP);
startService(intent);
ApplicationDependencies.getSignalCallManager().localHangup();
}
private void handleOutgoingCall(@NonNull WebRtcViewModel event) {
@@ -410,7 +452,7 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
private void handleCallBusy() {
EventBus.getDefault().removeStickyEvent(WebRtcViewModel.class);
callScreen.setStatus(getString(R.string.RedPhone_busy));
delayedFinish(WebRtcCallService.BUSY_TONE_LENGTH);
delayedFinish(SignalCallManager.BUSY_TONE_LENGTH);
}
private void handleCallConnected(@NonNull WebRtcViewModel event) {
@@ -429,7 +471,6 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
private void handleServerFailure() {
EventBus.getDefault().removeStickyEvent(WebRtcViewModel.class);
callScreen.setStatus(getString(R.string.RedPhone_network_failed));
delayedFinish();
}
private void handleNoSuchUser(final @NonNull WebRtcViewModel event) {
@@ -449,20 +490,49 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
final Recipient recipient = event.getRemoteParticipants().get(0).getRecipient();
if (theirKey == null) {
Log.w(TAG, "Untrusted identity without an identity key, terminating call.");
handleTerminate(recipient, HangupMessage.Type.NORMAL);
}
SafetyNumberChangeDialog.showForCall(getSupportFragmentManager(), recipient.getId());
}
@Override
public void onSendAnywayAfterSafetyNumberChange() {
Intent intent = new Intent(WebRtcCallActivity.this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_OUTGOING_CALL)
.putExtra(WebRtcCallService.EXTRA_REMOTE_PEER, new RemotePeer(viewModel.getRecipient().getId()))
.putExtra(WebRtcCallService.EXTRA_OFFER_TYPE, OfferMessage.Type.AUDIO_CALL.getCode());
public void handleSafetyNumberChangeEvent(@NonNull WebRtcCallViewModel.SafetyNumberChangeEvent safetyNumberChangeEvent) {
if (Util.hasItems(safetyNumberChangeEvent.getRecipientIds())) {
if (safetyNumberChangeEvent.isInPipMode()) {
GroupCallSafetyNumberChangeNotificationUtil.showNotification(this, viewModel.getRecipient().get());
} else {
GroupCallSafetyNumberChangeNotificationUtil.cancelNotification(this, viewModel.getRecipient().get());
SafetyNumberChangeDialog.showForDuringGroupCall(getSupportFragmentManager(), safetyNumberChangeEvent.getRecipientIds());
}
}
}
startService(intent);
private void updateGroupMembersForGroupCall() {
ApplicationDependencies.getSignalCallManager().requestUpdateGroupMembers();
}
private void updateSpeakerHint(boolean showSpeakerHint) {
if (showSpeakerHint) {
callScreen.showSpeakerViewHint();
} else {
callScreen.hideSpeakerViewHint();
}
}
@Override
public void onSendAnywayAfterSafetyNumberChange(@NonNull List<RecipientId> changedRecipients) {
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
if (state == null) {
return;
}
if (state.getGroupCallState().isConnected()) {
ApplicationDependencies.getSignalCallManager().groupApproveSafetyChange(changedRecipients);
} else {
viewModel.startCall(state.getLocalParticipant().isVideoEnabled());
}
}
@Override
@@ -470,7 +540,17 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
@Override
public void onCanceled() {
handleTerminate(viewModel.getRecipient().get(), HangupMessage.Type.NORMAL);
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
if (state != null && state.getGroupCallState().isNotIdle()) {
if (state.getCallState().isPreJoinOrNetworkUnavailable()) {
ApplicationDependencies.getSignalCallManager().cancelPreJoin();
finish();
} else {
handleEndCall();
}
} else {
handleTerminate(viewModel.getRecipient().get(), HangupMessage.Type.NORMAL);
}
}
private boolean isSystemPipEnabledAndAvailable() {
@@ -526,19 +606,23 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
}
}
private void startCall(boolean isVideoCall) {
enableVideoIfAvailable = isVideoCall;
if (isVideoCall) {
ApplicationDependencies.getSignalCallManager().startOutgoingVideoCall(viewModel.getRecipient().get());
} else {
ApplicationDependencies.getSignalCallManager().startOutgoingAudioCall(viewModel.getRecipient().get());
}
MessageSender.onMessageSent();
}
private final class ControlsListener implements WebRtcCallView.ControlsListener {
@Override
public void onStartCall(boolean isVideoCall) {
enableVideoIfAvailable = isVideoCall;
Intent intent = new Intent(WebRtcCallActivity.this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_OUTGOING_CALL)
.putExtra(WebRtcCallService.EXTRA_REMOTE_PEER, new RemotePeer(viewModel.getRecipient().getId()))
.putExtra(WebRtcCallService.EXTRA_OFFER_TYPE, (isVideoCall ? OfferMessage.Type.VIDEO_CALL : OfferMessage.Type.AUDIO_CALL).getCode());
startService(intent);
MessageSender.onMessageSent();
viewModel.startCall(isVideoCall);
}
@Override
@@ -553,6 +637,16 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
}
}
@Override
public void showSystemUI() {
fullscreenHelper.showSystemUI();
}
@Override
public void hideSystemUI() {
fullscreenHelper.hideSystemUI();
}
@Override
public void onAudioOutputChanged(@NonNull WebRtcAudioOutput audioOutput) {
switch (audioOutput) {
@@ -618,14 +712,10 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
public void onPageChanged(@NonNull CallParticipantsState.SelectedPage page) {
viewModel.setIsViewingFocusedParticipant(page);
}
}
private class EventListener implements WebRtcCallView.EventListener {
@Override
public void onPotentialLayoutChange() {
Intent intent = new Intent(WebRtcCallActivity.this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_GROUP_UPDATE_RENDERED_RESOLUTIONS);
startService(intent);
public void onLocalPictureInPictureClicked() {
viewModel.onLocalPictureInPictureClicked();
}
}
}

View File

@@ -108,6 +108,8 @@ public abstract class Attachment {
@Nullable
public abstract Uri getUri();
public abstract @Nullable Uri getPublicUri();
public int getTransferState() {
return transferState;
}

View File

@@ -65,6 +65,15 @@ public class DatabaseAttachment extends Attachment {
}
}
@Override
public @Nullable Uri getPublicUri() {
if (hasData) {
return PartAuthority.getAttachmentPublicUri(getUri());
} else {
return null;
}
}
public AttachmentId getAttachmentId() {
return attachmentId;
}

View File

@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.attachments;
import android.net.Uri;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
@@ -19,6 +20,11 @@ public class MmsNotificationAttachment extends Attachment {
return null;
}
@Override
public @Nullable Uri getPublicUri() {
return null;
}
private static int getTransferStateFromStatus(int status) {
if (status == MmsDatabase.Status.DOWNLOAD_INITIALIZED ||
status == MmsDatabase.Status.DOWNLOAD_NO_CONNECTIVITY)

View File

@@ -1,10 +1,10 @@
package org.thoughtcrime.securesms.attachments;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.audio.AudioHash;
import org.thoughtcrime.securesms.blurhash.BlurHash;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.stickers.StickerLocator;
@@ -46,6 +46,11 @@ public class PointerAttachment extends Attachment {
return null;
}
@Override
public @Nullable Uri getPublicUri() {
return null;
}
public static List<Attachment> forPointers(Optional<List<SignalServiceAttachment>> pointers) {
List<Attachment> results = new LinkedList<>();

View File

@@ -23,4 +23,9 @@ public class TombstoneAttachment extends Attachment {
public @Nullable Uri getUri() {
return null;
}
@Override
public @Nullable Uri getPublicUri() {
return null;
}
}

View File

@@ -58,6 +58,11 @@ public class UriAttachment extends Attachment {
return dataUri;
}
@Override
public @Nullable Uri getPublicUri() {
return null;
}
@Override
public boolean equals(Object other) {
return other != null && other instanceof UriAttachment && ((UriAttachment) other).dataUri.equals(this.dataUri);

View File

@@ -8,8 +8,9 @@ import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaRecorder;
import android.os.Build;
import org.thoughtcrime.securesms.logging.Log;
import org.signal.core.util.StreamUtil;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.util.Util;
import java.io.IOException;
@@ -19,7 +20,7 @@ import java.nio.ByteBuffer;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class AudioCodec {
private static final String TAG = AudioCodec.class.getSimpleName();
private static final String TAG = Log.tag(AudioCodec.class);
private static final int SAMPLE_RATE = 44100;
private static final int SAMPLE_RATE_INDEX = 4;
@@ -81,7 +82,7 @@ public class AudioCodec {
mediaCodec.release();
audioRecord.release();
Util.close(outputStream);
StreamUtil.close(outputStream);
setFinished();
}
}

View File

@@ -5,15 +5,16 @@ import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.logging.Log;
import androidx.annotation.NonNull;
import org.signal.core.util.ThreadUtil;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.whispersystems.libsignal.util.Pair;
import java.io.IOException;
@@ -22,7 +23,7 @@ import java.util.concurrent.ExecutorService;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class AudioRecorder {
private static final String TAG = AudioRecorder.class.getSimpleName();
private static final String TAG = Log.tag(AudioRecorder.class);
private static final ExecutorService executor = SignalExecutors.newCachedSingleThreadExecutor("signal-AudioRecorder");
@@ -89,10 +90,10 @@ public class AudioRecorder {
}
private <T> void sendToFuture(final SettableFuture<T> future, final Exception exception) {
Util.runOnMain(() -> future.setException(exception));
ThreadUtil.runOnMain(() -> future.setException(exception));
}
private <T> void sendToFuture(final SettableFuture<T> future, final T result) {
Util.runOnMain(() -> future.set(result));
ThreadUtil.runOnMain(() -> future.set(result));
}
}

View File

@@ -16,18 +16,18 @@ import androidx.core.util.Consumer;
import com.google.protobuf.ByteString;
import org.signal.core.util.ThreadUtil;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.model.databaseprotos.AudioWaveFormData;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.media.DecryptableUriMediaInput;
import org.thoughtcrime.securesms.media.MediaInput;
import org.thoughtcrime.securesms.mms.AudioSlide;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.concurrent.SerialExecutor;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -61,13 +61,13 @@ public final class AudioWaveForm {
if (uri == null) {
Log.w(TAG, "No uri");
Util.runOnMain(onFailure);
ThreadUtil.runOnMain(onFailure);
return;
}
if (!(attachment instanceof DatabaseAttachment)) {
Log.i(TAG, "Not yet in database");
Util.runOnMain(onFailure);
ThreadUtil.runOnMain(onFailure);
return;
}
@@ -75,7 +75,7 @@ public final class AudioWaveForm {
AudioFileInfo cached = WAVE_FORM_CACHE.get(cacheKey);
if (cached != null) {
Log.i(TAG, "Loaded wave form from cache " + cacheKey);
Util.runOnMain(() -> onSuccess.accept(cached));
ThreadUtil.runOnMain(() -> onSuccess.accept(cached));
return;
}
@@ -83,7 +83,7 @@ public final class AudioWaveForm {
AudioFileInfo cachedInExecutor = WAVE_FORM_CACHE.get(cacheKey);
if (cachedInExecutor != null) {
Log.i(TAG, "Loaded wave form from cache inside executor" + cacheKey);
Util.runOnMain(() -> onSuccess.accept(cachedInExecutor));
ThreadUtil.runOnMain(() -> onSuccess.accept(cachedInExecutor));
return;
}
@@ -92,14 +92,14 @@ public final class AudioWaveForm {
AudioFileInfo audioFileInfo = AudioFileInfo.fromDatabaseProtobuf(audioHash.getAudioWaveForm());
if (audioFileInfo.waveForm.length == 0) {
Log.w(TAG, "Recovering from a wave form generation error " + cacheKey);
Util.runOnMain(onFailure);
ThreadUtil.runOnMain(onFailure);
return;
} else if (audioFileInfo.waveForm.length != BAR_COUNT) {
Log.w(TAG, "Wave form from database does not match bar count, regenerating " + cacheKey);
} else {
WAVE_FORM_CACHE.put(cacheKey, audioFileInfo);
Log.i(TAG, "Loaded wave form from DB " + cacheKey);
Util.runOnMain(() -> onSuccess.accept(audioFileInfo));
ThreadUtil.runOnMain(() -> onSuccess.accept(audioFileInfo));
return;
}
}
@@ -120,10 +120,10 @@ public final class AudioWaveForm {
attachmentDatabase.writeAudioHash(dbAttachment.getAttachmentId(), fileInfo.toDatabaseProtobuf());
WAVE_FORM_CACHE.put(cacheKey, fileInfo);
Util.runOnMain(() -> onSuccess.accept(fileInfo));
ThreadUtil.runOnMain(() -> onSuccess.accept(fileInfo));
} catch (Throwable e) {
Log.w(TAG, "Failed to create audio wave form for " + cacheKey, e);
Util.runOnMain(onFailure);
ThreadUtil.runOnMain(onFailure);
}
});
}

View File

@@ -1,6 +1,7 @@
package org.thoughtcrime.securesms.backup;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
@@ -22,9 +23,9 @@ import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.registration.fragments.RestoreBackupFragment;
import org.thoughtcrime.securesms.service.LocalBackupListener;
import org.thoughtcrime.securesms.util.BackupUtil;
@@ -126,7 +127,12 @@ public class BackupDialog {
Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
Intent.FLAG_GRANT_READ_URI_PERMISSION);
fragment.startActivityForResult(intent, requestCode);
try {
fragment.startActivityForResult(intent, requestCode);
} catch (ActivityNotFoundException e) {
Toast.makeText(fragment.requireContext(), R.string.BackupDialog_no_file_picker_available, Toast.LENGTH_LONG)
.show();
}
dialog.dismiss();
}))

View File

@@ -13,6 +13,7 @@ import androidx.core.app.NotificationManagerCompat;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.notifications.NotificationCancellationHelper;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import java.io.IOException;
@@ -34,7 +35,7 @@ public enum BackupFileIOError {
}
public static void clearNotification(@NonNull Context context) {
NotificationManagerCompat.from(context).cancel(BACKUP_FAILED_ID);
NotificationCancellationHelper.cancelLegacy(context, BACKUP_FAILED_ID);
}
public void postNotification(@NonNull Context context) {

View File

@@ -6,8 +6,8 @@ import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.crypto.KeyStoreHelper;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
/**
@@ -18,7 +18,7 @@ public final class BackupPassphrase {
private BackupPassphrase() {
}
private static final String TAG = BackupPassphrase.class.getSimpleName();
private static final String TAG = Log.tag(BackupPassphrase.class);
public static @Nullable String get(@NonNull Context context) {
String passphrase = TextSecurePreferences.getBackupPassphrase(context);

View File

@@ -5,6 +5,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.greenrobot.eventbus.EventBus;
import org.signal.core.util.logging.Log;
import org.whispersystems.libsignal.util.ByteUtil;
import java.security.MessageDigest;
@@ -13,7 +14,7 @@ import java.security.NoSuchAlgorithmException;
public abstract class FullBackupBase {
@SuppressWarnings("unused")
private static final String TAG = FullBackupBase.class.getSimpleName();
private static final String TAG = Log.tag(FullBackupBase.class);
static class BackupStream {
static @NonNull byte[] getBackupKey(@NonNull String passphrase, @Nullable byte[] salt) {

View File

@@ -10,13 +10,14 @@ import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.documentfile.provider.DocumentFile;
import com.annimon.stream.function.Consumer;
import com.annimon.stream.function.Predicate;
import com.google.protobuf.ByteString;
import net.sqlcipher.database.SQLiteDatabase;
import org.greenrobot.eventbus.EventBus;
import org.signal.core.util.Conversions;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.attachments.AttachmentId;
import org.thoughtcrime.securesms.crypto.AttachmentSecret;
import org.thoughtcrime.securesms.crypto.ClassicDecryptingPartInputStream;
@@ -24,7 +25,6 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.ModernDecryptingPartInputStream;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.GroupReceiptDatabase;
import org.thoughtcrime.securesms.database.JobDatabase;
import org.thoughtcrime.securesms.database.KeyValueDatabase;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.MmsSmsColumns;
@@ -34,11 +34,13 @@ import org.thoughtcrime.securesms.database.SessionDatabase;
import org.thoughtcrime.securesms.database.SignedPreKeyDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.StickerDatabase;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.keyvalue.KeyValueDataSet;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.util.Conversions;
import org.thoughtcrime.securesms.util.SetUtil;
import org.thoughtcrime.securesms.util.Stopwatch;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.kdf.HKDFv3;
import org.whispersystems.libsignal.util.ByteUtil;
@@ -66,30 +68,26 @@ import javax.crypto.spec.SecretKeySpec;
public class FullBackupExporter extends FullBackupBase {
@SuppressWarnings("unused")
private static final String TAG = FullBackupExporter.class.getSimpleName();
private static final String TAG = Log.tag(FullBackupExporter.class);
private static final Set<String> BLACKLISTED_TABLES = SetUtil.newHashSet(
SignedPreKeyDatabase.TABLE_NAME,
OneTimePreKeyDatabase.TABLE_NAME,
SessionDatabase.TABLE_NAME,
SearchDatabase.SMS_FTS_TABLE_NAME,
SearchDatabase.MMS_FTS_TABLE_NAME,
JobDatabase.JOBS_TABLE_NAME,
JobDatabase.CONSTRAINTS_TABLE_NAME,
JobDatabase.DEPENDENCIES_TABLE_NAME,
KeyValueDatabase.TABLE_NAME
SearchDatabase.MMS_FTS_TABLE_NAME
);
public static void export(@NonNull Context context,
@NonNull AttachmentSecret attachmentSecret,
@NonNull SQLiteDatabase input,
@NonNull File output,
@NonNull String passphrase)
@NonNull String passphrase,
@NonNull BackupCancellationSignal cancellationSignal)
throws IOException
{
try (OutputStream outputStream = new FileOutputStream(output)) {
internalExport(context, attachmentSecret, input, outputStream, passphrase);
internalExport(context, attachmentSecret, input, outputStream, passphrase, true, cancellationSignal);
}
}
@@ -98,19 +96,32 @@ public class FullBackupExporter extends FullBackupBase {
@NonNull AttachmentSecret attachmentSecret,
@NonNull SQLiteDatabase input,
@NonNull DocumentFile output,
@NonNull String passphrase)
@NonNull String passphrase,
@NonNull BackupCancellationSignal cancellationSignal)
throws IOException
{
try (OutputStream outputStream = Objects.requireNonNull(context.getContentResolver().openOutputStream(output.getUri()))) {
internalExport(context, attachmentSecret, input, outputStream, passphrase);
internalExport(context, attachmentSecret, input, outputStream, passphrase, true, cancellationSignal);
}
}
public static void transfer(@NonNull Context context,
@NonNull AttachmentSecret attachmentSecret,
@NonNull SQLiteDatabase input,
@NonNull OutputStream outputStream,
@NonNull String passphrase)
throws IOException
{
internalExport(context, attachmentSecret, input, outputStream, passphrase, false, () -> false);
}
private static void internalExport(@NonNull Context context,
@NonNull AttachmentSecret attachmentSecret,
@NonNull SQLiteDatabase input,
@NonNull OutputStream fileOutputStream,
@NonNull String passphrase)
@NonNull String passphrase,
boolean closeOutputStream,
@NonNull BackupCancellationSignal cancellationSignal)
throws IOException
{
BackupFrameOutputStream outputStream = new BackupFrameOutputStream(fileOutputStream, passphrase);
@@ -118,36 +129,51 @@ public class FullBackupExporter extends FullBackupBase {
try {
outputStream.writeDatabaseVersion(input.getVersion());
count++;
List<String> tables = exportSchema(input, outputStream);
count += tables.size() * 3;
Stopwatch stopwatch = new Stopwatch("Backup");
for (String table : tables) {
throwIfCanceled(cancellationSignal);
if (table.equals(MmsDatabase.TABLE_NAME)) {
count = exportTable(table, input, outputStream, FullBackupExporter::isNonExpiringMmsMessage, null, count);
count = exportTable(table, input, outputStream, FullBackupExporter::isNonExpiringMmsMessage, null, count, cancellationSignal);
} else if (table.equals(SmsDatabase.TABLE_NAME)) {
count = exportTable(table, input, outputStream, FullBackupExporter::isNonExpiringSmsMessage, null, count);
count = exportTable(table, input, outputStream, FullBackupExporter::isNonExpiringSmsMessage, null, count, cancellationSignal);
} else if (table.equals(GroupReceiptDatabase.TABLE_NAME)) {
count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(GroupReceiptDatabase.MMS_ID))), null, count);
count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(GroupReceiptDatabase.MMS_ID))), null, count, cancellationSignal);
} else if (table.equals(AttachmentDatabase.TABLE_NAME)) {
count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.MMS_ID))), cursor -> exportAttachment(attachmentSecret, cursor, outputStream), count);
count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.MMS_ID))), (cursor, innerCount) -> exportAttachment(attachmentSecret, cursor, outputStream, innerCount), count, cancellationSignal);
} else if (table.equals(StickerDatabase.TABLE_NAME)) {
count = exportTable(table, input, outputStream, cursor -> true, cursor -> exportSticker(attachmentSecret, cursor, outputStream), count);
count = exportTable(table, input, outputStream, cursor -> true, (cursor, innerCount) -> exportSticker(attachmentSecret, cursor, outputStream, innerCount), count, cancellationSignal);
} else if (!BLACKLISTED_TABLES.contains(table) && !table.startsWith("sqlite_")) {
count = exportTable(table, input, outputStream, null, null, count);
count = exportTable(table, input, outputStream, null, null, count, cancellationSignal);
}
stopwatch.split("table::" + table);
}
for (BackupProtos.SharedPreference preference : IdentityKeyUtil.getBackupRecord(context)) {
throwIfCanceled(cancellationSignal);
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
outputStream.write(preference);
}
for (BackupProtos.SharedPreference preference : TextSecurePreferences.getPreferencesToSaveToBackup(context)) {
throwIfCanceled(cancellationSignal);
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
outputStream.write(preference);
}
stopwatch.split("prefs");
count = exportKeyValues(outputStream, SignalStore.getKeysToIncludeInBackup(), count, cancellationSignal);
stopwatch.split("key_values");
for (AvatarHelper.Avatar avatar : AvatarHelper.getAvatars(context)) {
throwIfCanceled(cancellationSignal);
if (avatar != null) {
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
outputStream.write(avatar.getFilename(), avatar.getInputStream(), avatar.getLength());
@@ -159,11 +185,19 @@ public class FullBackupExporter extends FullBackupBase {
outputStream.writeEnd();
} finally {
outputStream.close();
if (closeOutputStream) {
outputStream.close();
}
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.FINISHED, ++count));
}
}
private static void throwIfCanceled(@NonNull BackupCancellationSignal cancellationSignal) throws BackupCanceledException {
if (cancellationSignal.isCanceled()) {
throw new BackupCanceledException();
}
}
private static List<String> exportSchema(@NonNull SQLiteDatabase input, @NonNull BackupFrameOutputStream outputStream)
throws IOException
{
@@ -194,19 +228,20 @@ public class FullBackupExporter extends FullBackupBase {
return tables;
}
private static int exportTable(@NonNull String table,
@NonNull SQLiteDatabase input,
@NonNull BackupFrameOutputStream outputStream,
@Nullable Predicate<Cursor> predicate,
@Nullable Consumer<Cursor> postProcess,
int count)
private static int exportTable(@NonNull String table,
@NonNull SQLiteDatabase input,
@NonNull BackupFrameOutputStream outputStream,
@Nullable Predicate<Cursor> predicate,
@Nullable PostProcessor postProcess,
int count,
@NonNull BackupCancellationSignal cancellationSignal)
throws IOException
{
String template = "INSERT INTO " + table + " VALUES ";
try (Cursor cursor = input.rawQuery("SELECT * FROM " + table, null)) {
while (cursor != null && cursor.moveToNext()) {
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
throwIfCanceled(cancellationSignal);
if (predicate == null || predicate.test(cursor)) {
StringBuilder statement = new StringBuilder(template);
@@ -238,9 +273,12 @@ public class FullBackupExporter extends FullBackupBase {
statement.append(')');
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
outputStream.write(statementBuilder.setStatement(statement.toString()).build());
if (postProcess != null) postProcess.accept(cursor);
if (postProcess != null) {
count = postProcess.postProcess(cursor, count);
}
}
}
}
@@ -248,7 +286,7 @@ public class FullBackupExporter extends FullBackupBase {
return count;
}
private static void exportAttachment(@NonNull AttachmentSecret attachmentSecret, @NonNull Cursor cursor, @NonNull BackupFrameOutputStream outputStream) {
private static int exportAttachment(@NonNull AttachmentSecret attachmentSecret, @NonNull Cursor cursor, @NonNull BackupFrameOutputStream outputStream, int count) {
try {
long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.ROW_ID));
long uniqueId = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.UNIQUE_ID));
@@ -273,14 +311,17 @@ public class FullBackupExporter extends FullBackupBase {
if (random != null && random.length == 32) inputStream = ModernDecryptingPartInputStream.createFor(attachmentSecret, random, new File(data), 0);
else inputStream = ClassicDecryptingPartInputStream.createFor(attachmentSecret, new File(data));
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
outputStream.write(new AttachmentId(rowId, uniqueId), inputStream, size);
}
} catch (IOException e) {
Log.w(TAG, e);
}
return count;
}
private static void exportSticker(@NonNull AttachmentSecret attachmentSecret, @NonNull Cursor cursor, @NonNull BackupFrameOutputStream outputStream) {
private static int exportSticker(@NonNull AttachmentSecret attachmentSecret, @NonNull Cursor cursor, @NonNull BackupFrameOutputStream outputStream, int count) {
try {
long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(StickerDatabase._ID));
long size = cursor.getLong(cursor.getColumnIndexOrThrow(StickerDatabase.FILE_LENGTH));
@@ -289,12 +330,15 @@ public class FullBackupExporter extends FullBackupBase {
byte[] random = cursor.getBlob(cursor.getColumnIndexOrThrow(StickerDatabase.FILE_RANDOM));
if (!TextUtils.isEmpty(data) && size > 0) {
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
InputStream inputStream = ModernDecryptingPartInputStream.createFor(attachmentSecret, random, new File(data), 0);
outputStream.writeSticker(rowId, inputStream, size);
}
} catch (IOException e) {
Log.w(TAG, e);
}
return count;
}
private static long calculateVeryOldStreamLength(@NonNull AttachmentSecret attachmentSecret, @Nullable byte[] random, @NonNull String data) throws IOException {
@@ -314,6 +358,46 @@ public class FullBackupExporter extends FullBackupBase {
return result;
}
private static int exportKeyValues(@NonNull BackupFrameOutputStream outputStream,
@NonNull List<String> keysToIncludeInBackup,
int count,
BackupCancellationSignal cancellationSignal) throws IOException
{
KeyValueDataSet dataSet = KeyValueDatabase.getInstance(ApplicationDependencies.getApplication())
.getDataSet();
for (String key : keysToIncludeInBackup) {
throwIfCanceled(cancellationSignal);
if (!dataSet.containsKey(key)) {
continue;
}
BackupProtos.KeyValue.Builder builder = BackupProtos.KeyValue.newBuilder()
.setKey(key);
Class<?> type = dataSet.getType(key);
if (type == byte[].class) {
builder.setBlobValue(ByteString.copyFrom(dataSet.getBlob(key, null)));
} else if (type == Boolean.class) {
builder.setBooleanValue(dataSet.getBoolean(key, false));
} else if (type == Float.class) {
builder.setFloatValue(dataSet.getFloat(key, 0));
} else if (type == Integer.class) {
builder.setIntegerValue(dataSet.getInteger(key, 0));
} else if (type == Long.class) {
builder.setLongValue(dataSet.getLong(key, 0));
} else if (type == String.class) {
builder.setStringValue(dataSet.getString(key, null));
} else {
throw new AssertionError("Unknown type: " + type);
}
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
outputStream.write(builder.build());
}
return count;
}
private static boolean isNonExpiringMmsMessage(@NonNull Cursor cursor) {
return cursor.getInt(cursor.getColumnIndexOrThrow(MmsSmsColumns.EXPIRES_IN)) <= 0 &&
cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.VIEW_ONCE)) <= 0;
@@ -385,6 +469,10 @@ public class FullBackupExporter extends FullBackupBase {
write(outputStream, BackupProtos.BackupFrame.newBuilder().setPreference(preference).build());
}
public void write(BackupProtos.KeyValue keyValue) throws IOException {
write(outputStream, BackupProtos.BackupFrame.newBuilder().setKeyValue(keyValue).build());
}
public void write(BackupProtos.SqlStatement statement) throws IOException {
write(outputStream, BackupProtos.BackupFrame.newBuilder().setStatement(statement).build());
}
@@ -499,4 +587,14 @@ public class FullBackupExporter extends FullBackupBase {
outputStream.close();
}
}
public interface PostProcessor {
int postProcess(@NonNull Cursor cursor, int count);
}
public interface BackupCancellationSignal {
boolean isCanceled();
}
public static final class BackupCanceledException extends IOException { }
}

View File

@@ -14,6 +14,9 @@ import androidx.annotation.NonNull;
import net.sqlcipher.database.SQLiteDatabase;
import org.greenrobot.eventbus.EventBus;
import org.signal.core.util.Conversions;
import org.signal.core.util.StreamUtil;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.backup.BackupProtos.Attachment;
import org.thoughtcrime.securesms.backup.BackupProtos.BackupFrame;
import org.thoughtcrime.securesms.backup.BackupProtos.DatabaseVersion;
@@ -23,15 +26,15 @@ import org.thoughtcrime.securesms.backup.BackupProtos.Sticker;
import org.thoughtcrime.securesms.crypto.AttachmentSecret;
import org.thoughtcrime.securesms.crypto.ModernEncryptingPartOutputStream;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.KeyValueDatabase;
import org.thoughtcrime.securesms.database.SearchDatabase;
import org.thoughtcrime.securesms.database.StickerDatabase;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.keyvalue.KeyValueDataSet;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.BackupUtil;
import org.thoughtcrime.securesms.util.Conversions;
import org.thoughtcrime.securesms.util.SqlUtil;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.kdf.HKDFv3;
import org.whispersystems.libsignal.util.ByteUtil;
@@ -45,6 +48,8 @@ import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
@@ -60,25 +65,37 @@ import javax.crypto.spec.SecretKeySpec;
public class FullBackupImporter extends FullBackupBase {
@SuppressWarnings("unused")
private static final String TAG = FullBackupImporter.class.getSimpleName();
private static final String TAG = Log.tag(FullBackupImporter.class);
public static void importFile(@NonNull Context context, @NonNull AttachmentSecret attachmentSecret,
@NonNull SQLiteDatabase db, @NonNull Uri uri, @NonNull String passphrase)
throws IOException
{
try (InputStream is = getInputStream(context, uri)) {
importFile(context, attachmentSecret, db, is, passphrase);
}
}
public static void importFile(@NonNull Context context, @NonNull AttachmentSecret attachmentSecret,
@NonNull SQLiteDatabase db, @NonNull InputStream is, @NonNull String passphrase)
throws IOException
{
int count = 0;
try (InputStream is = getInputStream(context, uri)) {
SQLiteDatabase keyValueDatabase = KeyValueDatabase.getInstance(ApplicationDependencies.getApplication()).getSqlCipherDatabase();
try {
BackupRecordInputStream inputStream = new BackupRecordInputStream(is, passphrase);
db.beginTransaction();
keyValueDatabase.beginTransaction();
dropAllTables(db);
BackupFrame frame;
while (!(frame = inputStream.readFrame()).getEnd()) {
if (count++ % 100 == 0) EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, count));
if (count % 100 == 0) EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, count));
count++;
if (frame.hasVersion()) processVersion(db, frame.getVersion());
else if (frame.hasStatement()) processStatement(db, frame.getStatement());
@@ -86,18 +103,22 @@ public class FullBackupImporter extends FullBackupBase {
else if (frame.hasAttachment()) processAttachment(context, attachmentSecret, db, frame.getAttachment(), inputStream);
else if (frame.hasSticker()) processSticker(context, attachmentSecret, db, frame.getSticker(), inputStream);
else if (frame.hasAvatar()) processAvatar(context, db, frame.getAvatar(), inputStream);
else if (frame.hasKeyValue()) processKeyValue(frame.getKeyValue());
else count--;
}
db.setTransactionSuccessful();
keyValueDatabase.setTransactionSuccessful();
} finally {
db.endTransaction();
keyValueDatabase.endTransaction();
}
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.FINISHED, count));
}
private static @NonNull InputStream getInputStream(@NonNull Context context, @NonNull Uri uri) throws IOException{
if (BackupUtil.isUserSelectionRequired(context)) {
if (BackupUtil.isUserSelectionRequired(context) || uri.getScheme().equals("content")) {
return Objects.requireNonNull(context.getContentResolver().openInputStream(uri));
} else {
return new FileInputStream(new File(Objects.requireNonNull(uri.getPath())));
@@ -201,10 +222,40 @@ public class FullBackupImporter extends FullBackupBase {
}
}
private static void processKeyValue(BackupProtos.KeyValue keyValue) {
KeyValueDataSet dataSet = new KeyValueDataSet();
if (keyValue.hasBlobValue()) {
dataSet.putBlob(keyValue.getKey(), keyValue.getBlobValue().toByteArray());
} else if (keyValue.hasBooleanValue()) {
dataSet.putBoolean(keyValue.getKey(), keyValue.getBooleanValue());
} else if (keyValue.hasFloatValue()) {
dataSet.putFloat(keyValue.getKey(), keyValue.getFloatValue());
} else if (keyValue.hasIntegerValue()) {
dataSet.putInteger(keyValue.getKey(), keyValue.getIntegerValue());
} else if (keyValue.hasLongValue()) {
dataSet.putLong(keyValue.getKey(), keyValue.getLongValue());
} else if (keyValue.hasStringValue()) {
dataSet.putString(keyValue.getKey(), keyValue.getStringValue());
} else {
Log.i(TAG, "Unknown KeyValue backup value, skipping");
return;
}
KeyValueDatabase.getInstance(ApplicationDependencies.getApplication()).writeDataSet(dataSet, Collections.emptyList());
}
@SuppressLint("ApplySharedPref")
private static void processPreference(@NonNull Context context, SharedPreference preference) {
SharedPreferences preferences = context.getSharedPreferences(preference.getFile(), 0);
preferences.edit().putString(preference.getKey(), preference.getValue()).commit();
if (preference.hasValue()) {
preferences.edit().putString(preference.getKey(), preference.getValue()).commit();
} else if (preference.hasBooleanValue()) {
preferences.edit().putBoolean(preference.getKey(), preference.getBooleanValue()).commit();
} else if (preference.hasIsStringSetValue() && preference.getIsStringSetValue()) {
preferences.edit().putStringSet(preference.getKey(), new HashSet<>(preference.getStringSetValueList())).commit();
}
}
private static void dropAllTables(@NonNull SQLiteDatabase db) {
@@ -237,11 +288,11 @@ public class FullBackupImporter extends FullBackupBase {
this.in = in;
byte[] headerLengthBytes = new byte[4];
Util.readFully(in, headerLengthBytes);
StreamUtil.readFully(in, headerLengthBytes);
int headerLength = Conversions.byteArrayToInt(headerLengthBytes);
byte[] headerFrame = new byte[headerLength];
Util.readFully(in, headerFrame);
StreamUtil.readFully(in, headerFrame);
BackupFrame frame = BackupFrame.parseFrom(headerFrame);
@@ -313,7 +364,7 @@ public class FullBackupImporter extends FullBackupBase {
byte[] theirMac = new byte[10];
try {
Util.readFully(in, theirMac);
StreamUtil.readFully(in, theirMac);
} catch (IOException e) {
throw new IOException(e);
}
@@ -329,10 +380,10 @@ public class FullBackupImporter extends FullBackupBase {
private BackupFrame readFrame(InputStream in) throws IOException {
try {
byte[] length = new byte[4];
Util.readFully(in, length);
StreamUtil.readFully(in, length);
byte[] frame = new byte[Conversions.byteArrayToInt(length)];
Util.readFully(in, frame);
StreamUtil.readFully(in, frame);
byte[] theirMac = new byte[10];
System.arraycopy(frame, frame.length - 10, theirMac, 0, theirMac.length);

View File

@@ -124,8 +124,6 @@ public class BlockedUsersActivity extends PassphraseRequiredActivity implements
ContactSelectionListFragment fragment = new ContactSelectionListFragment();
Intent intent = getIntent();
fragment.setOnContactSelectedListener(this);
intent.putExtra(ContactSelectionListFragment.REFRESHABLE, false);
intent.putExtra(ContactSelectionListFragment.SELECTION_LIMITS, 1);
intent.putExtra(ContactSelectionListFragment.HIDE_COUNT, true);

View File

@@ -5,15 +5,15 @@ import android.content.Context;
import androidx.annotation.NonNull;
import androidx.core.util.Consumer;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import java.io.IOException;
import java.util.ArrayList;

View File

@@ -20,8 +20,6 @@
*/
package org.thoughtcrime.securesms.blurhash;
import android.text.TextUtils;
import androidx.annotation.Nullable;
final class Base83 {

View File

@@ -1,7 +1,6 @@
package org.thoughtcrime.securesms.color;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Color;
import androidx.annotation.ColorInt;

View File

@@ -1,15 +1,16 @@
package org.thoughtcrime.securesms.components;
import android.content.Context;
import androidx.annotation.ColorInt;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.Slide;

View File

@@ -4,17 +4,17 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build.VERSION_CODES;
import androidx.core.content.ContextCompat;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
public class AlertView extends LinearLayout {
private static final String TAG = AlertView.class.getSimpleName();
private static final String TAG = Log.tag(AlertView.class);
private ImageView approvalIndicator;
private ImageView failedIndicator;

View File

@@ -29,6 +29,7 @@ import com.pnikosis.materialishprogress.ProgressWheel;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.audio.AudioWaveForm;
import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState;
@@ -42,7 +43,7 @@ import java.util.concurrent.TimeUnit;
public final class AudioView extends FrameLayout {
private static final String TAG = AudioView.class.getSimpleName();
private static final String TAG = Log.tag(AudioView.class);
private static final int FORWARDS = 1;
private static final int REVERSE = -1;

View File

@@ -8,6 +8,7 @@ import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
@@ -15,10 +16,12 @@ import androidx.fragment.app.FragmentActivity;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
import org.thoughtcrime.securesms.groups.ui.managegroup.ManageGroupActivity;
import org.thoughtcrime.securesms.mms.GlideApp;
@@ -38,7 +41,7 @@ public final class AvatarImageView extends AppCompatImageView {
private static final int SIZE_SMALL = 2;
@SuppressWarnings("unused")
private static final String TAG = AvatarImageView.class.getSimpleName();
private static final String TAG = Log.tag(AvatarImageView.class);
private static final Paint LIGHT_THEME_OUTLINE_PAINT = new Paint();
private static final Paint DARK_THEME_OUTLINE_PAINT = new Paint();
@@ -117,11 +120,18 @@ public final class AvatarImageView extends AppCompatImageView {
* Shows self as the actual profile picture.
*/
public void setRecipient(@NonNull Recipient recipient) {
setRecipient(recipient, false);
}
/**
* Shows self as the actual profile picture.
*/
public void setRecipient(@NonNull Recipient recipient, boolean quickContactEnabled) {
if (recipient.isSelf()) {
setAvatar(GlideApp.with(this), null, false);
setAvatar(GlideApp.with(this), null, quickContactEnabled);
AvatarUtil.loadIconIntoImageView(recipient, this);
} else {
setAvatar(GlideApp.with(this), recipient, false);
setAvatar(GlideApp.with(this), recipient, quickContactEnabled);
}
}
@@ -132,9 +142,23 @@ public final class AvatarImageView extends AppCompatImageView {
setAvatar(GlideApp.with(this), recipient, false);
}
/**
* Shows self as the profile avatar.
*/
public void setAvatarUsingProfile(@Nullable Recipient recipient) {
setAvatar(GlideApp.with(this), recipient, false, true);
}
public void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient, boolean quickContactEnabled) {
setAvatar(requestManager, recipient, quickContactEnabled, false);
}
public void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient, boolean quickContactEnabled, boolean useSelfProfileAvatar) {
if (recipient != null) {
RecipientContactPhoto photo = new RecipientContactPhoto(recipient);
RecipientContactPhoto photo = (recipient.isSelf() && useSelfProfileAvatar) ? new RecipientContactPhoto(recipient,
new ProfileContactPhoto(Recipient.self(),
Recipient.self().getProfileAvatar()))
: new RecipientContactPhoto(recipient);
if (!photo.equals(recipientContactPhoto)) {
requestManager.clear(this);
@@ -189,8 +213,7 @@ public final class AvatarImageView extends AppCompatImageView {
}
});
} else {
super.setOnClickListener(listener);
setClickable(listener != null);
disableQuickContact();
}
}
@@ -211,6 +234,16 @@ public final class AvatarImageView extends AppCompatImageView {
.into(this);
}
public void setNonAvatarImageResource(@DrawableRes int imageResource) {
recipientContactPhoto = null;
setImageResource(imageResource);
}
public void disableQuickContact() {
super.setOnClickListener(listener);
setClickable(listener != null);
}
private static class RecipientContactPhoto {
private final @NonNull Recipient recipient;
@@ -218,9 +251,13 @@ public final class AvatarImageView extends AppCompatImageView {
private final boolean ready;
RecipientContactPhoto(@NonNull Recipient recipient) {
this(recipient, recipient.getContactPhoto());
}
RecipientContactPhoto(@NonNull Recipient recipient, @Nullable ContactPhoto contactPhoto) {
this.recipient = recipient;
this.ready = !recipient.isResolving();
this.contactPhoto = recipient.getContactPhoto();
this.contactPhoto = contactPhoto;
}
public boolean equals(@Nullable RecipientContactPhoto other) {

View File

@@ -1,12 +1,13 @@
package org.thoughtcrime.securesms.components;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.load.resource.bitmap.CenterInside;

View File

@@ -5,9 +5,10 @@ import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import androidx.appcompat.widget.AppCompatImageView;
import android.util.AttributeSet;
import androidx.appcompat.widget.AppCompatImageView;
import org.thoughtcrime.securesms.R;
public class CircleColorImageView extends AppCompatImageView {

View File

@@ -26,6 +26,7 @@ import androidx.core.view.inputmethod.EditorInfoCompat;
import androidx.core.view.inputmethod.InputConnectionCompat;
import androidx.core.view.inputmethod.InputContentInfoCompat;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.TransportOption;
import org.thoughtcrime.securesms.components.emoji.EmojiEditText;
@@ -34,12 +35,9 @@ import org.thoughtcrime.securesms.components.mention.MentionDeleter;
import org.thoughtcrime.securesms.components.mention.MentionRendererDelegate;
import org.thoughtcrime.securesms.components.mention.MentionValidatorWatcher;
import org.thoughtcrime.securesms.database.model.Mention;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.StringUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ThemeUtil;
import java.util.List;
@@ -83,8 +81,8 @@ public class ComposeText extends EmojiEditText {
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (!TextUtils.isEmpty(hint)) {
if (!TextUtils.isEmpty(subHint)) {
@@ -94,6 +92,7 @@ public class ComposeText extends EmojiEditText {
} else {
setHint(ellipsizeToWidth(hint));
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
@@ -366,7 +365,7 @@ public class ComposeText extends EmojiEditText {
private static class CommitContentListener implements InputConnectionCompat.OnCommitContentListener {
private static final String TAG = CommitContentListener.class.getSimpleName();
private static final String TAG = Log.tag(CommitContentListener.class);
private final InputPanel.MediaListener mediaListener;

View File

@@ -1,10 +1,11 @@
package org.thoughtcrime.securesms.components;
import android.content.Context;
import com.google.android.material.tabs.TabLayout;
import android.util.AttributeSet;
import android.view.View;
import com.google.android.material.tabs.TabLayout;
import java.util.List;
/**

View File

@@ -1,11 +1,12 @@
package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.viewpager.widget.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import org.thoughtcrime.securesms.components.viewpager.HackyViewPager;

View File

@@ -6,13 +6,13 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -20,6 +20,7 @@ import com.airbnb.lottie.LottieAnimationView;
import com.airbnb.lottie.LottieProperty;
import com.airbnb.lottie.model.KeyPath;
import org.signal.core.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.DatabaseFactory;
@@ -130,6 +131,20 @@ public class ConversationItemFooter extends LinearLayout {
presentDeliveryStatus(messageRecord);
}
public void enableBubbleBackground(@DrawableRes int drawableRes, @Nullable Integer tint) {
setBackgroundResource(drawableRes);
if (tint != null) {
getBackground().setColorFilter(tint, PorterDuff.Mode.MULTIPLY);
} else {
getBackground().clearColorFilter();
}
}
public void disableBubbleBackground() {
setBackground(null);
}
private void presentDate(@NonNull MessageRecord messageRecord, @NonNull Locale locale) {
dateView.forceLayout();
if (messageRecord.isFailed()) {
@@ -185,20 +200,16 @@ public class ConversationItemFooter extends LinearLayout {
ApplicationContext.getInstance(getContext()).getExpiringMessageManager().checkSchedule();
}
} else if (!messageRecord.isOutgoing() && !messageRecord.isMediaPending()) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
ExpiringMessageManager expirationManager = ApplicationContext.getInstance(getContext()).getExpiringMessageManager();
long id = messageRecord.getId();
boolean mms = messageRecord.isMms();
SignalExecutors.BOUNDED.execute(() -> {
ExpiringMessageManager expirationManager = ApplicationContext.getInstance(getContext()).getExpiringMessageManager();
long id = messageRecord.getId();
boolean mms = messageRecord.isMms();
if (mms) DatabaseFactory.getMmsDatabase(getContext()).markExpireStarted(id);
else DatabaseFactory.getSmsDatabase(getContext()).markExpireStarted(id);
if (mms) DatabaseFactory.getMmsDatabase(getContext()).markExpireStarted(id);
else DatabaseFactory.getSmsDatabase(getContext()).markExpireStarted(id);
expirationManager.scheduleDeletion(id, mms, messageRecord.getExpiresIn());
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
expirationManager.scheduleDeletion(id, mms, messageRecord.getExpiresIn());
});
}
} else {
this.timerView.setVisibility(View.GONE);
@@ -264,8 +275,8 @@ public class ConversationItemFooter extends LinearLayout {
addView(audioDuration, 0);
int padStart = ViewUtil.dpToPx(60);
int padLeft = getLayoutDirection() == LAYOUT_DIRECTION_LTR ? padStart : 0;
int padRight = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? padStart : 0;
int padLeft = ViewUtil.isLtr(this) ? padStart : 0;
int padRight = ViewUtil.isRtl(this) ? padStart : 0;
audioDuration.setPadding(padLeft, 0, padRight, 0);
}

View File

@@ -3,23 +3,22 @@ package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.widget.ImageView;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.core.content.ContextCompat;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.widget.ImageView;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideClickListener;
import org.thoughtcrime.securesms.mms.SlidesClickedListener;
import org.thoughtcrime.securesms.util.ThemeUtil;
import java.util.List;

View File

@@ -1,13 +1,14 @@
package org.thoughtcrime.securesms.components;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import org.thoughtcrime.securesms.R;
/**

View File

@@ -2,12 +2,13 @@ package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.graphics.PorterDuff;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient;
@@ -43,7 +44,7 @@ public class ConversationTypingView extends LinearLayout {
bubble.getBackground().setColorFilter(typist.getColor().toConversationColor(getContext()), PorterDuff.Mode.MULTIPLY);
if (isGroupThread) {
avatar.setAvatar(glideRequests, typist, false);
avatar.setAvatar(glideRequests, typist, true);
avatar.setVisibility(VISIBLE);
} else {
avatar.setVisibility(GONE);

View File

@@ -7,9 +7,9 @@ import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.view.View;
import androidx.annotation.NonNull;
import android.view.View;
public class CornerMask {

View File

@@ -4,15 +4,10 @@ import android.app.Dialog;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.DialogPreference;
import androidx.preference.PreferenceDialogFragmentCompat;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import org.thoughtcrime.securesms.logging.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
@@ -20,6 +15,12 @@ import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.DialogPreference;
import androidx.preference.PreferenceDialogFragmentCompat;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.CustomDefaultPreference.CustomDefaultPreferenceDialogFragmentCompat.CustomPreferenceValidator;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@@ -30,7 +31,7 @@ import java.net.URISyntaxException;
public class CustomDefaultPreference extends DialogPreference {
private static final String TAG = CustomDefaultPreference.class.getSimpleName();
private static final String TAG = Log.tag(CustomDefaultPreference.class);
private final int inputType;
private final String customPreference;

View File

@@ -1,7 +1,6 @@
package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.EditText;
@@ -9,10 +8,8 @@ import androidx.annotation.AttrRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.ThemeUtil;
/**
* Custom styled search view that we can insert into ActionBar menus

View File

@@ -2,25 +2,20 @@ package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import pl.tajchert.sample.DotsTextView;
public class DeliveryStatusView extends FrameLayout {
private static final String TAG = DeliveryStatusView.class.getSimpleName();
private static final String TAG = Log.tag(DeliveryStatusView.class);
private static final RotateAnimation ROTATION_ANIMATION = new RotateAnimation(0, 360f,
Animation.RELATIVE_TO_SELF, 0.5f,

View File

@@ -20,6 +20,7 @@ import com.pnikosis.materialishprogress.ProgressWheel;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.events.PartProgressEvent;
@@ -29,7 +30,7 @@ import org.thoughtcrime.securesms.util.Util;
public class DocumentView extends FrameLayout {
private static final String TAG = DocumentView.class.getSimpleName();
private static final String TAG = Log.tag(DocumentView.class);
private final @NonNull AnimatingToggle controlToggle;
private final @NonNull ImageView downloadButton;

View File

@@ -1,12 +1,13 @@
package org.thoughtcrime.securesms.components;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.util.AttributeSet;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.core.util.ThreadUtil;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.Util;
import java.lang.ref.WeakReference;
import java.util.concurrent.TimeUnit;
@@ -66,7 +67,7 @@ public class ExpirationTimerView extends androidx.appcompat.widget.AppCompatImag
else stopped = false;
}
Util.runOnMainDelayed(new AnimationUpdateRunnable(this), calculateAnimationDelay(this.startedAt, this.expiresIn));
ThreadUtil.runOnMainDelayed(new AnimationUpdateRunnable(this), calculateAnimationDelay(this.startedAt, this.expiresIn));
}
public void stopAnimation() {
@@ -115,7 +116,7 @@ public class ExpirationTimerView extends androidx.appcompat.widget.AppCompatImag
}
}
Util.runOnMainDelayed(this, timerView.calculateAnimationDelay(timerView.startedAt, timerView.expiresIn));
ThreadUtil.runOnMainDelayed(this, timerView.calculateAnimationDelay(timerView.startedAt, timerView.expiresIn));
}
}

View File

@@ -2,22 +2,22 @@ package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.graphics.Typeface;
import androidx.annotation.Nullable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.style.StyleSpan;
import android.util.AttributeSet;
import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
import org.thoughtcrime.securesms.recipients.Recipient;
public class FromTextView extends EmojiTextView {
private static final String TAG = FromTextView.class.getSimpleName();
private static final String TAG = Log.tag(FromTextView.class);
public FromTextView(Context context) {
super(context);

View File

@@ -27,8 +27,7 @@ public abstract class FullScreenDialogFragment extends DialogFragment {
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(STYLE_NO_FRAME, ThemeUtil.isDarkTheme(requireActivity()) ? R.style.TextSecure_DarkTheme_FullScreenDialog
: R.style.TextSecure_LightTheme_FullScreenDialog);
setStyle(STYLE_NO_FRAME, R.style.Signal_DayNight_Dialog_FullScreen);
}
@Override

View File

@@ -2,9 +2,10 @@ package org.thoughtcrime.securesms.components;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.widget.ImageView;
import com.bumptech.glide.request.target.BitmapImageViewTarget;

View File

@@ -1,9 +1,10 @@
package org.thoughtcrime.securesms.components;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.widget.ImageView;
import com.bumptech.glide.request.target.DrawableImageViewTarget;

View File

@@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.components;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import android.util.AttributeSet;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
@@ -11,6 +10,8 @@ import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.widget.LinearLayout;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
public class HidingLinearLayout extends LinearLayout {
public HidingLinearLayout(Context context) {

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