Compare commits

...

1735 Commits
v4.70.0 ... v

Author SHA1 Message Date
Greyson Parrelli
8004565c84 Bump version to 5.17.1 2021-07-16 15:55:54 -04:00
Greyson Parrelli
a101dc4fd1 Updated language translations. 2021-07-16 15:53:42 -04:00
Alex Hart
57f730d8ee Fix cursor issue for non-signal-contact searches. 2021-07-16 16:34:38 -03:00
Alex Hart
3543cc80ba Don't show SMS label for push groups. 2021-07-16 16:34:02 -03:00
Greyson Parrelli
71613d9db1 Ensure SQLCipher libraries are loaded. 2021-07-16 14:12:00 -04:00
Greyson Parrelli
4a0e6a3eb2 Improve logging around message sends. 2021-07-16 12:53:29 -04:00
Alex Hart
f1a87518e1 Fix contact search query returning outdated or bad recipients. 2021-07-16 13:53:17 -03:00
Alex Hart
61f880fd78 Hide all media for new conversations. 2021-07-16 13:20:30 -03:00
Greyson Parrelli
09904e7a16 Remove GIF button from attachment keyboard.
We've had it there for ~45 days for education purposes, but we can
remove it now.
2021-07-16 11:01:10 -04:00
Alex Hart
94658e9090 Fix bug where marquee text stopped scrolling. 2021-07-16 09:23:47 -03:00
Greyson Parrelli
a47448b6c6 Bump version to 5.17.0 2021-07-15 16:41:11 -04:00
Greyson Parrelli
7e4b9b685a Updated language translations. 2021-07-15 16:40:28 -04:00
lucio-signal
64922a8e51 Fix custom vibration settings. 2021-07-15 16:29:43 -04:00
Cody Henthorne
f65f4704c9 Improve routine around bulk attachment deletion. 2021-07-15 16:29:11 -04:00
Greyson Parrelli
b04ca202f6 Fix ApplicationMigrations UI. 2021-07-15 16:28:13 -04:00
Greyson Parrelli
83086a5a2b Make Sms/MmsDatabase ID's autoincrement. 2021-07-15 16:28:13 -04:00
Cody Henthorne
51a521594f Fix crash when deleting threads directly after backup restore. 2021-07-15 16:28:13 -04:00
Greyson Parrelli
0a7a7cf5a9 Fix envelope type conversion. 2021-07-15 16:28:13 -04:00
Greyson Parrelli
6bd689504c Make internal recipient details selectable. 2021-07-15 16:28:13 -04:00
Greyson Parrelli
efec40ff57 Fix crash with GV2 group repair during storage sync. 2021-07-15 16:28:13 -04:00
Greyson Parrelli
69716dde4a Fix navigation directly to the help screen. 2021-07-15 16:28:13 -04:00
Greyson Parrelli
e90fa05d60 Update recipient merging. 2021-07-15 16:28:13 -04:00
Greyson Parrelli
580c000bda Move distribution message processing into the decryption phase. 2021-07-15 16:28:13 -04:00
lucio-signal
2f3d04d3e8 Add EmojiFilter to SearchView input field. 2021-07-15 16:28:13 -04:00
Greyson Parrelli
bf37d412e9 Add message trimming info to the debug log. 2021-07-15 16:28:13 -04:00
Alex Hart
fd115ebb72 Drop voice notes that do not have a URI. 2021-07-15 16:28:13 -04:00
Greyson Parrelli
b9657208fe Make ThreadDatabase ID's autoincrement. 2021-07-15 16:28:13 -04:00
Cody Henthorne
5d6d78a51e Initial WebSocket refactor. 2021-07-15 16:28:13 -04:00
Cody Henthorne
916006e664 Tweak sizes and padding of various keyboard elements. 2021-07-15 16:28:13 -04:00
Cody Henthorne
55c69cd50a Add additional fallback logic for change dialog. 2021-07-15 16:28:13 -04:00
Cody Henthorne
14565b0864 Fix crash when building notification state for messages without threads. 2021-07-15 16:28:13 -04:00
Alex Hart
a157c1ae1d Refresh contact search views. 2021-07-15 16:28:13 -04:00
Greyson Parrelli
a4d458f969 Use current tag for nightly versionName. 2021-07-15 16:28:13 -04:00
Alex Hart
3f53abedab Migrate to new Share APIs. 2021-07-15 16:28:13 -04:00
Jordan Rose
68a2d5ed20 Reimplement ProfileCipherInputStream using libsignal-client.
libsignal-client provides an AES-GCM streaming interface that can
replace the implementation in AES-GCM-Provider. Using it from
ProfileCipherInputStream requires some knowledge about the tag size of
AES-GCM, but frees it from the JCE interface.

Note that it remains a serious error to not read the *entire* stream,
since the authentication tag is at the end!
2021-07-15 16:28:11 -04:00
Jordan Rose
35e9e31a7b Update to libsignal-client 0.8.3
This also fixes a misalignment where signal-client-android was on
0.8.0 but signal-client-java was 0.8.1, which was fortunately harmless
for this particular pair of versions.
2021-07-12 20:29:07 -04:00
Cody Henthorne
444d947743 Add RxJava. 2021-07-12 20:29:07 -04:00
Cody Henthorne
c427dbad08 Bump version to 5.16.3 2021-07-12 20:27:40 -04:00
Cody Henthorne
2cefe813e4 Updated language translations. 2021-07-12 20:17:43 -04:00
Alex Hart
123ffe42c3 Fix crash saving a FLAC file. 2021-07-12 13:37:59 -03:00
Alex Hart
da20e66ecd Fix issue where shared contact render would not hide audio view. 2021-07-12 13:24:04 -03:00
Alex Hart
901440017a Fix audio view width on very narrow screens. 2021-07-12 13:20:56 -03:00
Cody Henthorne
0be76a37fe Bump version to 5.16.2 2021-07-09 15:43:11 -04:00
Cody Henthorne
36dadc8777 Updated language translations. 2021-07-09 15:37:19 -04:00
Cody Henthorne
182749c101 Fix bug where some profile fetches would 400 over the websocket. 2021-07-09 15:30:08 -04:00
Alex Hart
d9228bd911 Fix issue where compose views still display under draft. 2021-07-09 15:30:08 -04:00
Greyson Parrelli
a361fcc8f3 Add additional logging to media send jobs. 2021-07-09 15:30:08 -04:00
Alex Hart
ff4f0b9f42 Stop voice note playback after user locks Signal. 2021-07-09 15:30:07 -04:00
Alex Hart
060dffc9cc Fix crash caused when quote draft left and re-entered. 2021-07-09 15:30:07 -04:00
Alex Hart
172cc302fc Add warning dialog for chat color deletion with no uses. 2021-07-09 15:30:07 -04:00
Alex Hart
416e62112f Refresh shared media screens. 2021-07-09 15:30:07 -04:00
Alex Hart
e584a90f81 Fix several voice note beta bugs.
* Sim label positioning
* Bad player state when navigating to and from conversations
* Scrolling date header placement
2021-07-09 15:29:40 -04:00
Cody Henthorne
9876ffb5e4 Bump version to 5.16.1 2021-07-08 17:52:50 -04:00
Cody Henthorne
53e10f2cad Updated language translations. 2021-07-08 17:43:16 -04:00
Cody Henthorne
cb79f75ac1 Fix bug when calling non-Signal contacts from Settings.
Fixes #11450
2021-07-08 17:36:14 -04:00
Cody Henthorne
5ec9c1cd90 Fix crash when saving media with octet stream content type. 2021-07-08 17:36:14 -04:00
Greyson Parrelli
1f28a30ace Add a nightly build type. 2021-07-08 17:36:14 -04:00
Alex Hart
7715917436 Fix issue where position would not update in draft. 2021-07-08 17:36:14 -04:00
Alex Hart
f79b445fdf Fix issue where drafts might not be properly deleted. 2021-07-08 17:36:14 -04:00
Alex Hart
14484deabe Implement count-down in inline player. 2021-07-08 17:36:14 -04:00
Alex Hart
3ac395d33e Fix row item size issue with huge fonts. 2021-07-08 17:36:14 -04:00
Alex Hart
f83b520ca9 Bump version to 5.16.0 2021-07-07 14:58:51 -03:00
Alex Hart
0123f9aa87 Updated language translations. 2021-07-07 14:58:51 -03:00
Alex Hart
06b64fe619 Add inline voice note player to conversation and conversation list. 2021-07-07 14:58:51 -03:00
Greyson Parrelli
1bb87834d8 Reduce recipient resolves in MessageContentProcessor. 2021-07-07 14:58:51 -03:00
Greyson Parrelli
ae4167ddae Write to RecipientIdCache on cache miss. 2021-07-07 14:58:51 -03:00
Greyson Parrelli
383beafdef Move 'you' to end of unnamed groups. 2021-07-07 14:58:51 -03:00
Greyson Parrelli
062e88b24f Rotate sender key flag. 2021-07-07 14:58:51 -03:00
Greyson Parrelli
8299d49042 Show an error for internal users for decryption failures. 2021-07-07 14:58:51 -03:00
Greyson Parrelli
4677883838 Improve mapping SignalServiceAddresses to Recipients. 2021-07-07 14:58:51 -03:00
Greyson Parrelli
7f0a0bef5a Incrementally insert MSL entries for legacy group sends. 2021-07-07 14:58:50 -03:00
Greyson Parrelli
acc825971b Handle additional places where MSL entries need to be deleted. 2021-07-07 14:58:50 -03:00
Greyson Parrelli
62040d06b4 Create a write-through cache for PendingRetryReceiptDatabase. 2021-07-07 14:58:50 -03:00
Greyson Parrelli
0921ebe5f1 Add read and viewed receipts to the MSL. 2021-07-07 14:58:50 -03:00
Greyson Parrelli
3d0e15e2b8 Add delivery receipts to the MSL. 2021-07-07 14:58:50 -03:00
Greyson Parrelli
5372f79c40 Allow for MSL entries to be associated with multiple messages. 2021-07-07 14:58:50 -03:00
Christian
92e8f9de0e Do not collapse list to hide only one entry. 2021-07-07 14:58:50 -03:00
Christian
c3cf846a10 Fix OutdatedBuildReminder duration.
Fixes #11438
2021-07-07 14:58:50 -03:00
Alex Hart
5826b0c068 Implement drafts for voice notes. 2021-07-07 14:58:50 -03:00
Alex Hart
2d7c043398 Implement a playback speed toggle for voice notes. 2021-07-07 14:58:50 -03:00
Alex Hart
e20d6b63cf Fix adaptive shortcut icon shapes. 2021-07-07 14:58:50 -03:00
Cody Henthorne
b85c5eb54a Make it more likely 8 emoji fit on a row, fix emoji search emoticons. 2021-07-07 14:58:50 -03:00
Greyson Parrelli
a1c8573fad Insert resent messages at the proper location. 2021-07-07 14:58:50 -03:00
Cody Henthorne
90a27d2227 Fix device transfer test dependent on native library. 2021-07-07 14:58:50 -03:00
Cody Henthorne
c54c6018b2 Remove dead keyboard code after refresh. 2021-06-30 16:13:42 -04:00
Rainer Matischek
7419570f94 Fix rotation not updated on phones using 'Legacy API'.
Fixes #10940
2021-06-30 16:13:42 -04:00
Jim Gustafson
8860f792c4 Update to RingRTC v2.10.6 2021-06-30 16:13:42 -04:00
Greyson Parrelli
e47db0d532 Ensure recipients added to the cache have an identifier. 2021-06-30 16:13:42 -04:00
Greyson Parrelli
ab5d3badc2 Enable WAL mode. 2021-06-30 16:13:42 -04:00
Greyson Parrelli
fce362960f Switch to LinkifyCompat.
We've seen some inconsistencies across OEMs with Linkify. Hopefully
LinkifyCompat will resolve them.
2021-06-30 16:13:42 -04:00
Greyson Parrelli
5bf23dcfb3 Bump version to 5.15.6 2021-06-30 16:12:58 -04:00
Greyson Parrelli
65c7dc6ca2 Updated language translations. 2021-06-30 16:12:36 -04:00
Greyson Parrelli
e30a8b6954 Use proper EmojiTextView in conversation settings toolbar. 2021-06-30 15:43:21 -04:00
Alex Hart
838e318200 Fix edit profile theming issue and mute until issue. 2021-06-30 11:11:35 -03:00
Greyson Parrelli
62ee411901 Bump version to 5.15.5 2021-06-29 14:16:06 -04:00
Greyson Parrelli
ceefd2d92f Updated language translations. 2021-06-29 14:15:28 -04:00
Cody Henthorne
e3870f5656 Fix Customize Reactions shadow. 2021-06-29 12:38:40 -04:00
Alex Hart
6e7022ab70 Fix custom notifications toggle and enable copy phone number on long press. 2021-06-29 11:19:51 -03:00
Alex Hart
031d1551e7 Prevent crash by ignoring call if view is null. 2021-06-29 11:02:57 -03:00
Greyson Parrelli
6755b25361 Bump version to 5.15.4 2021-06-28 18:07:36 -04:00
Greyson Parrelli
11d0a73675 Updated language translations. 2021-06-28 18:07:36 -04:00
Alex Hart
44119b6437 Do not crash if we try to access an item outside of the bounds of the conversation. 2021-06-28 18:07:36 -04:00
Cody Henthorne
d4a3b442f4 Add vertical scrolling to Sticker Keyboard. 2021-06-28 18:07:36 -04:00
Cody Henthorne
aba5774446 Fix share contact list updating improperly on selection change. 2021-06-28 18:07:36 -04:00
Alex Hart
911dd9efb1 Fix conversation media overview underline flicker. 2021-06-28 11:38:14 -03:00
Alex Hart
f2a490b07e Fix several conversation settings feedback issues.
* Mute icon in wrong location in RTL
* No exit animation when dismissing conversation settings
* Thumbnails flicker when you come back to conversation settings
* Rounded corners for mute dialog don't match other dialogs
* Mute button in note-to-self conversation settings
* Explore adding contact details to the contact bottom sheet
2021-06-28 11:11:57 -03:00
Cody Henthorne
5675f080f2 Fix text emoticons not showing up in recents. 2021-06-28 10:11:01 -04:00
Greyson Parrelli
f0dbe230b5 Bump version to 5.15.3 2021-06-25 17:41:53 -04:00
Greyson Parrelli
8b81800052 Updated language translations. 2021-06-25 17:41:53 -04:00
Greyson Parrelli
f598c14298 Update the sender key feature flag. 2021-06-25 17:41:53 -04:00
Greyson Parrelli
58b070e6e3 Fix job info log formatting. 2021-06-25 17:25:59 -04:00
Greyson Parrelli
71c92a1c90 Fix syncing group messages when you're the only member. 2021-06-25 17:00:14 -04:00
Greyson Parrelli
b86acb9773 Increase log size for internal users. 2021-06-25 16:55:15 -04:00
Greyson Parrelli
1b8758b657 Fix text wrapping issues in message details. 2021-06-25 16:49:48 -04:00
Cody Henthorne
ed4bab1b8b Add vertical scroll to Emoji Keyboard. 2021-06-25 16:39:04 -04:00
Greyson Parrelli
a71fe0fd75 Fix issue with group creation on linked devices. 2021-06-25 16:35:42 -04:00
Alan Evans
3d2a634aac Apply the ringer volume to the join/hangup sounds with 15% minimum. 2021-06-25 16:46:59 -03:00
Alex Hart
01047f0546 Apply style changes to shared media, color icon, and wallpaper previews. 2021-06-25 14:27:51 -03:00
Alex Hart
9dac5691f0 Fix issue where all content would be displayed if thread id was -1. 2021-06-25 11:28:28 -03:00
Alex Hart
3c489ad247 Check admin status in areContentsTheSame. 2021-06-25 11:16:53 -03:00
Alex Hart
7797351341 Fix see more icon tint and fix recipient bottom sheet scroll. 2021-06-25 11:09:49 -03:00
Alex Hart
f7212b9916 Update legacy text and fix small animation bug. 2021-06-25 10:57:58 -03:00
Alex Hart
93bb49dc16 Fix inconsistent toolbar animation state on back. 2021-06-25 10:35:07 -03:00
Alex Hart
e504c490c8 Prevent all menu invalidations if we have requested a conversation search. 2021-06-25 09:28:55 -03:00
Cody Henthorne
42e865813c Bump version to 5.15.2 2021-06-24 16:49:02 -04:00
Cody Henthorne
fc14d1d464 Updated language translations. 2021-06-24 16:45:50 -04:00
Cody Henthorne
2a1e5e4471 Add React With Any Search and update UX. 2021-06-24 16:36:13 -04:00
Alex Hart
da2ee33dff Refactor conversation settings screens into a single fragment with new UI. 2021-06-24 16:36:13 -04:00
Greyson Parrelli
f19033a7a2 Implement the message send log for sender key retries. 2021-06-24 16:36:13 -04:00
Greyson Parrelli
6502ef64ce Read the group history response as a stream. 2021-06-23 17:47:05 -04:00
Alan Evans
b3ebf778fd Group call server selection for internal users. 2021-06-23 17:50:59 -03:00
Cody Henthorne
1dca3698d2 Fix crash when adding person to an existing mms group. 2021-06-22 17:03:20 -04:00
Cody Henthorne
2bfe1198d1 Bump version to 5.15.1 2021-06-21 20:24:07 -04:00
Cody Henthorne
4f704670b1 Updated language translations. 2021-06-21 20:01:03 -04:00
Cody Henthorne
a1aafd7453 Fix incorrect mark as read behavior when leaving conversation. 2021-06-21 19:55:02 -04:00
Alex Hart
4932623937 Allow FABs to go as high as the bottom of the toolbar on the conversation list. 2021-06-21 19:55:02 -04:00
Alex Hart
b93568d9c6 Invoke onTick immediately in onResume. 2021-06-21 19:55:02 -04:00
Alex Hart
b3041ab6e0 Always update ViewOnceState before rendering hud. 2021-06-21 14:27:28 -03:00
Alex Hart
3a151b30ac Catch MediaCodecException in extractThumbnails for configuration crash. 2021-06-21 14:19:11 -03:00
Alex Hart
97b3d36433 Add support to MessageDetailsActivity for viewed reciepts. 2021-06-21 14:11:36 -03:00
Cody Henthorne
81e3252128 Do not apply universal timer to SMS chats. 2021-06-21 11:04:28 -04:00
Cody Henthorne
426c83c6cc Fix baby emoji in Help and Profile. 2021-06-21 10:54:55 -04:00
Greyson Parrelli
b427754a81 Fix quoted media rendering issue. 2021-06-21 10:31:14 -04:00
Cody Henthorne
08f023fb12 Revert "Fix ANR when leaving MediaPreviewActivity."
This reverts commit 8be659c1c8.
2021-06-21 09:55:40 -04:00
Greyson Parrelli
5f1454aeb8 Improve the performance of detecting duplicate messages.
To do this, we do two things:
- Make the index on DATE_SENT also include the other relevant fields:
the recipientId and threadId
- Use the most minimal projection possible
2021-06-21 09:51:51 -04:00
Greyson Parrelli
0d254e0724 Fix the mock data initializer.
Needed to ignore the emoji_data FTS tables.
2021-06-20 17:36:27 -04:00
Cody Henthorne
e882e6e111 Bump version to 5.15.0 2021-06-18 15:21:41 -04:00
Cody Henthorne
4b0811f9aa Revert "Temporarily block payments in all regions."
This reverts commit 4637e1b5d8.
2021-06-18 15:10:29 -04:00
Greyson Parrelli
817f1ee938 Add a feature flag to disable SMS megaphone.
As part of this work, we also make sure we fetch feature flags during
registration.
2021-06-18 15:10:16 -04:00
Cody Henthorne
2d93d74b9f Fix incorrect linting by preventing Github Actions from using Android S. 2021-06-18 15:10:16 -04:00
Greyson Parrelli
93f37ad70f Reduce fetches when you open a conversation. 2021-06-18 15:10:16 -04:00
Cody Henthorne
3c6bed90db Fix ANR by upgrading Firebase Messaging. 2021-06-18 15:10:16 -04:00
Greyson Parrelli
fa26fb6b8b Improve conversation query performance.
For the conversation query at least, we stopped joining on the
attachments tables, and instead get attachments on a page-by-page basis.
2021-06-18 15:10:15 -04:00
Cody Henthorne
263ddb0d1e Fix main thread recipient resolve in contact selection. 2021-06-18 15:10:15 -04:00
Cody Henthorne
8be659c1c8 Fix ANR when leaving MediaPreviewActivity. 2021-06-18 15:10:15 -04:00
Cody Henthorne
e5c9dddb5a Fix ANR when generating group message snippets. 2021-06-18 15:10:15 -04:00
Greyson Parrelli
6da72aad6d Log the build variant. 2021-06-18 15:10:15 -04:00
Greyson Parrelli
5dd5a024c9 Narrow locking in LiveRecipientCache.
This should make it so that we never hold a lock while accessing the
database.
2021-06-18 15:10:15 -04:00
Greyson Parrelli
c0eac5564c Clean up message processing locks. 2021-06-18 15:10:15 -04:00
Cody Henthorne
0d0ee753df Make portrait bubbled keyboard height dynamic based on bubble height. 2021-06-18 15:10:15 -04:00
Aaron Labiaga
908f952893 Update API for Activity in bubble check. 2021-06-18 15:10:15 -04:00
Cody Henthorne
1c80e65c5a Bump version to 5.14.5 2021-06-18 15:02:33 -04:00
Cody Henthorne
20b13a929b Updated language translations. 2021-06-18 14:55:16 -04:00
Alex Hart
4637e1b5d8 Temporarily block payments in all regions. 2021-06-18 14:47:32 -04:00
Greyson Parrelli
4b6cb79c75 Fix message exception handling. 2021-06-18 13:52:31 -04:00
Greyson Parrelli
feaf2a33a9 Bump version to 5.14.4 2021-06-17 17:39:30 -04:00
Greyson Parrelli
4c893a11fc Updated language translations. 2021-06-17 17:39:30 -04:00
Cody Henthorne
f4dd80c929 Switch logic order for detecting conversation channel changes. 2021-06-15 13:09:11 -04:00
Cody Henthorne
4af078007e Attempt to recover from encountering octet stream media. 2021-06-15 11:54:14 -04:00
Greyson Parrelli
be297120a1 Include 'you' in dynamic group name. 2021-06-15 11:37:28 -04:00
Cody Henthorne
a9741cadbf Fix logging around dialog flow. 2021-06-15 11:31:56 -04:00
Cody Henthorne
79200c82da Fix create bubble conversation notification. 2021-06-14 16:51:18 -04:00
Cody Henthorne
d9c9ae8dae Update MobileCoin dependency and add new configuration. 2021-06-14 13:25:50 -04:00
Greyson Parrelli
8ee96b40d0 Bump version to 5.14.3 2021-06-10 16:50:51 -04:00
Greyson Parrelli
67f0f45b67 Updated language translations. 2021-06-10 16:50:17 -04:00
Cody Henthorne
881ab90982 Add additional logging to dialog. 2021-06-10 16:06:32 -04:00
Alex Hart
6d7e09fec1 Fix bug preventing VIEWED receipts from being sent to group recipients. 2021-06-10 16:52:24 -03:00
Greyson Parrelli
c274ed6a96 Improve search performance. 2021-06-10 15:47:12 -04:00
Greyson Parrelli
53ffca964d Restrict group member names to 2 lines. 2021-06-10 11:08:45 -04:00
Greyson Parrelli
3da3367291 Ensure that multi-forwards have unique timestamps. 2021-06-10 11:03:07 -04:00
Cody Henthorne
412ee220ce Improve keyboard sizing in bubbled conversations. 2021-06-09 16:18:55 -04:00
Alex Hart
a3e3667dc2 Add 'tick' to update conversation bubble timestamps every 1m. 2021-06-09 16:35:36 -03:00
Greyson Parrelli
d5f63da9e4 Better database error handling. 2021-06-09 15:04:16 -04:00
Greyson Parrelli
f8d2044356 Bump version to 5.14.2 2021-06-09 11:16:19 -04:00
Greyson Parrelli
4d2dc61f5d Updated language translations. 2021-06-09 11:16:19 -04:00
Cody Henthorne
5492685df2 Fix fragment lifecycle crash in Edit Profile. 2021-06-09 11:16:19 -04:00
Alex Hart
ad8c6bc579 Hide 'remove from group' if not an admin of that group. 2021-06-09 11:16:19 -04:00
Alex Hart
fb08f8ae17 Fix issue preventing people blocking receipts from seeing incoming voice notes as viewed. 2021-06-09 11:16:10 -04:00
Greyson Parrelli
7833d7c99a Handle the sender key capability better. 2021-06-09 09:56:57 -04:00
Alex Hart
335ff61011 Fix several Gif MP4 UX issues. 2021-06-09 10:23:41 -03:00
Greyson Parrelli
2029ea378f Bump version to 5.14.1 2021-06-08 16:48:10 -04:00
Greyson Parrelli
cd7bc63cec Updated language translations. 2021-06-08 16:48:10 -04:00
Cody Henthorne
958331a8ea Fix bug with APNGParser over reading larger files and invalidating the stream. 2021-06-08 16:48:10 -04:00
Greyson Parrelli
2ba206b9db Rotate the mp4 gif feature flag. 2021-06-08 16:13:19 -04:00
Greyson Parrelli
9b90e371f9 Inline viewed receipt feature flags. 2021-06-08 16:10:34 -04:00
Alex Hart
ff1c298817 Allow video gifs to download as if they were images. 2021-06-08 17:00:07 -03:00
Alex Hart
dfe804dfa0 Increment GIF flag in AttachmentPointer to avoid android client bug. 2021-06-08 16:53:21 -03:00
Alex Hart
978c6f9349 Fix mp4 support and viewed dot coloring. 2021-06-08 16:10:08 -03:00
Alex Hart
c5c176a818 Remove use of transitionmanager to prevent sticky header flickering. 2021-06-08 14:02:05 -03:00
Cody Henthorne
9f2d57493d Hide quality selector when no images selected. 2021-06-08 12:53:14 -04:00
Greyson Parrelli
0972d8f1e1 Inline the GV1 forced migration flag. 2021-06-08 12:42:51 -04:00
Alex Hart
cf361334c4 Fix jank and decrease animation duration in share contact selection recycler. 2021-06-08 13:10:54 -03:00
Cody Henthorne
c72dd86fed Remove old notification system and notification rewrite feature flag. 2021-06-08 11:20:19 -04:00
Cody Henthorne
b6c653ff77 Remove Universal Expire Timer flag and fix bug with SMS. 2021-06-08 11:20:06 -04:00
Greyson Parrelli
5e3bbb0e64 Improve name rendering for nameless groups. 2021-06-08 11:18:08 -04:00
Greyson Parrelli
64124f6f4b Update strings from 'cellular' to 'mobile data'. 2021-06-08 08:16:02 -04:00
Cody Henthorne
6f6a6826d9 Restrict edit description to V2 and remove feature flag. 2021-06-07 20:07:49 -04:00
Greyson Parrelli
57c0b8fd0f Initial pre-alpha support for sender key. 2021-06-07 18:14:12 -04:00
Max Ullinger
c54f016213 Fix inconsistent text scaling in quotes.
Fixes #10188
2021-06-07 17:26:47 -04:00
Cody Henthorne
bece58d939 Improve notification channel consistency checks with Android Conversations. 2021-06-07 15:58:39 -04:00
Alex Hart
36443c59f9 Apply proximity wake lock in locked audio recording mode.
Fixes #10098
2021-06-07 16:55:26 -03:00
Cody Henthorne
02f0301f25 Change how we enable/disable vibration for notifications. 2021-06-07 15:44:38 -04:00
Alex Hart
334cf669ed Add support for multiple typing indicators in groups. 2021-06-07 15:35:19 -03:00
Greyson Parrelli
8442143818 Add support for the updated link device schema. 2021-06-07 11:19:06 -04:00
Greyson Parrelli
b25b8b90e4 Set last search index download time. 2021-06-07 10:32:18 -04:00
Alex Hart
06aec0b7d7 Move bubble rendering from onMeasure to onLayout. 2021-06-07 09:16:18 -03:00
Alex Hart
835d7f5ccb Bump version to 5.14.0 2021-06-04 16:36:16 -03:00
Alex Hart
ffd0b16753 Updated language translations. 2021-06-04 16:35:29 -03:00
Alex Hart
b351fb43e6 Revert "Temporarily block payments in all regions."
This reverts commit 1466875293.
2021-06-04 16:29:37 -03:00
Cody Henthorne
7da47c9586 Fix NPE in ThumbnailsTask.
The async task was being cancelled, but there was still a race condition
in how the thumbnails list was being managed. This attempts to fix that.
2021-06-04 16:29:23 -03:00
Alex Hart
e4755b298f Bump version to 5.13.8 2021-06-04 16:18:51 -03:00
Alex Hart
4a65487842 Updated language translations. 2021-06-04 16:18:09 -03:00
Alex Hart
1466875293 Temporarily block payments in all regions. 2021-06-04 16:18:09 -03:00
Alex Hart
fd1e552ad1 Update name colors palette. 2021-06-04 16:05:02 -03:00
Alex Hart
be3e89ac20 Utilize built in string id getter instead of using our own logic for name colors. 2021-06-04 16:05:02 -03:00
Alex Hart
b8f1b98c74 Use user avatar or avatar color for bubble on wallpaper fragment. 2021-06-04 16:05:02 -03:00
Alex Hart
4bdd07db16 Fix NPE if system ringtone name lookup returns null. 2021-06-04 09:09:34 -03:00
Greyson Parrelli
511b095647 Bump version to 5.13.7 2021-06-03 21:27:56 -04:00
Greyson Parrelli
23f4d30e57 Updated language translations. 2021-06-03 21:27:37 -04:00
Greyson Parrelli
45c587c5e4 Allow variation selection in emoji search results. 2021-06-03 21:18:18 -04:00
Greyson Parrelli
115e74d844 Use borderless ripple for keyboard category buttons. 2021-06-03 20:50:31 -04:00
Greyson Parrelli
1475a77260 Update "GIFs moved" education tooltip. 2021-06-03 20:38:36 -04:00
Greyson Parrelli
d0e2fbf8e7 Fix issues with emoji search backup/restore. 2021-06-03 20:30:44 -04:00
Greyson Parrelli
0f2f0450e3 Do not show chat color megaphone to new users.
They already have the onboarding variant.
2021-06-03 19:50:42 -04:00
Cody Henthorne
e57f24c062 Bump version to 5.13.6 2021-06-03 17:23:34 -04:00
Cody Henthorne
203d7de6a2 Updated language translations. 2021-06-03 17:20:43 -04:00
Cody Henthorne
6e5f2f50fb Fix padding issue with keyboard indicator in compose. 2021-06-03 17:11:07 -04:00
Cody Henthorne
875895524e Fix media keyboard sizing issue by trying two ways to find window insets. 2021-06-03 17:11:07 -04:00
Cody Henthorne
3a21a2a49e Fix bad sync of default timer to linked devices. 2021-06-03 17:11:07 -04:00
Alex Hart
262b4e7d62 Hide bottom bar on scroll for Emoji pager. 2021-06-03 17:11:07 -04:00
Cody Henthorne
c202f97088 Fix non-hiding bottom bar when not enough stickers. 2021-06-03 17:11:07 -04:00
Cody Henthorne
f96eac96f9 Update keyboard colors to improve consistency. 2021-06-03 17:11:07 -04:00
Alex Hart
c59006e06e Go back to emoji selection on keyboard close in search. 2021-06-03 14:21:56 -03:00
Cody Henthorne
84e27e7bff Remove GIFs from attachment keyboard. 2021-06-03 13:05:38 -04:00
Alex Hart
a3a4b10f83 Wrap emoji pages with coordinator layout. Fix issue with bubble coloring in wallpaper preview. 2021-06-03 14:02:37 -03:00
Cody Henthorne
a644c81736 Actually skip emoji searchd ata in backup restore. 2021-06-03 11:34:41 -04:00
Cody Henthorne
27b9fbe490 Add pull down search bar to stickers and auto hide when scrolling. 2021-06-03 11:33:06 -04:00
Alex Hart
2131c56513 Add unit testing for Recipient#getChatColors 2021-06-03 11:29:19 -03:00
Alex Hart
95dba15db8 Fix initial scroll position if there's not enough vertical space to hide search bar. 2021-06-03 11:26:49 -03:00
Cody Henthorne
c23215604d Bump version to 5.13.5 2021-06-03 10:18:32 -04:00
Cody Henthorne
8c9f274d5a Updated language translations. 2021-06-03 10:18:18 -04:00
Cody Henthorne
504a70f3ee Skip emoji search data in backup/restore. 2021-06-03 10:12:12 -04:00
Alex Hart
ad6f51901e Fix bad logic in chat color selection. 2021-06-03 10:12:12 -04:00
Cody Henthorne
52ef4c6235 Get more space on gif keyboard by hiding views. 2021-06-03 10:12:12 -04:00
Cody Henthorne
9ba4005433 Show keyboard when opening gif search. 2021-06-02 20:57:08 -04:00
Cody Henthorne
3cea3766ab Use correct GIF icon for dark theme. 2021-06-02 20:53:34 -04:00
Cody Henthorne
ede24e0e73 Bump version to 5.13.4 2021-06-02 18:08:02 -04:00
Cody Henthorne
df79bbc5aa Updated language translations. 2021-06-02 18:03:57 -04:00
Cody Henthorne
3c522c677b Fix crash when applying unknown fields. 2021-06-02 17:59:44 -04:00
Android Team
08e86b8c82 Add Emoji Search, Sticker Search, and GIF Keyboard.
Co-authored-by: Alex Hart <alex@signal.org>
Co-authored-by: Cody Henthorne <cody@signal.org>
Co-authored-by: ⁨Greyson Parrelli<greyson@signal.org>
2021-06-02 17:43:17 -04:00
Alex Hart
66c3b1388a Add new chat colors megaphone. 2021-06-02 16:52:21 -03:00
Alex Hart
8992f59c3b Update logic for color selection to match spec. 2021-06-02 16:51:23 -03:00
Alex Hart
1d6d27d46c Tweak name color palette and fix issue with non-present group members. 2021-06-02 16:31:55 -03:00
Alex Hart
625d36fb27 Start animation when megaphone is displayed. 2021-06-02 15:11:23 -03:00
Alex Hart
665ce14bb6 Fix RTL issue with thumbnail masking. 2021-06-02 14:49:26 -03:00
Alex Hart
6e4f002b6d Fix masking issue with multiselect highlighted items. 2021-06-02 14:34:34 -03:00
Cody Henthorne
39a7dbda94 Bump version to 5.13.3 2021-06-02 12:24:25 -04:00
Cody Henthorne
7ae8af4153 Updated language translations. 2021-06-02 12:22:17 -04:00
Alex Hart
fb817e0c3b Add Chat Colors onboarding. 2021-06-02 12:16:10 -04:00
Tomer Rosenfeld
1eae360470 Do not remove system contact badging during partial syncs.
Fixes #11236
2021-06-02 12:16:10 -04:00
Cody Henthorne
0314db0b58 Small UI tweaks for edit reactions. 2021-06-02 12:16:10 -04:00
Cody Henthorne
4598387187 Bump version to 5.13.2 2021-05-27 16:27:43 -04:00
Cody Henthorne
445c93a756 Updated language translations. 2021-05-27 16:23:09 -04:00
Alex Hart
6c168ec575 Fix revealable color. 2021-05-27 16:17:07 -04:00
Greyson Parrelli
1322f5bc08 Be more careful with unknown IDs during storage sync. 2021-05-27 16:17:07 -04:00
Alex Hart
1c40f2d167 Fix issue with disappearing colors upon group removal. 2021-05-27 16:17:07 -04:00
Alex Hart
18133e2a10 Fix several issues with chatcolors. 2021-05-27 16:17:07 -04:00
Cody Henthorne
e5b0941d30 Add ability to edit default reactions. 2021-05-27 16:17:07 -04:00
Cody Henthorne
811bef8c35 Bump version to 5.13.1 2021-05-26 20:07:20 -04:00
Cody Henthorne
057107ea7a Updated language translations. 2021-05-26 20:02:54 -04:00
Alex Hart
273e5f9168 Remove gradient support from api 19. 2021-05-26 19:56:20 -04:00
Alex Hart
35930fb23a Fix several ChatColors issues. 2021-05-26 20:06:57 -03:00
Alex Hart
c794b5c2e7 Only display edit pencil if custom color is selected. 2021-05-26 19:56:04 -03:00
Greyson Parrelli
e74d502ae6 Remove legacy session version.
Hasn't been used since the TextSecure days!
2021-05-26 17:46:58 -04:00
Greyson Parrelli
e5ce6e3e2e Fix internal preference. 2021-05-26 12:45:54 -04:00
Greyson Parrelli
65020dde1a Fix some missed cases for blocking unregistered sends. 2021-05-26 12:02:22 -04:00
Alex Hart
98f432d23c Fix advanced prefs dialog title. 2021-05-26 11:50:17 -03:00
Cody Henthorne
2651b789dd Fix some group description UX oddities. 2021-05-26 10:42:36 -04:00
Cody Henthorne
dbabac34b0 Fix video not showing until phone moved. 2021-05-26 10:25:58 -04:00
Alex Hart
6866b7a277 Fix chat color selection context menu positioning. 2021-05-26 11:13:25 -03:00
Alex Hart
03c19f54c2 Set background of typing indicator to match conversation. 2021-05-26 10:56:09 -03:00
Alex Hart
ba510ca77d Update chat pluralization. 2021-05-26 10:47:40 -03:00
Alex Hart
bb7409fd91 Add proper background color for quote preview. 2021-05-26 10:14:22 -03:00
Alex Hart
23e5da4d95 Fix issue where message sender was impacting bubble color in groups. 2021-05-26 09:41:20 -03:00
Greyson Parrelli
fb1b46b67e Bump version to 5.13.0 2021-05-26 00:45:32 -04:00
Greyson Parrelli
7a21e6b5f8 Updated language translations. 2021-05-26 00:45:06 -04:00
Greyson Parrelli
6342a45b4e Separate avatar colors from chat colors. 2021-05-26 00:39:59 -04:00
Alex Hart
bcc5d485ab Update chat colors. 2021-05-26 00:39:59 -04:00
Rainer Matischek
36fe150678 Increase maximum zoom level for large images. 2021-05-26 00:39:59 -04:00
Greyson Parrelli
54f92ae466 Do not send if unregistered. 2021-05-26 00:39:59 -04:00
Cody Henthorne
b9b2924939 Add screen share receive support and improve video calling rotation. 2021-05-26 00:39:59 -04:00
Greyson Parrelli
513e5b45c5 Show notifications for group creates. 2021-05-26 00:39:59 -04:00
Greyson Parrelli
1fad5e2c1e Add some extra preconditions to reaction processing. 2021-05-26 00:39:59 -04:00
Greyson Parrelli
5a28cf616d Do not allow bad QR data to crash. 2021-05-26 00:39:59 -04:00
Cody Henthorne
c08199659b Support pasting of images into input text. 2021-05-26 00:39:59 -04:00
Greyson Parrelli
ca508514a7 Updated flipper to 0.91.0 2021-05-26 00:39:59 -04:00
Greyson Parrelli
da2038dd46 Revert "Temporarily block payments in all regions."
This reverts commit 152cc27394.
2021-05-26 00:39:59 -04:00
Greyson Parrelli
f02e2d23d0 Bump version to 5.12.3 2021-05-26 00:31:33 -04:00
Greyson Parrelli
ef1c25c3d3 Updated language translations. 2021-05-26 00:31:02 -04:00
Alex Hart
152cc27394 Temporarily block payments in all regions. 2021-05-26 00:28:05 -04:00
Greyson Parrelli
c582aca465 Bump version to 5.12.2 2021-05-20 11:15:00 -04:00
Greyson Parrelli
80e85fb49a Updated language translations. 2021-05-20 11:14:01 -04:00
Greyson Parrelli
d660e22e61 Pull translations in parallel. 2021-05-20 11:10:16 -04:00
Cody Henthorne
51856c4f06 Add support back for Android Auto. 2021-05-20 10:42:06 -04:00
Cody Henthorne
fd37da42f9 Revert "Remove Android Auto support (for now)."
This reverts commit 6c2adfeec2.
2021-05-20 09:46:38 -04:00
Cody Henthorne
11df2bc51f Replace spongy with libsignal x509 generation for device transfer. 2021-05-19 17:29:48 -04:00
Cody Henthorne
6770d21cf7 Fix crash when processing invalid mentions. 2021-05-19 13:15:28 -04:00
Cody Henthorne
f490d1f6d2 Add long click copy for urls in group descriptions. 2021-05-19 12:29:34 -04:00
Cody Henthorne
f890ae8ddc Enforce two line limit on group description.
Sorry.
2021-05-19 11:57:53 -04:00
Cody Henthorne
5d5d61d8ed Pluralize units for custom timer dialog. 2021-05-19 09:40:20 -04:00
Cody Henthorne
75589f1b2d Use new expire timer dialog from overflow menu. 2021-05-18 20:23:59 -04:00
Greyson Parrelli
6225c676e2 Bump version to 5.12.1 2021-05-18 19:31:12 -04:00
Greyson Parrelli
9b18668f49 Updated language translations. 2021-05-18 19:30:53 -04:00
Greyson Parrelli
2f80e7f1ff Put the default message timer behind a feature flag. 2021-05-18 19:26:25 -04:00
Greyson Parrelli
790413680d Bump version to 5.12.0 2021-05-18 18:28:24 -04:00
Cody Henthorne
47e9a4ec29 Fix hard to see media send HUD. 2021-05-18 18:21:49 -04:00
Cody Henthorne
defd5e8047 Add universal disappearing messages. 2021-05-18 18:21:48 -04:00
Greyson Parrelli
8c6a88374b No longer use SignalServiceAddress legacy identifier.
We had to do this in the past because we previously didn't allow
UUID-only contacts back in the day. This hasn't been the case for some
time. We should be preferring the UUID in all cases.
2021-05-18 18:21:48 -04:00
Greyson Parrelli
7343613bea Revert "Temporarily block payments in all regions."
This reverts commit ec486d66f7.
2021-05-18 18:21:48 -04:00
Greyson Parrelli
155dda1fa4 Bump version to 5.11.5 2021-05-18 18:02:37 -04:00
Greyson Parrelli
3c74306c8d Updated language translations. 2021-05-18 18:02:18 -04:00
Alex Hart
13ecd9eee6 Temporarily block payments in all regions. 2021-05-18 17:56:38 -04:00
Alex Hart
c48f3b4582 Bump version to 5.11.4 2021-05-17 17:03:21 -03:00
Alex Hart
30c007194d Updated language translations. 2021-05-17 17:03:21 -03:00
Cody Henthorne
ef5b68eb35 Add report spam in message request state. 2021-05-17 17:03:21 -03:00
Cody Henthorne
c47dcd5720 Add code formatting styles. 2021-05-17 17:03:21 -03:00
Greyson Parrelli
ed3c5ab479 Do more to ensure that we have the latest self in StorageSyncJob. 2021-05-17 17:03:21 -03:00
Cody Henthorne
a697b6c3d4 Fix long text layout bug in media quality selector. 2021-05-17 17:03:21 -03:00
Alex Hart
3965df78c9 Fix several settings issues. 2021-05-17 17:03:21 -03:00
Alex Hart
64ebf20c1b Bump version to 5.11.3 2021-05-14 16:46:51 -03:00
Alex Hart
797bed6701 Updated language translations. 2021-05-14 16:46:08 -03:00
Alex Hart
e84e021127 Fix proxy settings navigation. 2021-05-14 16:46:08 -03:00
Greyson Parrelli
0b9515b58b Clean up another bad usage of self in StorageSyncJob. 2021-05-13 16:15:20 -04:00
Alex Hart
81ec9e96c7 Fix several settings issues. 2021-05-13 16:59:31 -03:00
Greyson Parrelli
ee09793ef2 Fix outage reminder in dark theme.
Fixes #11258
2021-05-13 13:21:30 -04:00
Greyson Parrelli
61a130e645 Handle ServerRejectedException in more jobs. 2021-05-13 13:16:11 -04:00
Greyson Parrelli
19d342749a Bump version to 5.11.2 2021-05-13 12:27:50 -04:00
Greyson Parrelli
94adcf04f5 Updated language translations. 2021-05-13 12:27:24 -04:00
Alex Hart
53e1da0f43 Fix bad preference class setting. 2021-05-13 12:20:08 -04:00
Greyson Parrelli
b41989de03 Be more consistent with 'self' in StorageSyncJob. 2021-05-13 12:20:08 -04:00
Greyson Parrelli
6c7848b750 Ensure we don't enqueue a ProfileKeySendJob to a v2 group. 2021-05-13 12:20:08 -04:00
Greyson Parrelli
07bd9ad840 Make debuglog submission slightly more discoverable. 2021-05-13 12:20:08 -04:00
Greyson Parrelli
14236d3062 Show About in AppSettings screen. 2021-05-13 12:00:24 -04:00
Cody Henthorne
6c4df30252 Fix flashing tap to view showing on conversation open. 2021-05-13 12:00:24 -04:00
Cody Henthorne
45218470af Update media send quality icons. 2021-05-13 12:00:24 -04:00
Greyson Parrelli
417ee1e047 Mark url as non-translatable. 2021-05-13 12:00:24 -04:00
Alex Hart
08a3bc457e Fix autodownload constraint. 2021-05-13 12:00:24 -04:00
Alex Hart
0cc2cba883 Clean up device fragments and utilize dsl toolbar. 2021-05-13 12:00:24 -04:00
Alex Hart
24d461c8b2 Fix settings crash and RTL bug. 2021-05-13 12:00:24 -04:00
Greyson Parrelli
4d472fccd2 Fix bugs with the bio preference in AppSettings.
- Always show the profile name.
- Pretty-print the phone number.
- Show the correct avatar when none is set.
2021-05-12 20:39:43 -04:00
Greyson Parrelli
45d010bdb6 Only update SMS setting if registration is complete.
Otherwise you could crash during registration if the user had previously
set Signal as the default.
2021-05-12 17:16:01 -04:00
Greyson Parrelli
70db617229 Fix some issues with avatar syncing.
- We weren't falling back to system avatars when no profile was present
- We weren't triggering a sync when the setting changed
2021-05-12 17:08:13 -04:00
Greyson Parrelli
d8256013a3 Bump version to 5.11.1 2021-05-12 15:48:46 -04:00
Greyson Parrelli
6d2c22addc Updated language translations. 2021-05-12 15:48:46 -04:00
Greyson Parrelli
9640f3f215 Do not allow profile given names to be empty when editing. 2021-05-12 15:48:37 -04:00
Greyson Parrelli
80c911e118 Sync whether or not our primary device can send SMS. 2021-05-12 14:58:19 -04:00
Alex Hart
f2d5ea0391 Refactor app settings. 2021-05-12 12:23:00 -04:00
Greyson Parrelli
a94d77d81e Ensure inbound messages mark recipients as registered. 2021-05-12 12:20:14 -04:00
Greyson Parrelli
2d2de1a652 Fix storage service record merge. 2021-05-12 10:56:34 -04:00
Greyson Parrelli
01f8823fb2 Show an error animation if you don't select a help category. 2021-05-12 00:05:41 -04:00
Greyson Parrelli
260575d139 Utilize RecipientIdCache during message processing. 2021-05-11 12:19:07 -04:00
Greyson Parrelli
1fb3290038 Be more direct with AccountRecord updates. 2021-05-11 10:05:13 -04:00
Greyson Parrelli
37596320e8 Bump version to 5.11.0 2021-05-10 19:37:20 -04:00
Greyson Parrelli
7a959c2c3e Updated language translations. 2021-05-10 19:36:52 -04:00
Greyson Parrelli
877c03e6a1 Fix issue where bulk-archive wasn't triggering a storage sync.
Also took the opportunity to consolidate our archive code to reduce
duplication.
2021-05-10 19:30:11 -04:00
Greyson Parrelli
d3431d227b Make selecting a help category mandatory. 2021-05-10 19:30:11 -04:00
Greyson Parrelli
fbf307bf01 Manually handle 6-digit short codes for UK.
Also cleans up some set usages.

Fixes #11274
2021-05-10 19:30:11 -04:00
Alex Hart
d672857e82 Fix layout designer deadlock. 2021-05-10 19:30:11 -04:00
Cody Henthorne
dd934e0095 Add photo media quality selector when sending images. 2021-05-10 19:30:11 -04:00
Cody Henthorne
8c9df8d3be Add support for Group V2 description field. 2021-05-10 19:30:10 -04:00
Chris Eager
b3aec58e69 Add additional test cases to VerificationCodeParserTest. 2021-05-10 19:30:10 -04:00
Greyson Parrelli
b4111cffef Guard against shared content not having proper permissions.
Fixes #11269
2021-05-10 19:30:10 -04:00
Greyson Parrelli
ecc8d1738e Respect system avatar preference when syncing with linked devices. 2021-05-10 19:30:10 -04:00
Greyson Parrelli
d1982cbc0a Do not fetch profiles when unregistered. 2021-05-10 19:30:10 -04:00
Greyson Parrelli
03b65ce6dc Update to libsignal-client 0.5.1 2021-05-10 19:30:10 -04:00
Greyson Parrelli
56ea11cdff Reactively share profiles to those who should already have it. 2021-05-10 19:30:10 -04:00
Greyson Parrelli
7a02404f7b Update SQLCipher to v4.4.3 2021-05-10 19:30:10 -04:00
Greyson Parrelli
b9a960a7c8 Revert "Temporarily block payments in all regions."
This reverts commit ec486d66f7.
2021-05-10 19:30:10 -04:00
Greyson Parrelli
02c87a4d7b Bump version to 5.10.8 2021-05-10 19:22:36 -04:00
Greyson Parrelli
0dd9cd82f8 Updated language translations. 2021-05-10 19:16:14 -04:00
Alex Hart
ec486d66f7 Temporarily block payments in all regions. 2021-05-10 19:16:14 -04:00
Alex Hart
69cd7eb449 Fix issue with sharing resizable media to MMS. 2021-05-10 13:56:54 -03:00
Greyson Parrelli
1427de7c65 Bump version to 5.10.7 2021-05-07 13:23:13 -04:00
Greyson Parrelli
8ad66e1e5e Updated language translations. 2021-05-07 13:11:57 -04:00
Greyson Parrelli
a2e31e97db Trim giphy queries. 2021-05-07 13:05:02 -04:00
Alex Hart
1f3e131690 Fix Emoji crashes when downloaded bitmap files cannot be found. 2021-05-07 13:56:14 -03:00
Greyson Parrelli
276b757e2d Fix the other possible NPE in database migration. 2021-05-07 10:43:45 -04:00
Cody Henthorne
093df70602 Bump version to 5.10.6 2021-05-06 18:06:50 -04:00
Cody Henthorne
fe9ab66f31 Updated language translations. 2021-05-06 18:06:26 -04:00
Alex Hart
138f9476ac Revert emoji cache to old pattern. 2021-05-06 17:47:36 -04:00
Alex Hart
cb9ab61b6b Fix issue where gifs would load as images. 2021-05-06 16:19:24 -03:00
Alex Hart
bcbd365326 Fix gif player audio. 2021-05-06 13:29:28 -03:00
Greyson Parrelli
afdf4e365f Fix possible NPE in database migration. 2021-05-05 17:56:06 -04:00
Greyson Parrelli
553b7522aa Bump version to 5.10.5 2021-05-05 16:52:51 -04:00
Greyson Parrelli
13f38dd594 Updated language translations. 2021-05-05 16:51:39 -04:00
Greyson Parrelli
31e1c6f7aa Handle 428 rate limiting. 2021-05-05 16:47:13 -04:00
Alex Hart
02d060ca0a Fix issue with gif search and emoji loading on lowmem devices. 2021-05-05 14:42:51 -04:00
Cody Henthorne
5e2a3ac644 Bump version to 5.10.4 2021-05-04 20:40:06 -04:00
Cody Henthorne
2fc461b85f Updated language translations. 2021-05-04 20:39:13 -04:00
Cody Henthorne
29a0b86411 Address API23 notification issues and update when conversation content changes. 2021-05-04 20:31:29 -04:00
Alex Hart
efc3e7b25d Fix emoji on odd densities and add internal pref to force built-in. 2021-05-04 12:20:18 -04:00
Greyson Parrelli
6c2adfeec2 Remove Android Auto support (for now). 2021-05-03 22:11:52 -04:00
Cody Henthorne
3124d6d43e Bump version to 5.10.3 2021-05-03 14:17:50 -04:00
Cody Henthorne
e5a6b7d47d Updated language translations. 2021-05-03 14:17:05 -04:00
Greyson Parrelli
add65cf592 Prevent crash when opening conversation with unregistered UUID-only recipient. 2021-05-03 14:02:58 -04:00
Alex Hart
129effd0ec Add lighter weight emoji. 2021-05-03 14:02:58 -04:00
Cody Henthorne
2aad00df85 Add ability to configure locale specific media quality settings.
Part 1 of improve media quality controls. User selection coming soon.
2021-05-03 14:02:58 -04:00
Alex Hart
85e0e74bc6 Add support for OTA emoji download. 2021-05-03 14:02:58 -04:00
Alex Hart
7fa200401c Fix content insets for API30+ devices. 2021-04-30 13:16:23 -03:00
Cody Henthorne
1a452efbb9 Bump version to 5.10.2 2021-04-30 10:37:03 -04:00
Cody Henthorne
eb4bdf1db2 Updated language translations. 2021-04-30 10:35:59 -04:00
Greyson Parrelli
d58f68cb44 Fix issue where we could give storageIds to MMS groups or emails.
Things like force-unread and mute could be applied to MMS groups or
unregistered users (the worst kind being email SMS contacts) that could
result in crashes down the line.

Includes a DB migration to clean up the bad stuff.
2021-04-30 00:19:48 -04:00
Greyson Parrelli
2f30d29351 Ensure we have a storageId for self. 2021-04-29 17:55:34 -04:00
Cody Henthorne
dc6dc192dc Bump version to 5.10.1 2021-04-28 20:56:28 -04:00
Cody Henthorne
751afadebd Fix notification issues introduced when adding lower API versions. 2021-04-28 20:49:36 -04:00
Alex Hart
ac71c02dfa Bump version to 5.10.0 2021-04-28 16:45:09 -03:00
Alex Hart
4567da193e Revert "Temporarily block payments in all regions."
This reverts commit f4ae39dd44.
2021-04-28 16:36:40 -03:00
Cody Henthorne
bd2a1d5574 Add support for lower APIs to new notification system. 2021-04-28 16:36:11 -03:00
Alex Hart
ab44d608d2 Add support for sending and syncing viewed receipts behind a feature flag. 2021-04-28 16:36:11 -03:00
Greyson Parrelli
cdc7f1565e Further simplify storage service syncing. 2021-04-28 16:36:11 -03:00
Jim Gustafson
1493581a4d Update to RingRTC v2.9.6 2021-04-28 16:36:11 -03:00
Greyson Parrelli
4461d6cf7f Rename StorageSyncJobV2 -> StorageSyncJob. 2021-04-28 16:36:11 -03:00
Greyson Parrelli
38e64b1f75 Remove old Storage Service V1 code. 2021-04-28 16:36:10 -03:00
Alex Hart
eb1daf4a20 Pass exception to thrown AssertionError in shortuct icon generation. 2021-04-28 16:36:10 -03:00
Alex Hart
e0c38f7c72 Bump version to 5.9.5 2021-04-28 16:27:31 -03:00
Alex Hart
5638ff4a3a Updated language translations. 2021-04-28 16:26:26 -03:00
Alex Hart
f4ae39dd44 Temporarily block payments in all regions. 2021-04-28 16:16:04 -03:00
Cody Henthorne
d235125138 Fix empty conversation banner view tap to unblur bug. 2021-04-28 14:08:30 -04:00
Cody Henthorne
78d7759197 Update witness file. 2021-04-28 12:09:57 -04:00
Cody Henthorne
eddaad3b05 Bump version to 5.9.4 2021-04-26 16:44:26 -04:00
Cody Henthorne
f2c80c800c Updated language translations. 2021-04-26 16:44:26 -04:00
Greyson Parrelli
a0e787e424 Disable additional storage service validations for internal users. 2021-04-26 16:44:26 -04:00
Cody Henthorne
c9d1fb8533 Fix reaction notification data inconsistencies.
Co-authored-by: Greyson Parrelli <greyson@signal.org>
2021-04-26 16:44:26 -04:00
Greyson Parrelli
006eebb09e Remove storageIds on rows that have no other identifier. 2021-04-26 16:44:26 -04:00
Alex Hart
4aec824bfd Retain minimum width for link previews. 2021-04-26 16:44:26 -04:00
Alex Hart
56f7564ce4 Re-enable internal sharing to SMS users. 2021-04-26 15:45:25 -03:00
Alex Hart
f89daefd43 Hide and show video players as content changes. 2021-04-26 15:03:06 -03:00
Cody Henthorne
8572a2d262 Bump version to 5.9.3 2021-04-24 15:06:34 -04:00
Cody Henthorne
d6e41be4b4 Updated language translations. 2021-04-24 15:05:44 -04:00
Cody Henthorne
5e715ffcce Fix crash when including self in contact search projection. 2021-04-24 14:55:00 -04:00
Cody Henthorne
5100341e60 Fix leaked receiver when call does not connect. 2021-04-24 14:34:16 -04:00
Cody Henthorne
5ca4db6ea5 Fix crashes and issues with blurred avatars.
- Tinting on Android 5/6 caused NPE deep in Android
- Invite group flow can have zero members
- Missed spot to blur avatar in old notification flow
2021-04-24 14:32:02 -04:00
Alex Hart
e02e07ae7a Bump version to 5.9.2 2021-04-23 16:43:45 -03:00
Alex Hart
f3caedc045 Updated language translations. 2021-04-23 16:38:23 -03:00
Cody Henthorne
59c49254e7 Insert temporary warning update message during message request state. 2021-04-23 15:29:59 -04:00
Cody Henthorne
ad81b310e3 Blur avatar photos from unknown senders when in message request state. 2021-04-23 14:42:51 -04:00
Alex Hart
bf124b87fa Fix bad flag parsing on attachment pointers. 2021-04-22 14:46:20 -03:00
Alex Hart
a4868602b5 Add better handling for non-existent response bodies or empty responses from giphy. 2021-04-22 14:33:56 -03:00
Greyson Parrelli
763aeabddd Bump version to 5.9.1 2021-04-21 16:43:59 -04:00
Greyson Parrelli
71fc5af320 Updated language translations. 2021-04-21 16:43:38 -04:00
Greyson Parrelli
d28f0e3544 Relax GIF size restrictions. 2021-04-21 16:43:38 -04:00
Greyson Parrelli
b4d0dde129 Always get the storage manifest for internal users.
This will hopefully help us track down some of the validation issues
when writing local changes.
2021-04-21 16:43:38 -04:00
Alex Hart
281630e751 Add support for inline video playback of gifs in Conversation. 2021-04-21 16:43:38 -04:00
Karalix
32d79ead15 Add unicode wildcards for equivalent latin characters in contact search. 2021-04-21 16:43:38 -04:00
Martin d'Allens
5a91c7e84a Remove seconds from screen lock timeout input for coherence
Configure the TimeDurationPickerDialog to hide seconds.
Seconds were already ignored below 1min. This avoids the user expecting it to work.

Feature regression: after this change, seconds above 1min will also be impossible to input (ex: 1m30s).
But it makes little sense anyway to allow it: they are even less useful for longer durations.

Another possibility to reach a point where eveything is coherent would have been to just remove the Math.max(..., 60) that ignored seconds.

The duration will be displayed as "xx:xx:00" to make it clear that xx:xx represents minutes.

Fixes #10788.
2021-04-21 16:43:38 -04:00
Alex Hart
e2e1200c89 Improvments to MP4 giphy fragment behaviour. 2021-04-21 16:43:38 -04:00
Cody Henthorne
ed1be76606 Scrub domains from debug logs. 2021-04-19 20:28:54 -04:00
Greyson Parrelli
a64de91781 Bump version to 5.9.0 2021-04-19 18:13:05 -04:00
Greyson Parrelli
e802c8b8cc Updated language translations. 2021-04-19 18:11:59 -04:00
Alex Hart
86f2cf0ac4 Remove support for linear gif flow. 2021-04-19 18:11:56 -04:00
Alex Hart
a844a6b6c1 Revert "Temporarily block payments in all regions."
This reverts commit 1169331462.
2021-04-19 18:11:56 -04:00
Alex Hart
c31146e902 Render gifs in gif search as MP4s. 2021-04-19 18:11:56 -04:00
Greyson Parrelli
fcc5db2fe6 Bump version to 5.8.10 2021-04-19 17:58:08 -04:00
Greyson Parrelli
9fdd3ae1be Updated language translations. 2021-04-19 17:56:33 -04:00
Greyson Parrelli
c99509a967 Temporarily disable some storage service validations. 2021-04-19 10:26:32 -04:00
Alex Hart
1169331462 Temporarily block payments in all regions. 2021-04-19 11:20:41 -03:00
Greyson Parrelli
0978822939 Bump version to 5.8.9 2021-04-18 11:27:59 -04:00
Greyson Parrelli
8bf8ecf7fa Reset manifest version to zero after account restore. 2021-04-18 11:27:59 -04:00
Greyson Parrelli
f55db6a5d7 Bump version to 5.8.8 2021-04-18 11:02:30 -04:00
Greyson Parrelli
e82d6cf91d Updated language translations. 2021-04-18 10:45:34 -04:00
Greyson Parrelli
65a1d165ac Fix issue where storage dirty state wasn't cleared. 2021-04-18 10:36:40 -04:00
Greyson Parrelli
e3b27bd39c Bump version to 5.8.7 2021-04-17 13:03:16 -04:00
Greyson Parrelli
07dde01c3b Updated language translations. 2021-04-17 13:03:16 -04:00
Greyson Parrelli
11a2e8686c Simplify local changes written to storage service. 2021-04-17 13:03:11 -04:00
Greyson Parrelli
daeeb17142 Restore storage manifest version during StorageAccountRestoreJob. 2021-04-17 10:31:54 -04:00
Greyson Parrelli
35ab2f6704 Rename 'key' to 'id' where appropriate for storage service. 2021-04-17 10:14:59 -04:00
Greyson Parrelli
9c428f6db7 Bump version to 5.8.6 2021-04-16 19:04:08 -04:00
Greyson Parrelli
a76b067b96 Updated language translations. 2021-04-16 19:03:44 -04:00
Cody Henthorne
a843619c5b Fix various notification display issues and properly support reply. 2021-04-16 18:59:21 -04:00
Greyson Parrelli
5bbc4aea95 Default storage sync feature flag to enabled. 2021-04-16 18:59:21 -04:00
Greyson Parrelli
4676043826 Simplify storage sync write construction.
Instead of trying to keep track of changes as we go and hope that lines
up with reality, now we just write all of our changes and do another
diff at the end to build our insert/delete set. Nice and simple.
2021-04-16 18:58:36 -04:00
Greyson Parrelli
64a841487f Fix storage sync validation error when re-registering with a new number. 2021-04-16 13:22:01 -04:00
Alex Hart
cfd69f2da8 Fix issue where we do not display initials for contacts we have names for. 2021-04-16 10:37:23 -03:00
Alex Hart
e97a14f617 Prevent crash when thumbnail decoder cannot stop, log instead. 2021-04-16 09:29:58 -03:00
Cody Henthorne
b7118b6bd8 Fix view once media in notifications. 2021-04-15 23:36:15 -04:00
Greyson Parrelli
742da4ccb8 Bump version to 5.8.5 2021-04-15 18:13:11 -04:00
Cody Henthorne
97296ca7d7 Fix bugs with preference and lock state changes. 2021-04-15 15:08:27 -04:00
Greyson Parrelli
1486a9ae1b Bump version to 5.8.4 2021-04-15 12:30:39 -04:00
Greyson Parrelli
a847e385cb Updated language translations. 2021-04-15 12:30:13 -04:00
Greyson Parrelli
134284723b Fix storage service crash when matching a local GV2 group without a master key. 2021-04-15 12:07:00 -04:00
Greyson Parrelli
a6eb44ba95 Log when there's local storage inserts. 2021-04-15 11:45:24 -04:00
Cody Henthorne
1457738905 Fix bug with notification privacy and bubbles. 2021-04-15 11:35:42 -04:00
Greyson Parrelli
3dd0a60555 Rotate storage service V2 feature flag. 2021-04-15 11:08:29 -04:00
Greyson Parrelli
1eef18dcd3 Add a failsafe for deleting storageIds. 2021-04-15 11:08:29 -04:00
Greyson Parrelli
c86ee33371 Skip new validations in old storage sync job. 2021-04-15 11:08:29 -04:00
Greyson Parrelli
60690208de Fix storage service crash when matching a local contact without an ID.
It's possible that we could match a local contact that doesn't have a
storageId, which would crash when we tried to make a model from it for
merging. This isn't an impossible case -- it could be that the manifest
has record of a user that is newly registered (or just registered at
some point and never deleted) and so we need to give our local record a
storageId for merging.
2021-04-15 11:08:29 -04:00
Cody Henthorne
69ebee3eeb Fix notification thumbnail being shown when content should be hidden. 2021-04-15 10:24:06 -04:00
Cody Henthorne
4bdb367c19 Fix thumbnail being shown for reaction notifications. 2021-04-15 10:02:53 -04:00
Greyson Parrelli
c817a3097d Bump version to 5.8.3 2021-04-14 18:50:48 -04:00
Greyson Parrelli
b3aa25ad59 Updated language translations. 2021-04-14 18:50:15 -04:00
Greyson Parrelli
cdddfd37d2 Dynamically respond to notificationsV2 feature flag.
We were only reading it once, possibly before the flags were
initialized. This lets us be more responsive to the flag changing within
an application cycle.
2021-04-14 18:50:15 -04:00
Cody Henthorne
2547db2a8e Revert "Prevent changes to conversations while device is unregistered."
This reverts commit ed8edb5aee.
2021-04-14 18:02:57 -04:00
Cody Henthorne
9363f0ebb4 Prevent NPE in safety number change dialog. 2021-04-14 17:28:07 -04:00
Cody Henthorne
8d6d8019fe Fix NPE in ComposeText. 2021-04-14 16:33:01 -04:00
Greyson Parrelli
e27089157d Bump version to 5.8.2 2021-04-14 15:56:00 -04:00
Greyson Parrelli
99fc75eeda Updated language translations. 2021-04-14 15:55:17 -04:00
Cody Henthorne
ec63dd704a Mark previous messages in thread as read when receiving a read sync message. 2021-04-14 15:50:40 -04:00
Cody Henthorne
d46a9f6d1d Rename Messages notification group and channel. 2021-04-14 15:50:40 -04:00
Christian
4b7d87c6bc Display GroupV1MigrationEvent as ActionMessage in conversation MenuState 2021-04-14 15:50:40 -04:00
Cody Henthorne
9c5a0ba7eb Hide message in notification when pending message request approval. 2021-04-14 15:50:40 -04:00
Greyson Parrelli
e461625da4 Add Log.internal() 2021-04-14 15:50:40 -04:00
Cody Henthorne
c393cd655d Fix bad notification state with in-thread reaction notifications. 2021-04-14 15:50:40 -04:00
Cody Henthorne
ed8edb5aee Prevent changes to conversations while device is unregistered. 2021-04-14 15:50:40 -04:00
Cody Henthorne
5df1fa3c65 Move contact join events to separate channel. 2021-04-14 15:50:40 -04:00
Cody Henthorne
e796968d19 Add new notification system. 2021-04-14 15:50:40 -04:00
Greyson Parrelli
c8f17e2ab0 Bump version to 5.8.1 2021-04-13 15:07:54 -04:00
Greyson Parrelli
69870eb229 Updated language translations. 2021-04-13 15:07:21 -04:00
Greyson Parrelli
670aed2074 Move ViewOnceMessageManager and ExpiringMessageManager to AppDependencies. 2021-04-13 14:49:32 -04:00
Greyson Parrelli
0020c7c6dc Clear storageIDs from recipient rows with bad data.
TBH this shouldn't affect external users. I believe this bad data was
only experienced internally a long time ago. But we want to make sure we
don't continue to sync that bad data, so we're just stripping the
storageID's from it.
2021-04-13 12:13:05 -04:00
Greyson Parrelli
20b98122c1 Send an empty group sync when linking devices if no groups exist. 2021-04-13 11:35:42 -04:00
Greyson Parrelli
35c102aa98 Fix issues with StorageSyncV2 bookkeeping.
1. I screwed up the comparators in the record processor. Pretty bad, glad this was caught.
2. Previously I was sort of keeping track of which local-only records were accounted for while I was merging, and then hoping everything worked out in the end. Now I just very directly take some set differences and retrieve the appropriate records, so it's clear that we should never fail certain validations.
3. Rev's the feature flag so we don't turn on something broken.
2021-04-13 11:32:24 -04:00
Cody Henthorne
fb316a22c6 Remove noisy log statement from DirectoryHelper. 2021-04-13 09:34:34 -04:00
Greyson Parrelli
5342af60cb Set archived when merging contact records. 2021-04-13 00:53:23 -04:00
Cody Henthorne
3d01bd7c57 Update gradle config to use 3g of ram. 2021-04-12 16:02:58 -04:00
Greyson Parrelli
1b3ac83876 Bump version to 5.8.0 2021-04-12 12:32:35 -04:00
Greyson Parrelli
4ba3104bf3 Updated language translations. 2021-04-12 12:32:11 -04:00
Cody Henthorne
eda2b87a57 Prevent race condition when closing/reopening message receiver. 2021-04-12 12:25:09 -04:00
Greyson Parrelli
ac0216d916 Only allow emojis as reactions. 2021-04-12 12:25:09 -04:00
Greyson Parrelli
d0986383ad Make some assets smaller. 2021-04-12 12:25:09 -04:00
Alex Hart
ab7f507b03 Add custom lint for AlertDialog.Builder usage. 2021-04-12 12:25:09 -04:00
Greyson Parrelli
e096ba27ce Sync mute status via storage service. 2021-04-12 12:25:09 -04:00
Greyson Parrelli
25ce2a649a Write additional storage validations based on previous manifest. 2021-04-12 12:25:09 -04:00
Greyson Parrelli
0e200b1fb6 Rewrite storage service change processing. 2021-04-12 12:25:09 -04:00
Alex Hart
552b19cbb0 Revert "Temporarily block payments for all regions."
This reverts commit 06ed124057.
2021-04-12 12:25:09 -04:00
Greyson Parrelli
3f0377a840 Bump version to 5.7.6 2021-04-12 11:49:43 -04:00
Greyson Parrelli
d9147874dd Updated language translations. 2021-04-12 11:49:10 -04:00
Alex Hart
06ed124057 Temporarily block payments for all regions. 2021-04-12 09:46:35 -03:00
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
Greyson Parrelli
0da6c83ce4 Bump version to 4.78.2 2020-11-18 19:52:48 -05:00
Greyson Parrelli
184b7db43c Updated language translations. 2020-11-18 19:51:15 -05:00
Greyson Parrelli
e442e34c1b More reliably setup initial preferences. 2020-11-18 19:47:27 -05:00
Greyson Parrelli
011efb0ce7 Request READ_PHONE_NUMBERS permission when necessary. 2020-11-18 19:47:27 -05:00
Alex Hart
63d00f87d8 Bump version to 4.78.1 2020-11-18 19:26:12 -04:00
Alex Hart
0323858145 Updated language translations. 2020-11-18 19:22:19 -04:00
Greyson Parrelli
a70e8ec7a7 Update reproducible build instructions. 2020-11-18 19:11:48 -04:00
Alex Hart
b306a3ef41 Update Dockerfile to utilize new commandline tools distributable. 2020-11-18 19:11:48 -04:00
Greyson Parrelli
ccd3467a61 Fix crash with MediaSendActivity progress dialog.
Co-authored-by: Alan Evans <alan@signal.org>
2020-11-18 17:31:43 -05:00
Alex Hart
40338afe7a Bump version to 4.78.0 2020-11-18 16:30:43 -04:00
Alex Hart
ff97f6af56 Updated language translations. 2020-11-18 16:30:43 -04:00
Alan Evans
6e7858e00f Restrict video send duration. 2020-11-18 16:30:43 -04:00
Greyson Parrelli
95468c85a8 Break large read receipt messages into chunks. 2020-11-18 14:19:28 -05:00
Cody Henthorne
f59e10d82c Fix read/unread conversation list colors. 2020-11-18 14:00:14 -05:00
Alex Hart
930370783e Implement ShortcutInfo for API 30. 2020-11-18 14:25:01 -04:00
Alex Hart
75062ada8a Upgrade SDK to 30. 2020-11-18 13:38:27 -04:00
Cody Henthorne
23618923d8 Attempt to recover from reoccurring exceptions when showing notifications. 2020-11-18 12:28:05 -05:00
Greyson Parrelli
f1d3a2f322 Fix Android 11 issue where keyboard wasn't auto-showing for PIN reminders. 2020-11-18 11:57:33 -05:00
Cody Henthorne
3b7fbbaf6e Fix crash when call concluded on non-existent remote peer. 2020-11-18 11:34:06 -05:00
Greyson Parrelli
725d793b20 Fix issue with link preview UI sizing. 2020-11-18 11:33:44 -05:00
Greyson Parrelli
5c3baca055 Add support for a donation megaphone. 2020-11-18 10:33:46 -05:00
Alan Evans
6e5abc92a0 Fix situation where group thread does not yet exist. 2020-11-17 15:52:38 -04:00
Alex Hart
8df6e95781 Stop proximity sensor on pause. 2020-11-17 15:15:13 -04:00
Alex Hart
2290a6c0df Synchronize voice note queue reads and writes. 2020-11-17 14:42:01 -04:00
Jack Lloyd
907e8d93a3 Move to Signal Protocol written in Rust.
Co-authored-by: Alex Hart <alex@signal.org>
2020-11-16 12:28:11 -05:00
Cody Henthorne
918497fb94 Bump version to 4.77.3 2020-11-16 11:49:35 -05:00
Cody Henthorne
3ccd6304c7 Updated language translations. 2020-11-16 11:47:55 -05:00
Greyson Parrelli
51d47adf57 Fix issue where FeatureFlags were triggering listeners for non-changes. 2020-11-16 11:27:58 -05:00
Cody Henthorne
f1e5206f56 Fix Invite Friend theming bug. 2020-11-16 10:17:42 -05:00
Cody Henthorne
f410635e2c Bump version to 4.77.2 2020-11-13 15:01:12 -05:00
Cody Henthorne
302d57bf19 Updated language translations. 2020-11-13 14:54:53 -05:00
Fumiaki Yoshimatsu
4c301a49b4 Fix appearance of small audio view to show correct background color and the progress circle. 2020-11-13 14:39:46 -05:00
Cody Henthorne
4ecfee292e Fix incorrect restarting and theming when system changes night mode. 2020-11-13 14:39:00 -05:00
Alex Hart
2a193ef455 Refactor with WindowUtil and correct some colors. 2020-11-13 14:43:58 -04:00
Cody Henthorne
96e241ef9c Fix RTL constraints for Help screen. 2020-11-13 12:32:55 -05:00
Cody Henthorne
e294a895e8 Bump version to 4.77.1 2020-11-12 12:54:33 -05:00
Cody Henthorne
003b9b1551 Updated language translations. 2020-11-12 12:49:45 -05:00
Alex Hart
a4e4af502e Retheme action modes. 2020-11-12 13:42:07 -04:00
Alex Hart
06aada20c1 Open keyboard when we open contact selection from blocked preference. 2020-11-12 13:39:38 -04:00
Greyson Parrelli
2dace38d43 Add support for GV1->GV2 forced migration. 2020-11-12 12:32:10 -05:00
Greyson Parrelli
554aa1ddf0 Trim message bodies at display time. 2020-11-12 12:18:20 -05:00
Greyson Parrelli
3b2a5f1ce3 Remove old profile sharing UI. 2020-11-12 12:01:43 -05:00
Cody Henthorne
3fc4b098e8 Show correct emojis for recipient names. 2020-11-12 11:22:00 -05:00
Fumiaki Yoshimatsu
a7d672f6b4 Apply locale updates correctly for appcompat-v1.2.0.
Fixes #9736

See https://developer.android.com/jetpack/androidx/releases/appcompat#1.2.0
for how the code is "correctly" applying a new configuration.

Co-authored-by: Cody Henthorne <cody@signal.org>
2020-11-12 09:56:07 -05:00
Greyson Parrelli
7e347f5cce Add support for manual initiation of GV1->GV2 migrations. 2020-11-12 09:52:21 -05:00
Cody Henthorne
4eaa6ebb47 Bump version to 4.77.0 2020-11-11 15:39:00 -05:00
Cody Henthorne
e85ef6881d Updated language translations. 2020-11-11 15:34:15 -05:00
Cody Henthorne
b1f6786392 Add initial support for Group Calling. 2020-11-11 15:29:02 -05:00
Cody Henthorne
696fffb603 Improve mention notifications by only showing alerting notifications once. 2020-11-11 15:29:02 -05:00
Alan Evans
3bb366ee04 Do not send typing indicator when deleting from the end & send stopped typing indicator when compose completely empty. 2020-11-11 15:29:02 -05:00
Alex Hart
6a59974f89 Add group settings UI polish. 2020-11-11 15:29:02 -05:00
Alan Evans
8e39267c42 Center number display vertically for non-signal contacts. 2020-11-11 15:29:02 -05:00
Jim Gustafson
b937534ce5 Update to RingRTC v2.8.0. 2020-11-11 15:29:01 -05:00
Alex Hart
f5b46f7356 Consolidate AnimatedDialog themes to single DayNight theme. 2020-11-11 15:29:01 -05:00
Greyson Parrelli
cd58c09be3 Proper handling of GV1->GV2 migrations in storage service. 2020-11-11 15:29:01 -05:00
Greyson Parrelli
e8f0038c36 Perform bulk receipt processing in a transaction. 2020-11-11 15:29:01 -05:00
Greyson Parrelli
0b77b33902 Add the ability to trace methods in internal builds.
Currently only for internal builds. Use the @Trace annotation to trace
methods for viewing in Perfetto.
2020-11-11 15:29:01 -05:00
Cody Henthorne
c3b5323010 Update assets and themes to leverage DayNight system. 2020-11-11 15:29:01 -05:00
Greyson Parrelli
81eaae4070 Update emoji to Unicode 13.0 2020-11-11 15:29:01 -05:00
Cody Henthorne
65461ce86f Fix incorrect reaction notification copy for various attachment types.
Fixes #10141. Thanks to @Sgn-32 for the initial PR.
2020-11-11 15:29:01 -05:00
Cody Henthorne
536e3139a2 Add foundation for using Android's DayNight theming system. 2020-11-11 15:29:01 -05:00
Alex Hart
e9c7b120a0 Improve contact blocking UX via settings. 2020-11-11 15:29:01 -05:00
Cody Henthorne
d6a230a235 Update AppCompat to 1.2 along with other Android UI libraries. 2020-11-11 15:29:01 -05:00
Alex Hart
6bf300ada8 Do not require write to read from single backup uri. 2020-11-11 15:29:01 -05:00
Greyson Parrelli
d307db8a95 Add the ability to add suggested members after a GV1 migration. 2020-11-11 15:29:01 -05:00
Alex Hart
c4c32d80b2 Update CameraX to 1.0.0-beta11. 2020-11-11 15:29:01 -05:00
Greyson Parrelli
f4c1e34402 Enforce max envelope size in more places. 2020-11-11 15:29:00 -05:00
Alan Evans
0068d62122 Bump version to 4.76.3 2020-11-09 14:39:30 -04:00
Alan Evans
3f1fa59e09 Updated language translations. 2020-11-09 14:38:11 -04:00
Greyson Parrelli
df5114c62c Fix website signing task. 2020-11-09 14:21:56 -04:00
Greyson Parrelli
956e3924ff Log the version in our PersistentLogger. 2020-11-09 12:47:10 -05:00
Greyson Parrelli
20ad166e0f Fix issue where we were double-logging job info. 2020-11-09 12:18:45 -05:00
Greyson Parrelli
12ea88f409 Improve logging around deletions. 2020-11-09 12:18:27 -05:00
Alan Evans
0c5648bfb1 Hide "Read More" when long message is remote deleted. 2020-11-09 10:24:11 -04:00
Greyson Parrelli
91ca19f294 Bump version to 4.76.2 2020-11-05 18:19:51 -05:00
Greyson Parrelli
71250afd2c Updated language translations. 2020-11-05 18:19:22 -05:00
Greyson Parrelli
cfdef7bca7 Only use the NATIONAL format for the US and UK. 2020-11-05 18:14:37 -05:00
Alan Evans
872f935fd5 Revert "Do not set or read quote author phone number."
This reverts commit 936e772ba0.
2020-11-05 18:56:17 -04:00
Alex Hart
0ed1f73990 Fix crash with multitouch in call screen pip. 2020-11-05 17:43:14 -04:00
Cody Henthorne
349a2f72cb Fix crash when handling call messaging failures. 2020-11-05 15:56:56 -05:00
Alex Hart
2b4a4d6109 Add support for Incoming / Outgoing Video Type. 2020-11-05 13:41:22 -04:00
Greyson Parrelli
9f882d2fbb Fix crash around creating MMS groups. 2020-11-05 10:57:31 -05:00
Greyson Parrelli
cb4a9730aa Bump version to 4.76.1 2020-11-04 20:11:55 -05:00
Greyson Parrelli
e0657d09d8 Fix issue where we weren't calling setTransactionSuccessful().
In a chain of events, this manifested by preventing the persistence of
media messages in group threads.
2020-11-04 20:07:57 -05:00
Alan Evans
01b9cb13b4 Bump version to 4.76.0 2020-11-04 16:51:23 -04:00
Alan Evans
2c7260557c Updated language translations. 2020-11-04 16:51:23 -04:00
Greyson Parrelli
9e5156ab73 Pretty-print phone numbers. 2020-11-04 16:51:23 -04:00
Alex Hart
3dc1614fbc Add basic profile spoofing detection. 2020-11-04 16:24:45 -04:00
Alan Evans
2f69a9c38e Share media from within Media Preview and share QR code image. 2020-11-04 16:05:35 -04:00
Greyson Parrelli
5e536c3fa5 Render GV1->GV2 migration event. 2020-11-04 16:05:35 -04:00
Greyson Parrelli
6bb9d27d4e Add the ability to migrate GV1 groups to GV2.
Co-authored-by: Alan Evans <alan@signal.org>
2020-11-04 16:05:35 -04:00
Greyson Parrelli
2d1bf33902 Update group table schema to support GV1->GV2 migration.
Also puts in protections to make sure we don't insert bad recipients or
groups.
2020-11-04 16:05:35 -04:00
Alan Evans
985a220fca Migrate GV1 to GV2 on to server. Allow query of group status. 2020-11-04 16:05:34 -04:00
Alex Hart
31e137cf6d Add support for MISSED_VIDEO_CALL type. 2020-11-04 16:05:34 -04:00
Alex Hart
f796447815 Add better error logging for single backup Uris. 2020-11-04 16:05:34 -04:00
Alan Evans
936e772ba0 Do not set or read quote author phone number. 2020-11-04 16:05:34 -04:00
Greyson Parrelli
ecee797d00 Always consider yourself a member of MMS groups.
Fixes #10162
2020-11-04 16:05:34 -04:00
Greyson Parrelli
357a8fc124 Remove name change for flipper and internal releases. 2020-11-04 16:02:11 -04:00
Alan Evans
1233af0ddd Add environment dimension. 2020-11-04 16:02:11 -04:00
Alex Hart
a264d10685 Fix issue with KitKat picture saves.
Fixes #10153
2020-11-04 16:01:58 -04:00
Alex Hart
ed17701a0a Remove look-behind and ding for single voice notes. 2020-11-02 11:50:37 -04:00
Greyson Parrelli
49e1ccea28 Allow more control over debug and staging signing. 2020-11-02 10:01:59 -05:00
Alan Evans
4c43b0d1e3 Update gradle plugin to 4.1.0, gradle to 6.5. 2020-11-02 10:01:59 -05:00
Greyson Parrelli
5ce09defca Include whether a user has a linked device in the debug log. 2020-11-02 10:01:59 -05:00
Greyson Parrelli
da9064b714 Bump version to 4.75.8 2020-11-02 10:00:23 -05:00
Greyson Parrelli
7bb53e4b06 Updated language translations. 2020-11-02 09:59:52 -05:00
Cody Henthorne
6a4ce1b658 Fix SMS role bug introduced for pre-Q devices. 2020-10-30 17:45:28 -04:00
Greyson Parrelli
f84595e1e8 Bump version to 4.75.7 2020-10-30 16:15:12 -04:00
Greyson Parrelli
41d5c54033 Updated language translations. 2020-10-30 16:14:30 -04:00
Greyson Parrelli
b9d6b63c09 Fix name of internal signing task. 2020-10-30 16:06:57 -04:00
Cody Henthorne
506ad0b3f1 Fix bug handling mentions in sync messages. 2020-10-30 15:13:54 -04:00
Cody Henthorne
c8302174a9 Fix mention suggestions for groups of 1.
Fixes #10152
2020-10-30 13:05:14 -04:00
Cody Henthorne
39cebfbb4e Fix SMS role request for Q+. 2020-10-30 12:34:47 -04:00
Cody Henthorne
d36ec9af47 Fix permission bug with avatar gallery selection. 2020-10-30 11:36:12 -04:00
Greyson Parrelli
5f6d971bf7 Bump version to 4.75.6 2020-10-30 08:24:14 -04:00
Greyson Parrelli
7a722d92a3 Updated language translations. 2020-10-30 08:23:25 -04:00
Greyson Parrelli
0bf0eba450 Fix NPE in BackupUtil. 2020-10-30 08:17:50 -04:00
Greyson Parrelli
d40783f794 Add signing task for internal builds. 2020-10-30 08:17:29 -04:00
Greyson Parrelli
88733473e2 Bump version to 4.75.5 2020-10-29 15:55:17 -04:00
Greyson Parrelli
7b65533095 Updated language translations. 2020-10-29 15:51:04 -04:00
Cody Henthorne
52b533c121 Add internal product flavor. 2020-10-29 15:33:15 -04:00
Greyson Parrelli
a4fa2e14fb Fix versioning issue with Dockerfile. 2020-10-29 15:31:05 -04:00
Cody Henthorne
6933f1d818 Fail call gracefully on turn server network error. 2020-10-29 13:51:30 -04:00
Greyson Parrelli
b5d6cb2a8d Notify about accidentally disabled backups. 2020-10-29 13:32:55 -04:00
Greyson Parrelli
d1478c5ce0 Reduce impact of CDS rate-limiting issues.
This will at least allow users with > RateLimit contacts to perform a successful sync. More work needs to be done here in the future to handle this better.
2020-10-29 10:16:21 -04:00
Greyson Parrelli
fbe62f0f3e Add more Huawei phones to the CameraX blacklist. 2020-10-29 08:04:29 -04:00
Greyson Parrelli
f84705b756 Include additional system properties in debuglog. 2020-10-28 17:01:34 -04:00
Cody Henthorne
cf2189c11a Ensure speakerphone is correctly enabled during call setup.
Race condition between handleStartOutgoingCall being enqueued from ringrtc and
handleSetEnableVideo being enqueued from the main thread.
2020-10-28 17:01:34 -04:00
Alex Hart
dfc4178252 Localize 'camera' folder title. 2020-10-28 17:01:34 -04:00
Greyson Parrelli
07952f2146 Bump version to 4.75.4.
Accidentally went the wrong direction with canonicalVersionCode in
4.75.3. So this release just fixes that and uses the correct
canonicalVersionCode.
2020-10-28 16:54:00 -04:00
Cody Henthorne
a90dad22a9 Bump version to 4.75.3 2020-10-28 16:22:16 -04:00
Cody Henthorne
64f7330609 Updated language translations. 2020-10-28 16:21:12 -04:00
Cody Henthorne
5e382c120b Fix security crash during directory refresh. 2020-10-28 16:14:45 -04:00
Greyson Parrelli
3eea568f5f Fix possible storage permission crash on camera. 2020-10-28 16:00:01 -04:00
Cody Henthorne
0077b29d6e Mitigate PSTN callback crash when service is in background. 2020-10-28 15:48:04 -04:00
Cody Henthorne
dfa6306b61 Bump version to 4.75.2 2020-10-26 16:08:44 -04:00
Cody Henthorne
a4bf075a1a Updated language translations. 2020-10-26 16:06:57 -04:00
Alex Hart
373d622535 Fix SMS, bad MODIFIED timestamp, and API19 beta crash. 2020-10-26 13:41:30 -03:00
Greyson Parrelli
ba1df58eb3 Do not show modern profile sharing on brand new conversations. 2020-10-26 12:08:01 -04:00
Greyson Parrelli
9fb85f7c76 Build log sections in series.
Doing them in parallel was causing possible bad blocked thread reports,
since the thread section could be built at the same time we were
building the jobs section.
2020-10-26 11:07:44 -04:00
Cody Henthorne
5e58f0a212 Bump version to 4.75.1 2020-10-23 15:45:20 -04:00
Cody Henthorne
8fa01f13e9 Updated language translations. 2020-10-23 15:44:07 -04:00
Alan Evans
4ce136be17 Fix missing message request on V2 re-invites. 2020-10-23 15:37:42 -04:00
Alan Evans
4099154dc0 Infer contact multi-select allowing assertion removal.
Hide count on invite friends.

Fixes #10125
2020-10-23 15:37:42 -04:00
Greyson Parrelli
3f983a5c82 Various UI adjustments to conversation updates. 2020-10-23 15:37:42 -04:00
Alex Hart
9743e3689a Add MimeType to MediaStore values. 2020-10-23 14:11:42 -03:00
Greyson Parrelli
1363f55f77 Fix back button behavior on OnePlus phones.
Couple things happened:
- Core issue: The device always thought the keyboard was open, so it was
always trying to dismiss the keyboard when you pressed back (instead of
actually going back)
- Big fix: Increase the tolerance of our view height differentialt that
detects if the keyboard is open
- Other fix: the getViewInset() method is always missing on Q, so as a
temp fix we fall back to the status bar height. Gets the calculation to
be closer, even if not truly correct.
2020-10-23 12:43:34 -04:00
Alex Hart
f1d98f6c7b Fix failed media saves on API < 29.
Fixes #10119
2020-10-23 13:12:07 -03:00
Alex Hart
9279a54d28 Fix bad voice note duration and listener breakage. 2020-10-23 13:00:46 -03:00
Alan Evans
81889d8130 Fix plural. 2020-10-23 11:13:37 -03:00
Cody Henthorne
6aecb8fbc1 Bump version to 4.75.0. 2020-10-22 17:04:24 -04:00
Cody Henthorne
8aa413032d Updated language translations. 2020-10-22 17:02:27 -04:00
Alan Evans
5bc4686eb8 Ignore some more ZKGroup dependent tests on mac. 2020-10-22 16:56:16 -04:00
Greyson Parrelli
f676d1c61c Enforce a configurable max envelope size. 2020-10-22 16:56:16 -04:00
Alex Hart
ac54b5cbdf Add polish to voice note bubbles. 2020-10-22 16:56:16 -04:00
Alan Evans
b4b1e5b605 Add feature flag driven group recommended size and hard size limits. 2020-10-22 16:56:16 -04:00
Greyson Parrelli
5eace49739 Improve PushProcessMessageJob logging. 2020-10-22 16:56:16 -04:00
Alex Hart
e93d7518f3 Add some polish to backups changes. 2020-10-22 16:56:16 -04:00
Greyson Parrelli
9c97cd8816 Improve conversation update message stylings. 2020-10-22 16:56:16 -04:00
Jim Gustafson
90f20c36c5 Update to RingRTC v2.7.3 2020-10-22 16:56:16 -04:00
Greyson Parrelli
9f8dd7992a Remove remote delete option for group updates. 2020-10-22 16:56:16 -04:00
Alex Hart
f4d3fe9176 Implement better backup failure notification strategy. 2020-10-22 16:56:16 -04:00
Alan Evans
ffc7c13717 Group GET 404 and PUT 409 handling. 2020-10-22 16:56:16 -04:00
Greyson Parrelli
daf93c473b Reduce verbosity of KeyboardAwareLinearLayout logs. 2020-10-22 16:56:16 -04:00
Greyson Parrelli
d21782696a Read the new GV1 Migration capability. 2020-10-22 15:55:18 -03:00
Greyson Parrelli
3357475fc4 Move capabilities into a single column. 2020-10-22 15:55:18 -03:00
Greyson Parrelli
ead64d92a5 Rename Recipient.isLocalNumber() to Recipient.isSelf() 2020-10-22 15:55:18 -03:00
Cody Henthorne
5eaac6cb17 Call handling state machine refactor. 2020-10-22 15:55:18 -03:00
Alex Hart
b3f0a44f10 Bump version to 4.74.3 2020-10-21 11:11:43 -03:00
Alex Hart
e4d0e2f730 Updated language translations. 2020-10-21 11:11:43 -03:00
Cody Henthorne
492a42883e Change Surveygizmo to Alchemer due to name change. 2020-10-21 11:11:43 -03:00
Alex Hart
b182f73415 Fix wakelock release exception. 2020-10-21 11:11:42 -03:00
Alan Evans
e766b9737e Do not enable admin approval on group links by default. 2020-10-20 19:39:51 -03:00
Alan Evans
2335f93579 Staging CDS enclave change. 2020-10-20 19:20:01 -03:00
Greyson Parrelli
1730260343 Bump version to 4.74.2 2020-10-19 17:34:08 -04:00
Greyson Parrelli
27506e9ed8 Updated language translations. 2020-10-19 17:33:25 -04:00
Alex Hart
dc64a186d5 Fix mediastore access for Android Q. 2020-10-19 18:16:29 -03:00
Alex Hart
3163e09b98 Fix issue with backup deletion. 2020-10-19 10:27:18 -03:00
Alex Hart
dcb9978bb1 Bump version to 4.74.1 2020-10-16 16:40:15 -03:00
Alex Hart
4a94a0a5c5 Updated language translations. 2020-10-16 16:36:47 -03:00
Alex Hart
8a2d20403e Add Proximity sensing back to voice note. 2020-10-16 16:23:04 -03:00
Alex Hart
ec706e95cc Backup style and copy tweak. 2020-10-16 16:17:34 -03:00
Alex Hart
bd3b14a27f Fix seeking voice notes that do not have waveforms. 2020-10-16 15:37:26 -03:00
Alex Hart
082d9e852c Voice Note Beta Feedback fixes. 2020-10-16 13:14:01 -03:00
Alex Hart
36da519b26 Bump version to 4.74.0 2020-10-15 17:43:35 -03:00
Alex Hart
06ffdde892 Updated language translations. 2020-10-15 17:42:28 -03:00
Greyson Parrelli
1ec57c080c Update targetSdk to 29. 2020-10-15 16:19:17 -04:00
Alan Evans
a635f27c68 Hide group link when not enabled. 2020-10-15 16:19:17 -04:00
Alex Hart
ee3d7a9a35 Implement new workflow for scoped storage backup selection. 2020-10-15 16:19:17 -04:00
Alex Hart
9a1c869efe Allow consecutive voice notes to be played as a playlist. 2020-10-15 16:19:17 -04:00
Alan Evans
837ed76f85 Show reminder banner to administrators for pending group join requests. 2020-10-15 16:19:17 -04:00
Cody Henthorne
b46589cd14 Remove mentions feature flag. 2020-10-15 16:19:17 -04:00
Alan Evans
d04e4606d2 Remove GV2 create flag. 2020-10-15 16:19:17 -04:00
Greyson Parrelli
385bd0eb8a Fix possible crash for unregistered devices. 2020-10-15 16:19:17 -04:00
Greyson Parrelli
089656e5c4 Add an application migration to do a CDS refresh. 2020-10-15 16:19:17 -04:00
Greyson Parrelli
84ec6dd458 Improve network reliability during resumable uploads. 2020-10-15 16:19:17 -04:00
Cody Henthorne
322c139c26 Fix bug of video showing on next call after cancel pre-join.
Fixes #10083
2020-10-15 16:19:17 -04:00
Alan Evans
babe1833bb Derive GV2 master key and group id from GV1. 2020-10-15 16:19:17 -04:00
Alex Hart
9effa47dd8 Allow voice notes to continue playback after leaving conversation. 2020-10-15 16:19:17 -04:00
Greyson Parrelli
7ef57cc0cf Add support for syncing pinned status with storage service. 2020-10-15 16:19:17 -04:00
Greyson Parrelli
97420aae1b Add a Github Action to test our docker build every day.
Runs at 5am UTC, which is ~midnight EST.
2020-10-15 16:19:17 -04:00
Greyson Parrelli
415e6309f9 Ensure CI runs on 5.x branches. 2020-10-15 16:19:17 -04:00
Greyson Parrelli
83e63ff854 Improve the reproducible build process.
* Moved stuff into it's own `reproducible-builds` directory.
* Improved reproducible build by using a debian snapshot and more clearly listing dependencies.
* Removed signing from assembleReelase.
* Updated README.
2020-10-15 16:19:17 -04:00
Greyson Parrelli
de7f103130 Add support for modern profile sharing. 2020-10-15 16:19:12 -04:00
Alan Evans
2cb912681d Bump version to 4.73.4 2020-10-13 15:18:00 -03:00
Alan Evans
04bdf94b78 Updated language translations. 2020-10-13 15:18:00 -03:00
Cody Henthorne
c7389ddaa7 Fix bug causing incorrect mention suggestions. 2020-10-13 15:18:00 -03:00
Greyson Parrelli
e778ab2e3a Fix issue with remote delete sent transcripts. 2020-10-13 13:50:21 -04:00
Alan Evans
533d86607f Bump version to 4.73.3 2020-10-12 15:24:34 -03:00
Alan Evans
cb2096670f Updated language translations. 2020-10-12 15:19:00 -03:00
Alan Evans
284f221a9d Handle no actual change to group. 2020-10-12 15:11:57 -03:00
Greyson Parrelli
bc639dd438 Show error message when unable to compute safety number. 2020-10-12 12:14:13 -04:00
Greyson Parrelli
1baddbb40e Fix some oddities with message request behavior.
There was a weird case where how our intent checking could behave
differently when coming from search. There's also some funny
interactions where backups, where because the 'time message requests was
enabled' is reset to System.currentTimeMillis() post-restore, we thought
there were always 'pre-message-request messages'. Only mattered when
profileSharing is also disabled, so impact isn't huge. Given a lot of
this UI is going away soon, rather than doing the complicated thing of
backing up the true timestamp, I just default it to 0 to mitigate
things.
2020-10-12 10:09:35 -04:00
Alan Evans
f784dab868 Bump version to 4.73.2 2020-10-09 17:46:21 -03:00
Alan Evans
85192aaa21 Updated language translations. 2020-10-09 17:46:21 -03:00
Alan Evans
054c705fe2 Respect the 206 paged response from the server group logs endpoint.
Prevent the deduplicate message logic firing and log it if it does.
2020-10-09 17:46:21 -03:00
Alan Evans
07b0d8cf6e Utilities for correctly handling json parsing errors on network responses. 2020-10-09 17:11:19 -03:00
Greyson Parrelli
597d16f566 Ensure one row per recipient in getRecipientSettingsForSync().
Technically there's no unique constraint in ThreadDatabase to guarantee
only one thread per recipient. We saw a crash that indicated that one
user has two threads for the same recipient. That's not true for any of
my devices. Still, best to play it safe here while we try to figure out
why this is happening.
2020-10-09 12:16:38 -04:00
Greyson Parrelli
0ca2c781c3 Only show the delivery status icon for 'sending' on remote deletes. 2020-10-08 16:29:13 -04:00
Greyson Parrelli
f642de9c41 Disable mention clicks in multi-select mode. 2020-10-08 14:09:44 -04:00
Greyson Parrelli
8965388d05 Fix rendering of remote-deleted view-once messages. 2020-10-08 14:04:00 -04:00
Alan Evans
58c4582f15 Bump version to 4.73.1 2020-10-08 12:53:17 -03:00
Alan Evans
44bc1b5cc0 Updated language translations. 2020-10-08 12:51:08 -03:00
Greyson Parrelli
714ebb3e08 Allow remote deletes of pending messages. 2020-10-08 10:58:55 -04:00
Greyson Parrelli
8f871c2e3a Don't allow quote-jumps to remote deleted messages. 2020-10-08 10:29:46 -04:00
Greyson Parrelli
5cdc5bc441 Ensure reactions are deleted for remote-deleted messages.
We were doing this for MmsDatabase, but not SmsDatabase. Includes a
migration to cleanup any existing bad state.
2020-10-08 10:21:57 -04:00
Cody Henthorne
8d060837ad Cleanup abandoned mentions during backup restore. 2020-10-08 09:46:26 -04:00
Greyson Parrelli
1d230d4cd6 Schedule another attribute refresh for GV2. 2020-10-07 20:29:40 -04:00
Greyson Parrelli
3636ae7667 Add the Pixel 4 back to the CameraX blacklist.
It's having pretty bad exposure problems.
2020-10-07 19:54:24 -04:00
Greyson Parrelli
9ffb5112c6 Bump version to 4.73.0 2020-10-07 17:22:05 -04:00
Greyson Parrelli
ca5d574cd7 Updated language translations. 2020-10-07 17:22:05 -04:00
Greyson Parrelli
c80283dbcc Inline remote delete feature flag. 2020-10-07 17:22:05 -04:00
Greyson Parrelli
3fcaddf2d3 Update delete for everyone education text. 2020-10-07 17:22:05 -04:00
Greyson Parrelli
6ecff5bce9 Ensure the storage manifest has all inserts and deletes.
A user hit a fishy case where not all inserts were present in the full
keyset. It's unclear how that would happen, so I'm being even more
explicit here.
2020-10-07 17:22:05 -04:00
Greyson Parrelli
a103c7dcb6 Apply storage service values for phone number privacy. 2020-10-07 17:22:05 -04:00
Greyson Parrelli
63746bbb47 Add support for syncing forced unread status. 2020-10-07 17:22:05 -04:00
Alan Evans
ed0be6fc9a Add dialog transitions to group manager. 2020-10-07 17:22:05 -04:00
Alan Evans
26404ff5d7 More descriptive copy for group link permission errors. 2020-10-07 17:22:05 -04:00
Alan Evans
adf1674877 Support sgnl://signal.group links. 2020-10-07 17:22:05 -04:00
Greyson Parrelli
ab2235fc88 Prefer remote value for profile sharing for groups during storage sync. 2020-10-07 17:22:05 -04:00
Cody Henthorne
441a6d3fe7 Fix start call resizing improperly with wrapping text. 2020-10-07 17:22:05 -04:00
Greyson Parrelli
e00397620a Simplify storing storage-service-specific recipient values.
This gives us the ability to separate things we need for the Recipient
class from things we only need for storage syncing.

Not only does this simplify the storage service model building code
(i.e. we no longer need to pass around a set of archived recipients),
but it also eliminates a join on the Identity table for building regular
recipients, which should help perf.
2020-10-07 17:22:05 -04:00
Alan Evans
38fa58c0a3 Write previous group state to the database for advanced change messages. 2020-10-06 11:21:56 -03:00
Alan Evans
b40fd7b243 Fix Audio slides reporting images.
Fixes #10063
2020-10-06 11:09:50 -03:00
Alan Evans
ae34877496 Use Emoji respecting textview in group member lists. 2020-10-06 10:36:48 -03:00
Greyson Parrelli
599cf1e5cb Ensure we refresh recipients after changing storage keys. 2020-10-06 10:32:03 -03:00
Greyson Parrelli
474963dcf1 Add the ability to migrate to new KBS enclaves. 2020-10-06 10:32:03 -03:00
Alan Evans
e22384b6b4 New copy for GV2 direct add message request. 2020-10-05 14:54:18 -03:00
Cody Henthorne
fb00652396 Fix incorrect UI for inactive groups. 2020-10-05 12:59:00 -04:00
Alan Evans
a5dbb5d91f Block unknown group messages from blocked senders. 2020-10-05 12:30:29 -03:00
Alan Evans
e75a03b6f8 Bump version to 4.72.6 2020-10-02 12:25:40 -03:00
Alan Evans
eb7fe7f3e0 Updated language translations. 2020-10-02 12:25:40 -03:00
Cody Henthorne
3179808f17 Cleanup mentions with bad thread ids or ranges, or duplicates. 2020-10-02 12:25:40 -03:00
Alan Evans
fde9f05bd0 Use GV2 change descriptions for invite events. 2020-10-02 10:40:57 -03:00
Alan Evans
8de4290c5b Fix can create backups when timed backup is waiting for charging constraint. 2020-10-02 10:32:04 -03:00
Alan Evans
19c74c8872 Fix English use of quantity zero string. 2020-10-02 10:31:11 -03:00
Alan Evans
50edb5d1f4 Bump version to 4.72.5 2020-09-30 17:38:38 -03:00
Cody Henthorne
c6ccfd7e75 Fix API19 crash when inflating new WebRTC UI. 2020-09-30 17:38:15 -03:00
Alan Evans
3796ce69e4 Clear auth cache on first verification failure. 2020-09-30 17:28:42 -03:00
Cody Henthorne
9835e31b46 Attempt to cleanup invalid mentions. 2020-09-30 15:56:23 -04:00
Alan Evans
a35040c909 Bump version to 4.72.4 2020-09-30 16:05:27 -03:00
Alan Evans
a4c94638ca Updated language translations. 2020-09-30 15:59:29 -03:00
Cody Henthorne
e70a8ae6a0 Drop messages with mentions not sent to V2 Groups. 2020-09-30 14:52:18 -04:00
Alan Evans
100359e38d Allow in notification reply to multi message if you can reply to latest. 2020-09-30 15:42:07 -03:00
Cody Henthorne
cd995aca56 Fix incorrect mention association when messages are deleted. 2020-09-30 14:35:02 -04:00
Alan Evans
3a4bae88ca Add network spinner to add members. 2020-09-30 13:59:39 -03:00
Cody Henthorne
e60eae27fb Tweak font sizes and PIP boundaries in call view. 2020-09-30 11:51:48 -04:00
Alan Evans
cd6c01e230 Fix spinner not disappearing when adding members with no network. 2020-09-30 12:25:35 -03:00
Alan Evans
0af264429f During GV2 storage sync, recover from recipient present but group not present. 2020-09-30 10:11:51 -03:00
Alan Evans
a6d3862350 Ignore bad messages from blocked senders. 2020-09-30 10:08:21 -03:00
Alan Evans
3fca4850dd Fix xml inflation crash. 2020-09-29 16:40:37 -03:00
Alan Evans
ba7e41d9a6 Fix missing Submit Debug Log loading progress spinner. 2020-09-29 15:23:31 -03:00
Alan Evans
fe33ce3413 Various groups V2 dialog copy changes. 2020-09-29 12:03:32 -03:00
Alan Evans
4e25e8aaa2 Ensure clock adjustments does not stop remote config refresh. 2020-09-29 11:10:25 -03:00
Alan Evans
91be826c7d Bump version to 4.72.3 2020-09-28 16:35:44 -03:00
Alan Evans
fdfe0cddb8 Updated language translations. 2020-09-28 16:32:18 -03:00
Alan Evans
e8ef62116f Write gv2-3 capability. 2020-09-28 14:15:19 -03:00
Alan Evans
caf8bb39d8 Fix desktop sync with body-less messages. 2020-09-28 11:53:27 -03:00
Alan Evans
222ba6ee53 Hide admin options on bottom sheet for members not currently in group. 2020-09-28 10:15:29 -03:00
Alan Evans
8dcda73072 Fix media preview crash. 2020-09-28 09:45:06 -03:00
Alan Evans
810365d334 Bump version to 4.72.2 2020-09-25 15:29:36 -03:00
Alan Evans
4b31510589 Updated language translations. 2020-09-25 15:24:47 -03:00
Alan Evans
dfce9a34b8 Fix leave group crash. 2020-09-25 15:18:34 -03:00
Alex Hart
dc9370c32b Fix false group name and avatar updates. 2020-09-25 15:18:34 -03:00
Cody Henthorne
8dbc721c08 Fix stale call preview state by finishing when leaving. 2020-09-25 15:18:34 -03:00
Cody Henthorne
6448b84430 Fix various mention issues.
Fixes #9960
2020-09-25 15:18:34 -03:00
Alan Evans
93d6ce40c3 GV2 learn more copy update. 2020-09-25 15:18:34 -03:00
Alan Evans
ce5be2c1be Share group link via signal to one recipient. 2020-09-25 12:33:14 -03:00
Alan Evans
20fe837022 Enable and disable group link options with first switch. 2020-09-25 12:32:48 -03:00
Greyson Parrelli
e3ce18fa3e Fix possible threading issues with attachment cleanup.
The way things were ordered, it was possible for us to create an
attachment file, but have it 'cleaned up' before we were able to link it
to an attachment row.
2020-09-24 16:51:20 -04:00
Greyson Parrelli
864a1d5e93 Prefer remote value for profile sharing during storage sync. 2020-09-24 12:41:31 -04:00
Greyson Parrelli
9cf7eec247 Log sent timestamps when hitting message processing errors. 2020-09-24 12:26:18 -04:00
Greyson Parrelli
d9c15621f6 Log more details around conversation fetch times. 2020-09-24 12:26:02 -04:00
Greyson Parrelli
fea14218a9 Don't allow borderless images to have quotes attached.
Fixes #9924
2020-09-24 12:11:40 -04:00
Greyson Parrelli
dbbded5250 Bump version to 4.72.1 2020-09-24 10:54:07 -04:00
Greyson Parrelli
d65cfc7981 Updated language translations. 2020-09-24 10:53:44 -04:00
Greyson Parrelli
dc9124f291 Fix crash in RetrieveProfileJob. 2020-09-24 10:46:56 -04:00
Cody Henthorne
4cd433b6bc Retain call start timestamp per peer to prevent race conditions. 2020-09-24 10:43:39 -04:00
Greyson Parrelli
f9a9ee6b0c Bump version to 4.72.0 2020-09-23 16:54:38 -04:00
Greyson Parrelli
1741f7ed58 Updated language translations. 2020-09-23 16:54:38 -04:00
Alan Evans
d459c751be Show linked device update message if we don't have the capability to join a group by link. 2020-09-23 16:54:38 -04:00
Alan Evans
34ef8b52f6 Display a loading message if group update message is taking a while to load. 2020-09-23 16:54:38 -04:00
Alan Evans
5ae96905bb Do not allow replying on reactions and messages without visible content. 2020-09-23 16:54:38 -04:00
Alan Evans
b1fdbc0151 Refresh own GV2 capability on group create. 2020-09-23 16:54:38 -04:00
Alan Evans
a5ad27b5f2 Hide "My contacts" phone number privacy option. 2020-09-23 16:54:38 -04:00
Greyson Parrelli
efcd5052a2 Remove Pixel 4 from the CameraX blacklist on Android 11. 2020-09-23 16:54:38 -04:00
Greyson Parrelli
f2b10c0ba8 Always include ourselves in optimistic profile fetches. 2020-09-23 16:54:38 -04:00
Greyson Parrelli
f182be2d79 Inline CDS feature flag. 2020-09-23 16:54:38 -04:00
Greyson Parrelli
41b10630bb Default to WEBP for sticker contentTypes. 2020-09-23 16:54:38 -04:00
Alan Evans
45915bed90 Inline GV2 feature flag. 2020-09-23 16:54:38 -04:00
Greyson Parrelli
a2c2ab428a Fallback to profile fetches for unlisted contacts. 2020-09-23 16:54:38 -04:00
Alan Evans
a05f74d302 Do not set color before profile name is known. 2020-09-23 16:54:38 -04:00
Alan Evans
74e94f3a97 Separate capability reads from writes and introduce gv2-2 write flag. 2020-09-23 16:54:38 -04:00
Christian Ascheberg
15ee8c6cac Fix timestamp of missed call record.
Fixes #7647
2020-09-23 16:54:38 -04:00
Alex Hart
18957b1f41 Remove members menu item for group message requests. 2020-09-23 16:54:38 -04:00
Cody Henthorne
29930cac41 Use mention-updated body for unread reaction notification text. 2020-09-23 16:54:38 -04:00
Cody Henthorne
e3338dc3ff Add MMS info to conversation settings. 2020-09-23 16:54:38 -04:00
Greyson Parrelli
97b7b4a501 Fix crash when receiving SMS before finishing registration.
If someone has set Signal as the default SMS but has cleared data or
otherwise reset the app's storage state, it can get into a weird
situation. Notably, it'll crash because SmsReceiveJob.onRun() expects
Recipient.self() to be available.

However, it also makes it impossible to get the registration SMS,
because the app won't post a notification for the code.

This change will post notifications and SmsRetriever broadcasts for
relevant SMS messages.
2020-09-23 16:54:38 -04:00
Greyson Parrelli
b471a72856 Don't show the link preview megaphone to new users. 2020-09-23 16:54:38 -04:00
Greyson Parrelli
fed7d911a3 Revert "Listen to the uiMode configuration changes."
This reverts commit dda98a474d.

This commit ended up causing spontaneous theme changes that have been
hard to track down. It's likely it just didn't fit into our theme system
well. We need to take a closer look, but in the meantime, a revert is in
order.
2020-09-23 16:54:38 -04:00
Cody Henthorne
ca442970a3 Add Research Megaphone. 2020-09-23 16:54:38 -04:00
Angus Turnbull
9dbb77c10a Remove some calls to GMS APIs for utility functions.
Fixes #9629
2020-09-23 16:54:38 -04:00
Dan
1116502bc0 Add vCard support for received MMS. 2020-09-23 16:54:38 -04:00
Cody Henthorne
edaf17bdd4 Fix invisible media controls and notch jank.
Fixes #9993.
2020-09-23 16:54:38 -04:00
Alan Evans
c61d731358 Allow side-by-side installation of staging build. 2020-09-23 16:54:38 -04:00
Cody Henthorne
a8415a3484 Add pre-join vanity view for 1:1 video calls. 2020-09-23 16:54:38 -04:00
Alan Evans
cd2467085e Correct storage query deleted filter argument. 2020-09-23 16:54:38 -04:00
Alan Evans
64efb3d2a4 Do not set or read reaction target phone number. 2020-09-23 16:54:38 -04:00
Alex Hart
e05f137bd8 Add animations to call screen. 2020-09-23 16:54:38 -04:00
Greyson Parrelli
0c73ddc08b Ensure we HTML-decode the <title> tag.
Fixes #10020
2020-09-23 16:54:38 -04:00
Greyson Parrelli
19cc43c442 Add a charging constraint to the backup job. 2020-09-23 16:54:38 -04:00
Greyson Parrelli
7108fc81a9 Prevent redundant JobScheduler jobs.
Some devices actually enforce a scheduling rate, and will crash if you
submit more than, say, 250 jobs in 1 minute. This can happen when
catching up with messages and scheduling a lot of
PushDecryptMessageJobs.

While it'd be tricky to limit jobs with constraints, this just does the
simple thing of not enqueueing unnecessary jobs for constraint-less
jobs.
2020-09-23 16:54:38 -04:00
Alex Hart
5943b9d7d6 Fix sending receipts.
Fixes #10016
2020-09-23 16:54:38 -04:00
Alex Hart
0271e4c918 Add lifecycle check in SnackbarAsyncTask. 2020-09-23 16:54:38 -04:00
Greyson Parrelli
9dc33eff3a Remove thumbnails from the AttachmentDatabase.
Glide can do everything for us now, including video thumbnails.
2020-09-23 16:54:38 -04:00
Jim Gustafson
5aef1c8a68 Update to RingRTC v2.7.0 2020-09-23 16:54:38 -04:00
Alan Evans
c608a05270 Prevent a resolve call in main. 2020-09-23 16:54:38 -04:00
Cody Henthorne
e2cfd247c3 Fix mention parsing for quotes. 2020-09-23 16:54:38 -04:00
Greyson Parrelli
97eb9154b2 Prevent NPE when setting sticker emoji. 2020-09-23 16:54:38 -04:00
Jim Gustafson
d7ff635445 RingRTC: Update to v2.6.0
Co-authored-by: Peter Thatcher <peter@signal.org>
2020-09-23 16:54:38 -04:00
Alan Evans
aff57fb54e Create the temporary backup file hidden in the final location.
Fixes #10003
2020-09-23 16:54:38 -04:00
Greyson Parrelli
e89285a219 Reduce log noise. 2020-09-23 16:54:38 -04:00
Greyson Parrelli
706f43caa8 Remove AttachmentsV3 feature flag. 2020-09-23 16:54:38 -04:00
Cody Henthorne
dc4faf57cb Add foundational UX and state support for Group Calling. 2020-09-23 16:54:38 -04:00
Alex Hart
7baf8052a2 Fix savedInstanceState crash. 2020-09-23 16:54:37 -04:00
Alan Evans
d3c59585fd Bump version to 4.71.5 2020-09-14 11:16:09 -03:00
Alan Evans
859bb8dc79 Updated language translations. 2020-09-14 11:12:30 -03:00
Alan Evans
58cd2e07ba Add some required face blurring models back.
Fixes #10009
2020-09-14 10:49:33 -03:00
Greyson Parrelli
a5a6fb590a Bump version to 4.71.4 2020-09-10 18:03:51 -04:00
Greyson Parrelli
3619993e68 Updated language translations. 2020-09-10 18:03:28 -04:00
Greyson Parrelli
88e12c78fa Disable mentions megaphone. 2020-09-10 17:54:57 -04:00
Alan Evans
5c285b4ac6 Cycle groups v2 feature flag. 2020-09-10 18:47:36 -03:00
Cody Henthorne
c6b729c470 Bump version to 4.71.3 2020-09-10 15:38:55 -04:00
Cody Henthorne
890014759e Updated language translations. 2020-09-10 15:38:12 -04:00
Cody Henthorne
68c1c43381 Update radio styling in storage settings. 2020-09-10 14:40:29 -04:00
Greyson Parrelli
d0dfcaaad5 Fix issue with storage key intersections.
- When doing the intersection, ignore keys that have type mismatches (same storageId, different types)
- If we detect that scenario, schedule a force push to happen afterwards
- Also schedule a force push afterwards if we detect that there's keys in the manifest that don't have any storage item on the service
2020-09-10 14:01:41 -04:00
Alan Evans
3cffaddc0a Validate incoming Group lengths and remote delete entries if wrong.
Ignore incoming messages with bad V1 group lengths.
2020-09-10 14:39:29 -03:00
Alex Hart
bf4cac0c82 Fix unarchive menu action. 2020-09-10 13:49:16 -03:00
Alex Hart
f680749a00 Use proper lifecycle for SimpleTask which touches fragment view. 2020-09-10 13:40:09 -03:00
Cody Henthorne
13a67980d9 Fix wrong timestamp being used when trimming by length. 2020-09-10 12:09:28 -04:00
Alan Evans
f110d595d2 Fix selection limit for add members GV1.
Fixes #10005
2020-09-10 09:59:57 -03:00
Cody Henthorne
9c8857352b Bump version to 4.71.2 2020-09-09 16:09:49 -04:00
Cody Henthorne
c09a1fdba8 Updated language translations. 2020-09-09 16:04:27 -04:00
Greyson Parrelli
cdc7033a51 Update CDS enclave. 2020-09-09 15:38:42 -04:00
Alex Hart
fa30c759d7 Fix PIP positioning in video calls. 2020-09-09 13:06:38 -03:00
Fumiaki Yoshimatsu
d040be2df0 Use the light styles in the action bar style in the light theme, but keep the dark theme version of it in the action mode.
Fixes #9932
2020-09-09 12:24:45 -03:00
Alan Evans
935c831a7f Fix equality comparison causing blank updates and "The group was updated" messages. 2020-09-09 12:16:09 -03:00
Cody Henthorne
867e95eef1 Re-download sticker if backing file data no longer exists. 2020-09-09 11:15:34 -04:00
Alan Evans
2ee04bd1b6 Insert placeholder group on GV2 storage service sync. 2020-09-09 11:59:09 -03:00
Greyson Parrelli
75d567e555 Implement new client deprecation UI. 2020-09-09 10:22:22 -04:00
Alex Hart
d8a489971c Fix missing reply arrows. 2020-09-09 10:42:14 -03:00
Greyson Parrelli
19ce5b5c76 Reduce APNGParser logging. 2020-09-08 18:08:40 -04:00
Greyson Parrelli
7c70ea4d3e Change directory refresh interval to every 24 hours. 2020-09-08 18:06:09 -04:00
Greyson Parrelli
2784285d47 Add support for fetching remote deprecation. 2020-09-08 18:03:56 -04:00
Cody Henthorne
c946a7a1d5 Bump version to 4.71.1 2020-09-08 14:30:22 -04:00
Greyson Parrelli
3e60b49b8b Updated language translations. 2020-09-08 14:25:34 -04:00
Cody Henthorne
4e7331bbb8 Fix typo in trim message history copy. 2020-09-08 14:15:10 -04:00
Cody Henthorne
b8c7e86223 Fix improper deletion of stickers when restored from backup. 2020-09-08 14:07:56 -04:00
Alex Hart
3b925f8674 Add in-app donate button to preferences screen. 2020-09-08 12:48:52 -03:00
Cody Henthorne
f1f6d41c73 Bumped version to 4.71.0 2020-09-08 09:47:58 -04:00
Alan Evans
29ef1cb1be Updated language translations. 2020-09-08 09:47:58 -04:00
Alan Evans
4296085d65 Show no notification actions when the message content is hidden.
Fixes #9928
2020-09-08 09:47:57 -04:00
Alan Evans
c797b09228 Set profile sharing based on who added you to the group. 2020-09-08 09:47:57 -04:00
Greyson Parrelli
a870ef0030 Set isRecipientUpdate based on delivery status, not address count.
We were setting isRecipientUpdate to `true` incorrectly if there were
unregistered people in the group, resulting in the message not being
rendered on linked devices. Instead of using the address count, we can
just look at the current receipt status of the message.

Fixes #9981
2020-09-08 09:47:57 -04:00
Alan Evans
43ed9e7310 Set discoverable account attribute. 2020-09-08 09:47:57 -04:00
Cody Henthorne
bcd27355f9 Add trim conversations by time option. 2020-09-08 09:47:57 -04:00
Alan Evans
6a14dc69c0 Make Group V2 creation driven by version flag. 2020-09-03 20:23:26 -04:00
Jim Gustafson
ed9acd25f9 Ensure serial handling of calling events and improve busy UX. 2020-09-03 20:23:26 -04:00
Alan Evans
7b24e66ed3 Phone number privacy settings and certificate support behind feature flag. 2020-09-03 20:23:26 -04:00
Alan Evans
abd3d4b546 Group link copy changes. 2020-09-03 20:23:26 -04:00
Alan Evans
4040c4240a Lighter weight mentions membership query. 2020-09-03 20:23:26 -04:00
Alan Evans
1ee747f3ef Always share profile as part of unblocking. 2020-09-03 20:23:26 -04:00
Alan Evans
f88874bec8 Default values for member level and admin when no UUID. 2020-09-03 20:23:26 -04:00
Greyson Parrelli
ed440a2150 Do not clear UUID for unregistered users.
Otherwise, a number could be unregistered and re-registered by a
different person, assigning a new UUID to an existing RecipientId,
which we never want to do.
2020-09-03 20:23:26 -04:00
Greyson Parrelli
2fd46b196b Show sticker emoji in notification. 2020-09-03 20:23:26 -04:00
Greyson Parrelli
12dfcaf7e7 Log sent timestamp with message sends. 2020-09-03 20:23:26 -04:00
Greyson Parrelli
f4a199f621 Add support for animated stickers. 2020-09-03 20:23:26 -04:00
Alan Evans
bb708e0aa3 Ignore link preview descriptions that match the title. 2020-09-03 20:23:26 -04:00
Alan Evans
d625740ca4 Ensure feature flag is string before cast. 2020-09-03 20:23:26 -04:00
Greyson Parrelli
250402e9b9 Add support for rendering APNGs. 2020-09-03 20:23:26 -04:00
Jim Gustafson
1d2ffe56fb Update to RingRTC v2.5.1 2020-09-01 15:43:07 -04:00
Alan Evans
d16c0d2887 Prevent autofill for username editor. 2020-09-01 15:43:07 -04:00
Cody Henthorne
b3555f2f94 Use updated Safety Number Change dialog for calls.
Fixes [#9940](https://github.com/signalapp/Signal-Android/issues/9940)
2020-09-01 15:43:07 -04:00
Greyson Parrelli
83a638fc6d Bump version to 4.70.5 2020-09-01 14:56:32 -04:00
Greyson Parrelli
f1534a710f Updated language translations. 2020-09-01 14:56:08 -04:00
Greyson Parrelli
a16845340b Update CDS enclave. 2020-09-01 14:56:08 -04:00
Alan Evans
ffa4725f8e Bump version to 4.70.4 2020-08-31 12:54:22 -03:00
Alan Evans
7792c66c64 Updated language translations. 2020-08-31 12:50:08 -03:00
Alan Evans
1a3985d709 Add QR group link share. 2020-08-31 12:35:38 -03:00
Greyson Parrelli
4714895c59 Do not attempt to send to unregistered users when using CDS flag.
CDS is slow, and unregistered users will always trigger a CDS lookup on
send (since we can't get their UUID).

This starts skipping sends to unregistered users and shortens the time
window to do a full CDS lookup from every 12 hours to every 6 hours.
2020-08-31 11:33:57 -04:00
Fumiaki Yoshimatsu
1e37951701 Use onCreateOptionsMenu when to inflate a menu in order for menu items to appear correctly in RTL languages.
The bug was reported in
https://community.signalusers.org/t/beta-feedback-for-the-upcoming-android-4-70-release/16449/20?u=alan-signal, but it was not necessarily a regression caused by the commit suggested in the forum post. It is more like that the bug was finally exposed by the commit. Before the commit the menu items were not properly aligned nor translated upon configuration changes in RTL languages.
2020-08-31 12:12:15 -03:00
Alan Evans
e8be1ad752 Handle GV2 sync messages. 2020-08-31 12:07:03 -03:00
Alan Evans
e316a70b6c Fix group limit enforcement and display. 2020-08-31 12:02:50 -03:00
Alan Evans
40a8d21c15 Fix to allow send of Signal invitation SMS to a single person.
Fixes #9970
2020-08-31 11:33:50 -03:00
Alan Evans
28d5ca7ed9 Bump version to 4.70.3 2020-08-28 10:49:31 -03:00
Alan Evans
110b18545f Updated language translations. 2020-08-28 10:44:03 -03:00
Alan Evans
a478605da4 Remove requesting members if they are directly added to the group. 2020-08-28 10:32:20 -03:00
Alan Evans
f5f1589813 Fix class cast exception when member is approved. 2020-08-28 10:32:20 -03:00
Greyson Parrelli
0c332b6adb Fix corner cases with LinkPreviewViewModel enabled state. 2020-08-28 09:30:03 -04:00
Greyson Parrelli
ba712ce357 Fix crash with link preview date formatting on Android < 7.
The 'X' wasn't supported until Android 7.
2020-08-28 09:30:03 -04:00
Alan Evans
2d2395accf Hide block options if recipient is not blockable. 2020-08-28 10:13:23 -03:00
Alan Evans
8634289b7a Bump version to 4.70.2 2020-08-27 17:39:17 -03:00
Alan Evans
45043fb9a8 Updated language translations. 2020-08-27 17:38:23 -03:00
Cody Henthorne
0449795725 Make top gradient disappear with call controls.
Fixes [#9951](https://github.com/signalapp/Signal-Android/issues/9951)
2020-08-27 16:26:15 -04:00
Alan Evans
a96093f1b7 Exclude unused facial models from APK. 2020-08-27 17:01:10 -03:00
Alex Hart
bd4f7691e9 Add proper background color to camera icon.
Fixes #9945
2020-08-27 17:00:05 -03:00
Alex Hart
e12acbae70 Add @ to username in preferences. 2020-08-27 16:34:21 -03:00
Alan Evans
48dc4eac10 Bump version to 4.70.1 2020-08-27 12:25:39 -03:00
Alan Evans
a869c92eee Updated language translations. 2020-08-27 12:23:00 -03:00
Greyson Parrelli
4fefd14538 Add unit test to prevent shipping forced feature flags. 2020-08-27 11:14:20 -04:00
Greyson Parrelli
c09dbfa47c Prevent corner-case where link previews were generated for SMS.
Also added some hardening to make sure that it's impossible for any link
previews to be fetched if the setting is disabled (this was already the
case in practice, we just have some assertions in there now).

Fixes #9956
2020-08-27 12:12:44 -03:00
Alan Evans
d3c9f66de6 Prevent simple dialog flicker. 2020-08-27 12:12:44 -03:00
Alan Evans
01d7694108 Add reset confirmation dialog and copy to group link management screen. 2020-08-27 12:12:44 -03:00
Alex Hart
1425b651d4 Update username UX and UI. 2020-08-27 12:12:44 -03:00
Greyson Parrelli
b1befbeefc Add additional LinkPreviewUtil unit tests.
Also updated the date format -- funnily enough Android will work with
either Z or X in the format, but the test JVM will fail if it doesn't
use X. X is definitely the correct thing to use based on the Javadoc, I
think Android's implementation is just a little more lenient.
2020-08-27 09:32:33 -04:00
Panagiotis Vasilopoulos
3a9a84a0b1 Do not attempt to create link previews for .i2p links 2020-08-27 10:01:50 -03:00
Alan Evans
368284cccc Enable auto verify for signal.group links. 2020-08-26 20:48:42 -03:00
Alan Evans
ef777f4db9 Make group links remote capable. 2020-08-26 18:02:42 -03:00
3702 changed files with 250179 additions and 72456 deletions

4
.editorconfig Normal file
View File

@@ -0,0 +1,4 @@
root = true
[*.kt]
indent_size = 2

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

@@ -6,6 +6,7 @@ on:
branches:
- 'master'
- '4.**'
- '5.**'
jobs:
build:
@@ -13,18 +14,25 @@ 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;20.0.5594570" --sdk_root=${ANDROID_SDK_ROOT}
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
- name: Remove Android S
run: $ANDROID_HOME/tools/bin/sdkmanager --uninstall "platforms;android-S"
- 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'

18
.github/workflows/docker.yml vendored Normal file
View File

@@ -0,0 +1,18 @@
name: Reproducible Build Check
on:
schedule:
- cron: '0 5 * * *'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build image
run: cd reproducible-builds && docker build -t signal-android . && cd ..
- name: Test build
run: docker run --rm -v $(pwd):/project -w /project signal-android ./gradlew clean assembleRelease

4
.gitignore vendored
View File

@@ -1,6 +1,8 @@
.classpath
captures/
project.properties
keystore.debug.properties
keystore.staging.properties
.project
.settings
bin/
@@ -23,5 +25,5 @@ ffpr
test/androidTestEspresso/res/values/arrays.xml
obj/
jni/libspeex/.deps/
*.sh
pkcs11.password
dev.keystore

193
.idea/codeStyles/Project.xml generated Normal file
View File

@@ -0,0 +1,193 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="RIGHT_MARGIN" value="240" />
<option name="FORMATTER_TAGS_ENABLED" value="true" />
<option name="SOFT_MARGINS" value="160" />
<JavaCodeStyleSettings>
<option name="GENERATE_FINAL_LOCALS" value="true" />
<option name="DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION" value="true" />
<option name="ALIGN_MULTILINE_ANNOTATION_PARAMETERS" value="true" />
<option name="ALIGN_MULTILINE_TEXT_BLOCKS" value="true" />
</JavaCodeStyleSettings>
<JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value />
</option>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<codeStyleSettings language="JAVA">
<option name="BRACE_STYLE" value="5" />
<option name="CLASS_BRACE_STYLE" value="5" />
<option name="METHOD_BRACE_STYLE" value="5" />
<option name="ALIGN_MULTILINE_CHAINED_METHODS" value="true" />
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
<option name="ALIGN_MULTILINE_BINARY_OPERATION" value="true" />
<option name="ALIGN_MULTILINE_ASSIGNMENT" value="true" />
<option name="ALIGN_MULTILINE_TERNARY_OPERATION" value="true" />
<option name="ALIGN_MULTILINE_THROWS_LIST" value="true" />
<option name="ALIGN_MULTILINE_EXTENDS_LIST" value="true" />
<option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
<option name="ALIGN_GROUP_FIELD_DECLARATIONS" value="true" />
<option name="ALIGN_CONSECUTIVE_VARIABLE_DECLARATIONS" value="true" />
<option name="ALIGN_CONSECUTIVE_ASSIGNMENTS" value="true" />
<option name="SPACE_WITHIN_ARRAY_INITIALIZER_BRACES" value="true" />
<option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="WRAP_FIRST_METHOD_IN_CALL_CHAIN" value="true" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="KEEP_SIMPLE_BLOCKS_IN_ONE_LINE" value="true" />
<option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="true" />
<option name="KEEP_SIMPLE_LAMBDAS_IN_ONE_LINE" value="true" />
<option name="KEEP_MULTIPLE_EXPRESSIONS_IN_ONE_LINE" value="true" />
<option name="METHOD_ANNOTATION_WRAP" value="0" />
<option name="CLASS_ANNOTATION_WRAP" value="0" />
<option name="FIELD_ANNOTATION_WRAP" value="0" />
<option name="ENUM_CONSTANTS_WRAP" value="5" />
<option name="WRAP_ON_TYPING" value="0" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
<arrangement>
<groups>
<group>
<type>GETTERS_AND_SETTERS</type>
<order>KEEP</order>
</group>
<group>
<type>OVERRIDDEN_METHODS</type>
<order>KEEP</order>
</group>
<group>
<type>DEPENDENT_METHODS</type>
<order>BREADTH_FIRST</order>
</group>
</groups>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="XML">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@@ -1,25 +0,0 @@
FROM ubuntu:17.10
RUN dpkg --add-architecture i386 && \
apt-get update -y && \
apt-get install -y software-properties-common && \
apt-get update -y && \
apt-get install -y libc6:i386=2.26-0ubuntu2.1 libncurses5:i386=6.0+20160625-1ubuntu1 libstdc++6:i386=7.2.0-8ubuntu3.2 lib32z1=1:1.2.11.dfsg-0ubuntu2 wget openjdk-8-jdk=8u171-b11-0ubuntu0.17.10.1 git unzip opensc pcscd && \
rm -rf /var/lib/apt/lists/* && \
apt-get autoremove -y && \
apt-get clean
ENV ANDROID_SDK_FILENAME android-sdk_r24.4.1-linux.tgz
ENV ANDROID_SDK_URL https://dl.google.com/android/${ANDROID_SDK_FILENAME}
ENV ANDROID_API_LEVELS android-28
ENV ANDROID_BUILD_TOOLS_VERSION 28.0.3
ENV ANDROID_HOME /usr/local/android-sdk-linux
ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools
RUN cd /usr/local/ && \
wget -q ${ANDROID_SDK_URL} && \
tar -xzf ${ANDROID_SDK_FILENAME} && \
rm ${ANDROID_SDK_FILENAME}
RUN echo y | android update sdk --no-ui -a --filter ${ANDROID_API_LEVELS}
RUN echo y | android update sdk --no-ui -a --filter extra-android-m2repository,extra-android-support,extra-google-google_play_services,extra-google-m2repository
RUN echo y | android update sdk --no-ui -a --filter tools,platform-tools,build-tools-${ANDROID_BUILD_TOOLS_VERSION}
RUN rm -rf ${ANDROID_HOME}/tools && unzip ${ANDROID_HOME}/temp/*.zip -d ${ANDROID_HOME}

View File

@@ -2,31 +2,17 @@ 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'
}
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.3'
classpath 'androidx.navigation:navigation-safe-args-gradle-plugin:2.1.0'
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.10'
}
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.google.protobuf'
apply plugin: 'androidx.navigation.safeargs'
apply plugin: 'witness'
apply plugin: 'org.jlleitschuh.gradle.ktlint'
apply from: 'translations.gradle'
apply from: 'witness-verifications.gradle'
apply plugin: 'org.jetbrains.kotlin.android'
apply plugin: 'app.cash.exhaustive'
repositories {
maven {
@@ -35,24 +21,12 @@ 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 {
includeGroupByRegex "com\\.github\\.dmytrodanylyk\\.circular-progress-button\\.*"
}
}
maven {
url "https://raw.github.com/signalapp/maven/master/sqlcipher/release/"
content {
includeGroupByRegex "org\\.signal.*"
}
}
maven { // textdrawable
url 'https://dl.bintray.com/amulyakhare/maven'
content {
@@ -63,6 +37,9 @@ repositories {
mavenCentral()
jcenter()
mavenLocal()
maven {
url "https://dl.cloudsmith.io/qxAgwaeEE1vN8aLU/mobilecoin/mobilecoin/maven/"
}
}
protobuf {
@@ -80,38 +57,59 @@ protobuf {
}
}
def canonicalVersionCode = 697
def canonicalVersionName = "4.70.0"
def canonicalVersionCode = 879
def canonicalVersionName = "5.17.1"
def postFixSize = 10
def postFixSize = 100
def abiPostFix = ['universal' : 0,
'armeabi-v7a' : 1,
'arm64-v8a' : 2,
'x86' : 3,
'x86_64' : 4]
def keystores = [ 'debug' : loadKeystoreProperties('keystore.debug.properties') ]
android {
flavorDimensions "none"
compileSdkVersion 28
buildToolsVersion '28.0.3'
buildToolsVersion BUILD_TOOL_VERSION
compileSdkVersion COMPILE_SDK
flavorDimensions 'distribution', 'environment'
useLibrary 'org.apache.http.legacy'
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = ["-Xallow-result-return-type"]
}
dexOptions {
javaMaxHeapSize "4g"
}
signingConfigs {
if (keystores.debug != null) {
debug {
storeFile file("${project.rootDir}/${keystores.debug.storeFile}")
storePassword keystores.debug.storePassword
keyAlias keystores.debug.keyAlias
keyPassword keystores.debug.keyPassword
}
}
}
defaultConfig {
versionCode canonicalVersionCode * postFixSize
versionName canonicalVersionName
minSdkVersion 19
targetSdkVersion 28
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\""
@@ -119,17 +117,29 @@ 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[]", "SIGNAL_SFU_INTERNAL_NAMES", "new String[]{\"Test\", \"Staging\"}"
buildConfigField "String[]", "SIGNAL_SFU_INTERNAL_URLS", "new String[]{\"https://sfu.test.voip.signal.org\", \"https://sfu.staging.voip.signal.org\"}"
buildConfigField "String", "CONTENT_PROXY_HOST", "\"contentproxy.signal.org\""
buildConfigField "int", "CONTENT_PROXY_PORT", "443"
buildConfigField "String", "SIGNAL_AGENT", "\"OWA\""
buildConfigField "String", "CDS_MRENCLAVE", "\"bd123560b01c8fa92935bc5ae15cd2064e5c45215f23f0bd40364d521329d2ad\""
buildConfigField "String", "KBS_ENCLAVE_NAME", "\"fe7c1bfae98f9b073d220366ea31163ee82f6d04bead774f71ca8e5c40847bfe\""
buildConfigField "String", "KBS_SERVICE_ID", "\"fe7c1bfae98f9b073d220366ea31163ee82f6d04bead774f71ca8e5c40847bfe\""
buildConfigField "String", "KBS_MRENCLAVE", "\"a3baab19ef6ce6f34ab9ebb25ba722725ae44a8872dc0ff08ad6d83a9489de87\""
buildConfigField "String", "CDS_MRENCLAVE", "\"c98e00a4e3ff977a56afefe7362a27e4961e4f19e211febfbb19b897e6b80b15\""
buildConfigField "KbsEnclave", "KBS_ENCLAVE", "new KbsEnclave(\"fe7c1bfae98f9b073d220366ea31163ee82f6d04bead774f71ca8e5c40847bfe\"," +
"\"fe7c1bfae98f9b073d220366ea31163ee82f6d04bead774f71ca8e5c40847bfe\", " +
"\"a3baab19ef6ce6f34ab9ebb25ba722725ae44a8872dc0ff08ad6d83a9489de87\")";
buildConfigField "KbsEnclave[]", "KBS_FALLBACKS", "new KbsEnclave[0]"
buildConfigField "String", "UNIDENTIFIED_SENDER_TRUST_ROOT", "\"BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF\""
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 "String", "DEFAULT_CURRENCIES", "\"EUR,AUD,GBP,CAD,CNY\""
buildConfigField "int[]", "MOBILE_COIN_REGIONS", "new int[]{44}"
buildConfigField "String", "GIPHY_API_KEY", "\"3o6ZsYH6U6Eri53TXy\""
buildConfigField "String", "RECAPTCHA_PROOF_URL", "\"https://signalcaptchas.org/challenge/generate.html\""
buildConfigField "String", "BUILD_DISTRIBUTION_TYPE", "\"unset\""
buildConfigField "String", "BUILD_ENVIRONMENT_TYPE", "\"unset\""
buildConfigField "String", "BUILD_VARIANT_TYPE", "\"unset\""
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
@@ -150,8 +160,9 @@ android {
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
coreLibraryDesugaringEnabled true
sourceCompatibility JAVA_VERSION
targetCompatibility JAVA_VERSION
}
packagingOptions {
@@ -162,10 +173,16 @@ android {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
exclude 'META-INF/proguard/androidx-annotations.pro'
exclude '/org/spongycastle/x509/CertPathReviewerMessages.properties'
exclude '/org/spongycastle/x509/CertPathReviewerMessages_de.properties'
}
buildTypes {
debug {
if (keystores['debug'] != null) {
signingConfig signingConfigs.debug
}
isDefault true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard/proguard-firebase-messaging.pro',
@@ -188,9 +205,95 @@ android {
'proguard/proguard.cfg'
testProguardFiles 'proguard/proguard-automation.pro',
'proguard/proguard.cfg'
buildConfigField "String", "BUILD_VARIANT_TYPE", "\"Debug\""
}
staging {
flipper {
initWith debug
isDefault false
minifyEnabled false
matchingFallbacks = ['debug']
buildConfigField "String", "BUILD_VARIANT_TYPE", "\"Flipper\""
}
release {
minifyEnabled true
proguardFiles = buildTypes.debug.proguardFiles
buildConfigField "String", "BUILD_VARIANT_TYPE", "\"Release\""
}
perf {
initWith debug
isDefault false
debuggable false
matchingFallbacks = ['debug']
buildConfigField "String", "BUILD_VARIANT_TYPE", "\"Perf\""
}
mock {
initWith debug
isDefault false
minifyEnabled false
matchingFallbacks = ['debug']
buildConfigField "String", "BUILD_VARIANT_TYPE", "\"Mock\""
}
}
productFlavors {
play {
dimension 'distribution'
isDefault true
ext.websiteUpdateUrl = "null"
buildConfigField "boolean", "PLAY_STORE_DISABLED", "false"
buildConfigField "String", "NOPLAY_UPDATE_URL", "$ext.websiteUpdateUrl"
buildConfigField "String", "BUILD_DISTRIBUTION_TYPE", "\"play\""
}
website {
dimension 'distribution'
ext.websiteUpdateUrl = "https://updates.signal.org/android"
buildConfigField "boolean", "PLAY_STORE_DISABLED", "true"
buildConfigField "String", "NOPLAY_UPDATE_URL", "\"$ext.websiteUpdateUrl\""
buildConfigField "String", "BUILD_DISTRIBUTION_TYPE", "\"website\""
}
internal {
dimension 'distribution'
ext.websiteUpdateUrl = "null"
buildConfigField "boolean", "PLAY_STORE_DISABLED", "false"
buildConfigField "String", "NOPLAY_UPDATE_URL", "$ext.websiteUpdateUrl"
buildConfigField "String", "BUILD_DISTRIBUTION_TYPE", "\"internal\""
}
nightly {
dimension 'distribution'
versionNameSuffix "-nightly-untagged-${getDateSuffix()}"
ext.websiteUpdateUrl = "null"
buildConfigField "boolean", "PLAY_STORE_DISABLED", "false"
buildConfigField "String", "NOPLAY_UPDATE_URL", "$ext.websiteUpdateUrl"
buildConfigField "String", "BUILD_DISTRIBUTION_TYPE", "\"internal\""
}
study {
dimension 'distribution'
applicationIdSuffix ".study"
ext.websiteUpdateUrl = "null"
buildConfigField "boolean", "PLAY_STORE_DISABLED", "false"
buildConfigField "String", "NOPLAY_UPDATE_URL", "$ext.websiteUpdateUrl"
buildConfigField "String", "BUILD_DISTRIBUTION_TYPE", "\"study\""
}
prod {
dimension 'environment'
isDefault true
buildConfigField "String", "MOBILE_COIN_ENVIRONMENT", "\"mainnet\""
buildConfigField "String", "BUILD_ENVIRONMENT_TYPE", "\"Prod\""
}
staging {
dimension 'environment'
applicationIdSuffix ".staging"
buildConfigField "String", "SIGNAL_URL", "\"https://textsecure-service-staging.whispersystems.org\""
buildConfigField "String", "STORAGE_URL", "\"https://storage-staging.signal.org\""
@@ -198,47 +301,55 @@ android {
buildConfigField "String", "SIGNAL_CDN2_URL", "\"https://cdn2-staging.signal.org\""
buildConfigField "String", "SIGNAL_CONTACT_DISCOVERY_URL", "\"https://api-staging.directory.signal.org\""
buildConfigField "String", "SIGNAL_KEY_BACKUP_URL", "\"https://api-staging.backup.signal.org\""
buildConfigField "String", "CDS_MRENCLAVE", "\"bd123560b01c8fa92935bc5ae15cd2064e5c45215f23f0bd40364d521329d2ad\""
buildConfigField "String", "KBS_ENCLAVE_NAME", "\"823a3b2c037ff0cbe305cc48928cfcc97c9ed4a8ca6d49af6f7d6981fb60a4e9\""
buildConfigField "String", "KBS_SERVICE_ID", "\"038c40bbbacdc873caa81ac793bb75afde6dfe436a99ab1f15e3f0cbb7434ced\""
buildConfigField "String", "CDS_MRENCLAVE", "\"c98e00a4e3ff977a56afefe7362a27e4961e4f19e211febfbb19b897e6b80b15\""
buildConfigField "KbsEnclave", "KBS_ENCLAVE", "new KbsEnclave(\"823a3b2c037ff0cbe305cc48928cfcc97c9ed4a8ca6d49af6f7d6981fb60a4e9\", " +
"\"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=\""
}
flipper {
initWith debug
minifyEnabled false
}
release {
minifyEnabled true
proguardFiles = buildTypes.debug.proguardFiles
}
}
buildConfigField "String", "MOBILE_COIN_ENVIRONMENT", "\"testnet\""
buildConfigField "String", "RECAPTCHA_PROOF_URL", "\"https://signalcaptchas.org/staging/challenge/generate.html\""
productFlavors {
play {
dimension "none"
ext.websiteUpdateUrl = "null"
buildConfigField "boolean", "PLAY_STORE_DISABLED", "false"
buildConfigField "String", "NOPLAY_UPDATE_URL", "$ext.websiteUpdateUrl"
}
website {
dimension "none"
ext.websiteUpdateUrl = "https://updates.signal.org/android"
buildConfigField "boolean", "PLAY_STORE_DISABLED", "true"
buildConfigField "String", "NOPLAY_UPDATE_URL", "\"$ext.websiteUpdateUrl\""
buildConfigField "String", "BUILD_ENVIRONMENT_TYPE", "\"Staging\""
}
}
android.applicationVariants.all { variant ->
variant.outputs.each { output ->
output.outputFileName = output.outputFileName.replace(".apk", "-${variant.versionName}.apk")
def abiName = output.getFilter("ABI") ?: 'universal'
def postFix = abiPostFix.get(abiName, 0)
if (output.baseName.contains('nightly')) {
output.versionCodeOverride = canonicalVersionCode * postFixSize + 5
def tag = getCurrentGitTag()
if (tag != null && tag.length() > 0) {
output.versionNameOverride = tag
}
} else {
output.outputFileName = output.outputFileName.replace(".apk", "-${variant.versionName}.apk")
def abiName = output.getFilter("ABI") ?: 'universal'
def postFix = abiPostFix.get(abiName, 0)
if (postFix >= postFixSize) throw new AssertionError("postFix is too large")
if (postFix >= postFixSize) throw new AssertionError("postFix is too large")
output.versionCodeOverride = canonicalVersionCode * postFixSize + postFix
output.versionCodeOverride = canonicalVersionCode * postFixSize + postFix
}
}
}
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)
} else if (distribution == 'internal' && buildType != 'flipper' && buildType != 'perf' && buildType != 'release') {
variant.setIgnore(true)
} else if (distribution == 'nightly' && environment != 'prod') {
variant.setIgnore(true)
} else if (distribution == 'nightly' && buildType != 'flipper' && buildType != 'perf' && buildType != 'release') {
variant.setIgnore(true)
}
}
@@ -256,37 +367,40 @@ android {
}
dependencies {
implementation 'androidx.core:core-ktx:1.5.0'
implementation 'androidx.fragment:fragment-ktx:1.2.5'
lintChecks project(':lintchecks')
implementation('androidx.appcompat:appcompat:1.1.0-beta01') {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
implementation ('androidx.appcompat:appcompat:1.2.0') {
force = true
}
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.legacy:legacy-support-v13:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.preference:preference:1.0.0'
implementation 'androidx.legacy:legacy-preference-v14:1.0.0'
implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation 'androidx.exifinterface:exifinterface:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.navigation:navigation-fragment:2.1.0'
implementation 'androidx.navigation:navigation-ui:2.1.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:1.0.0-alpha05'
implementation 'androidx.lifecycle:lifecycle-common-java8:2.1.0'
implementation "androidx.camera:camera-core:1.0.0-beta01"
implementation "androidx.camera:camera-camera2:1.0.0-beta01"
implementation "androidx.camera:camera-lifecycle:1.0.0-beta01"
implementation "androidx.camera:camera-core:1.0.0-beta11"
implementation "androidx.camera:camera-camera2:1.0.0-beta11"
implementation "androidx.camera:camera-lifecycle:1.0.0-beta11"
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 "androidx.sharetarget:sharetarget:1.1.0"
implementation ('com.google.firebase:firebase-messaging:20.2.0') {
implementation ('com.google.firebase:firebase-messaging:22.0.0') {
exclude group: 'com.google.firebase', module: 'firebase-core'
exclude group: 'com.google.firebase', module: 'firebase-analytics'
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
@@ -297,25 +411,37 @@ dependencies {
implementation 'com.google.android.exoplayer:exoplayer-core:2.9.1'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.9.1'
implementation 'com.google.android.exoplayer:extension-mediasession:2.9.1'
implementation 'org.conscrypt:conscrypt-android:2.0.0'
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.8.3'
implementation 'com.google.protobuf:protobuf-javalite:3.10.0'
implementation('com.mobilecoin:android-sdk:1.1.0') {
exclude group: 'com.google.protobuf'
}
implementation 'org.signal:argon2:13.1@aar'
implementation 'org.signal:ringrtc-android:2.5.0'
implementation 'org.signal:ringrtc-android:2.10.6'
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'
implementation 'com.github.chrisbanes:PhotoView:2.1.3'
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
annotationProcessor 'androidx.annotation:annotation:1.1.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0'
kapt 'androidx.annotation:annotation:1.1.0'
implementation 'com.makeramen:roundedimageview:2.1.0'
implementation 'com.pnikosis:materialish-progress:1.5'
implementation 'org.greenrobot:eventbus:3.0.0'
@@ -344,19 +470,22 @@ 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'
implementation 'org.signal:android-database-sqlcipher:3.5.9-S3'
implementation "net.zetetic:android-database-sqlcipher:4.4.3"
implementation "androidx.sqlite:sqlite:2.1.0"
implementation ('com.googlecode.ez-vcard:ez-vcard:0.9.11') {
exclude group: 'com.fasterxml.jackson.core'
exclude group: 'org.freemarker'
}
implementation 'dnsjava:dnsjava:2.1.9'
flipperImplementation 'com.facebook.flipper:flipper:0.32.2'
flipperImplementation 'com.facebook.soloader:soloader:0.8.2'
flipperImplementation 'com.facebook.flipper:flipper:0.91.0'
flipperImplementation 'com.facebook.soloader:soloader:0.10.1'
testImplementation 'junit:junit:4.12'
testImplementation 'org.assertj:assertj-core:3.11.1'
@@ -367,20 +496,28 @@ dependencies {
testImplementation 'org.powermock:powermock-classloading-xstream:1.7.4'
testImplementation 'androidx.test:core:1.2.0'
testImplementation ('org.robolectric:robolectric:4.2') {
testImplementation ('org.robolectric:robolectric:4.4') {
exclude group: 'com.google.protobuf', module: 'protobuf-java'
}
testImplementation 'org.robolectric:shadows-multidex:4.2'
testImplementation 'org.robolectric:shadows-multidex:4.4'
testImplementation 'org.hamcrest:hamcrest:2.2'
testImplementation(testFixtures(project(":libsignal-service")))
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.12.0"
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
implementation 'io.reactivex.rxjava3:rxkotlin:3.0.1'
}
dependencyVerification {
configuration = '(play|website)(Debug|Release)RuntimeClasspath'
configuration = '(play|website)(Prod|Staging)(Debug|Release)RuntimeClasspath'
}
def assembleWebsiteDescriptor = { variant, file ->
if (file.exists()) {
MessageDigest md = MessageDigest.getInstance("SHA-256");
@@ -424,29 +561,29 @@ def signProductionRelease = { variant ->
task signProductionPlayRelease {
doLast {
signProductionRelease(android.applicationVariants.find { (it.name == 'playRelease') })
signProductionRelease(android.applicationVariants.find { (it.name == 'playProdRelease') })
}
}
task signProductionInternalRelease {
doLast {
signProductionRelease(android.applicationVariants.find { (it.name == 'internalProdRelease') })
}
}
task signProductionWebsiteRelease {
doLast {
def variant = android.applicationVariants.find { (it.name == 'websiteRelease') }
def variant = android.applicationVariants.find { (it.name == 'websiteProdRelease') }
File signedRelease = signProductionRelease(variant).find { it.name.contains('universal') }
assembleWebsiteDescriptor(variant, signedRelease)
}
}
tasks.whenTaskAdded { task ->
if (task.name.equals("assemblePlayRelease")) {
task.finalizedBy signProductionPlayRelease
}
if (task.name.equals("assembleWebsiteRelease")) {
task.finalizedBy signProductionWebsiteRelease
}
}
def getLastCommitTimestamp() {
if (!(new File('.git').exists())) {
return System.currentTimeMillis().toString()
}
new ByteArrayOutputStream().withStream { os ->
def result = exec {
executable = 'git'
@@ -458,6 +595,39 @@ def getLastCommitTimestamp() {
}
}
def getGitHash() {
if (!(new File('.git').exists())) {
return "abcd1234"
}
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'rev-parse', '--short', 'HEAD'
standardOutput = stdout
}
return stdout.toString().trim()
}
def getCurrentGitTag() {
if (!(new File('.git').exists())) {
return ''
}
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'tag', '--points-at', 'HEAD'
standardOutput = stdout
}
def output = stdout.toString().trim()
if (output != null && output.size() > 0) {
return output.split('\n')[0];
} else {
return null
}
}
tasks.withType(Test) {
testLogging {
events "failed"
@@ -467,3 +637,20 @@ tasks.withType(Test) {
showStackTraces true
}
}
def loadKeystoreProperties(filename) {
def keystorePropertiesFile = file("${project.rootDir}/${filename}")
if (keystorePropertiesFile.exists()) {
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
return keystoreProperties;
} else {
return null;
}
}
def getDateSuffix() {
def date = new Date()
def formattedDate = date.format('yyyy-MM-dd-HH:mm')
return formattedDate
}

View File

@@ -31,6 +31,8 @@
<issue id="LogNotAppSignal" severity="error" />
<issue id="LogTagInlined" severity="error" />
<issue id="AlertDialogBuilderUsage" severity="warning" />
<issue id="RestrictedApi" severity="error">
<ignore path="*/org/thoughtcrime/securesms/mediasend/camerax/VideoCapture.java" />
<ignore path="*/org/thoughtcrime/securesms/mediasend/camerax/CameraXModule.java" />

View File

@@ -5,5 +5,12 @@
<application
android:name=".FlipperApplicationContext"
tools:replace="android:name"/>
tools:replace="android:name">
<activity
android:name="com.facebook.flipper.android.diagnostics.FlipperDiagnosticActivity"
android:exported="true" />
</application>
</manifest>

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,14 +15,18 @@ 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.util.Hex;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
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}
@@ -29,13 +34,31 @@ import java.util.Map;
*/
public class FlipperSqlCipherAdapter extends DatabaseDriver<FlipperSqlCipherAdapter.Descriptor> {
private static final String TAG = Log.tag(FlipperSqlCipherAdapter.class);
public FlipperSqlCipherAdapter(Context context) {
super(context);
}
@Override
public List<Descriptor> getDatabases() {
return Collections.singletonList(new Descriptor(DatabaseFactory.getRawDatabase(getContext())));
try {
Field databaseHelperField = DatabaseFactory.class.getDeclaredField("databaseHelper");
databaseHelperField.setAccessible(true);
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);
}
return Collections.emptyList();
}
@Override
@@ -215,7 +238,12 @@ public class FlipperSqlCipherAdapter extends DatabaseDriver<FlipperSqlCipherAdap
case Cursor.FIELD_TYPE_FLOAT:
return cursor.getDouble(column);
case Cursor.FIELD_TYPE_BLOB:
return cursor.getBlob(column);
byte[] blob = cursor.getBlob(column);
String bytes = blob != null ? "(blob) " + Hex.toStringCondensed(Arrays.copyOf(blob, Math.min(blob.length, 32))) : null;
if (bytes != null && bytes.length() == 32 && blob.length > 32) {
bytes += "...";
}
return bytes;
case Cursor.FIELD_TYPE_STRING:
default:
return cursor.getString(column);
@@ -223,9 +251,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;
}
@@ -235,11 +263,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,4 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="app_name">Signal (Flipper)</string>
</resources>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/core_red_shade"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

View File

@@ -3,9 +3,9 @@
xmlns:tools="http://schemas.android.com/tools"
package="org.thoughtcrime.securesms">
<uses-sdk tools:overrideLibrary="androidx.camera.core,androidx.camera.camera2,androidx.camera.lifecycle" />
<uses-sdk tools:overrideLibrary="androidx.camera.core,androidx.camera.camera2,androidx.camera.lifecycle,androidx.camera.view" />
<permission android:name="org.thoughtcrime.securesms.ACCESS_SECRETS"
<permission android:name="${applicationId}.ACCESS_SECRETS"
android:label="Access to TextSecure Secrets"
android:protectionLevel="signature" />
@@ -35,8 +35,10 @@
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.WRITE_SMS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.CAMERA" />
@@ -62,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" />
@@ -113,8 +114,8 @@
<meta-data android:name="google_analytics_adid_collection_enabled" android:value="false" />
<meta-data android:name="firebase_messaging_auto_init_enabled" android:value="false" />
<activity android:name="org.thoughtcrime.securesms.WebRtcCallActivity"
android:theme="@style/TextSecure.LightTheme.WebRTCCall"
<activity android:name=".WebRtcCallActivity"
android:theme="@style/TextSecure.DarkTheme.WebRTCCall"
android:excludeFromRecents="true"
android:screenOrientation="portrait"
android:supportsPictureInPicture="true"
@@ -127,44 +128,55 @@
android:theme="@style/TextSecure.DarkNoActionBar"
android:screenOrientation="portrait"
android:noHistory="true"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".InviteActivity"
android:theme="@style/Signal.Light.NoActionBar.Invite"
android:windowSoftInputMode="stateHidden"
android:parentActivityName=".MainActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode">
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.thoughtcrime.securesms.MainActivity" />
android:value=".MainActivity" />
</activity>
<activity android:name=".PromptMmsActivity"
android:label="Configure MMS Settings"
android:windowSoftInputMode="stateUnchanged"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".DeviceProvisioningActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode">
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
<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="tsdevice"/>
</intent-filter>
<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="sgnl"
android:host="linkdevice"/>
</intent-filter>
</activity>
<activity android:name=".preferences.MmsPreferencesActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
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|uiMode">
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT"/>
@@ -186,7 +198,7 @@
<meta-data
android:name="android.service.chooser.chooser_target_service"
android:value=".service.DirectShareService" />
android:value="androidx.sharetarget.ChooserTargetServiceCompat" />
</activity>
@@ -195,7 +207,7 @@
android:launchMode="singleTask"
android:noHistory="true"
android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode">
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
@@ -223,14 +235,6 @@
<category android:name="android.intent.category.MULTIWINDOW_LAUNCHER" />
</intent-filter>
<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.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"
@@ -238,16 +242,53 @@
</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" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="sgnl"
android:host="signal.group" />
</intent-filter>
<intent-filter android:autoVerify="true"
tools:targetApi="23">
<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.group"/>
</intent-filter>
<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"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:parentActivityName=".MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
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"
@@ -256,131 +297,151 @@
android:taskAffinity=""
android:excludeFromRecents="true"
android:theme="@style/TextSecure.LightTheme.Popup"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode" />
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|uiMode"/>
<activity android:name=".groups.ui.pendingmemberinvites.PendingMemberInvitesActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"
android:theme="@style/Theme.Signal.DayNight.NoActionBar" />
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".groups.ui.invitesandrequests.ManagePendingAndRequestingMembersActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"
android:theme="@style/Theme.Signal.DayNight.NoActionBar" />
<activity android:name=".groups.ui.managegroup.ManageGroupActivity"
android:windowSoftInputMode="stateAlwaysHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
<activity android:name=".recipients.ui.managerecipient.ManageRecipientActivity"
android:windowSoftInputMode="stateAlwaysHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
<activity android:name=".recipients.ui.disappearingmessages.RecipientDisappearingMessagesActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:theme="@style/Signal.DayNight.NoActionBar"
android:windowSoftInputMode="adjustResize"/>
<activity android:name=".DatabaseMigrationActivity"
android:theme="@style/NoAnimation.Theme.AppCompat.Light.DarkActionBar"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".migrations.ApplicationMigrationActivity"
android:theme="@style/NoAnimation.Theme.AppCompat.Light.DarkActionBar"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".PassphraseCreateActivity"
android:label="@string/AndroidManifest__create_passphrase"
android:windowSoftInputMode="stateUnchanged"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".PassphrasePromptActivity"
android:launchMode="singleTask"
android:theme="@style/TextSecure.LightIntroTheme"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".NewConversationActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:windowSoftInputMode="stateAlwaysVisible"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".PushContactSelectionActivity"
android:label="@string/AndroidManifest__select_contacts"
android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".giph.ui.GiphyActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".mediasend.MediaSendActivity"
android:theme="@style/TextSecure.FullScreenMedia"
android:windowSoftInputMode="stateHidden"
android:launchMode="singleTop"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".PassphraseChangeActivity"
android:label="@string/AndroidManifest__change_passphrase"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".VerifyIdentityActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".ApplicationPreferencesActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode">
<activity android:name=".components.settings.app.AppSettingsActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:theme="@style/Signal.DayNight.NoActionBar"
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=".components.settings.conversation.ConversationSettingsActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:theme="@style/Signal.DayNight.ConversationSettings"
android:windowSoftInputMode="stateAlwaysHidden">
</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"
android:windowSoftInputMode="stateUnchanged"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".revealable.ViewOnceMessageActivity"
android:launchMode="singleTask"
android:theme="@style/TextSecure.FullScreenMedia"
android:windowSoftInputMode="stateHidden"
android:excludeFromRecents="true"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".stickers.StickerManagementActivity"
android:launchMode="singleTask"
android:theme="@style/TextSecure.LightTheme"
android:windowSoftInputMode="stateUnchanged"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".DeviceActivity"
android:label="@string/AndroidManifest__linked_devices"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
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|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".MediaPreviewActivity"
android:label="@string/AndroidManifest__media_preview"
android:windowSoftInputMode="stateHidden"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".AvatarPreviewActivity"
android:label="@string/AndroidManifest__media_preview"
android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".mediaoverview.MediaOverviewActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".DummyActivity"
android:theme="@android:style/Theme.NoDisplay"
@@ -395,7 +456,7 @@
<activity android:name=".PlayServicesProblemActivity"
android:theme="@style/TextSecure.DialogActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".SmsSendtoActivity">
<intent-filter>
@@ -419,7 +480,7 @@
android:excludeFromRecents="true"
android:theme="@style/NoAnimation.Theme.BlackScreen"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode">
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@@ -431,41 +492,43 @@
<activity android:name=".mediasend.AvatarSelectionActivity"
android:theme="@style/TextSecure.FullScreenMedia"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".BlockedContactsActivity"
<activity android:name=".blocked.BlockedUsersActivity"
android:theme="@style/TextSecure.LightTheme"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".scribbles.ImageEditorStickerSelectActivity"
android:theme="@style/TextSecure.DarkTheme"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:theme="@style/Signal.DayNight.NoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".profiles.edit.EditProfileActivity"
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"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".lock.v2.KbsMigrationActivity"
android:theme="@style/TextSecure.LightRegistrationTheme"
android:windowSoftInputMode="adjustResize"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
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|uiMode"
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" />
@@ -473,39 +536,38 @@
<activity android:name=".messagerequests.MessageRequestMegaphoneActivity"
android:theme="@style/TextSecure.LightRegistrationTheme"
android:windowSoftInputMode="adjustResize"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".contactshare.ContactShareEditActivity"
android:theme="@style/TextSecure.LightTheme"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".contactshare.ContactNameEditActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".contactshare.SharedContactDetailsActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".ShortcutLauncherActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:exported="true"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity
android:name=".maps.PlacePickerActivity"
android:label="@string/PlacePickerActivity_title"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".MainActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" />
<activity android:name=".pin.PinRestoreActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" />
<activity android:name=".groups.ui.creategroup.CreateGroupActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar" />
@@ -520,13 +582,47 @@
android:theme="@style/Theme.Signal.DayNight.NoActionBar" />
<activity android:name=".groups.ui.chooseadmin.ChooseNewAdminActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"/>
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" />
<service android:enabled="true" android:name="org.thoughtcrime.securesms.service.WebRtcCallService"/>
<activity android:name=".megaphone.ClientDeprecatedActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode"
android:launchMode="singleTask" />
<activity android:name=".ratelimit.RecaptchaProofActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode" />
<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" />
<activity android:name=".reactions.edit.EditReactionsActivity"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<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"/>
<service android:name=".components.voice.VoiceNotePlaybackService">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
<receiver android:name="androidx.media.session.MediaButtonReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
<service android:name=".service.QuickResponseService"
android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
android:exported="true" >
@@ -555,13 +651,6 @@
<meta-data android:name="android.provider.CONTACTS_STRUCTURE" android:resource="@xml/contactsformat" />
</service>
<service android:name=".service.DirectShareService"
android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
<intent-filter>
<action android:name="android.service.chooser.ChooserTargetService" />
</intent-filter>
</service>
<service android:name=".service.GenericForegroundService"/>
<service android:name=".gcm.FcmFetchService" />
@@ -621,36 +710,33 @@
</intent-filter>
</receiver>
<receiver android:name=".notifications.AndroidAutoHeardReceiver"
android:exported="false">
<intent-filter>
<action android:name="org.thoughtcrime.securesms.notifications.ANDROID_AUTO_HEARD"/>
</intent-filter>
</receiver>
<receiver android:name=".notifications.AndroidAutoReplyReceiver"
android:exported="false">
<intent-filter>
<action android:name="org.thoughtcrime.securesms.notifications.ANDROID_AUTO_REPLY"/>
</intent-filter>
</receiver>
<receiver android:name=".service.ExpirationListener" />
<receiver android:name=".revealable.ViewOnceMessageManager$ViewOnceAlarm" />
<receiver android:name=".service.PendingRetryReceiptManager$PendingRetryReceiptAlarm" />
<receiver android:name=".service.TrimThreadsByDateManager$TrimThreadsByDateAlarm" />
<receiver android:name=".payments.backup.phrase.ClearClipboardAlarmReceiver" />
<provider android:name=".providers.PartProvider"
android:grantUriPermissions="true"
android:exported="false"
android:authorities="org.thoughtcrime.provider.securesms" />
android:authorities="${applicationId}.part" />
<provider android:name=".providers.BlobContentProvider"
android:authorities="${applicationId}.blob"
android:exported="false"
android:grantUriPermissions="true" />
<provider android:name=".providers.MmsBodyProvider"
android:grantUriPermissions="true"
android:exported="false"
android:authorities="org.thoughtcrime.provider.securesms.mms" />
android:authorities="${applicationId}.mms" />
<provider android:name="androidx.core.content.FileProvider"
android:authorities="org.thoughtcrime.securesms.fileprovider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
@@ -659,23 +745,19 @@
</provider>
<provider android:name=".database.DatabaseContentProviders$Conversation"
android:authorities="org.thoughtcrime.securesms.database.conversation"
android:exported="false" />
<provider android:name=".database.DatabaseContentProviders$ConversationList"
android:authorities="org.thoughtcrime.securesms.database.conversationlist"
android:authorities="${applicationId}.database.conversation"
android:exported="false" />
<provider android:name=".database.DatabaseContentProviders$Attachment"
android:authorities="org.thoughtcrime.securesms.database.attachment"
android:authorities="${applicationId}.database.attachment"
android:exported="false" />
<provider android:name=".database.DatabaseContentProviders$Sticker"
android:authorities="org.thoughtcrime.securesms.database.sticker"
android:authorities="${applicationId}.database.sticker"
android:exported="false" />
<provider android:name=".database.DatabaseContentProviders$StickerPack"
android:authorities="org.thoughtcrime.securesms.database.stickerpack"
android:authorities="${applicationId}.database.stickerpack"
android:exported="false" />
<receiver android:name=".service.BootReceiver">
@@ -703,6 +785,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" />
@@ -768,12 +857,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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 225 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 415 KiB

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 KiB

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 395 KiB

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 622 KiB

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 599 KiB

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 559 KiB

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 643 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 647 KiB

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 602 KiB

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 589 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 531 KiB

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 589 KiB

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 384 KiB

After

Width:  |  Height:  |  Size: 93 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.thoughtcrime.securesms.mediasend.camerax;
package androidx.camera.view;
import android.Manifest.permission;
import android.annotation.SuppressLint;
@@ -45,43 +45,46 @@ import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.DisplayOrientedMeteringPointFactory;
import androidx.camera.core.FocusMeteringAction;
import androidx.camera.core.FocusMeteringResult;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCapture.OnImageCapturedCallback;
import androidx.camera.core.ImageCapture.OnImageSavedCallback;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Logger;
import androidx.camera.core.MeteringPoint;
import androidx.camera.core.MeteringPointFactory;
import androidx.camera.core.VideoCapture;
import androidx.camera.core.VideoCapture.OnVideoSavedCallback;
import androidx.camera.core.impl.LensFacingConverter;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.impl.utils.futures.FutureCallback;
import androidx.camera.core.impl.utils.futures.Futures;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import com.google.common.util.concurrent.ListenableFuture;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.logging.Log;
import org.signal.core.util.logging.Log;
import java.io.FileDescriptor;
import java.io.File;
import java.util.concurrent.Executor;
/**
* A {@link View} that displays a preview of the camera with methods {@link
* #takePicture(Executor, OnImageCapturedCallback)},
* {@link #startRecording(FileDescriptor, Executor, VideoCapture.OnVideoSavedCallback)} and {@link #stopRecording()}.
* {@link #takePicture(ImageCapture.OutputFileOptions, Executor, OnImageSavedCallback)},
* {@link #startRecording(File , Executor , OnVideoSavedCallback callback)}
* and {@link #stopRecording()}.
*
* <p>Because the Camera is a limited resource and consumes a high amount of power, CameraView must
* be opened/closed. CameraView will handle opening/closing automatically through use of a {@link
* LifecycleOwner}. Use {@link #bindToLifecycle(LifecycleOwner)} to start the camera.
*/
// Begin Signal Custom Code Block
@RequiresApi(21)
@SuppressLint("RestrictedApi")
// End Signal Custom Code Block
public final class CameraXView extends FrameLayout {
static final String TAG = CameraXView.class.getSimpleName();
static final boolean DEBUG = false;
public final class SignalCameraView extends FrameLayout {
static final String TAG = Log.tag(SignalCameraView.class);
static final int INDEFINITE_VIDEO_DURATION = -1;
static final int INDEFINITE_VIDEO_SIZE = -1;
@@ -107,7 +110,7 @@ public final class CameraXView extends FrameLayout {
// For pinch-to-zoom
private PinchToZoomGestureDetector mPinchToZoomGestureDetector;
private boolean mIsPinchToZoomEnabled = true;
CameraXModule mCameraModule;
SignalCameraXModule mCameraModule;
private final DisplayManager.DisplayListener mDisplayListener =
new DisplayListener() {
@Override
@@ -124,26 +127,25 @@ public final class CameraXView extends FrameLayout {
}
};
private PreviewView mPreviewView;
private ScaleType mScaleType = ScaleType.CENTER_CROP;
// For accessibility event
private MotionEvent mUpEvent;
public CameraXView(@NonNull Context context) {
public SignalCameraView(@NonNull Context context) {
this(context, null);
}
public CameraXView(@NonNull Context context, @Nullable AttributeSet attrs) {
public SignalCameraView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CameraXView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
public SignalCameraView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
@RequiresApi(21)
public CameraXView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
public SignalCameraView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
@@ -172,23 +174,23 @@ public final class CameraXView extends FrameLayout {
private void init(Context context, @Nullable AttributeSet attrs) {
addView(mPreviewView = new PreviewView(getContext()), 0 /* view position */);
mCameraModule = new CameraXModule(this);
mCameraModule = new SignalCameraXModule(this);
if (attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CameraXView);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CameraView);
setScaleType(
ScaleType.fromId(
a.getInteger(R.styleable.CameraXView_scaleType,
PreviewView.ScaleType.fromId(
a.getInteger(R.styleable.CameraView_scaleType,
getScaleType().getId())));
setPinchToZoomEnabled(
a.getBoolean(
R.styleable.CameraXView_pinchToZoomEnabled, isPinchToZoomEnabled()));
R.styleable.CameraView_pinchToZoomEnabled, isPinchToZoomEnabled()));
setCaptureMode(
CaptureMode.fromId(
a.getInteger(R.styleable.CameraXView_captureMode,
a.getInteger(R.styleable.CameraView_captureMode,
getCaptureMode().getId())));
int lensFacing = a.getInt(R.styleable.CameraXView_lensFacing, LENS_FACING_BACK);
int lensFacing = a.getInt(R.styleable.CameraView_lensFacing, LENS_FACING_BACK);
switch (lensFacing) {
case LENS_FACING_NONE:
setCameraLensFacing(null);
@@ -203,7 +205,7 @@ public final class CameraXView extends FrameLayout {
// Unhandled event.
}
int flashMode = a.getInt(R.styleable.CameraXView_flash, 0);
int flashMode = a.getInt(R.styleable.CameraView_flash, 0);
switch (flashMode) {
case FLASH_MODE_AUTO:
setFlash(ImageCapture.FLASH_MODE_AUTO);
@@ -265,7 +267,7 @@ public final class CameraXView extends FrameLayout {
if (savedState instanceof Bundle) {
Bundle state = (Bundle) savedState;
super.onRestoreInstanceState(state.getParcelable(EXTRA_SUPER));
setScaleType(ScaleType.fromId(state.getInt(EXTRA_SCALE_TYPE)));
setScaleType(PreviewView.ScaleType.fromId(state.getInt(EXTRA_SCALE_TYPE)));
setZoomRatio(state.getFloat(EXTRA_ZOOM_RATIO));
setPinchToZoomEnabled(state.getBoolean(EXTRA_PINCH_TO_ZOOM_ENABLED));
setFlash(FlashModeConverter.valueOf(state.getString(EXTRA_FLASH)));
@@ -298,6 +300,21 @@ public final class CameraXView extends FrameLayout {
dpyMgr.unregisterDisplayListener(mDisplayListener);
}
/**
* Gets the {@link LiveData} of the underlying {@link PreviewView}'s
* {@link PreviewView.StreamState}.
*
* @return A {@link LiveData} containing the {@link PreviewView.StreamState}. Apps can either
* get current value by {@link LiveData#getValue()} or register a observer by
* {@link LiveData#observe}.
* @see PreviewView#getPreviewStreamState()
*/
@NonNull
public LiveData<PreviewView.StreamState> getPreviewStreamState() {
return mPreviewView.getPreviewStreamState();
}
@NonNull
PreviewView getPreviewView() {
return mPreviewView;
}
@@ -347,11 +364,11 @@ public final class CameraXView extends FrameLayout {
/**
* Returns the scale type used to scale the preview.
*
* @return The current {@link ScaleType}.
* @return The current {@link PreviewView.ScaleType}.
*/
@NonNull
public ScaleType getScaleType() {
return mScaleType;
public PreviewView.ScaleType getScaleType() {
return mPreviewView.getScaleType();
}
/**
@@ -359,13 +376,10 @@ public final class CameraXView extends FrameLayout {
*
* <p>This controls how the view finder should be scaled and positioned within the view.
*
* @param scaleType The desired {@link ScaleType}.
* @param scaleType The desired {@link PreviewView.ScaleType}.
*/
public void setScaleType(@NonNull ScaleType scaleType) {
if (scaleType != mScaleType) {
mScaleType = scaleType;
requestLayout();
}
public void setScaleType(@NonNull PreviewView.ScaleType scaleType) {
mPreviewView.setScaleType(scaleType);
}
/**
@@ -401,8 +415,10 @@ public final class CameraXView extends FrameLayout {
}
/**
* Sets the maximum video duration before {@link VideoCapture.OnVideoSavedCallback#onVideoSaved(FileDescriptor)} is
* called automatically. Use {@link #INDEFINITE_VIDEO_DURATION} to disable the timeout.
* Sets the maximum video duration before
* {@link OnVideoSavedCallback#onVideoSaved(VideoCapture.OutputFileResults)} is called
* automatically.
* Use {@link #INDEFINITE_VIDEO_DURATION} to disable the timeout.
*/
private void setMaxVideoDuration(long duration) {
mCameraModule.setMaxVideoDuration(duration);
@@ -417,7 +433,8 @@ public final class CameraXView extends FrameLayout {
}
/**
* Sets the maximum video size in bytes before {@link VideoCapture.OnVideoSavedCallback#onVideoSaved(FileDescriptor)}
* Sets the maximum video size in bytes before
* {@link OnVideoSavedCallback#onVideoSaved(VideoCapture.OutputFileResults)}
* is called automatically. Use {@link #INDEFINITE_VIDEO_SIZE} to disable the size restriction.
*/
private void setMaxVideoSize(long size) {
@@ -435,28 +452,38 @@ public final class CameraXView extends FrameLayout {
mCameraModule.takePicture(executor, callback);
}
/**
* Takes a picture and calls
* {@link OnImageSavedCallback#onImageSaved(ImageCapture.OutputFileResults)} when done.
*
* <p> The value of {@link ImageCapture.Metadata#isReversedHorizontal()} in the
* {@link ImageCapture.OutputFileOptions} will be overwritten based on camera direction. For
* front camera, it will be set to true; for back camera, it will be set to false.
*
* @param outputFileOptions Options to store the newly captured image.
* @param executor The executor in which the callback methods will be run.
* @param callback Callback which will receive success or failure.
*/
public void takePicture(@NonNull ImageCapture.OutputFileOptions outputFileOptions,
@NonNull Executor executor,
@NonNull OnImageSavedCallback callback) {
mCameraModule.takePicture(outputFileOptions, executor, callback);
}
/**
* Takes a video and calls the OnVideoSavedCallback when done.
*
* @param file The destination.
* @param executor The executor in which the callback methods will be run.
* @param callback Callback which will receive success or failure.
* @param outputFileOptions Options to store the newly captured video.
* @param executor The executor in which the callback methods will be run.
* @param callback Callback which will receive success or failure.
*/
// Begin Signal Custom Code Block
@RequiresApi(26)
// End Signal Custom Code Block
public void startRecording(// Begin Signal Custom Code Block
@NonNull FileDescriptor file,
// End Signal Custom Code Block
public void startRecording(@NonNull VideoCapture.OutputFileOptions outputFileOptions,
@NonNull Executor executor,
@NonNull VideoCapture.OnVideoSavedCallback callback) {
mCameraModule.startRecording(file, executor, callback);
@NonNull OnVideoSavedCallback callback) {
mCameraModule.startRecording(outputFileOptions, executor, callback);
}
/** Stops an in progress video. */
// Begin Signal Custom Code Block
@RequiresApi(26)
// End Signal Custom Code Block
public void stopRecording() {
mCameraModule.stopRecording();
}
@@ -554,7 +581,8 @@ public final class CameraXView extends FrameLayout {
mDownEventTimestamp = System.currentTimeMillis();
break;
case MotionEvent.ACTION_UP:
if (delta() < ViewConfiguration.getLongPressTimeout()) {
if (delta() < ViewConfiguration.getLongPressTimeout()
&& mCameraModule.isBoundToLifecycle()) {
mUpEvent = event;
performClick();
}
@@ -578,19 +606,14 @@ public final class CameraXView extends FrameLayout {
final float y = (mUpEvent != null) ? mUpEvent.getY() : getY() + getHeight() / 2f;
mUpEvent = null;
CameraSelector cameraSelector =
new CameraSelector.Builder().requireLensFacing(
mCameraModule.getLensFacing()).build();
DisplayOrientedMeteringPointFactory pointFactory = new DisplayOrientedMeteringPointFactory(
getDisplay(), cameraSelector, mPreviewView.getWidth(), mPreviewView.getHeight());
float afPointWidth = 1.0f / 6.0f; // 1/6 total area
float aePointWidth = afPointWidth * 1.5f;
MeteringPoint afPoint = pointFactory.createPoint(x, y, afPointWidth);
MeteringPoint aePoint = pointFactory.createPoint(x, y, aePointWidth);
Camera camera = mCameraModule.getCamera();
if (camera != null) {
MeteringPointFactory pointFactory = mPreviewView.getMeteringPointFactory();
float afPointWidth = 1.0f / 6.0f; // 1/6 total area
float aePointWidth = afPointWidth * 1.5f;
MeteringPoint afPoint = pointFactory.createPoint(x, y, afPointWidth);
MeteringPoint aePoint = pointFactory.createPoint(x, y, aePointWidth);
ListenableFuture<FocusMeteringResult> future =
camera.getCameraControl().startFocusAndMetering(
new FocusMeteringAction.Builder(afPoint,
@@ -609,7 +632,7 @@ public final class CameraXView extends FrameLayout {
}, CameraXExecutors.directExecutor());
} else {
Log.d(TAG, "cannot access camera");
Logger.d(TAG, "cannot access camera");
}
return true;
@@ -711,45 +734,11 @@ public final class CameraXView extends FrameLayout {
return mCameraModule.isTorchOn();
}
/** Options for scaling the bounds of the view finder to the bounds of this view. */
public enum ScaleType {
/**
* Scale the view finder, maintaining the source aspect ratio, so the view finder fills the
* entire view. This will cause the view finder to crop the source image if the camera
* aspect ratio does not match the view aspect ratio.
*/
CENTER_CROP(0),
/**
* Scale the view finder, maintaining the source aspect ratio, so the view finder is
* entirely contained within the view.
*/
CENTER_INSIDE(1);
private final int mId;
int getId() {
return mId;
}
ScaleType(int id) {
mId = id;
}
static ScaleType fromId(int id) {
for (ScaleType st : values()) {
if (st.mId == id) {
return st;
}
}
throw new IllegalArgumentException();
}
}
/**
* The capture mode used by CameraView.
*
* <p>This enum can be used to determine which capture mode will be enabled for {@link
* CameraXView}.
* SignalCameraView}.
*/
public enum CaptureMode {
/** A mode where image capture is enabled. */
@@ -832,4 +821,4 @@ public final class CameraXView extends FrameLayout {
public void onScaleEnd(ScaleGestureDetector detector) {
}
}
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.thoughtcrime.securesms.mediasend.camerax;
package androidx.camera.view;
import android.Manifest.permission;
import android.annotation.SuppressLint;
@@ -28,16 +28,19 @@ import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RequiresPermission;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraInfoUnavailableException;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.CameraX;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCapture.OnImageCapturedCallback;
import androidx.camera.core.ImageCapture.OnImageSavedCallback;
import androidx.camera.core.Logger;
import androidx.camera.core.Preview;
import androidx.camera.core.TorchState;
import androidx.camera.core.UseCase;
import androidx.camera.core.VideoCapture;
import androidx.camera.core.VideoCapture.OnVideoSavedCallback;
import androidx.camera.core.impl.CameraInternal;
import androidx.camera.core.impl.LensFacingConverter;
import androidx.camera.core.impl.VideoCaptureConfig;
import androidx.camera.core.impl.utils.CameraOrientationUtil;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.impl.utils.futures.FutureCallback;
@@ -51,11 +54,10 @@ import androidx.lifecycle.OnLifecycleEvent;
import com.google.common.util.concurrent.ListenableFuture;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mediasend.camerax.CameraXUtil;
import org.thoughtcrime.securesms.mms.MediaConstraints;
import org.thoughtcrime.securesms.video.VideoUtil;
import java.io.FileDescriptor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
@@ -68,10 +70,9 @@ 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}. */
// Begin Signal Custom Code Block
@RequiresApi(21)
// End Signal Custom Code Block
final class CameraXModule {
@SuppressLint("RestrictedApi")
final class SignalCameraXModule {
public static final String TAG = "CameraXModule";
private static final float UNITY_ZOOM_SCALE = 1f;
@@ -82,13 +83,13 @@ final class CameraXModule {
private static final Rational ASPECT_RATIO_3_4 = new Rational(3, 4);
private final Preview.Builder mPreviewBuilder;
private final VideoCaptureConfig.Builder mVideoCaptureConfigBuilder;
private final VideoCapture.Builder mVideoCaptureBuilder;
private final ImageCapture.Builder mImageCaptureBuilder;
private final CameraXView mCameraXView;
private final SignalCameraView mCameraView;
final AtomicBoolean mVideoIsRecording = new AtomicBoolean(false);
private CameraXView.CaptureMode mCaptureMode = CameraXView.CaptureMode.IMAGE;
private long mMaxVideoDuration = CameraXView.INDEFINITE_VIDEO_DURATION;
private long mMaxVideoSize = CameraXView.INDEFINITE_VIDEO_SIZE;
private SignalCameraView.CaptureMode mCaptureMode = SignalCameraView.CaptureMode.IMAGE;
private long mMaxVideoDuration = SignalCameraView.INDEFINITE_VIDEO_DURATION;
private long mMaxVideoSize = SignalCameraView.INDEFINITE_VIDEO_SIZE;
@ImageCapture.FlashMode
private int mFlash = FLASH_MODE_OFF;
@Nullable
@@ -110,7 +111,6 @@ final class CameraXModule {
public void onDestroy(LifecycleOwner owner) {
if (owner == mCurrentLifecycle) {
clearCurrentLifecycle();
mPreview.setSurfaceProvider(null);
}
}
};
@@ -123,8 +123,8 @@ final class CameraXModule {
@Nullable
ProcessCameraProvider mCameraProvider;
CameraXModule(CameraXView view) {
mCameraXView = view;
SignalCameraXModule(SignalCameraView view) {
mCameraView = view;
Futures.addCallback(ProcessCameraProvider.getInstance(view.getContext()),
new FutureCallback<ProcessCameraProvider>() {
@@ -149,14 +149,12 @@ final class CameraXModule {
mImageCaptureBuilder = new ImageCapture.Builder().setTargetName("ImageCapture");
// Begin Signal Custom Code Block
mVideoCaptureConfigBuilder =
new VideoCaptureConfig.Builder().setTargetName("VideoCapture")
.setAudioBitRate(VideoUtil.AUDIO_BIT_RATE)
.setVideoFrameRate(VideoUtil.VIDEO_FRAME_RATE)
.setBitRate(VideoUtil.VIDEO_BIT_RATE);
// End Signal Custom Code Block
mVideoCaptureBuilder = new VideoCapture.Builder().setTargetName("VideoCapture")
.setAudioBitRate(VideoUtil.AUDIO_BIT_RATE)
.setVideoFrameRate(VideoUtil.VIDEO_FRAME_RATE)
.setBitRate(VideoUtil.VIDEO_BIT_RATE);
}
@RequiresPermission(permission.CAMERA)
void bindToLifecycle(LifecycleOwner lifecycleOwner) {
mNewLifecycle = lifecycleOwner;
@@ -173,12 +171,15 @@ final class CameraXModule {
}
clearCurrentLifecycle();
if (mNewLifecycle.getLifecycle().getCurrentState() == Lifecycle.State.DESTROYED) {
// Lifecycle is already in a destroyed state. Since it may have been a valid
// lifecycle when bound, but became destroyed while waiting for layout, treat this as
// a no-op now that we have cleared the previous lifecycle.
mNewLifecycle = null;
return;
}
mCurrentLifecycle = mNewLifecycle;
mNewLifecycle = null;
if (mCurrentLifecycle.getLifecycle().getCurrentState() == Lifecycle.State.DESTROYED) {
mCurrentLifecycle = null;
throw new IllegalArgumentException("Cannot bind to lifecycle in a destroyed state.");
}
if (mCameraProvider == null) {
// try again once the camera provider is no longer null
@@ -188,18 +189,18 @@ final class CameraXModule {
Set<Integer> available = getAvailableCameraLensFacing();
if (available.isEmpty()) {
Log.w(TAG, "Unable to bindToLifeCycle since no cameras available");
Logger.w(TAG, "Unable to bindToLifeCycle since no cameras available");
mCameraLensFacing = null;
}
// Ensure the current camera exists, or default to another camera
if (mCameraLensFacing != null && !available.contains(mCameraLensFacing)) {
Log.w(TAG, "Camera does not exist with direction " + mCameraLensFacing);
Logger.w(TAG, "Camera does not exist with direction " + mCameraLensFacing);
// Default to the first available camera direction
mCameraLensFacing = available.iterator().next();
Log.w(TAG, "Defaulting to primary camera with direction " + mCameraLensFacing);
Logger.w(TAG, "Defaulting to primary camera with direction " + mCameraLensFacing);
}
// Do not attempt to create use cases for a null cameraLensFacing. This could occur if
@@ -216,14 +217,12 @@ final class CameraXModule {
boolean isDisplayPortrait = getDisplayRotationDegrees() == 0
|| getDisplayRotationDegrees() == 180;
Rational targetAspectRatio;
// Begin Signal Custom Code Block
int resolution = CameraXUtil.getIdealResolution(Resources.getSystem().getDisplayMetrics().widthPixels, Resources.getSystem().getDisplayMetrics().heightPixels);
// End Signal Custom Code Block
if (getCaptureMode() == CameraXView.CaptureMode.IMAGE) {
// mImageCaptureBuilder.setTargetAspectRatio(AspectRatio.RATIO_4_3);
Rational targetAspectRatio;
if (getCaptureMode() == SignalCameraView.CaptureMode.IMAGE) {
// Begin Signal Custom Code Block
mImageCaptureBuilder.setTargetResolution(CameraXUtil.buildResolutionForRatio(resolution, ASPECT_RATIO_4_3, isDisplayPortrait));
// End Signal Custom Code Block
@@ -232,7 +231,6 @@ final class CameraXModule {
// Begin Signal Custom Code Block
mImageCaptureBuilder.setTargetResolution(CameraXUtil.buildResolutionForRatio(resolution, ASPECT_RATIO_16_9, isDisplayPortrait));
// End Signal Custom Code Block
// mImageCaptureBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
targetAspectRatio = isDisplayPortrait ? ASPECT_RATIO_9_16 : ASPECT_RATIO_16_9;
}
@@ -245,15 +243,14 @@ final class CameraXModule {
// Begin Signal Custom Code Block
Size size = VideoUtil.getVideoRecordingSize();
mVideoCaptureConfigBuilder.setTargetResolution(size);
mVideoCaptureConfigBuilder.setMaxResolution(size);
mVideoCaptureBuilder.setTargetResolution(size);
mVideoCaptureBuilder.setMaxResolution(size);
// End Signal Custom Code Block
mVideoCaptureConfigBuilder.setTargetRotation(getDisplaySurfaceRotation());
mVideoCaptureBuilder.setTargetRotation(getDisplaySurfaceRotation());
// Begin Signal Custom Code Block
if (MediaConstraints.isVideoTranscodeAvailable()) {
mVideoCapture = new VideoCapture(mVideoCaptureConfigBuilder.getUseCaseConfig());
mVideoCapture = mVideoCaptureBuilder.build();
}
// End Signal Custom Code Block
@@ -262,15 +259,15 @@ final class CameraXModule {
mPreviewBuilder.setTargetResolution(new Size(getMeasuredWidth(), height));
mPreview = mPreviewBuilder.build();
mPreview.setSurfaceProvider(mCameraXView.getPreviewView().getPreviewSurfaceProvider());
mPreview.setSurfaceProvider(mCameraView.getPreviewView().getSurfaceProvider());
CameraSelector cameraSelector =
new CameraSelector.Builder().requireLensFacing(mCameraLensFacing).build();
if (getCaptureMode() == CameraXView.CaptureMode.IMAGE) {
if (getCaptureMode() == SignalCameraView.CaptureMode.IMAGE) {
mCamera = mCameraProvider.bindToLifecycle(mCurrentLifecycle, cameraSelector,
mImageCapture,
mPreview);
} else if (getCaptureMode() == CameraXView.CaptureMode.VIDEO) {
} else if (getCaptureMode() == SignalCameraView.CaptureMode.VIDEO) {
mCamera = mCameraProvider.bindToLifecycle(mCurrentLifecycle, cameraSelector,
mVideoCapture,
mPreview);
@@ -301,7 +298,7 @@ final class CameraXModule {
return;
}
if (getCaptureMode() == CameraXView.CaptureMode.VIDEO) {
if (getCaptureMode() == SignalCameraView.CaptureMode.VIDEO) {
throw new IllegalStateException("Can not take picture under VIDEO capture mode.");
}
@@ -312,17 +309,32 @@ final class CameraXModule {
mImageCapture.takePicture(executor, callback);
}
// Begin Signal Custom Code Block
@RequiresApi(26)
public void startRecording(FileDescriptor file,
// End Signal Custom Code Block
Executor executor,
final VideoCapture.OnVideoSavedCallback callback) {
public void takePicture(@NonNull ImageCapture.OutputFileOptions outputFileOptions,
@NonNull Executor executor, OnImageSavedCallback callback) {
if (mImageCapture == null) {
return;
}
if (getCaptureMode() == SignalCameraView.CaptureMode.VIDEO) {
throw new IllegalStateException("Can not take picture under VIDEO capture mode.");
}
if (callback == null) {
throw new IllegalArgumentException("OnImageSavedCallback should not be empty");
}
outputFileOptions.getMetadata().setReversedHorizontal(mCameraLensFacing != null
&& mCameraLensFacing == CameraSelector.LENS_FACING_FRONT);
mImageCapture.takePicture(outputFileOptions, executor, callback);
}
public void startRecording(VideoCapture.OutputFileOptions outputFileOptions,
Executor executor, final OnVideoSavedCallback callback) {
if (mVideoCapture == null) {
return;
}
if (getCaptureMode() == CameraXView.CaptureMode.IMAGE) {
if (getCaptureMode() == SignalCameraView.CaptureMode.IMAGE) {
throw new IllegalStateException("Can not record video under IMAGE capture mode.");
}
@@ -332,15 +344,14 @@ final class CameraXModule {
mVideoIsRecording.set(true);
mVideoCapture.startRecording(
file,
outputFileOptions,
executor,
new VideoCapture.OnVideoSavedCallback() {
@Override
// Begin Signal Custom Code Block
public void onVideoSaved(@NonNull FileDescriptor savedFile) {
// End Signal Custom Code Block
public void onVideoSaved(
@NonNull VideoCapture.OutputFileResults outputFileResults) {
mVideoIsRecording.set(false);
callback.onVideoSaved(savedFile);
callback.onVideoSaved(outputFileResults);
}
@Override
@@ -349,15 +360,12 @@ final class CameraXModule {
@NonNull String message,
@Nullable Throwable cause) {
mVideoIsRecording.set(false);
Log.e(TAG, message, cause);
Logger.e(TAG, message, cause);
callback.onError(videoCaptureError, message, cause);
}
});
}
// Begin Signal Custom Code Block
@RequiresApi(26)
// End Signal Custom Code Block
public void stopRecording() {
if (mVideoCapture == null) {
return;
@@ -388,14 +396,15 @@ final class CameraXModule {
@RequiresPermission(permission.CAMERA)
public boolean hasCameraWithLensFacing(@CameraSelector.LensFacing int lensFacing) {
String cameraId;
try {
cameraId = CameraX.getCameraWithLensFacing(lensFacing);
} catch (Exception e) {
throw new IllegalStateException("Unable to query lens facing.", e);
if (mCameraProvider == null) {
return false;
}
try {
return mCameraProvider.hasCamera(
new CameraSelector.Builder().requireLensFacing(lensFacing).build());
} catch (CameraInfoUnavailableException e) {
return false;
}
return cameraId != null;
}
@Nullable
@@ -454,7 +463,7 @@ final class CameraXModule {
}
}, CameraXExecutors.directExecutor());
} else {
Log.e(TAG, "Failed to set zoom ratio");
Logger.e(TAG, "Failed to set zoom ratio");
}
}
@@ -486,6 +495,10 @@ final class CameraXModule {
}
}
boolean isBoundToLifecycle() {
return mCamera != null;
}
int getRelativeCameraOrientation(boolean compensateForMirroring) {
int rotationDegrees = 0;
if (mCamera != null) {
@@ -499,7 +512,12 @@ final class CameraXModule {
return rotationDegrees;
}
@SuppressLint("UnsafeExperimentalUsageError")
public void invalidateView() {
if (mPreview != null) {
mPreview.setTargetRotation(getDisplaySurfaceRotation()); // Fixes issue #10940 (rotation not updated on phones using "Legacy API")
}
updateViewInfo();
}
@@ -520,6 +538,11 @@ final class CameraXModule {
if (!toUnbind.isEmpty()) {
mCameraProvider.unbind(toUnbind.toArray((new UseCase[0])));
}
// Remove surface provider once unbound.
if (mPreview != null) {
mPreview.setSurfaceProvider(null);
}
}
mCamera = null;
mCurrentLifecycle = null;
@@ -532,7 +555,7 @@ final class CameraXModule {
mImageCapture.setTargetRotation(getDisplaySurfaceRotation());
}
if (mVideoCapture != null && MediaConstraints.isVideoTranscodeAvailable()) {
if (mVideoCapture != null) {
mVideoCapture.setTargetRotation(getDisplaySurfaceRotation());
}
}
@@ -567,7 +590,7 @@ final class CameraXModule {
return false;
}
CameraInternal camera = mImageCapture.getBoundCamera();
CameraInternal camera = mImageCapture.getCamera();
if (camera == null) {
return false;
@@ -614,15 +637,15 @@ final class CameraXModule {
}
public Context getContext() {
return mCameraXView.getContext();
return mCameraView.getContext();
}
public int getWidth() {
return mCameraXView.getWidth();
return mCameraView.getWidth();
}
public int getHeight() {
return mCameraXView.getHeight();
return mCameraView.getHeight();
}
public int getDisplayRotationDegrees() {
@@ -630,15 +653,15 @@ final class CameraXModule {
}
protected int getDisplaySurfaceRotation() {
return mCameraXView.getDisplaySurfaceRotation();
return mCameraView.getDisplaySurfaceRotation();
}
private int getMeasuredWidth() {
return mCameraXView.getMeasuredWidth();
return mCameraView.getMeasuredWidth();
}
private int getMeasuredHeight() {
return mCameraXView.getMeasuredHeight();
return mCameraView.getMeasuredHeight();
}
@Nullable
@@ -647,11 +670,11 @@ final class CameraXModule {
}
@NonNull
public CameraXView.CaptureMode getCaptureMode() {
public SignalCameraView.CaptureMode getCaptureMode() {
return mCaptureMode;
}
public void setCaptureMode(@NonNull CameraXView.CaptureMode captureMode) {
public void setCaptureMode(@NonNull SignalCameraView.CaptureMode captureMode) {
this.mCaptureMode = captureMode;
rebindToLifecycle();
}

View File

@@ -0,0 +1,58 @@
package org.signal.glide;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public final class Log {
private Log() {}
public static void v(@NonNull String tag, @NonNull String message) {
SignalGlideCodecs.getLogProvider().v(tag, message);
}
public static void d(@NonNull String tag, @NonNull String message) {
SignalGlideCodecs.getLogProvider().d(tag, message);
}
public static void i(@NonNull String tag, @NonNull String message) {
SignalGlideCodecs.getLogProvider().i(tag, message);
}
public static void w(@NonNull String tag, @NonNull String message) {
SignalGlideCodecs.getLogProvider().w(tag, message);
}
public static void e(@NonNull String tag, @NonNull String message) {
SignalGlideCodecs.getLogProvider().e(tag, message, null);
}
public static void e(@NonNull String tag, @NonNull String message, @Nullable Throwable throwable) {
SignalGlideCodecs.getLogProvider().e(tag, message, throwable);
}
public interface Provider {
void v(@NonNull String tag, @NonNull String message);
void d(@NonNull String tag, @NonNull String message);
void i(@NonNull String tag, @NonNull String message);
void w(@NonNull String tag, @NonNull String message);
void e(@NonNull String tag, @NonNull String message, @Nullable Throwable throwable);
Provider EMPTY = new Provider() {
@Override
public void v(@NonNull String tag, @NonNull String message) { }
@Override
public void d(@NonNull String tag, @NonNull String message) { }
@Override
public void i(@NonNull String tag, @NonNull String message) { }
@Override
public void w(@NonNull String tag, @NonNull String message) { }
@Override
public void e(@NonNull String tag, @NonNull String message, @NonNull Throwable throwable) { }
};
}
}

View File

@@ -0,0 +1,18 @@
package org.signal.glide;
import androidx.annotation.NonNull;
public final class SignalGlideCodecs {
private static Log.Provider logProvider = Log.Provider.EMPTY;
private SignalGlideCodecs() {}
public static void setLogProvider(@NonNull Log.Provider provider) {
logProvider = provider;
}
public static @NonNull Log.Provider getLogProvider() {
return logProvider;
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.apng;
import android.content.Context;
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;
import org.signal.glide.common.loader.Loader;
import org.signal.glide.common.loader.ResourceStreamLoader;
/**
* @Description: APNGDrawable
* @Author: pengfei.zhou
* @CreateDate: 2019/3/27
*/
public class APNGDrawable extends FrameAnimationDrawable<APNGDecoder> {
public APNGDrawable(Loader provider) {
super(provider);
}
public APNGDrawable(APNGDecoder decoder) {
super(decoder);
}
@Override
protected APNGDecoder createFrameSeqDecoder(Loader streamLoader, FrameSeqDecoder.RenderListener listener) {
return new APNGDecoder(streamLoader, listener);
}
public static APNGDrawable fromAsset(Context context, String assetPath) {
AssetStreamLoader assetStreamLoader = new AssetStreamLoader(context, assetPath);
return new APNGDrawable(assetStreamLoader);
}
public static APNGDrawable fromFile(String filePath) {
FileLoader fileLoader = new FileLoader(filePath);
return new APNGDrawable(fileLoader);
}
public static APNGDrawable fromResource(Context context, int resId) {
ResourceStreamLoader resourceStreamLoader = new ResourceStreamLoader(context, resId);
return new APNGDrawable(resourceStreamLoader);
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.apng.decode;
import org.signal.glide.apng.io.APNGReader;
import java.io.IOException;
/**
* @Description: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/APNG#.27acTL.27:_The_Animation_Control_Chunk
* @Author: pengfei.zhou
* @CreateDate: 2019/3/27
*/
class ACTLChunk extends Chunk {
static final int ID = fourCCToInt("acTL");
int num_frames;
int num_plays;
@Override
void innerParse(APNGReader apngReader) throws IOException {
num_frames = apngReader.readInt();
num_plays = apngReader.readInt();
}
}

View File

@@ -0,0 +1,211 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.apng.decode;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
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;
import org.signal.glide.common.decode.FrameSeqDecoder;
import org.signal.glide.common.io.Reader;
import org.signal.glide.common.loader.Loader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
/**
* @Description: APNG4Android
* @Author: pengfei.zhou
* @CreateDate: 2019-05-13
*/
public class APNGDecoder extends FrameSeqDecoder<APNGReader, APNGWriter> {
private static final String TAG = Log.tag(APNGDecoder.class);
private APNGWriter apngWriter;
private int mLoopCount;
private final Paint paint = new Paint();
private class SnapShot {
byte dispose_op;
Rect dstRect = new Rect();
ByteBuffer byteBuffer;
}
private SnapShot snapShot = new SnapShot();
/**
* @param loader webp的reader
* @param renderListener 渲染的回调
*/
public APNGDecoder(Loader loader, FrameSeqDecoder.RenderListener renderListener) {
super(loader, renderListener);
paint.setAntiAlias(true);
}
@Override
protected APNGWriter getWriter() {
if (apngWriter == null) {
apngWriter = new APNGWriter();
}
return apngWriter;
}
@Override
protected APNGReader getReader(Reader reader) {
return new APNGReader(reader);
}
@Override
protected int getLoopCount() {
return mLoopCount;
}
@Override
protected void release() {
snapShot.byteBuffer = null;
apngWriter = null;
}
@Override
protected Rect read(APNGReader reader) throws IOException {
List<Chunk> chunks = APNGParser.parse(reader);
List<Chunk> otherChunks = new ArrayList<>();
boolean actl = false;
APNGFrame lastFrame = null;
byte[] ihdrData = new byte[0];
int canvasWidth = 0, canvasHeight = 0;
for (Chunk chunk : chunks) {
if (chunk instanceof ACTLChunk) {
mLoopCount = ((ACTLChunk) chunk).num_plays;
actl = true;
} else if (chunk instanceof FCTLChunk) {
APNGFrame frame = new APNGFrame(reader, (FCTLChunk) chunk);
frame.prefixChunks = otherChunks;
frame.ihdrData = ihdrData;
frames.add(frame);
lastFrame = frame;
} else if (chunk instanceof FDATChunk) {
if (lastFrame != null) {
lastFrame.imageChunks.add(chunk);
}
} else if (chunk instanceof IDATChunk) {
if (!actl) {
//如果为非APNG图片则只解码PNG
Frame frame = new StillFrame(reader);
frame.frameWidth = canvasWidth;
frame.frameHeight = canvasHeight;
frames.add(frame);
mLoopCount = 1;
break;
}
if (lastFrame != null) {
lastFrame.imageChunks.add(chunk);
}
} else if (chunk instanceof IHDRChunk) {
canvasWidth = ((IHDRChunk) chunk).width;
canvasHeight = ((IHDRChunk) chunk).height;
ihdrData = ((IHDRChunk) chunk).data;
} else if (!(chunk instanceof IENDChunk)) {
otherChunks.add(chunk);
}
}
frameBuffer = ByteBuffer.allocate((canvasWidth * canvasHeight / (sampleSize * sampleSize) + 1) * 4);
snapShot.byteBuffer = ByteBuffer.allocate((canvasWidth * canvasHeight / (sampleSize * sampleSize) + 1) * 4);
return new Rect(0, 0, canvasWidth, canvasHeight);
}
@Override
protected void renderFrame(Frame frame) {
if (frame == null || fullRect == null) {
return;
}
try {
Bitmap bitmap = obtainBitmap(fullRect.width() / sampleSize, fullRect.height() / sampleSize);
Canvas canvas = cachedCanvas.get(bitmap);
if (canvas == null) {
canvas = new Canvas(bitmap);
cachedCanvas.put(bitmap, canvas);
}
if (frame instanceof APNGFrame) {
// 从缓存中恢复当前帧
frameBuffer.rewind();
bitmap.copyPixelsFromBuffer(frameBuffer);
// 开始绘制前,处理快照中的设定
if (this.frameIndex == 0) {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
} else {
canvas.save();
canvas.clipRect(snapShot.dstRect);
switch (snapShot.dispose_op) {
// 从快照中恢复上一帧之前的显示内容
case FCTLChunk.APNG_DISPOSE_OP_PREVIOUS:
snapShot.byteBuffer.rewind();
bitmap.copyPixelsFromBuffer(snapShot.byteBuffer);
break;
// 清空上一帧所画区域
case FCTLChunk.APNG_DISPOSE_OP_BACKGROUND:
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
break;
// 什么都不做
case FCTLChunk.APNG_DISPOSE_OP_NON:
default:
break;
}
canvas.restore();
}
// 然后根据dispose设定传递到快照信息中
if (((APNGFrame) frame).dispose_op == FCTLChunk.APNG_DISPOSE_OP_PREVIOUS) {
if (snapShot.dispose_op != FCTLChunk.APNG_DISPOSE_OP_PREVIOUS) {
snapShot.byteBuffer.rewind();
bitmap.copyPixelsToBuffer(snapShot.byteBuffer);
}
}
snapShot.dispose_op = ((APNGFrame) frame).dispose_op;
canvas.save();
if (((APNGFrame) frame).blend_op == FCTLChunk.APNG_BLEND_OP_SOURCE) {
canvas.clipRect(
frame.frameX / sampleSize,
frame.frameY / sampleSize,
(frame.frameX + frame.frameWidth) / sampleSize,
(frame.frameY + frame.frameHeight) / sampleSize);
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
}
snapShot.dstRect.set(frame.frameX / sampleSize,
frame.frameY / sampleSize,
(frame.frameX + frame.frameWidth) / sampleSize,
(frame.frameY + frame.frameHeight) / sampleSize);
canvas.restore();
}
//开始真正绘制当前帧的内容
Bitmap inBitmap = obtainBitmap(frame.frameWidth, frame.frameHeight);
recycleBitmap(frame.draw(canvas, paint, sampleSize, inBitmap, getWriter()));
recycleBitmap(inBitmap);
frameBuffer.rewind();
bitmap.copyPixelsToBuffer(frameBuffer);
recycleBitmap(bitmap);
} catch (Throwable t) {
Log.e(TAG, "Failed to render!", t);
}
}
}

View File

@@ -0,0 +1,147 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.apng.decode;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import org.signal.glide.apng.io.APNGReader;
import org.signal.glide.apng.io.APNGWriter;
import org.signal.glide.common.decode.Frame;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.CRC32;
/**
* @Description: APNG4Android
* @Author: pengfei.zhou
* @CreateDate: 2019-05-13
*/
public class APNGFrame extends Frame<APNGReader, APNGWriter> {
public final byte blend_op;
public final byte dispose_op;
byte[] ihdrData;
List<Chunk> imageChunks = new ArrayList<>();
List<Chunk> prefixChunks = new ArrayList<>();
private static final byte[] sPNGSignatures = {(byte) 137, 80, 78, 71, 13, 10, 26, 10};
private static final byte[] sPNGEndChunk = {0, 0, 0, 0, 0x49, 0x45, 0x4E, 0x44, (byte) 0xAE, 0x42, 0x60, (byte) 0x82};
private static ThreadLocal<CRC32> sCRC32 = new ThreadLocal<>();
private CRC32 getCRC32() {
CRC32 crc32 = sCRC32.get();
if (crc32 == null) {
crc32 = new CRC32();
sCRC32.set(crc32);
}
return crc32;
}
public APNGFrame(APNGReader reader, FCTLChunk fctlChunk) {
super(reader);
blend_op = fctlChunk.blend_op;
dispose_op = fctlChunk.dispose_op;
frameDuration = fctlChunk.delay_num * 1000 / (fctlChunk.delay_den == 0 ? 100 : fctlChunk.delay_den);
frameWidth = fctlChunk.width;
frameHeight = fctlChunk.height;
frameX = fctlChunk.x_offset;
frameY = fctlChunk.y_offset;
}
private int encode(APNGWriter apngWriter) throws IOException {
int fileSize = 8 + 13 + 12;
//prefixChunks
for (Chunk chunk : prefixChunks) {
fileSize += chunk.length + 12;
}
//imageChunks
for (Chunk chunk : imageChunks) {
if (chunk instanceof IDATChunk) {
fileSize += chunk.length + 12;
} else if (chunk instanceof FDATChunk) {
fileSize += chunk.length + 8;
}
}
fileSize += sPNGEndChunk.length;
apngWriter.reset(fileSize);
apngWriter.putBytes(sPNGSignatures);
//IHDR Chunk
apngWriter.writeInt(13);
int start = apngWriter.position();
apngWriter.writeFourCC(IHDRChunk.ID);
apngWriter.writeInt(frameWidth);
apngWriter.writeInt(frameHeight);
apngWriter.putBytes(ihdrData);
CRC32 crc32 = getCRC32();
crc32.reset();
crc32.update(apngWriter.toByteArray(), start, 17);
apngWriter.writeInt((int) crc32.getValue());
//prefixChunks
for (Chunk chunk : prefixChunks) {
if (chunk instanceof IENDChunk) {
continue;
}
reader.reset();
reader.skip(chunk.offset);
reader.read(apngWriter.toByteArray(), apngWriter.position(), chunk.length + 12);
apngWriter.skip(chunk.length + 12);
}
//imageChunks
for (Chunk chunk : imageChunks) {
if (chunk instanceof IDATChunk) {
reader.reset();
reader.skip(chunk.offset);
reader.read(apngWriter.toByteArray(), apngWriter.position(), chunk.length + 12);
apngWriter.skip(chunk.length + 12);
} else if (chunk instanceof FDATChunk) {
apngWriter.writeInt(chunk.length - 4);
start = apngWriter.position();
apngWriter.writeFourCC(IDATChunk.ID);
reader.reset();
// skip to fdat data position
reader.skip(chunk.offset + 4 + 4 + 4);
reader.read(apngWriter.toByteArray(), apngWriter.position(), chunk.length - 4);
apngWriter.skip(chunk.length - 4);
crc32.reset();
crc32.update(apngWriter.toByteArray(), start, chunk.length);
apngWriter.writeInt((int) crc32.getValue());
}
}
//endChunk
apngWriter.putBytes(sPNGEndChunk);
return fileSize;
}
@Override
public Bitmap draw(Canvas canvas, Paint paint, int sampleSize, Bitmap reusedBitmap, APNGWriter writer) {
try {
int length = encode(writer);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = false;
options.inSampleSize = sampleSize;
options.inMutable = true;
options.inBitmap = reusedBitmap;
byte[] bytes = writer.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, length, options);
assert bitmap != null;
canvas.drawBitmap(bitmap, (float) frameX / sampleSize, (float) frameY / sampleSize, paint);
return bitmap;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}

View File

@@ -0,0 +1,143 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.apng.decode;
import android.content.Context;
import org.signal.glide.apng.io.APNGReader;
import org.signal.glide.common.io.Reader;
import org.signal.glide.common.io.StreamReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
* @link {https://www.w3.org/TR/PNG/#5PNG-file-signature}
* @Author: pengfei.zhou
* @CreateDate: 2019-05-13
*/
public class APNGParser {
static class FormatException extends IOException {
FormatException() {
super("APNG Format error");
}
}
public static boolean isAPNG(String filePath) {
InputStream inputStream = null;
try {
inputStream = new FileInputStream(filePath);
return isAPNG(new StreamReader(inputStream));
} catch (Exception e) {
return false;
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static boolean isAPNG(Context context, String assetPath) {
InputStream inputStream = null;
try {
inputStream = context.getAssets().open(assetPath);
return isAPNG(new StreamReader(inputStream));
} catch (Exception e) {
return false;
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static boolean isAPNG(Context context, int resId) {
InputStream inputStream = null;
try {
inputStream = context.getResources().openRawResource(resId);
return isAPNG(new StreamReader(inputStream));
} catch (Exception e) {
return false;
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static boolean isAPNG(Reader in) {
APNGReader reader = (in instanceof APNGReader) ? (APNGReader) in : new APNGReader(in);
try {
if (!reader.matchFourCC("\u0089PNG") || !reader.matchFourCC("\r\n\u001a\n")) {
throw new FormatException();
}
while (reader.available() > 0) {
Chunk chunk = parseChunk(reader);
if (chunk instanceof ACTLChunk) {
return true;
}
}
} catch (IOException e) {
return false;
}
return false;
}
public static List<Chunk> parse(APNGReader reader) throws IOException {
if (!reader.matchFourCC("\u0089PNG") || !reader.matchFourCC("\r\n\u001a\n")) {
throw new FormatException();
}
List<Chunk> chunks = new ArrayList<>();
while (reader.available() > 0) {
chunks.add(parseChunk(reader));
}
return chunks;
}
private static Chunk parseChunk(APNGReader reader) throws IOException {
int offset = reader.position();
int size = reader.readInt();
int fourCC = reader.readFourCC();
Chunk chunk;
if (fourCC == ACTLChunk.ID) {
chunk = new ACTLChunk();
} else if (fourCC == FCTLChunk.ID) {
chunk = new FCTLChunk();
} else if (fourCC == FDATChunk.ID) {
chunk = new FDATChunk();
} else if (fourCC == IDATChunk.ID) {
chunk = new IDATChunk();
} else if (fourCC == IENDChunk.ID) {
chunk = new IENDChunk();
} else if (fourCC == IHDRChunk.ID) {
chunk = new IHDRChunk();
} else {
chunk = new Chunk();
}
chunk.offset = offset;
chunk.fourcc = fourCC;
chunk.length = size;
chunk.parse(reader);
chunk.crc = reader.readInt();
return chunk;
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.apng.decode;
import android.text.TextUtils;
import org.signal.glide.apng.io.APNGReader;
import java.io.IOException;
/**
* @Description: Length (长度) 4字节 指定数据块中数据域的长度,其长度不超过(2311)字节
* Chunk Type Code (数据块类型码) 4字节 数据块类型码由ASCII字母(A-Z和a-z)组成
* Chunk Data (数据块数据) 可变长度 存储按照Chunk Type Code指定的数据
* CRC (循环冗余检测) 4字节 存储用来检测是否有错误的循环冗余码
* @Link https://www.w3.org/TR/PNG
* @Author: pengfei.zhou
* @CreateDate: 2019/3/27
*/
class Chunk {
int length;
int fourcc;
int crc;
int offset;
static int fourCCToInt(String fourCC) {
if (TextUtils.isEmpty(fourCC) || fourCC.length() != 4) {
return 0xbadeffff;
}
return (fourCC.charAt(0) & 0xff)
| (fourCC.charAt(1) & 0xff) << 8
| (fourCC.charAt(2) & 0xff) << 16
| (fourCC.charAt(3) & 0xff) << 24
;
}
void parse(APNGReader reader) throws IOException {
int available = reader.available();
innerParse(reader);
int offset = available - reader.available();
if (offset > length) {
throw new IOException("Out of chunk area");
} else if (offset < length) {
reader.skip(length - offset);
}
}
void innerParse(APNGReader reader) throws IOException {
}
}

View File

@@ -0,0 +1,121 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.apng.decode;
import org.signal.glide.apng.io.APNGReader;
import java.io.IOException;
/**
* @Author: pengfei.zhou
* @CreateDate: 2019/3/27
* @see {link=https://developer.mozilla.org/en-US/docs/Mozilla/Tech/APNG#.27fcTL.27:_The_Frame_Control_Chunk}
*/
class FCTLChunk extends Chunk {
static final int ID = fourCCToInt("fcTL");
int sequence_number;
/**
* x_offset >= 0
* y_offset >= 0
* width > 0
* height > 0
* x_offset + width <= 'IHDR' width
* y_offset + height <= 'IHDR' height
*/
/**
* Width of the following frame.
*/
int width;
/**
* Height of the following frame.
*/
int height;
/**
* X position at which to render the following frame.
*/
int x_offset;
/**
* Y position at which to render the following frame.
*/
int y_offset;
/**
* The delay_num and delay_den parameters together specify a fraction indicating the time to
* display the current frame, in seconds. If the denominator is 0, it is to be treated as if it
* were 100 (that is, delay_num then specifies 1/100ths of a second).
* If the the value of the numerator is 0 the decoder should render the next frame as quickly as
* possible, though viewers may impose a reasonable lower bound.
* <p>
* Frame timings should be independent of the time required for decoding and display of each frame,
* so that animations will run at the same rate regardless of the performance of the decoder implementation.
*/
/**
* Frame delay fraction numerator.
*/
short delay_num;
/**
* Frame delay fraction denominator.
*/
short delay_den;
/**
* Type of frame area disposal to be done after rendering this frame.
* dispose_op specifies how the output buffer should be changed at the end of the delay (before rendering the next frame).
* If the first 'fcTL' chunk uses a dispose_op of APNG_DISPOSE_OP_PREVIOUS it should be treated as APNG_DISPOSE_OP_BACKGROUND.
*/
byte dispose_op;
/**
* Type of frame area rendering for this frame.
*/
byte blend_op;
/**
* No disposal is done on this frame before rendering the next; the contents of the output buffer are left as is.
*/
static final int APNG_DISPOSE_OP_NON = 0;
/**
* The frame's region of the output buffer is to be cleared to fully transparent black before rendering the next frame.
*/
static final int APNG_DISPOSE_OP_BACKGROUND = 1;
/**
* The frame's region of the output buffer is to be reverted to the previous contents before rendering the next frame.
*/
static final int APNG_DISPOSE_OP_PREVIOUS = 2;
/**
* blend_op<code> specifies whether the frame is to be alpha blended into the current output buffer content,
* or whether it should completely replace its region in the output buffer.
*/
/**
* All color components of the frame, including alpha, overwrite the current contents of the frame's output buffer region.
*/
static final int APNG_BLEND_OP_SOURCE = 0;
/**
* The frame should be composited onto the output buffer based on its alpha,
* using a simple OVER operation as described in the Alpha Channel Processing section of the Extensions
* to the PNG Specification, Version 1.2.0. Note that the second variation of the sample code is applicable.
*/
static final int APNG_BLEND_OP_OVER = 1;
@Override
void innerParse(APNGReader reader) throws IOException {
sequence_number = reader.readInt();
width = reader.readInt();
height = reader.readInt();
x_offset = reader.readInt();
y_offset = reader.readInt();
delay_num = reader.readShort();
delay_den = reader.readShort();
dispose_op = reader.peek();
blend_op = reader.peek();
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.apng.decode;
import org.signal.glide.apng.io.APNGReader;
import java.io.IOException;
/**
* @Description: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/APNG#.27fdAT.27:_The_Frame_Data_Chunk
* @Author: pengfei.zhou
* @CreateDate: 2019/3/27
*/
class FDATChunk extends Chunk {
static final int ID = fourCCToInt("fdAT");
int sequence_number;
@Override
void innerParse(APNGReader reader) throws IOException {
sequence_number = reader.readInt();
}
}

View File

@@ -0,0 +1,15 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.apng.decode;
/**
* @Description: 作用描述
* @Author: pengfei.zhou
* @CreateDate: 2019/3/27
*/
class IDATChunk extends Chunk {
static final int ID = fourCCToInt("IDAT");
}

View File

@@ -0,0 +1,15 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.apng.decode;
/**
* @Description: 作用描述
* @Author: pengfei.zhou
* @CreateDate: 2019/3/27
*/
class IENDChunk extends Chunk {
static final int ID = Chunk.fourCCToInt("IEND");
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.apng.decode;
import org.signal.glide.apng.io.APNGReader;
import java.io.IOException;
/**
* The IHDR chunk shall be the first chunk in the PNG datastream. It contains:
* <p>
* Width 4 bytes
* Height 4 bytes
* Bit depth 1 byte
* Colour type 1 byte
* Compression method 1 byte
* Filter method 1 byte
* Interlace method 1 byte
*
* @Author: pengfei.zhou
* @CreateDate: 2019/3/27
*/
class IHDRChunk extends Chunk {
static final int ID = fourCCToInt("IHDR");
/**
* 图像宽度,以像素为单位
*/
int width;
/**
* 图像高度,以像素为单位
*/
int height;
byte[] data = new byte[5];
@Override
void innerParse(APNGReader reader) throws IOException {
width = reader.readInt();
height = reader.readInt();
reader.read(data, 0, data.length);
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.apng.decode;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import org.signal.glide.apng.io.APNGReader;
import org.signal.glide.apng.io.APNGWriter;
import org.signal.glide.common.decode.Frame;
import java.io.IOException;
/**
* @Description: APNG4Android
* @Author: pengfei.zhou
* @CreateDate: 2019-05-13
*/
public class StillFrame extends Frame<APNGReader, APNGWriter> {
public StillFrame(APNGReader reader) {
super(reader);
}
@Override
public Bitmap draw(Canvas canvas, Paint paint, int sampleSize, Bitmap reusedBitmap, APNGWriter writer) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = false;
options.inSampleSize = sampleSize;
options.inMutable = true;
options.inBitmap = reusedBitmap;
Bitmap bitmap = null;
try {
reader.reset();
bitmap = BitmapFactory.decodeStream(reader.toInputStream(), null, options);
assert bitmap != null;
paint.setXfermode(null);
canvas.drawBitmap(bitmap, 0, 0, paint);
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.apng.io;
import android.text.TextUtils;
import org.signal.glide.common.io.FilterReader;
import org.signal.glide.common.io.Reader;
import java.io.IOException;
/**
* @Description: APNGReader
* @Author: pengfei.zhou
* @CreateDate: 2019-05-13
*/
public class APNGReader extends FilterReader {
private static ThreadLocal<byte[]> __intBytes = new ThreadLocal<>();
protected static byte[] ensureBytes() {
byte[] bytes = __intBytes.get();
if (bytes == null) {
bytes = new byte[4];
__intBytes.set(bytes);
}
return bytes;
}
public APNGReader(Reader in) {
super(in);
}
public int readInt() throws IOException {
byte[] buf = ensureBytes();
read(buf, 0, 4);
return buf[3] & 0xFF |
(buf[2] & 0xFF) << 8 |
(buf[1] & 0xFF) << 16 |
(buf[0] & 0xFF) << 24;
}
public short readShort() throws IOException {
byte[] buf = ensureBytes();
read(buf, 0, 2);
return (short) (buf[1] & 0xFF |
(buf[0] & 0xFF) << 8);
}
/**
* @return read FourCC and match chars
*/
public boolean matchFourCC(String chars) throws IOException {
if (TextUtils.isEmpty(chars) || chars.length() != 4) {
return false;
}
int fourCC = readFourCC();
for (int i = 0; i < 4; i++) {
if (((fourCC >> (i * 8)) & 0xff) != chars.charAt(i)) {
return false;
}
}
return true;
}
public int readFourCC() throws IOException {
byte[] buf = ensureBytes();
read(buf, 0, 4);
return buf[0] & 0xff | (buf[1] & 0xff) << 8 | (buf[2] & 0xff) << 16 | (buf[3] & 0xff) << 24;
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.apng.io;
import org.signal.glide.common.io.ByteBufferWriter;
import java.nio.ByteOrder;
/**
* @Description: APNGWriter
* @Author: pengfei.zhou
* @CreateDate: 2019-05-13
*/
public class APNGWriter extends ByteBufferWriter {
public APNGWriter() {
super();
}
public void writeFourCC(int val) {
putByte((byte) (val & 0xff));
putByte((byte) ((val >> 8) & 0xff));
putByte((byte) ((val >> 16) & 0xff));
putByte((byte) ((val >> 24) & 0xff));
}
public void writeInt(int val) {
putByte((byte) ((val >> 24) & 0xff));
putByte((byte) ((val >> 16) & 0xff));
putByte((byte) ((val >> 8) & 0xff));
putByte((byte) (val & 0xff));
}
@Override
public void reset(int size) {
super.reset(size);
this.byteBuffer.order(ByteOrder.BIG_ENDIAN);
}
}

View File

@@ -0,0 +1,253 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.common;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.DrawFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import androidx.annotation.NonNull;
import androidx.vectordrawable.graphics.drawable.Animatable2Compat;
import org.signal.core.util.logging.Log;
import org.signal.glide.common.decode.FrameSeqDecoder;
import org.signal.glide.common.loader.Loader;
import java.nio.ByteBuffer;
import java.util.HashSet;
import java.util.Set;
/**
* @Description: Frame animation drawable
* @Author: pengfei.zhou
* @CreateDate: 2019/3/27
*/
public abstract class FrameAnimationDrawable<Decoder extends FrameSeqDecoder> extends Drawable implements Animatable2Compat, FrameSeqDecoder.RenderListener {
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);
private Matrix matrix = new Matrix();
private Set<AnimationCallback> animationCallbacks = new HashSet<>();
private Bitmap bitmap;
private static final int MSG_ANIMATION_START = 1;
private static final int MSG_ANIMATION_END = 2;
private Handler uiHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_ANIMATION_START:
for (AnimationCallback animationCallback : animationCallbacks) {
animationCallback.onAnimationStart(FrameAnimationDrawable.this);
}
break;
case MSG_ANIMATION_END:
for (AnimationCallback animationCallback : animationCallbacks) {
animationCallback.onAnimationEnd(FrameAnimationDrawable.this);
}
break;
}
}
};
private Runnable invalidateRunnable = new Runnable() {
@Override
public void run() {
invalidateSelf();
}
};
private boolean autoPlay = true;
public FrameAnimationDrawable(Decoder frameSeqDecoder) {
paint.setAntiAlias(true);
this.frameSeqDecoder = frameSeqDecoder;
}
public FrameAnimationDrawable(Loader provider) {
paint.setAntiAlias(true);
this.frameSeqDecoder = createFrameSeqDecoder(provider, this);
}
public void setAutoPlay(boolean autoPlay) {
this.autoPlay = autoPlay;
}
protected abstract Decoder createFrameSeqDecoder(Loader streamLoader, FrameSeqDecoder.RenderListener listener);
/**
* @param loopLimit <=0为无限播放,>0为实际播放次数
*/
public void setLoopLimit(int loopLimit) {
frameSeqDecoder.setLoopLimit(loopLimit);
}
public void reset() {
frameSeqDecoder.reset();
}
public void pause() {
frameSeqDecoder.pause();
}
public void resume() {
frameSeqDecoder.resume();
}
public boolean isPaused() {
return frameSeqDecoder.isPaused();
}
@Override
public void start() {
if (autoPlay) {
frameSeqDecoder.start();
} else {
this.frameSeqDecoder.addRenderListener(this);
if (!this.frameSeqDecoder.isRunning()) {
this.frameSeqDecoder.start();
}
}
}
@Override
public void stop() {
if (autoPlay) {
frameSeqDecoder.stop();
} else {
this.frameSeqDecoder.removeRenderListener(this);
this.frameSeqDecoder.stopIfNeeded();
}
}
@Override
public boolean isRunning() {
return frameSeqDecoder.isRunning();
}
@Override
public void draw(Canvas canvas) {
if (bitmap == null || bitmap.isRecycled()) {
return;
}
canvas.setDrawFilter(drawFilter);
canvas.drawBitmap(bitmap, matrix, paint);
}
@Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, bottom);
boolean sampleSizeChanged = frameSeqDecoder.setDesiredSize(getBounds().width(), getBounds().height());
matrix.setScale(
1.0f * getBounds().width() * frameSeqDecoder.getSampleSize() / frameSeqDecoder.getBounds().width(),
1.0f * getBounds().height() * frameSeqDecoder.getSampleSize() / frameSeqDecoder.getBounds().height());
if (sampleSizeChanged)
this.bitmap = Bitmap.createBitmap(
frameSeqDecoder.getBounds().width() / frameSeqDecoder.getSampleSize(),
frameSeqDecoder.getBounds().height() / frameSeqDecoder.getSampleSize(),
Bitmap.Config.ARGB_8888);
}
@Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
paint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public void onStart() {
Message.obtain(uiHandler, MSG_ANIMATION_START).sendToTarget();
}
@Override
public void onRender(ByteBuffer byteBuffer) {
if (!isRunning()) {
return;
}
if (this.bitmap == null || this.bitmap.isRecycled()) {
this.bitmap = Bitmap.createBitmap(
frameSeqDecoder.getBounds().width() / frameSeqDecoder.getSampleSize(),
frameSeqDecoder.getBounds().height() / frameSeqDecoder.getSampleSize(),
Bitmap.Config.ARGB_8888);
}
byteBuffer.rewind();
if (byteBuffer.remaining() < this.bitmap.getByteCount()) {
Log.e(TAG, "onRender:Buffer not large enough for pixels");
return;
}
this.bitmap.copyPixelsFromBuffer(byteBuffer);
uiHandler.post(invalidateRunnable);
}
@Override
public void onEnd() {
Message.obtain(uiHandler, MSG_ANIMATION_END).sendToTarget();
}
@Override
public boolean setVisible(boolean visible, boolean restart) {
if (this.autoPlay) {
if (visible) {
if (!isRunning()) {
start();
}
} else if (isRunning()) {
stop();
}
}
return super.setVisible(visible, restart);
}
@Override
public int getIntrinsicWidth() {
try {
return frameSeqDecoder.getBounds().width();
} catch (Exception exception) {
return 0;
}
}
@Override
public int getIntrinsicHeight() {
try {
return frameSeqDecoder.getBounds().height();
} catch (Exception exception) {
return 0;
}
}
@Override
public void registerAnimationCallback(@NonNull AnimationCallback animationCallback) {
this.animationCallbacks.add(animationCallback);
}
@Override
public boolean unregisterAnimationCallback(@NonNull AnimationCallback animationCallback) {
return this.animationCallbacks.remove(animationCallback);
}
@Override
public void clearAnimationCallbacks() {
this.animationCallbacks.clear();
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.common.decode;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import org.signal.glide.common.io.Reader;
import org.signal.glide.common.io.Writer;
/**
* @Description: One frame in an animation
* @Author: pengfei.zhou
* @CreateDate: 2019-05-13
*/
public abstract class Frame<R extends Reader, W extends Writer> {
protected final R reader;
public int frameWidth;
public int frameHeight;
public int frameX;
public int frameY;
public int frameDuration;
public Frame(R reader) {
this.reader = reader;
}
public abstract Bitmap draw(Canvas canvas, Paint paint, int sampleSize, Bitmap reusedBitmap, W writer);
}

View File

@@ -0,0 +1,539 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.common.decode;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
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;
import org.signal.glide.common.loader.Loader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;
/**
* @Description: Abstract Frame Animation Decoder
* @Author: pengfei.zhou
* @CreateDate: 2019/3/27
*/
public abstract class FrameSeqDecoder<R extends Reader, W extends Writer> {
private static final String TAG = Log.tag(FrameSeqDecoder.class);
private final int taskId;
private final Loader mLoader;
private final Handler workerHandler;
protected List<Frame> frames = new ArrayList<>();
protected int frameIndex = -1;
private int playCount;
private Integer loopLimit = null;
private Set<RenderListener> renderListeners = new HashSet<>();
private AtomicBoolean paused = new AtomicBoolean(true);
private static final Rect RECT_EMPTY = new Rect();
private Runnable renderTask = new Runnable() {
@Override
public void run() {
if (paused.get()) {
return;
}
if (canStep()) {
long start = System.currentTimeMillis();
long delay = step();
long cost = System.currentTimeMillis() - start;
workerHandler.postDelayed(this, Math.max(0, delay - cost));
for (RenderListener renderListener : renderListeners) {
renderListener.onRender(frameBuffer);
}
} else {
stop();
}
}
};
protected int sampleSize = 1;
private Set<Bitmap> cacheBitmaps = new HashSet<>();
protected Map<Bitmap, Canvas> cachedCanvas = new WeakHashMap<>();
protected ByteBuffer frameBuffer;
protected volatile Rect fullRect;
private W mWriter = getWriter();
private R mReader = null;
/**
* If played all the needed
*/
private boolean finished = false;
private enum State {
IDLE,
RUNNING,
INITIALIZING,
FINISHING,
}
private volatile State mState = State.IDLE;
public Loader getLoader() {
return mLoader;
}
protected abstract W getWriter();
protected abstract R getReader(Reader reader);
protected Bitmap obtainBitmap(int width, int height) {
Bitmap ret = null;
Iterator<Bitmap> iterator = cacheBitmaps.iterator();
while (iterator.hasNext()) {
int reuseSize = width * height * 4;
ret = iterator.next();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (ret != null && ret.getAllocationByteCount() >= reuseSize) {
iterator.remove();
if (ret.getWidth() != width || ret.getHeight() != height) {
ret.reconfigure(width, height, Bitmap.Config.ARGB_8888);
}
ret.eraseColor(0);
return ret;
}
} else {
if (ret != null && ret.getByteCount() >= reuseSize) {
if (ret.getWidth() == width && ret.getHeight() == height) {
iterator.remove();
ret.eraseColor(0);
}
return ret;
}
}
}
try {
Bitmap.Config config = Bitmap.Config.ARGB_8888;
ret = Bitmap.createBitmap(width, height, config);
} catch (OutOfMemoryError e) {
e.printStackTrace();
}
return ret;
}
protected void recycleBitmap(Bitmap bitmap) {
if (bitmap != null && !cacheBitmaps.contains(bitmap)) {
cacheBitmaps.add(bitmap);
}
}
/**
* 解码器的渲染回调
*/
public interface RenderListener {
/**
* 播放开始
*/
void onStart();
/**
* 帧播放
*/
void onRender(ByteBuffer byteBuffer);
/**
* 播放结束
*/
void onEnd();
}
/**
* @param loader webp的reader
* @param renderListener 渲染的回调
*/
public FrameSeqDecoder(Loader loader, @Nullable RenderListener renderListener) {
this.mLoader = loader;
if (renderListener != null) {
this.renderListeners.add(renderListener);
}
this.taskId = FrameDecoderExecutor.getInstance().generateTaskId();
this.workerHandler = new Handler(FrameDecoderExecutor.getInstance().getLooper(taskId));
}
public void addRenderListener(final RenderListener renderListener) {
this.workerHandler.post(new Runnable() {
@Override
public void run() {
renderListeners.add(renderListener);
}
});
}
public void removeRenderListener(final RenderListener renderListener) {
this.workerHandler.post(new Runnable() {
@Override
public void run() {
renderListeners.remove(renderListener);
}
});
}
public void stopIfNeeded() {
this.workerHandler.post(new Runnable() {
@Override
public void run() {
if (renderListeners.size() == 0) {
stop();
}
}
});
}
public Rect getBounds() {
if (fullRect == null) {
if (mState == State.FINISHING) {
Log.e(TAG, "In finishing,do not interrupt");
}
final Thread thread = Thread.currentThread();
workerHandler.post(new Runnable() {
@Override
public void run() {
try {
if (fullRect == null) {
if (mReader == null) {
mReader = getReader(mLoader.obtain());
} else {
mReader.reset();
}
initCanvasBounds(read(mReader));
}
} catch (Exception e) {
e.printStackTrace();
fullRect = RECT_EMPTY;
} finally {
LockSupport.unpark(thread);
}
}
});
LockSupport.park(thread);
}
return fullRect;
}
private void initCanvasBounds(Rect rect) {
fullRect = rect;
frameBuffer = ByteBuffer.allocate((rect.width() * rect.height() / (sampleSize * sampleSize) + 1) * 4);
if (mWriter == null) {
mWriter = getWriter();
}
}
private int getFrameCount() {
return this.frames.size();
}
/**
* @return Loop Count defined in file
*/
protected abstract int getLoopCount();
public void start() {
if (fullRect == RECT_EMPTY) {
return;
}
if (mState == State.RUNNING || mState == State.INITIALIZING) {
Log.i(TAG, debugInfo() + " Already started");
return;
}
if (mState == State.FINISHING) {
Log.e(TAG, debugInfo() + " Processing,wait for finish at " + mState);
}
mState = State.INITIALIZING;
if (Looper.myLooper() == workerHandler.getLooper()) {
innerStart();
} else {
workerHandler.post(new Runnable() {
@Override
public void run() {
innerStart();
}
});
}
}
@WorkerThread
private void innerStart() {
paused.compareAndSet(true, false);
final long start = System.currentTimeMillis();
try {
if (frames.size() == 0) {
try {
if (mReader == null) {
mReader = getReader(mLoader.obtain());
} else {
mReader.reset();
}
initCanvasBounds(read(mReader));
} catch (Throwable e) {
e.printStackTrace();
}
}
} finally {
Log.i(TAG, debugInfo() + " Set state to RUNNING,cost " + (System.currentTimeMillis() - start));
mState = State.RUNNING;
}
if (getNumPlays() == 0 || !finished) {
this.frameIndex = -1;
renderTask.run();
for (RenderListener renderListener : renderListeners) {
renderListener.onStart();
}
} else {
Log.i(TAG, debugInfo() + " No need to started");
}
}
@WorkerThread
private void innerStop() {
workerHandler.removeCallbacks(renderTask);
frames.clear();
for (Bitmap bitmap : cacheBitmaps) {
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
}
cacheBitmaps.clear();
if (frameBuffer != null) {
frameBuffer = null;
}
cachedCanvas.clear();
try {
if (mReader != null) {
mReader.close();
mReader = null;
}
if (mWriter != null) {
mWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
release();
mState = State.IDLE;
for (RenderListener renderListener : renderListeners) {
renderListener.onEnd();
}
}
public void stop() {
if (fullRect == RECT_EMPTY) {
return;
}
if (mState == State.FINISHING || mState == State.IDLE) {
Log.i(TAG, debugInfo() + "No need to stop");
return;
}
if (mState == State.INITIALIZING) {
Log.e(TAG, debugInfo() + "Processing,wait for finish at " + mState);
}
mState = State.FINISHING;
if (Looper.myLooper() == workerHandler.getLooper()) {
innerStop();
} else {
workerHandler.post(new Runnable() {
@Override
public void run() {
innerStop();
}
});
}
}
private String debugInfo() {
return "";
}
protected abstract void release();
public boolean isRunning() {
return mState == State.RUNNING || mState == State.INITIALIZING;
}
public boolean isPaused() {
return paused.get();
}
public void setLoopLimit(int limit) {
this.loopLimit = limit;
}
public void reset() {
this.playCount = 0;
this.frameIndex = -1;
this.finished = false;
}
public void pause() {
workerHandler.removeCallbacks(renderTask);
paused.compareAndSet(false, true);
}
public void resume() {
paused.compareAndSet(true, false);
workerHandler.removeCallbacks(renderTask);
workerHandler.post(renderTask);
}
public int getSampleSize() {
return sampleSize;
}
public boolean setDesiredSize(int width, int height) {
boolean sampleSizeChanged = false;
int sample = getDesiredSample(width, height);
if (sample != this.sampleSize) {
this.sampleSize = sample;
sampleSizeChanged = true;
final boolean tempRunning = isRunning();
workerHandler.removeCallbacks(renderTask);
workerHandler.post(new Runnable() {
@Override
public void run() {
innerStop();
try {
initCanvasBounds(read(getReader(mLoader.obtain())));
if (tempRunning) {
innerStart();
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
return sampleSizeChanged;
}
protected int getDesiredSample(int desiredWidth, int desiredHeight) {
if (desiredWidth == 0 || desiredHeight == 0) {
return 1;
}
int radio = Math.min(getBounds().width() / desiredWidth, getBounds().height() / desiredHeight);
int sample = 1;
while ((sample * 2) <= radio) {
sample *= 2;
}
return sample;
}
protected abstract Rect read(R reader) throws IOException;
private int getNumPlays() {
return this.loopLimit != null ? this.loopLimit : this.getLoopCount();
}
private boolean canStep() {
if (!isRunning()) {
return false;
}
if (frames.size() == 0) {
return false;
}
if (getNumPlays() <= 0) {
return true;
}
if (this.playCount < getNumPlays() - 1) {
return true;
} else if (this.playCount == getNumPlays() - 1 && this.frameIndex < this.getFrameCount() - 1) {
return true;
}
finished = true;
return false;
}
@WorkerThread
private long step() {
this.frameIndex++;
if (this.frameIndex >= this.getFrameCount()) {
this.frameIndex = 0;
this.playCount++;
}
Frame frame = getFrame(this.frameIndex);
if (frame == null) {
return 0;
}
renderFrame(frame);
return frame.frameDuration;
}
protected abstract void renderFrame(Frame frame);
private Frame getFrame(int index) {
if (index < 0 || index >= frames.size()) {
return null;
}
return frames.get(index);
}
/**
* Get Indexed frame
*
* @param index <0 means reverse from last index
*/
public Bitmap getFrameBitmap(int index) throws IOException {
if (mState != State.IDLE) {
Log.e(TAG, debugInfo() + ",stop first");
return null;
}
mState = State.RUNNING;
paused.compareAndSet(true, false);
if (frames.size() == 0) {
if (mReader == null) {
mReader = getReader(mLoader.obtain());
} else {
mReader.reset();
}
initCanvasBounds(read(mReader));
}
if (index < 0) {
index += this.frames.size();
}
if (index < 0) {
index = 0;
}
frameIndex = -1;
while (frameIndex < index) {
if (canStep()) {
step();
} else {
break;
}
}
frameBuffer.rewind();
Bitmap bitmap = Bitmap.createBitmap(getBounds().width() / getSampleSize(), getBounds().height() / getSampleSize(), Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(frameBuffer);
innerStop();
return bitmap;
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.common.executor;
import android.os.HandlerThread;
import android.os.Looper;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @Description: com.github.penfeizhou.animation.executor
* @Author: pengfei.zhou
* @CreateDate: 2019-11-21
*/
public class FrameDecoderExecutor {
private static int sPoolNumber = 4;
private ArrayList<HandlerThread> mHandlerThreadGroup = new ArrayList<>();
private AtomicInteger counter = new AtomicInteger(0);
private FrameDecoderExecutor() {
}
static class Inner {
static final FrameDecoderExecutor sInstance = new FrameDecoderExecutor();
}
public void setPoolSize(int size) {
sPoolNumber = size;
}
public static FrameDecoderExecutor getInstance() {
return Inner.sInstance;
}
public Looper getLooper(int taskId) {
int idx = taskId % sPoolNumber;
if (idx >= mHandlerThreadGroup.size()) {
HandlerThread handlerThread = new HandlerThread("FrameDecoderExecutor-" + idx);
handlerThread.start();
mHandlerThreadGroup.add(handlerThread);
Looper looper = handlerThread.getLooper();
if (looper != null) {
return looper;
} else {
return Looper.getMainLooper();
}
} else {
if (mHandlerThreadGroup.get(idx) != null) {
Looper looper = mHandlerThreadGroup.get(idx).getLooper();
if (looper != null) {
return looper;
} else {
return Looper.getMainLooper();
}
} else {
return Looper.getMainLooper();
}
}
}
public int generateTaskId() {
return counter.getAndIncrement();
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.common.io;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
/**
* @Description: APNG4Android
* @Author: pengfei.zhou
* @CreateDate: 2019-05-14
*/
public class ByteBufferReader implements Reader {
private final ByteBuffer byteBuffer;
public ByteBufferReader(ByteBuffer byteBuffer) {
this.byteBuffer = byteBuffer;
byteBuffer.position(0);
}
@Override
public long skip(long total) throws IOException {
byteBuffer.position((int) (byteBuffer.position() + total));
return total;
}
@Override
public byte peek() throws IOException {
return byteBuffer.get();
}
@Override
public void reset() throws IOException {
byteBuffer.position(0);
}
@Override
public int position() {
return byteBuffer.position();
}
@Override
public int read(byte[] buffer, int start, int byteCount) throws IOException {
byteBuffer.get(buffer, start, byteCount);
return byteCount;
}
@Override
public int available() throws IOException {
return byteBuffer.limit() - byteBuffer.position();
}
@Override
public void close() throws IOException {
}
@Override
public InputStream toInputStream() throws IOException {
return new ByteArrayInputStream(byteBuffer.array());
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.common.io;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* @Description: ByteBufferWriter
* @Author: pengfei.zhou
* @CreateDate: 2019-05-12
*/
public class ByteBufferWriter implements Writer {
protected ByteBuffer byteBuffer;
public ByteBufferWriter() {
reset(10 * 1024);
}
@Override
public void putByte(byte b) {
byteBuffer.put(b);
}
@Override
public void putBytes(byte[] b) {
byteBuffer.put(b);
}
@Override
public int position() {
return byteBuffer.position();
}
@Override
public void skip(int length) {
byteBuffer.position(length + position());
}
@Override
public byte[] toByteArray() {
return byteBuffer.array();
}
@Override
public void close() {
}
@Override
public void reset(int size) {
if (byteBuffer == null || size > byteBuffer.capacity()) {
byteBuffer = ByteBuffer.allocate(size);
this.byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
}
byteBuffer.clear();
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.common.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
* @Description: FileReader
* @Author: pengfei.zhou
* @CreateDate: 2019-05-23
*/
public class FileReader extends FilterReader {
private final File mFile;
public FileReader(File file) throws IOException {
super(new StreamReader(new FileInputStream(file)));
mFile = file;
}
@Override
public void reset() throws IOException {
reader.close();
reader = new StreamReader(new FileInputStream(mFile));
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.common.io;
import java.io.IOException;
import java.io.InputStream;
/**
* @Description: FilterReader
* @Author: pengfei.zhou
* @CreateDate: 2019-05-23
*/
public class FilterReader implements Reader {
protected Reader reader;
public FilterReader(Reader in) {
this.reader = in;
}
@Override
public long skip(long total) throws IOException {
return reader.skip(total);
}
@Override
public byte peek() throws IOException {
return reader.peek();
}
@Override
public void reset() throws IOException {
reader.reset();
}
@Override
public int position() {
return reader.position();
}
@Override
public int read(byte[] buffer, int start, int byteCount) throws IOException {
return reader.read(buffer, start, byteCount);
}
@Override
public int available() throws IOException {
return reader.available();
}
@Override
public void close() throws IOException {
reader.close();
}
@Override
public InputStream toInputStream() throws IOException {
reset();
return reader.toInputStream();
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.common.io;
import java.io.IOException;
import java.io.InputStream;
/**
* @link {https://developers.google.com/speed/webp/docs/riff_container#terminology_basics}
* @Author: pengfei.zhou
* @CreateDate: 2019-05-11
*/
public interface Reader {
long skip(long total) throws IOException;
byte peek() throws IOException;
void reset() throws IOException;
int position();
int read(byte[] buffer, int start, int byteCount) throws IOException;
int available() throws IOException;
/**
* close io
*/
void close() throws IOException;
InputStream toInputStream() throws IOException;
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.common.io;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* @Author: pengfei.zhou
* @CreateDate: 2019-05-11
*/
public class StreamReader extends FilterInputStream implements Reader {
private int position;
public StreamReader(InputStream in) {
super(in);
try {
in.reset();
} catch (IOException e) {
// e.printStackTrace();
}
}
@Override
public byte peek() throws IOException {
byte ret = (byte) read();
position++;
return ret;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int ret = super.read(b, off, len);
position += Math.max(0, ret);
return ret;
}
@Override
public synchronized void reset() throws IOException {
super.reset();
position = 0;
}
@Override
public long skip(long n) throws IOException {
long ret = super.skip(n);
position += ret;
return ret;
}
@Override
public int position() {
return position;
}
@Override
public InputStream toInputStream() throws IOException {
return this;
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.common.io;
import java.io.IOException;
/**
* @Description: APNG4Android
* @Author: pengfei.zhou
* @CreateDate: 2019-05-12
*/
public interface Writer {
void reset(int size);
void putByte(byte b);
void putBytes(byte[] b);
int position();
void skip(int length);
byte[] toByteArray();
void close() throws IOException;
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.common.loader;
import android.content.Context;
import java.io.IOException;
import java.io.InputStream;
/**
* @Description: 从Asset中读取流
* @Author: pengfei.zhou
* @CreateDate: 2019/3/28
*/
public class AssetStreamLoader extends StreamLoader {
private final Context mContext;
private final String mAssetName;
public AssetStreamLoader(Context context, String assetName) {
mContext = context.getApplicationContext();
mAssetName = assetName;
}
@Override
protected InputStream getInputStream() throws IOException {
return mContext.getAssets().open(mAssetName);
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.common.loader;
import org.signal.glide.common.io.ByteBufferReader;
import org.signal.glide.common.io.Reader;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* @Description: ByteBufferLoader
* @Author: pengfei.zhou
* @CreateDate: 2019-05-15
*/
public abstract class ByteBufferLoader implements Loader {
public abstract ByteBuffer getByteBuffer();
@Override
public Reader obtain() throws IOException {
return new ByteBufferReader(getByteBuffer());
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.common.loader;
import org.signal.glide.common.io.FileReader;
import org.signal.glide.common.io.Reader;
import java.io.File;
import java.io.IOException;
/**
* @Description: 从文件加载流
* @Author: pengfei.zhou
* @CreateDate: 2019/3/28
*/
public class FileLoader implements Loader {
private final File mFile;
private Reader mReader;
public FileLoader(String path) {
mFile = new File(path);
}
@Override
public synchronized Reader obtain() throws IOException {
return new FileReader(mFile);
}
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.common.loader;
import org.signal.glide.common.io.Reader;
import java.io.IOException;
/**
* @Description: Loader
* @Author: pengfei.zhou
* @CreateDate: 2019-05-14
*/
public interface Loader {
Reader obtain() throws IOException;
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.common.loader;
import android.content.Context;
import java.io.IOException;
import java.io.InputStream;
/**
* @Description: 从资源加载流
* @Author: pengfei.zhou
* @CreateDate: 2019/3/28
*/
public class ResourceStreamLoader extends StreamLoader {
private final Context mContext;
private final int mResId;
public ResourceStreamLoader(Context context, int resId) {
mContext = context.getApplicationContext();
mResId = resId;
}
@Override
protected InputStream getInputStream() throws IOException {
return mContext.getResources().openRawResource(mResId);
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright 2019 Zhou Pengfei
* SPDX-License-Identifier: Apache-2.0
*/
package org.signal.glide.common.loader;
import org.signal.glide.common.io.Reader;
import org.signal.glide.common.io.StreamReader;
import java.io.IOException;
import java.io.InputStream;
/**
* @Author: pengfei.zhou
* @CreateDate: 2019/3/28
*/
public abstract class StreamLoader implements Loader {
protected abstract InputStream getInputStream() throws IOException;
public final synchronized Reader obtain() throws IOException {
return new StreamReader(getInputStream());
}
}

View File

@@ -1,20 +1,22 @@
package org.thoughtcrime.securesms;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
import org.whispersystems.signalservice.api.account.AccountAttributes;
public final class AppCapabilities {
private AppCapabilities() {
}
private static final boolean UUID_CAPABLE = false;
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 SignalServiceProfile.Capabilities getCapabilities(boolean storageCapable) {
return new SignalServiceProfile.Capabilities(UUID_CAPABLE, FeatureFlags.groupsV2(), storageCapable);
public static AccountAttributes.Capabilities getCapabilities(boolean storageCapable) {
return new AccountAttributes.Capabilities(UUID_CAPABLE, GV2_CAPABLE, storageCapable, GV1_MIGRATION, FeatureFlags.senderKey());
}
}

View File

@@ -4,12 +4,13 @@ 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.EmojiSearchIndexDownloadJob;
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;
@@ -34,10 +35,16 @@ public final class AppInitialization {
TextSecurePreferences.setJobManagerVersion(context, JobManager.CURRENT_VERSION);
TextSecurePreferences.setLastExperienceVersionCode(context, Util.getCanonicalVersionCode());
TextSecurePreferences.setHasSeenStickerIntroTooltip(context, true);
TextSecurePreferences.setPasswordDisabled(context, true);
TextSecurePreferences.setLastExperienceVersionCode(context, Util.getCanonicalVersionCode());
TextSecurePreferences.setReadReceiptsEnabled(context, true);
TextSecurePreferences.setTypingIndicatorsEnabled(context, true);
TextSecurePreferences.setHasSeenWelcomeScreen(context, false);
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()));
}
@@ -47,8 +54,34 @@ 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()));
EmojiSearchIndexDownloadJob.scheduleImmediately();
}
/**
* 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,69 +16,82 @@
*/
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 net.sqlcipher.database.SQLiteDatabase;
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.components.TypingStatusRepository;
import org.thoughtcrime.securesms.components.TypingStatusSender;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.SqlCipherLibraryLoader;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencyProvider;
import org.thoughtcrime.securesms.emoji.EmojiSource;
import org.thoughtcrime.securesms.gcm.FcmJobService;
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
import org.thoughtcrime.securesms.jobs.DownloadLatestEmojiDataJob;
import org.thoughtcrime.securesms.jobs.EmojiSearchIndexDownloadJob;
import org.thoughtcrime.securesms.jobs.FcmRefreshJob;
import org.thoughtcrime.securesms.jobs.GroupV1MigrationJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
import org.thoughtcrime.securesms.jobs.RefreshPreKeysJob;
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
import org.thoughtcrime.securesms.logging.AndroidLogger;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
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;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.ratelimit.RateLimitUtil;
import org.thoughtcrime.securesms.registration.RegistrationUtil;
import org.thoughtcrime.securesms.revealable.ViewOnceMessageManager;
import org.thoughtcrime.securesms.ringrtc.RingRtcLogger;
import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.service.LocalBackupListener;
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.util.AppForegroundObserver;
import org.thoughtcrime.securesms.util.AppStartup;
import org.thoughtcrime.securesms.util.ByteUnit;
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.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.util.Util;
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;
import io.reactivex.rxjava3.plugins.RxJavaPlugins;
import io.reactivex.rxjava3.schedulers.Schedulers;
/**
* Will be called once when the TextSecure process is created.
*
@@ -87,17 +100,11 @@ import java.util.concurrent.TimeUnit;
*
* @author Moxie Marlinspike
*/
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 TypingStatusRepository typingStatusRepository;
private TypingStatusSender typingStatusSender;
private PersistentLogger persistentLogger;
private volatile boolean isAppVisible;
private PersistentLogger persistentLogger;
public static ApplicationContext getInstance(Context context) {
return (ApplicationContext)context.getApplicationContext();
@@ -105,90 +112,117 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
@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();
initializeTypingStatusRepository();
initializeTypingStatusSender();
initializeGcmCheck();
initializeSignedPreKeyCheck();
initializePeriodicTasks();
initializeCircumvention();
initializeRingRtc();
initializePendingMessages();
initializeBlobProvider();
initializeCleanup();
FeatureFlags.init();
NotificationChannels.create(this);
RefreshPreKeysJob.scheduleIfNecessary();
StorageSyncHelper.scheduleRoutineSync();
RetrieveProfileJob.enqueueRoutineFetchIfNecessary(this);
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();
AppStartup.getInstance().addBlocking("security-provider", this::initializeSecurityProvider)
.addBlocking("logging", () -> {
initializeLogging();
Log.i(TAG, "onCreate()");
})
.addBlocking("crash-handling", this::initializeCrashHandling)
.addBlocking("sqlcipher-init", () -> SqlCipherLibraryLoader.load(this))
.addBlocking("rx-init", () -> {
RxJavaPlugins.setInitIoSchedulerHandler(schedulerSupplier -> Schedulers.from(SignalExecutors.BOUNDED_IO, true, false));
RxJavaPlugins.setInitComputationSchedulerHandler(schedulerSupplier -> Schedulers.from(SignalExecutors.BOUNDED, true, false));
})
.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)
.addBlocking("feature-flags", FeatureFlags::init)
.addNonBlocking(this::initializeRevealableMessageManager)
.addNonBlocking(this::initializePendingRetryReceiptManager)
.addNonBlocking(this::initializeGcmCheck)
.addNonBlocking(this::initializeSignedPreKeyCheck)
.addNonBlocking(this::initializePeriodicTasks)
.addNonBlocking(this::initializeCircumvention)
.addNonBlocking(this::initializePendingMessages)
.addNonBlocking(this::initializeCleanup)
.addNonBlocking(this::initializeGlideCodecs)
.addNonBlocking(RefreshPreKeysJob::scheduleIfNecessary)
.addNonBlocking(StorageSyncHelper::scheduleRoutineSync)
.addNonBlocking(() -> ApplicationDependencies.getJobManager().beginJobLoop())
.addNonBlocking(EmojiSource::refresh)
.addPostRender(() -> RateLimitUtil.retryAllRateLimitedMessages(this))
.addPostRender(this::initializeExpiringMessageManager)
.addPostRender(() -> SignalStore.settings().setDefaultSms(Util.isDefaultSmsProvider(this)))
.addPostRender(() -> DownloadLatestEmojiDataJob.scheduleIfNecessary(this))
.addPostRender(EmojiSearchIndexDownloadJob::scheduleIfNecessary)
.addPostRender(() -> DatabaseFactory.getMessageLogDatabase(this).trimOldMessages(System.currentTimeMillis(), FeatureFlags.retryRespondMaxAge()))
.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();
executePendingContactSync();
KeyCachingService.onAppForegrounded(this);
ApplicationDependencies.getFrameRateTracker().begin();
ApplicationDependencies.getMegaphoneRepository().onAppForegrounded();
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();
}
public ExpiringMessageManager getExpiringMessageManager() {
return expiringMessageManager;
}
public ViewOnceMessageManager getViewOnceMessageManager() {
return viewOnceMessageManager;
}
public TypingStatusRepository getTypingStatusRepository() {
return typingStatusRepository;
}
public TypingStatusSender getTypingStatusSender() {
return typingStatusSender;
}
public boolean isAppVisible() {
return isAppVisible;
ApplicationDependencies.getShakeToReport().disable();
}
public PersistentLogger getPersistentLogger() {
return persistentLogger;
}
public void checkBuildExpiration() {
if (Util.getTimeUntilBuildExpiry() <= 0 && !SignalStore.misc().isClientDeprecated()) {
Log.w(TAG, "Build expired!");
SignalStore.misc().markClientDeprecated();
}
}
private void initializeSecurityProvider() {
try {
Class.forName("org.signal.aesgcmprovider.AesGcmCipher");
@@ -214,8 +248,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, FeatureFlags.internalUser() ? 15 : 7, ByteUnit.KILOBYTES.toBytes(300));
org.signal.core.util.logging.Log.initialize(FeatureFlags::internalUser, new AndroidLogger(), persistentLogger);
SignalProtocolLoggerProvider.setProvider(new CustomSignalProtocolLogger());
}
@@ -234,18 +268,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);
}
}
@@ -266,19 +306,15 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi
}
private void initializeExpiringMessageManager() {
this.expiringMessageManager = new ExpiringMessageManager(this);
ApplicationDependencies.getExpiringMessageManager().checkSchedule();
}
private void initializeRevealableMessageManager() {
this.viewOnceMessageManager = new ViewOnceMessageManager(this);
ApplicationDependencies.getViewOnceMessageManager().scheduleIfNecessary();
}
private void initializeTypingStatusRepository() {
this.typingStatusRepository = new TypingStatusRepository();
}
private void initializeTypingStatusSender() {
this.typingStatusSender = new TypingStatusSender(this);
private void initializePendingRetryReceiptManager() {
ApplicationDependencies.getPendingRetryReceiptManager().scheduleIfNecessary();
}
private void initializePeriodicTasks() {
@@ -286,6 +322,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);
@@ -294,31 +331,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);
}
@@ -328,23 +345,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() {
@@ -359,28 +368,56 @@ 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() {
SignalGlideCodecs.setLogProvider(new org.signal.glide.Log.Provider() {
@Override
public void v(@NonNull String tag, @NonNull String message) {
Log.v(tag, message);
}
@Override
public void d(@NonNull String tag, @NonNull String message) {
Log.d(tag, message);
}
@Override
public void i(@NonNull String tag, @NonNull String message) {
Log.i(tag, message);
}
@Override
public void w(@NonNull String tag, @NonNull String message) {
Log.w(tag, message);
}
@Override
public void e(@NonNull String tag, @NonNull String message, @Nullable Throwable throwable) {
Log.e(tag, message, throwable);
}
});
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(DynamicLanguageContextWrapper.updateContext(base, TextSecurePreferences.getLanguage(base)));
DynamicLanguageContextWrapper.updateContext(base);
super.attachBaseContext(base);
}
private static class ProviderInitializationException extends RuntimeException {

View File

@@ -1,281 +0,0 @@
/*
* Copyright (C) 2011 Whisper Systems
* Copyright (C) 2013-2017 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.PorterDuff;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.preference.Preference;
import org.thoughtcrime.securesms.help.HelpFragment;
import org.thoughtcrime.securesms.preferences.AdvancedPreferenceFragment;
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
import org.thoughtcrime.securesms.preferences.AppearancePreferenceFragment;
import org.thoughtcrime.securesms.preferences.ChatsPreferenceFragment;
import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment;
import org.thoughtcrime.securesms.preferences.NotificationsPreferenceFragment;
import org.thoughtcrime.securesms.preferences.SmsMmsPreferenceFragment;
import org.thoughtcrime.securesms.preferences.StoragePreferenceFragment;
import org.thoughtcrime.securesms.preferences.widgets.ProfilePreference;
import org.thoughtcrime.securesms.profiles.edit.EditProfileActivity;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ThemeUtil;
/**
* The Activity for application preference display and management.
*
* @author Moxie Marlinspike
*
*/
public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
implements SharedPreferences.OnSharedPreferenceChangeListener
{
@SuppressWarnings("unused")
private static final String TAG = ApplicationPreferencesActivity.class.getSimpleName();
private static final String PREFERENCE_CATEGORY_PROFILE = "preference_category_profile";
private static final String PREFERENCE_CATEGORY_SMS_MMS = "preference_category_sms_mms";
private static final String PREFERENCE_CATEGORY_NOTIFICATIONS = "preference_category_notifications";
private static final String PREFERENCE_CATEGORY_APP_PROTECTION = "preference_category_app_protection";
private static final String PREFERENCE_CATEGORY_APPEARANCE = "preference_category_appearance";
private static final String PREFERENCE_CATEGORY_CHATS = "preference_category_chats";
private static final String PREFERENCE_CATEGORY_STORAGE = "preference_category_storage";
private static final String PREFERENCE_CATEGORY_DEVICES = "preference_category_devices";
private static final String PREFERENCE_CATEGORY_HELP = "preference_category_help";
private static final String PREFERENCE_CATEGORY_ADVANCED = "preference_category_advanced";
private final DynamicTheme dynamicTheme = new DynamicTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
@Override
protected void onPreCreate() {
dynamicTheme.onCreate(this);
dynamicLanguage.onCreate(this);
}
@Override
protected void onCreate(Bundle icicle, boolean ready) {
//noinspection ConstantConditions
this.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
if (getIntent() != null && getIntent().getCategories() != null && getIntent().getCategories().contains("android.intent.category.NOTIFICATION_PREFERENCES")) {
initFragment(android.R.id.content, new NotificationsPreferenceFragment());
} else if (icicle == null) {
initFragment(android.R.id.content, new ApplicationPreferenceFragment());
}
}
@Override
public void onResume() {
super.onResume();
dynamicTheme.onResume(this);
dynamicLanguage.onResume(this);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
Fragment fragment = getSupportFragmentManager().findFragmentById(android.R.id.content);
fragment.onActivityResult(requestCode, resultCode, data);
}
@Override
public boolean onSupportNavigateUp() {
FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
fragmentManager.popBackStack();
} else {
// TODO [greyson] Navigation
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
}
return true;
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(TextSecurePreferences.THEME_PREF)) {
recreate();
} else if (key.equals(TextSecurePreferences.LANGUAGE_PREF)) {
recreate();
Intent intent = new Intent(this, KeyCachingService.class);
intent.setAction(KeyCachingService.LOCALE_CHANGE_EVENT);
startService(intent);
}
}
public static class ApplicationPreferenceFragment extends CorrectedPreferenceFragment {
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
this.findPreference(PREFERENCE_CATEGORY_PROFILE)
.setOnPreferenceClickListener(new ProfileClickListener());
this.findPreference(PREFERENCE_CATEGORY_SMS_MMS)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_SMS_MMS));
this.findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_NOTIFICATIONS));
this.findPreference(PREFERENCE_CATEGORY_APP_PROTECTION)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_APP_PROTECTION));
this.findPreference(PREFERENCE_CATEGORY_APPEARANCE)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_APPEARANCE));
this.findPreference(PREFERENCE_CATEGORY_CHATS)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_CHATS));
this.findPreference(PREFERENCE_CATEGORY_STORAGE)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_STORAGE));
this.findPreference(PREFERENCE_CATEGORY_DEVICES)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_DEVICES));
this.findPreference(PREFERENCE_CATEGORY_HELP)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_HELP));
this.findPreference(PREFERENCE_CATEGORY_ADVANCED)
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_ADVANCED));
tintIcons();
}
private void tintIcons() {
if (Build.VERSION.SDK_INT >= 21) return;
Preference preference = this.findPreference(PREFERENCE_CATEGORY_SMS_MMS);
preference.getIcon().setColorFilter(ThemeUtil.getThemedColor(requireContext(), R.attr.icon_tint), PorterDuff.Mode.SRC_IN);
}
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences);
}
@Override
public void onResume() {
super.onResume();
//noinspection ConstantConditions
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.text_secure_normal__menu_settings);
setCategorySummaries();
setCategoryVisibility();
}
private void setCategorySummaries() {
((ProfilePreference)this.findPreference(PREFERENCE_CATEGORY_PROFILE)).refresh();
this.findPreference(PREFERENCE_CATEGORY_SMS_MMS)
.setSummary(SmsMmsPreferenceFragment.getSummary(getActivity()));
this.findPreference(PREFERENCE_CATEGORY_NOTIFICATIONS)
.setSummary(NotificationsPreferenceFragment.getSummary(getActivity()));
this.findPreference(PREFERENCE_CATEGORY_APP_PROTECTION)
.setSummary(AppProtectionPreferenceFragment.getSummary(getActivity()));
this.findPreference(PREFERENCE_CATEGORY_APPEARANCE)
.setSummary(AppearancePreferenceFragment.getSummary(getActivity()));
this.findPreference(PREFERENCE_CATEGORY_CHATS)
.setSummary(ChatsPreferenceFragment.getSummary(getActivity()));
}
private void setCategoryVisibility() {
Preference devicePreference = this.findPreference(PREFERENCE_CATEGORY_DEVICES);
if (devicePreference != null && !TextSecurePreferences.isPushRegistered(getActivity())) {
getPreferenceScreen().removePreference(devicePreference);
}
}
private class CategoryClickListener implements Preference.OnPreferenceClickListener {
private String category;
CategoryClickListener(String category) {
this.category = category;
}
@Override
public boolean onPreferenceClick(Preference preference) {
Fragment fragment = null;
switch (category) {
case PREFERENCE_CATEGORY_SMS_MMS:
fragment = new SmsMmsPreferenceFragment();
break;
case PREFERENCE_CATEGORY_NOTIFICATIONS:
fragment = new NotificationsPreferenceFragment();
break;
case PREFERENCE_CATEGORY_APP_PROTECTION:
fragment = new AppProtectionPreferenceFragment();
break;
case PREFERENCE_CATEGORY_APPEARANCE:
fragment = new AppearancePreferenceFragment();
break;
case PREFERENCE_CATEGORY_CHATS:
fragment = new ChatsPreferenceFragment();
break;
case PREFERENCE_CATEGORY_STORAGE:
fragment = new StoragePreferenceFragment();
break;
case PREFERENCE_CATEGORY_DEVICES:
Intent intent = new Intent(getActivity(), DeviceActivity.class);
startActivity(intent);
break;
case PREFERENCE_CATEGORY_ADVANCED:
fragment = new AdvancedPreferenceFragment();
break;
case PREFERENCE_CATEGORY_HELP:
fragment = new HelpFragment();
break;
default:
throw new AssertionError();
}
if (fragment != null) {
Bundle args = new Bundle();
fragment.setArguments(args);
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.slide_from_end, R.anim.slide_to_start, R.anim.slide_from_start, R.anim.slide_to_end);
fragmentTransaction.replace(android.R.id.content, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
return true;
}
}
private class ProfileClickListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
requireActivity().startActivity(EditProfileActivity.getIntentForUserProfileEdit(preference.getContext()));
return true;
}
}
}
}

View File

@@ -1,6 +1,5 @@
package org.thoughtcrime.securesms;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
@@ -10,12 +9,7 @@ import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.transition.TransitionInflater;
import android.view.DisplayCutout;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import androidx.annotation.NonNull;
@@ -32,14 +26,15 @@ 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;
import org.thoughtcrime.securesms.util.FullscreenHelper;
/**
* Activity for displaying avatars full screen.
@@ -81,26 +76,16 @@ public final class AvatarPreviewActivity extends PassphraseRequiredActivity {
setSupportActionBar(toolbar);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
if (Build.VERSION.SDK_INT >= 28) {
getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
toolbar.getViewTreeObserver().addOnGlobalLayoutListener(new DisplayCutoutAdjuster(toolbar, findViewById(R.id.toolbar_cutout_spacer)));
}
showSystemUI();
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
requireSupportActionBar().setDisplayHomeAsUpEnabled(true);
Context context = getApplicationContext();
RecipientId recipientId = RecipientId.from(getIntent().getStringExtra(RECIPIENT_ID_EXTRA));
Recipient.live(recipientId).observe(this, recipient -> {
ContactPhoto contactPhoto = recipient.isLocalNumber() ? new ProfileContactPhoto(recipient, recipient.getProfileAvatar())
: recipient.getContactPhoto();
FallbackContactPhoto fallbackPhoto = recipient.isLocalNumber() ? new ResourceContactPhoto(R.drawable.ic_profile_outline_40, R.drawable.ic_profile_outline_20, R.drawable.ic_person_large)
: recipient.getFallbackContactPhoto();
ContactPhoto contactPhoto = recipient.isSelf() ? new ProfileContactPhoto(recipient, recipient.getProfileAvatar())
: recipient.getContactPhoto();
FallbackContactPhoto fallbackPhoto = recipient.isSelf() ? new ResourceContactPhoto(R.drawable.ic_profile_outline_40, R.drawable.ic_profile_outline_20, R.drawable.ic_person_large)
: recipient.getFallbackContactPhoto();
Resources resources = this.getResources();
@@ -140,47 +125,13 @@ public final class AvatarPreviewActivity extends PassphraseRequiredActivity {
toolbar.setTitle(recipient.getDisplayName(context));
});
avatar.setOnClickListener(v -> toggleUiVisibility());
FullscreenHelper fullscreenHelper = new FullscreenHelper(this);
showAndHideWithSystemUI(getWindow(), findViewById(R.id.toolbar_layout));
}
findViewById(android.R.id.content).setOnClickListener(v -> fullscreenHelper.toggleUiVisibility());
private static void showAndHideWithSystemUI(@NonNull Window window, @NonNull View... views) {
window.getDecorView().setOnSystemUiVisibilityChangeListener(visibility -> {
boolean hide = (visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
fullscreenHelper.configureToolbarSpacer(findViewById(R.id.toolbar_cutout_spacer));
for (View view : views) {
view.animate()
.alpha(hide ? 0 : 1)
.start();
}
});
}
private void toggleUiVisibility() {
int systemUiVisibility = getWindow().getDecorView().getSystemUiVisibility();
if ((systemUiVisibility & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0) {
showSystemUI();
} else {
hideSystemUI();
}
}
private void hideSystemUI() {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_IMMERSIVE |
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_FULLSCREEN );
}
private void showSystemUI() {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN );
fullscreenHelper.showAndHideWithSystemUI(getWindow(), findViewById(R.id.toolbar_layout));
}
@Override
@@ -188,36 +139,4 @@ public final class AvatarPreviewActivity extends PassphraseRequiredActivity {
onBackPressed();
return true;
}
/**
* Adjust a spacer for the toolbar when a display cutout is detected. Runs within
* a layout listener because the activity delays view attachment due to the transitions
* and needs to update on device rotation.
*/
@TargetApi(28)
private static class DisplayCutoutAdjuster implements ViewTreeObserver.OnGlobalLayoutListener {
private final View view;
private final View spacer;
private DisplayCutoutAdjuster(@NonNull View view, @NonNull View spacer) {
this.view = view;
this.spacer = spacer;
}
@Override
public void onGlobalLayout() {
if (view.getRootWindowInsets() == null) {
return;
}
DisplayCutout cutout = view.getRootWindowInsets().getDisplayCutout();
if (cutout != null) {
ViewGroup.LayoutParams params = spacer.getLayoutParams();
params.height = cutout.getSafeInsetTop();
spacer.setLayoutParams(params);
spacer.setVisibility(View.VISIBLE);
}
}
}
}

View File

@@ -1,23 +1,24 @@
package org.thoughtcrime.securesms;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.content.res.Configuration;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.core.app.ActivityCompat;
import androidx.core.app.ActivityOptionsCompat;
import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import android.view.WindowManager;
import org.thoughtcrime.securesms.logging.Log;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.app.ActivityCompat;
import androidx.core.app.ActivityOptionsCompat;
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.TextSecurePreferences;
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageActivityHelper;
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper;
import java.util.Objects;
@@ -32,20 +33,22 @@ public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
AppStartup.getInstance().onCriticalRenderEventStart();
logEvent("onCreate()");
super.onCreate(savedInstanceState);
AppStartup.getInstance().onCriticalRenderEventEnd();
}
@Override
protected void onResume() {
super.onResume();
initializeScreenshotSecurity();
DynamicLanguageActivityHelper.recreateIfNotInCorrectLanguage(this, TextSecurePreferences.getLanguage(this));
}
@Override
protected void onStart() {
logEvent("onStart()");
ApplicationDependencies.getShakeToReport().registerActivity(this);
super.onStart();
}
@@ -75,23 +78,39 @@ public abstract class BaseActivity extends AppCompatActivity {
ActivityCompat.startActivity(this, intent, bundle);
}
@TargetApi(21)
protected void setStatusBarColor(int color) {
if (Build.VERSION.SDK_INT >= 21) {
getWindow().setStatusBarColor(color);
}
@Override
protected void attachBaseContext(@NonNull Context newBase) {
super.attachBaseContext(newBase);
Configuration configuration = new Configuration(newBase.getResources().getConfiguration());
int appCompatNightMode = getDelegate().getLocalNightMode() != AppCompatDelegate.MODE_NIGHT_UNSPECIFIED ? getDelegate().getLocalNightMode()
: AppCompatDelegate.getDefaultNightMode();
configuration.uiMode = (configuration.uiMode & ~Configuration.UI_MODE_NIGHT_MASK) | mapNightModeToConfigurationUiMode(newBase, appCompatNightMode);
applyOverrideConfiguration(configuration);
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(DynamicLanguageContextWrapper.updateContext(newBase, TextSecurePreferences.getLanguage(newBase)));
public void applyOverrideConfiguration(@NonNull Configuration overrideConfiguration) {
DynamicLanguageContextWrapper.prepareOverrideConfiguration(this, overrideConfiguration);
super.applyOverrideConfiguration(overrideConfiguration);
}
private void logEvent(@NonNull String event) {
Log.d(TAG, "[" + Log.tag(getClass()) + "] " + event);
}
protected final @NonNull ActionBar requireSupportActionBar() {
public final @NonNull ActionBar requireSupportActionBar() {
return Objects.requireNonNull(getSupportActionBar());
}
private static int mapNightModeToConfigurationUiMode(@NonNull Context context, @AppCompatDelegate.NightMode int appCompatNightMode) {
if (appCompatNightMode == AppCompatDelegate.MODE_NIGHT_YES) {
return Configuration.UI_MODE_NIGHT_YES;
} else if (appCompatNightMode == AppCompatDelegate.MODE_NIGHT_NO) {
return Configuration.UI_MODE_NIGHT_NO;
}
return ConfigurationUtil.getNightModeConfiguration(context.getApplicationContext());
}
}

View File

@@ -1,28 +1,39 @@
package org.thoughtcrime.securesms;
import android.net.Uri;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.Observer;
import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState;
import org.thoughtcrime.securesms.contactshare.Contact;
import org.thoughtcrime.securesms.conversation.ConversationMessage;
import org.thoughtcrime.securesms.conversation.colors.Colorizable;
import org.thoughtcrime.securesms.conversation.colors.Colorizer;
import org.thoughtcrime.securesms.database.model.InMemoryMessageRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.giph.mp4.GiphyMp4Playable;
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;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.stickers.StickerLocator;
import org.thoughtcrime.securesms.video.exo.AttachmentMediaSourceFactory;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.List;
import java.util.Locale;
import java.util.Set;
public interface BindableConversationItem extends Unbindable {
void bind(@NonNull ConversationMessage messageRecord,
public interface BindableConversationItem extends Unbindable, GiphyMp4Playable, Colorizable {
void bind(@NonNull LifecycleOwner lifecycleOwner,
@NonNull ConversationMessage messageRecord,
@NonNull Optional<MessageRecord> previousMessageRecord,
@NonNull Optional<MessageRecord> nextMessageRecord,
@NonNull GlideRequests glideRequests,
@@ -30,12 +41,21 @@ public interface BindableConversationItem extends Unbindable {
@NonNull Set<ConversationMessage> batchSelected,
@NonNull Recipient recipients,
@Nullable String searchQuery,
boolean pulseMention);
boolean pulseMention,
boolean hasWallpaper,
boolean isMessageRequestAccepted,
@NonNull AttachmentMediaSourceFactory attachmentMediaSourceFactory,
boolean canPlayInline,
@NonNull Colorizer colorizer);
ConversationMessage getConversationMessage();
void setEventListener(@Nullable EventListener listener);
default void updateTimestamps() {
// Intentionally Blank.
}
interface EventListener {
void onQuoteClicked(MmsMessageRecord messageRecord);
void onLinkPreviewClicked(@NonNull LinkPreview linkPreview);
@@ -49,6 +69,24 @@ public interface BindableConversationItem extends Unbindable {
void onReactionClicked(@NonNull View reactionTarget, long messageId, boolean isMms);
void onGroupMemberClicked(@NonNull RecipientId recipientId, @NonNull GroupId groupId);
void onMessageWithErrorClicked(@NonNull MessageRecord messageRecord);
void onMessageWithRecaptchaNeededClicked(@NonNull MessageRecord messageRecord);
void onIncomingIdentityMismatchClicked(@NonNull RecipientId recipientId);
void onRegisterVoiceNoteCallbacks(@NonNull Observer<VoiceNotePlaybackState> onPlaybackStartObserver);
void onUnregisterVoiceNoteCallbacks(@NonNull Observer<VoiceNotePlaybackState> onPlaybackStartObserver);
void onVoiceNotePause(@NonNull Uri uri);
void onVoiceNotePlay(@NonNull Uri uri, long messageId, double position);
void onVoiceNoteSeekTo(@NonNull Uri uri, double position);
void onVoiceNotePlaybackSpeedChanged(@NonNull Uri uri, float speed);
void onGroupMigrationLearnMoreClicked(@NonNull GroupMigrationMembershipChange membershipChange);
void onChatSessionRefreshLearnMoreClicked();
void onBadDecryptLearnMoreClicked(@NonNull RecipientId author);
void onSafetyNumberLearnMoreClicked(@NonNull Recipient recipient);
void onJoinGroupCallClicked();
void onInviteFriendsToGroupClicked(@NonNull GroupId.V2 groupId);
void onEnableCallNotificationsClicked();
void onPlayInlineContent(ConversationMessage conversationMessage);
void onInMemoryMessageClicked(@NonNull InMemoryMessageRecord messageRecord);
void onViewGroupDescriptionChange(@Nullable GroupId groupId, @NonNull String description, boolean isMessageRequestAccepted);
/** @return true if handled, false if you want to let the normal url handling continue */
boolean onUrlClicked(@NonNull String url);

View File

@@ -9,11 +9,10 @@ import androidx.annotation.WorkerThread;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.Lifecycle;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
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;
/**
@@ -33,15 +32,15 @@ public final class BlockUnblockDialog {
AlertDialog.Builder::show);
}
public static void showBlockAndDeleteFor(@NonNull Context context,
@NonNull Lifecycle lifecycle,
@NonNull Recipient recipient,
@NonNull Runnable onBlock,
@NonNull Runnable onBlockAndDelete)
public static void showBlockAndReportSpamFor(@NonNull Context context,
@NonNull Lifecycle lifecycle,
@NonNull Recipient recipient,
@NonNull Runnable onBlock,
@NonNull Runnable onBlockAndReportSpam)
{
SimpleTask.run(lifecycle,
() -> buildBlockFor(context, recipient, onBlock, onBlockAndDelete),
AlertDialog.Builder::show);
() -> buildBlockFor(context, recipient, onBlock, onBlockAndReportSpam),
AlertDialog.Builder::show);
}
public static void showUnblockFor(@NonNull Context context,
@@ -58,11 +57,11 @@ public final class BlockUnblockDialog {
private static AlertDialog.Builder buildBlockFor(@NonNull Context context,
@NonNull Recipient recipient,
@NonNull Runnable onBlock,
@Nullable Runnable onBlockAndDelete)
@Nullable Runnable onBlockAndReportSpam)
{
recipient = recipient.resolve();
AlertDialog.Builder builder = new AlertDialog.Builder(context);
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(context);
Resources resources = context.getResources();
if (recipient.isGroup()) {
@@ -81,10 +80,10 @@ public final class BlockUnblockDialog {
builder.setTitle(resources.getString(R.string.BlockUnblockDialog_block_s, recipient.getDisplayName(context)));
builder.setMessage(R.string.BlockUnblockDialog_blocked_people_wont_be_able_to_call_you_or_send_you_messages);
if (onBlockAndDelete != null) {
if (onBlockAndReportSpam != null) {
builder.setNeutralButton(android.R.string.cancel, null);
builder.setPositiveButton(R.string.BlockUnblockDialog_block_and_delete, (d, w) -> onBlockAndDelete.run());
builder.setNegativeButton(R.string.BlockUnblockDialog_block, (d, w) -> onBlock.run());
builder.setNegativeButton(R.string.BlockUnblockDialog_report_spam_and_block, (d, w) -> onBlockAndReportSpam.run());
builder.setPositiveButton(R.string.BlockUnblockDialog_block, (d, w) -> onBlock.run());
} else {
builder.setPositiveButton(R.string.BlockUnblockDialog_block, ((dialog, which) -> onBlock.run()));
builder.setNegativeButton(android.R.string.cancel, null);
@@ -101,7 +100,7 @@ public final class BlockUnblockDialog {
{
recipient = recipient.resolve();
AlertDialog.Builder builder = new AlertDialog.Builder(context);
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(context);
Resources resources = context.getResources();
if (recipient.isGroup()) {

View File

@@ -1,139 +0,0 @@
package org.thoughtcrime.securesms;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.cursoradapter.widget.CursorAdapter;
import androidx.fragment.app.ListFragment;
import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.loaders.BlockedContactsLoader;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.preferences.BlockedContactListItem;
import org.thoughtcrime.securesms.recipients.LiveRecipient;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.util.DynamicTheme;
public class BlockedContactsActivity extends PassphraseRequiredActivity {
private final DynamicTheme dynamicTheme = new DynamicTheme();
@Override
public void onPreCreate() {
dynamicTheme.onCreate(this);
}
@Override
public void onCreate(Bundle bundle, boolean ready) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(R.string.BlockedContactsActivity_blocked_contacts);
initFragment(android.R.id.content, new BlockedContactsFragment());
}
@Override
public void onResume() {
super.onResume();
dynamicTheme.onResume(this);
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
public static class BlockedContactsFragment
extends ListFragment
implements LoaderManager.LoaderCallbacks<Cursor>, ListView.OnItemClickListener
{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
return inflater.inflate(R.layout.blocked_contacts_fragment, container, false);
}
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setListAdapter(new BlockedContactAdapter(requireActivity(), GlideApp.with(this), null));
LoaderManager.getInstance(this).initLoader(0, null, this);
}
@Override
public void onStart() {
super.onStart();
LoaderManager.getInstance(this).restartLoader(0, null, this);
}
@Override
public void onActivityCreated(Bundle bundle) {
super.onActivityCreated(bundle);
getListView().setOnItemClickListener(this);
}
@Override
public @NonNull Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new BlockedContactsLoader(getActivity());
}
@Override
public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor data) {
if (getListAdapter() != null) {
((CursorAdapter) getListAdapter()).changeCursor(data);
}
}
@Override
public void onLoaderReset(@NonNull Loader<Cursor> loader) {
if (getListAdapter() != null) {
((CursorAdapter) getListAdapter()).changeCursor(null);
}
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Recipient recipient = ((BlockedContactListItem)view).getRecipient();
BlockUnblockDialog.showUnblockFor(requireContext(), getLifecycle(), recipient, () -> {
RecipientUtil.unblock(requireContext(), recipient);
LoaderManager.getInstance(this).restartLoader(0, null, this);
});
}
private static class BlockedContactAdapter extends CursorAdapter {
private final GlideRequests glideRequests;
BlockedContactAdapter(@NonNull Context context, @NonNull GlideRequests glideRequests, @Nullable Cursor c) {
super(context, c);
this.glideRequests = glideRequests;
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context)
.inflate(R.layout.blocked_contact_list_item, parent, false);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
RecipientId recipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RecipientDatabase.ID)));
LiveRecipient recipient = Recipient.live(recipientId);
((BlockedContactListItem) view).set(glideRequests, recipient);
}
}
}
}

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

@@ -1,181 +0,0 @@
package org.thoughtcrime.securesms;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
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;
import org.thoughtcrime.securesms.jobs.PushDecryptMessageJob;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.sms.MessageSender;
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.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 OnClickListener callback;
public ConfirmIdentityDialog(Context context,
MessageRecord messageRecord,
IdentityKeyMismatch mismatch)
{
super(context);
Recipient recipient = Recipient.resolved(mismatch.getRecipientId(context));
String name = recipient.getDisplayName(context);
String introduction = context.getString(R.string.ConfirmIdentityDialog_your_safety_number_with_s_has_changed, name, name);
SpannableString spannableString = new SpannableString(introduction + " " +
context.getString(R.string.ConfirmIdentityDialog_you_may_wish_to_verify_your_safety_number_with_this_contact));
spannableString.setSpan(new VerifySpan(context, mismatch),
introduction.length()+1, spannableString.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
setTitle(name);
setMessage(spannableString);
setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.ConfirmIdentityDialog_accept), new AcceptListener(messageRecord, mismatch, recipient.getId()));
setButton(AlertDialog.BUTTON_NEGATIVE, context.getString(android.R.string.cancel), new CancelListener());
}
@Override
public void show() {
super.show();
((TextView)this.findViewById(android.R.id.message))
.setMovementMethod(LinkMovementMethod.getInstance());
}
public void setCallback(OnClickListener callback) {
this.callback = callback;
}
private class AcceptListener implements OnClickListener {
private final MessageRecord messageRecord;
private final IdentityKeyMismatch mismatch;
private final RecipientId recipientId;
private AcceptListener(MessageRecord messageRecord, IdentityKeyMismatch mismatch, RecipientId recipientId) {
this.messageRecord = messageRecord;
this.mismatch = mismatch;
this.recipientId = recipientId;
}
@SuppressLint("StaticFieldLeak")
@Override
public void onClick(DialogInterface dialog, int which) {
new AsyncTask<Void, Void, Void>()
{
@Override
protected Void doInBackground(Void... params) {
synchronized (SESSION_LOCK) {
SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(Recipient.resolved(recipientId).requireServiceId(), 1);
TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(getContext());
identityKeyStore.saveIdentity(mismatchAddress, mismatch.getIdentityKey(), true);
}
processMessageRecord(messageRecord);
return null;
}
private void processMessageRecord(MessageRecord messageRecord) {
if (messageRecord.isOutgoing()) processOutgoingMessageRecord(messageRecord);
else processIncomingMessageRecord(messageRecord);
}
private void processOutgoingMessageRecord(MessageRecord messageRecord) {
MessageDatabase smsDatabase = DatabaseFactory.getSmsDatabase(getContext());
MessageDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(getContext());
if (messageRecord.isMms()) {
mmsDatabase.removeMismatchedIdentity(messageRecord.getId(),
mismatch.getRecipientId(getContext()),
mismatch.getIdentityKey());
if (messageRecord.getRecipient().isPushGroup()) {
MessageSender.resendGroupMessage(getContext(), messageRecord, Recipient.resolved(mismatch.getRecipientId(getContext())).getId());
} else {
MessageSender.resend(getContext(), messageRecord);
}
} else {
smsDatabase.removeMismatchedIdentity(messageRecord.getId(),
mismatch.getRecipientId(getContext()),
mismatch.getIdentityKey());
MessageSender.resend(getContext(), messageRecord);
}
}
private void processIncomingMessageRecord(MessageRecord messageRecord) {
try {
PushDatabase pushDatabase = DatabaseFactory.getPushDatabase(getContext());
MessageDatabase smsDatabase = DatabaseFactory.getSmsDatabase(getContext());
smsDatabase.removeMismatchedIdentity(messageRecord.getId(),
mismatch.getRecipientId(getContext()),
mismatch.getIdentityKey());
boolean legacy = !messageRecord.isContentBundleKeyExchange();
SignalServiceEnvelope envelope = new SignalServiceEnvelope(SignalServiceProtos.Envelope.Type.PREKEY_BUNDLE_VALUE,
Optional.of(RecipientUtil.toSignalServiceAddress(getContext(), messageRecord.getIndividualRecipient())),
messageRecord.getRecipientDeviceId(),
messageRecord.getDateSent(),
legacy ? Base64.decode(messageRecord.getBody()) : null,
!legacy ? Base64.decode(messageRecord.getBody()) : null,
0,
0,
null);
long pushId = pushDatabase.insert(envelope);
ApplicationDependencies.getJobManager().add(new PushDecryptMessageJob(getContext(), pushId, messageRecord.getId()));
} catch (IOException e) {
throw new AssertionError(e);
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
if (callback != null) callback.onClick(null, 0);
}
}
private class CancelListener implements OnClickListener {
@Override
public void onClick(DialogInterface dialog, int which) {
if (callback != null) callback.onClick(null, 0);
}
}
}

View File

@@ -20,17 +20,18 @@ import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.appcompat.widget.Toolbar;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.thoughtcrime.securesms.components.ContactFilterToolbar;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.components.ContactFilterView;
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;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Optional;
import java.io.IOException;
@@ -47,7 +48,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";
@@ -55,7 +56,8 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActivit
protected ContactSelectionListFragment contactsFragment;
private ContactFilterToolbar toolbar;
private Toolbar toolbar;
private ContactFilterView contactFilterView;
@Override
protected void onPreCreate() {
@@ -65,13 +67,14 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActivit
@Override
protected void onCreate(Bundle icicle, boolean ready) {
if (!getIntent().hasExtra(ContactSelectionListFragment.DISPLAY_MODE)) {
int displayMode = TextSecurePreferences.isSmsEnabled(this) ? DisplayMode.FLAG_ALL
: DisplayMode.FLAG_PUSH | DisplayMode.FLAG_ACTIVE_GROUPS | DisplayMode.FLAG_INACTIVE_GROUPS | DisplayMode.FLAG_SELF;
int displayMode = Util.isDefaultSmsProvider(this) ? DisplayMode.FLAG_ALL
: DisplayMode.FLAG_PUSH | DisplayMode.FLAG_ACTIVE_GROUPS | DisplayMode.FLAG_INACTIVE_GROUPS | DisplayMode.FLAG_SELF;
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, displayMode);
}
setContentView(getIntent().getIntExtra(EXTRA_LAYOUT_RES_ID, R.layout.contact_selection_activity));
initializeContactFilterView();
initializeToolbar();
initializeResources();
initializeSearch();
@@ -83,28 +86,34 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActivit
dynamicTheme.onResume(this);
}
protected ContactFilterToolbar getToolbar() {
protected Toolbar getToolbar() {
return toolbar;
}
protected ContactFilterView getContactFilterView() {
return contactFilterView;
}
private void initializeContactFilterView() {
this.contactFilterView = findViewById(R.id.contact_filter_edit_text);
}
private void initializeToolbar() {
this.toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setIcon(null);
getSupportActionBar().setLogo(null);
}
private void initializeResources() {
contactsFragment = (ContactSelectionListFragment) getSupportFragmentManager().findFragmentById(R.id.contact_selection_list_fragment);
contactsFragment.setOnContactSelectedListener(this);
contactsFragment.setOnRefreshListener(this);
}
private void initializeSearch() {
toolbar.setOnFilterChangedListener(filter -> contactsFragment.setQueryFilter(filter));
contactFilterView.setOnFilterChangedListener(filter -> contactsFragment.setQueryFilter(filter));
}
@Override
@@ -113,7 +122,7 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActivit
}
@Override
public boolean onContactSelected(Optional<RecipientId> recipientId, String number) {
public boolean onBeforeContactSelected(Optional<RecipientId> recipientId, String number) {
return true;
}
@@ -155,7 +164,7 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActivit
ContactSelectionActivity activity = this.activity.get();
if (activity != null && !activity.isFinishing()) {
activity.toolbar.clear();
activity.contactFilterView.clear();
activity.contactsFragment.resetQueryFilter();
}
}

View File

@@ -21,6 +21,7 @@ import android.Manifest;
import android.animation.LayoutTransition;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -29,7 +30,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.CycleInterpolator;
import android.widget.Button;
import android.widget.HorizontalScrollView;
import android.widget.TextView;
@@ -55,25 +55,29 @@ 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.recyclerview.ToolbarShadowAnimationHelper;
import org.thoughtcrime.securesms.contacts.AbstractContactsCursorLoader;
import org.thoughtcrime.securesms.contacts.ContactChip;
import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter;
import org.thoughtcrime.securesms.contacts.ContactSelectionListItem;
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader;
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
import org.thoughtcrime.securesms.contacts.LetterHeaderDecoration;
import org.thoughtcrime.securesms.contacts.SelectedContact;
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.groups.SelectionLimits;
import org.thoughtcrime.securesms.groups.ui.GroupLimitDialog;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.recipients.LiveRecipient;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.FeatureFlags;
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;
@@ -83,7 +87,6 @@ import org.whispersystems.libsignal.util.guava.Optional;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Set;
/**
@@ -104,35 +107,46 @@ public final class ContactSelectionListFragment extends LoggingFragment
public static final int NO_LIMIT = Integer.MAX_VALUE;
public static final String DISPLAY_MODE = "display_mode";
public static final String MULTI_SELECT = "multi_select";
public static final String REFRESHABLE = "refreshable";
public static final String RECENTS = "recents";
public static final String TOTAL_CAPACITY = "total_capacity";
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";
public static final String RV_PADDING_BOTTOM = "recycler_view_padding_bottom";
public static final String RV_CLIP = "recycler_view_clipping";
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 OnSelectionLimitReachedListener onSelectionLimitReachedListener;
private AbstractContactsCursorLoaderFactoryProvider cursorFactoryProvider;
private View shadowView;
private ToolbarShadowAnimationHelper toolbarShadowAnimationHelper;
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 TextView groupLimit;
@Nullable private FixedViewsAdapter headerAdapter;
@Nullable private FixedViewsAdapter footerAdapter;
@Nullable private ListCallback listCallback;
@Nullable private ScrollCallback scrollCallback;
private GlideRequests glideRequests;
private int selectionLimit;
private SelectionLimits selectionLimit = SelectionLimits.NO_LIMITS;
private Set<RecipientId> currentSelection;
private boolean isMulti;
private boolean hideCount;
private boolean canSelectSelf;
@Override
public void onAttach(@NonNull Context context) {
@@ -142,9 +156,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
@@ -173,7 +211,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();
@@ -196,9 +234,12 @@ public final class ContactSelectionListFragment extends LoggingFragment
showContactsProgress = view.findViewById(R.id.progress);
chipGroup = view.findViewById(R.id.chipGroup);
chipGroupScrollContainer = view.findViewById(R.id.chipGroupScrollContainer);
groupLimit = view.findViewById(R.id.group_limit);
constraintLayout = view.findViewById(R.id.container);
shadowView = view.findViewById(R.id.toolbar_shadow);
toolbarShadowAnimationHelper = new ToolbarShadowAnimationHelper(shadowView);
recyclerView.addOnScrollListener(toolbarShadowAnimationHelper);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setItemAnimator(new DefaultItemAnimator() {
@Override
@@ -207,23 +248,39 @@ public final class ContactSelectionListFragment extends LoggingFragment
}
});
swipeRefresh.setEnabled(requireActivity().getIntent().getBooleanExtra(REFRESHABLE, true));
Intent intent = requireActivity().getIntent();
Bundle arguments = safeArguments();
int recyclerViewPadBottom = arguments.getInt(RV_PADDING_BOTTOM, intent.getIntExtra(RV_PADDING_BOTTOM, -1));
boolean recyclerViewClipping = arguments.getBoolean(RV_CLIP, intent.getBooleanExtra(RV_CLIP, true));
if (recyclerViewPadBottom != -1) {
ViewUtil.setPaddingBottom(recyclerView, recyclerViewPadBottom);
}
recyclerView.setClipToPadding(recyclerViewClipping);
swipeRefresh.setEnabled(arguments.getBoolean(REFRESHABLE, intent.getBooleanExtra(REFRESHABLE, true)));
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;
}
selectionLimit = requireActivity().getIntent().getIntExtra(TOTAL_CAPACITY, NO_LIMIT);
currentSelection = getCurrentSelection();
updateGroupLimit(getChipCount());
return view;
}
private void updateGroupLimit(int chipCount) {
if (selectionLimit != NO_LIMIT) {
groupLimit.setText(String.format(Locale.getDefault(), "%d/%d", currentSelection.size() + chipCount, selectionLimit));
groupLimit.setVisibility(View.VISIBLE);
} else {
groupLimit.setVisibility(View.GONE);
}
private @NonNull Bundle safeArguments() {
return getArguments() != null ? getArguments() : new Bundle();
}
@Override
@@ -247,15 +304,26 @@ public final class ContactSelectionListFragment extends LoggingFragment
return cursorRecyclerViewAdapter.getSelectedContactsCount();
}
public int getTotalMemberCount() {
if (cursorRecyclerViewAdapter == null) {
return 0;
}
return cursorRecyclerViewAdapter.getSelectedContactsCount() + cursorRecyclerViewAdapter.getCurrentContactsCount();
}
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()));
}
public boolean isMulti() {
return requireActivity().getIntent().getBooleanExtra(MULTI_SELECT, false);
return isMulti;
}
private void initializeCursor() {
@@ -265,7 +333,7 @@ public final class ContactSelectionListFragment extends LoggingFragment
glideRequests,
null,
new ListClickListener(),
isMulti(),
isMulti,
currentSelection);
RecyclerViewConcatenateAdapterStickyHeader concatenateAdapter = new RecyclerViewConcatenateAdapterStickyHeader();
@@ -284,8 +352,8 @@ public final class ContactSelectionListFragment extends LoggingFragment
concatenateAdapter.addAdapter(footerAdapter);
}
recyclerView.addItemDecoration(new LetterHeaderDecoration(requireContext(), this::hideLetterHeaders));
recyclerView.setAdapter(concatenateAdapter);
recyclerView.addItemDecoration(new StickyHeaderDecoration(concatenateAdapter, true, true));
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
@@ -296,6 +364,14 @@ public final class ContactSelectionListFragment extends LoggingFragment
}
}
});
if (onContactSelectedListener != null) {
onContactSelectedListener.onSelectionChanged();
}
}
private boolean hideLetterHeaders() {
return hasQueryFilter() || shouldDisplayRecents();
}
private View createInviteActionView(@NonNull ListCallback listCallback) {
@@ -362,10 +438,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 = shouldDisplayRecents();
if (cursorFactoryProvider != null) {
return cursorFactoryProvider.get().create();
} else {
return new ContactsCursorLoader.Factory(activity, displayMode, cursorFilter, displayRecents).create();
}
}
@Override
@@ -405,6 +486,10 @@ public final class ContactSelectionListFragment extends LoggingFragment
fastScroller.setVisibility(View.GONE);
}
private boolean shouldDisplayRecents() {
return safeArguments().getBoolean(RECENTS, requireActivity().getIntent().getBooleanExtra(RECENTS, false));
}
@SuppressLint("StaticFieldLeak")
private void handleContactPermissionGranted() {
final Context context = requireContext();
@@ -438,8 +523,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();
@@ -451,15 +539,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 (selectionLimitReached()) {
Toast.makeText(requireContext(), R.string.ContactSelectionListFragment_the_group_is_full, Toast.LENGTH_SHORT).show();
groupLimit.animate().scaleX(1.3f).scaleY(1.3f).setInterpolator(new CycleInterpolator(0.5f)).start();
if (!isMulti || !cursorRecyclerViewAdapter.isSelectedContact(selectedContact)) {
if (selectionHardLimitReached()) {
if (onSelectionLimitReachedListener != null) {
onSelectionLimitReachedListener.onHardLimitReached(selectionLimit.getHardLimit());
} else {
GroupLimitDialog.showHardLimitMessage(requireContext());
}
return;
}
@@ -475,58 +566,74 @@ public final class ContactSelectionListFragment extends LoggingFragment
SelectedContact selected = SelectedContact.forUsername(recipient.getId(), contact.getNumber());
if (onContactSelectedListener != null) {
if (onContactSelectedListener.onContactSelected(Optional.of(recipient.getId()), 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())
.setTitle(R.string.ContactSelectionListFragment_username_not_found)
.setMessage(getString(R.string.ContactSelectionListFragment_s_is_not_a_signal_user, contact.getNumber()))
.setPositiveButton(R.string.ContactSelectionListFragment_okay, (dialog, which) -> dialog.dismiss())
.setPositiveButton(android.R.string.ok, (dialog, which) -> dialog.dismiss())
.show();
}
});
} else {
if (onContactSelectedListener != null) {
if (onContactSelectedListener.onContactSelected(contact.getRecipientId(), contact.getNumber())) {
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());
}
}}
}
}
}
private boolean selectionLimitReached() {
return getChipCount() >= selectionLimit;
private boolean selectionHardLimitReached() {
return getChipCount() + currentSelection.size() >= selectionLimit.getHardLimit();
}
private boolean selectionWarningLimitReachedExactly() {
return getChipCount() + currentSelection.size() == selectionLimit.getRecommendedLimit();
}
private boolean selectionWarningLimitExceeded() {
return getChipCount() + currentSelection.size() > selectionLimit.getRecommendedLimit();
}
private void markContactSelected(@NonNull SelectedContact selectedContact) {
cursorRecyclerViewAdapter.addSelectedContact(selectedContact);
if (isMulti()) {
if (isMulti) {
addChipForSelectedContact(selectedContact);
}
if (onContactSelectedListener != null) {
onContactSelectedListener.onSelectionChanged();
}
}
private void markContactUnselected(@NonNull SelectedContact selectedContact) {
cursorRecyclerViewAdapter.removeFromSelectedContacts(selectedContact);
cursorRecyclerViewAdapter.notifyItemRangeChanged(0, cursorRecyclerViewAdapter.getItemCount(), ContactSelectionListAdapter.PAYLOAD_SELECTION_CHANGE);
removeChipForContact(selectedContact);
if (onContactSelectedListener != null) {
onContactSelectedListener.onSelectionChanged();
}
}
private void removeChipForContact(@NonNull SelectedContact contact) {
@@ -537,8 +644,6 @@ public final class ContactSelectionListFragment extends LoggingFragment
}
}
updateGroupLimit(getChipCount());
if (getChipCount() == 0) {
setChipGroupVisibility(ConstraintSet.GONE);
}
@@ -588,7 +693,13 @@ public final class ContactSelectionListFragment extends LoggingFragment
private void addChip(@NonNull ContactChip chip) {
chipGroup.addView(chip);
updateGroupLimit(getChipCount());
if (selectionWarningLimitReachedExactly()) {
if (onSelectionLimitReachedListener != null) {
onSelectionLimitReachedListener.onSuggestedLimitReached(selectionLimit.getRecommendedLimit());
} else {
GroupLimitDialog.showRecommendedLimitMessage(requireContext());
}
}
}
private int getChipCount() {
@@ -609,6 +720,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();
@@ -617,23 +732,25 @@ 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);
}
public interface OnContactSelectedListener {
/** @return True if the contact is allowed to be selected, otherwise false. */
boolean onContactSelected(Optional<RecipientId> recipientId, String number);
boolean onBeforeContactSelected(Optional<RecipientId> recipientId, String number);
void onContactDeselected(Optional<RecipientId> recipientId, String number);
void onSelectionChanged();
}
public interface OnSelectionLimitReachedListener {
void onSuggestedLimitReached(int limit);
void onHardLimitReached(int limit);
}
public interface ListCallback {
@@ -644,4 +761,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

@@ -16,19 +16,21 @@ import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
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.DynamicNoActionBarTheme;
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,9 +47,9 @@ 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 DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
private DeviceAddFragment deviceAddFragment;
@@ -62,9 +64,14 @@ public class DeviceActivity extends PassphraseRequiredActivity
@Override
public void onCreate(Bundle bundle, boolean ready) {
getSupportActionBar().setHomeAsUpIndicator(ContextCompat.getDrawable(this, R.drawable.ic_arrow_left_24));
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(R.string.AndroidManifest__linked_devices);
setContentView(R.layout.device_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
requireSupportActionBar().setDisplayHomeAsUpEnabled(true);
requireSupportActionBar().setTitle(R.string.AndroidManifest__linked_devices);
this.deviceAddFragment = new DeviceAddFragment();
this.deviceListFragment = new DeviceListFragment();
this.deviceLinkFragment = new DeviceLinkFragment();
@@ -73,20 +80,10 @@ public class DeviceActivity extends PassphraseRequiredActivity
this.deviceAddFragment.setScanListener(this);
if (getIntent().getBooleanExtra("add", false)) {
initFragment(android.R.id.content, deviceAddFragment, dynamicLanguage.getCurrentLocale());
initFragment(R.id.fragment_container, deviceAddFragment, dynamicLanguage.getCurrentLocale());
} else {
initFragment(android.R.id.content, deviceListFragment, dynamicLanguage.getCurrentLocale());
initFragment(R.id.fragment_container, deviceListFragment, dynamicLanguage.getCurrentLocale());
}
overridePendingTransition(R.anim.slide_from_end, R.anim.slide_to_start);
}
@Override
protected void onPause() {
if (isFinishing()) {
overridePendingTransition(R.anim.slide_from_start, R.anim.slide_to_end);
}
super.onPause();
}
@Override
@@ -98,8 +95,9 @@ public class DeviceActivity extends PassphraseRequiredActivity
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home: finish(); return true;
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return false;
@@ -113,7 +111,7 @@ public class DeviceActivity extends PassphraseRequiredActivity
.withPermanentDenialDialog(getString(R.string.DeviceActivity_signal_needs_the_camera_permission_in_order_to_scan_a_qr_code))
.onAllGranted(() -> {
getSupportFragmentManager().beginTransaction()
.replace(android.R.id.content, deviceAddFragment)
.replace(R.id.fragment_container, deviceAddFragment)
.addToBackStack(null)
.commitAllowingStateLoss();
})
@@ -123,12 +121,12 @@ 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);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (Build.VERSION.SDK_INT >= 21) {
deviceAddFragment.setSharedElementReturnTransition(TransitionInflater.from(DeviceActivity.this).inflateTransition(R.transition.fragment_shared));
deviceAddFragment.setExitTransition(TransitionInflater.from(DeviceActivity.this).inflateTransition(android.R.transition.fade));
@@ -138,14 +136,14 @@ public class DeviceActivity extends PassphraseRequiredActivity
getSupportFragmentManager().beginTransaction()
.addToBackStack(null)
.addSharedElement(deviceAddFragment.getDevicesImage(), "devices")
.replace(android.R.id.content, deviceLinkFragment)
.replace(R.id.fragment_container, deviceLinkFragment)
.commit();
} else {
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.slide_from_bottom, R.anim.slide_to_bottom,
R.anim.slide_from_bottom, R.anim.slide_to_bottom)
.replace(android.R.id.content, deviceLinkFragment)
.replace(R.id.fragment_container, deviceLinkFragment)
.addToBackStack(null)
.commit();
}

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);
@@ -42,9 +42,9 @@ public class DeviceAddFragment extends LoggingFragment {
this.overlay.setOrientation(LinearLayout.VERTICAL);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (Build.VERSION.SDK_INT >= 21) {
this.container.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@TargetApi(21)
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom)
@@ -80,7 +80,7 @@ public class DeviceAddFragment extends LoggingFragment {
}
@Override
public void onConfigurationChanged(Configuration newConfiguration) {
public void onConfigurationChanged(@NonNull Configuration newConfiguration) {
super.onConfigurationChanged(newConfiguration);
this.scannerView.onPause();
@@ -107,6 +107,4 @@ public class DeviceAddFragment extends LoggingFragment {
this.scanningThread.setScanListener(scanListener);
}
}
}

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;
@@ -31,7 +32,7 @@ public class DeviceLinkFragment extends Fragment implements View.OnClickListener
}
@Override
public void onConfigurationChanged(Configuration newConfiguration) {
public void onConfigurationChanged(@NonNull Configuration newConfiguration) {
super.onConfigurationChanged(newConfiguration);
if (newConfiguration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
container.setOrientation(LinearLayout.HORIZONTAL);

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,21 @@ 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.google.android.material.dialog.MaterialAlertDialogBuilder;
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 +41,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;
@@ -53,12 +53,12 @@ public class DeviceListFragment extends ListFragment
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.locale = (Locale) getArguments().getSerializable(PassphraseRequiredActivity.LOCALE_EXTRA);
this.locale = (Locale) requireArguments().getSerializable(PassphraseRequiredActivity.LOCALE_EXTRA);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
public void onAttach(@NonNull Context context) {
super.onAttach(context);
this.accountManager = ApplicationDependencies.getSignalServiceAccountManager();
}
@@ -68,7 +68,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;
@@ -122,42 +122,22 @@ public class DeviceListFragment extends ListFragment
final String deviceName = ((DeviceListItem)view).getDeviceName();
final long deviceId = ((DeviceListItem)view).getDeviceId();
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(getActivity().getString(R.string.DeviceListActivity_unlink_s, deviceName));
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(requireActivity());
builder.setTitle(getString(R.string.DeviceListActivity_unlink_s, deviceName));
builder.setMessage(R.string.DeviceListActivity_by_unlinking_this_device_it_will_no_longer_be_able_to_send_or_receive);
builder.setNegativeButton(android.R.string.cancel, null);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
handleDisconnectDevice(deviceId);
}
});
builder.setPositiveButton(android.R.string.ok, (dialog, which) -> handleDisconnectDevice(deviceId));
builder.show();
}
private void handleLoaderFailed() {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(requireActivity());
builder.setMessage(R.string.DeviceListActivity_network_connection_failed);
builder.setPositiveButton(R.string.DeviceListActivity_try_again,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
getLoaderManager().restartLoader(0, null, DeviceListFragment.this);
}
});
(dialog, which) -> getLoaderManager().restartLoader(0, null, DeviceListFragment.this));
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
DeviceListFragment.this.getActivity().onBackPressed();
}
});
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
DeviceListFragment.this.getActivity().onBackPressed();
}
});
builder.setNegativeButton(android.R.string.cancel, (dialog, which) -> requireActivity().onBackPressed());
builder.setOnCancelListener(dialog -> requireActivity().onBackPressed());
builder.show();
}

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

@@ -1,103 +0,0 @@
package org.thoughtcrime.securesms;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import org.thoughtcrime.securesms.util.ExpirationUtil;
import java.util.Arrays;
import cn.carbswang.android.numberpickerview.library.NumberPickerView;
public class ExpirationDialog extends AlertDialog {
protected ExpirationDialog(Context context) {
super(context);
}
protected ExpirationDialog(Context context, int theme) {
super(context, theme);
}
protected ExpirationDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
}
public static void show(final Context context,
final int currentExpiration,
final @NonNull OnClickListener listener)
{
final View view = createNumberPickerView(context, currentExpiration);
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(context.getString(R.string.ExpirationDialog_disappearing_messages));
builder.setView(view);
builder.setPositiveButton(android.R.string.ok, (dialog, which) -> {
int selected = ((NumberPickerView)view.findViewById(R.id.expiration_number_picker)).getValue();
listener.onClick(getExpirationTimes(context, currentExpiration)[selected]);
});
builder.setNegativeButton(android.R.string.cancel, null);
builder.show();
}
private static View createNumberPickerView(final Context context, final int currentExpiration) {
final LayoutInflater inflater = LayoutInflater.from(context);
final View view = inflater.inflate(R.layout.expiration_dialog, null);
final NumberPickerView numberPickerView = view.findViewById(R.id.expiration_number_picker);
final TextView textView = view.findViewById(R.id.expiration_details);
final int[] expirationTimes = getExpirationTimes(context, currentExpiration);
final String[] expirationDisplayValues = new String[expirationTimes.length];
int selectedIndex = expirationTimes.length - 1;
for (int i=0;i<expirationTimes.length;i++) {
expirationDisplayValues[i] = ExpirationUtil.getExpirationDisplayValue(context, expirationTimes[i]);
if ((currentExpiration >= expirationTimes[i]) &&
(i == expirationTimes.length -1 || currentExpiration < expirationTimes[i+1])) {
selectedIndex = i;
}
}
numberPickerView.setDisplayedValues(expirationDisplayValues);
numberPickerView.setMinValue(0);
numberPickerView.setMaxValue(expirationTimes.length-1);
NumberPickerView.OnValueChangeListener listener = (picker, oldVal, newVal) -> {
if (newVal == 0) {
textView.setText(R.string.ExpirationDialog_your_messages_will_not_expire);
} else {
textView.setText(context.getString(R.string.ExpirationDialog_your_messages_will_disappear_s_after_they_have_been_seen, picker.getDisplayedValues()[newVal]));
}
};
numberPickerView.setOnValueChangedListener(listener);
numberPickerView.setValue(selectedIndex);
listener.onValueChange(numberPickerView, selectedIndex, selectedIndex);
return view;
}
private static int[] getExpirationTimes(Context context, int currentExpiration) {
int[] expirationTimes = context.getResources().getIntArray(R.array.expiration_times);
int location = Arrays.binarySearch(expirationTimes, currentExpiration);
if (location < 0) {
int[] temp = Arrays.copyOf(expirationTimes, expirationTimes.length + 1);
temp[temp.length - 1] = currentExpiration;
Arrays.sort(temp);
expirationTimes = temp;
}
return expirationTimes;
}
public interface OnClickListener {
public void onClick(int expirationTime);
}
}

View File

@@ -28,7 +28,7 @@ public final class GroupMembersDialog {
public void display() {
AlertDialog dialog = new AlertDialog.Builder(fragmentActivity)
.setTitle(R.string.ConversationActivity_group_members)
.setIconAttribute(R.attr.group_members_dialog_icon)
.setIcon(R.drawable.ic_group_24)
.setCancelable(true)
.setView(R.layout.dialog_group_members)
.setPositiveButton(android.R.string.ok, null)

View File

@@ -22,11 +22,12 @@ import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import org.thoughtcrime.securesms.components.ContactFilterToolbar;
import org.thoughtcrime.securesms.components.ContactFilterToolbar.OnFilterChangedListener;
import org.thoughtcrime.securesms.components.ContactFilterView;
import org.thoughtcrime.securesms.components.ContactFilterView.OnFilterChangedListener;
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
import org.thoughtcrime.securesms.contacts.SelectedContact;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.groups.SelectionLimits;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.sms.MessageSender;
@@ -34,13 +35,14 @@ 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.List;
import java.util.concurrent.ExecutionException;
public class InviteActivity extends PassphraseRequiredActivity implements ContactSelectionListFragment.OnContactSelectedListener {
@@ -63,7 +65,8 @@ public class InviteActivity extends PassphraseRequiredActivity implements Contac
@Override
protected void onCreate(Bundle savedInstanceState, boolean ready) {
getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_SMS);
getIntent().putExtra(ContactSelectionListFragment.MULTI_SELECT, true);
getIntent().putExtra(ContactSelectionListFragment.SELECTION_LIMITS, SelectionLimits.NO_LIMITS);
getIntent().putExtra(ContactSelectionListFragment.HIDE_COUNT, true);
getIntent().putExtra(ContactSelectionListFragment.REFRESHABLE, false);
setContentView(R.layout.invite_activity);
@@ -92,26 +95,41 @@ 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);
Toolbar smsToolbar = findViewById(R.id.sms_send_frame_toolbar);
ContactFilterView contactFilter = findViewById(R.id.contact_filter_edit_text);
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)));
updateSmsButtonText();
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);
smsToolbar.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) {
@@ -121,14 +139,18 @@ public class InviteActivity extends PassphraseRequiredActivity implements Contac
}
@Override
public boolean onContactSelected(Optional<RecipientId> recipientId, String number) {
updateSmsButtonText();
public boolean onBeforeContactSelected(Optional<RecipientId> recipientId, String number) {
updateSmsButtonText(contactsFragment.getSelectedContacts().size() + 1);
return true;
}
@Override
public void onContactDeselected(Optional<RecipientId> recipientId, String number) {
updateSmsButtonText();
updateSmsButtonText(contactsFragment.getSelectedContacts().size());
}
@Override
public void onSelectionChanged() {
}
private void sendSmsInvites() {
@@ -138,12 +160,11 @@ public class InviteActivity extends PassphraseRequiredActivity implements Contac
.toArray(new SelectedContact[0]));
}
private void updateSmsButtonText() {
List<SelectedContact> selectedContacts = contactsFragment.getSelectedContacts();
private void updateSmsButtonText(int count) {
smsSendButton.setText(getResources().getQuantityString(R.plurals.InviteActivity_send_sms_to_friends,
selectedContacts.size(),
selectedContacts.size()));
smsSendButton.setEnabled(!selectedContacts.isEmpty());
count,
count));
smsSendButton.setEnabled(count > 0);
}
@Override public void onBackPressed() {
@@ -157,17 +178,17 @@ public class InviteActivity extends PassphraseRequiredActivity implements Contac
private void cancelSmsSelection() {
setPrimaryColorsToolbarNormal();
contactsFragment.reset();
updateSmsButtonText();
updateSmsButtonText(contactsFragment.getSelectedContacts().size());
ViewUtil.animateOut(smsSendFrame, slideOutAnimation, View.GONE);
}
private void setPrimaryColorsToolbarNormal() {
primaryToolbar.setBackgroundColor(0);
primaryToolbar.getNavigationIcon().setColorFilter(null);
primaryToolbar.setTitleTextColor(ThemeUtil.getThemedColor(this, R.attr.title_text_color_primary));
primaryToolbar.setTitleTextColor(ContextCompat.getColor(this, R.color.signal_text_primary));
if (Build.VERSION.SDK_INT >= 23) {
getWindow().setStatusBarColor(ThemeUtil.getThemedColor(this, android.R.attr.statusBarColor));
WindowUtil.setStatusBarColor(getWindow(), ThemeUtil.getThemedColor(this, android.R.attr.statusBarColor));
getWindow().setNavigationBarColor(ThemeUtil.getThemedColor(this, android.R.attr.navigationBarColor));
WindowUtil.setLightStatusBarFromTheme(this);
}
@@ -177,11 +198,11 @@ public class InviteActivity extends PassphraseRequiredActivity implements Contac
private void setPrimaryColorsToolbarForSms() {
primaryToolbar.setBackgroundColor(ContextCompat.getColor(this, R.color.core_ultramarine));
primaryToolbar.getNavigationIcon().setColorFilter(ThemeUtil.getThemedColor(this, R.attr.conversation_subtitle_color), PorterDuff.Mode.SRC_IN);
primaryToolbar.setTitleTextColor(ThemeUtil.getThemedColor(this, R.attr.conversation_title_color));
primaryToolbar.getNavigationIcon().setColorFilter(ContextCompat.getColor(this, R.color.signal_text_toolbar_subtitle), PorterDuff.Mode.SRC_IN);
primaryToolbar.setTitleTextColor(ContextCompat.getColor(this, R.color.signal_text_toolbar_title));
if (Build.VERSION.SDK_INT >= 23) {
getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.core_ultramarine));
WindowUtil.setStatusBarColor(getWindow(), ContextCompat.getColor(this, R.color.core_ultramarine));
WindowUtil.clearLightStatusBar(getWindow());
}

View File

@@ -0,0 +1,49 @@
package org.thoughtcrime.securesms;
import androidx.annotation.NonNull;
import java.util.Objects;
/**
* Used in our {@link BuildConfig} to tie together the various attributes of a KBS instance. This
* is sitting in the root directory so it can be accessed by the build config.
*/
public final class KbsEnclave {
private final String enclaveName;
private final String serviceId;
private final String mrEnclave;
public KbsEnclave(@NonNull String enclaveName, @NonNull String serviceId, @NonNull String mrEnclave) {
this.enclaveName = enclaveName;
this.serviceId = serviceId;
this.mrEnclave = mrEnclave;
}
public @NonNull String getMrEnclave() {
return mrEnclave;
}
public @NonNull String getEnclaveName() {
return enclaveName;
}
public @NonNull String getServiceId() {
return serviceId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
KbsEnclave enclave = (KbsEnclave) o;
return enclaveName.equals(enclave.enclaveName) &&
serviceId.equals(enclave.serviceId) &&
mrEnclave.equals(enclave.mrEnclave);
}
@Override
public int hashCode() {
return Objects.hash(enclaveName, serviceId, mrEnclave);
}
}

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,34 +1,70 @@
package org.thoughtcrime.securesms;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController;
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaControllerOwner;
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;
public class MainActivity extends PassphraseRequiredActivity {
public class MainActivity extends PassphraseRequiredActivity implements VoiceNoteMediaControllerOwner {
public static final int RESULT_CONFIG_CHANGED = Activity.RESULT_FIRST_USER + 901;
private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme();
private final MainNavigator navigator = new MainNavigator(this);
private VoiceNoteMediaController mediaController;
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);
mediaController = new VoiceNoteMediaController(this);
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
@@ -41,6 +77,9 @@ public class MainActivity extends PassphraseRequiredActivity {
protected void onResume() {
super.onResume();
dynamicTheme.onResume(this);
if (SignalStore.misc().isOldDeviceTransferLocked()) {
OldDeviceTransferLockedDialog.show(getSupportFragmentManager());
}
}
@Override
@@ -50,6 +89,14 @@ public class MainActivity extends PassphraseRequiredActivity {
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == MainNavigator.REQUEST_CONFIG_CHANGES && resultCode == RESULT_CONFIG_CHANGED) {
recreate();
}
}
public @NonNull MainNavigator getNavigator() {
return navigator;
}
@@ -60,4 +107,16 @@ 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());
}
}
@Override
public @NonNull VoiceNoteMediaController getVoiceNoteMediaController() {
return mediaController;
}
}

View File

@@ -9,7 +9,9 @@ import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import org.thoughtcrime.securesms.conversation.ConversationActivity;
import org.thoughtcrime.securesms.components.settings.DSLSettingsActivity;
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
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;
@@ -18,6 +20,8 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
public class MainNavigator {
public static final int REQUEST_CONFIG_CHANGES = 901;
private final MainActivity activity;
public MainNavigator(@NonNull MainActivity activity) {
@@ -57,18 +61,19 @@ 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);
}
public void goToAppSettings() {
Intent intent = new Intent(activity, ApplicationPreferencesActivity.class);
activity.startActivity(intent);
activity.startActivityForResult(AppSettingsActivity.home(activity), REQUEST_CONFIG_CHANGES);
}
public void goToArchiveList() {
getFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.slide_from_end, R.anim.slide_to_start, R.anim.slide_from_start, R.anim.slide_to_end)

View File

@@ -18,12 +18,14 @@ package org.thoughtcrime.securesms;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
@@ -31,14 +33,14 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.app.ShareCompat;
import androidx.core.util.Pair;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.Fragment;
@@ -51,26 +53,29 @@ 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;
import org.thoughtcrime.securesms.mediapreview.MediaRailAdapter;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.sharing.ShareActivity;
import org.thoughtcrime.securesms.util.AttachmentUtil;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.FullscreenHelper;
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment;
import org.thoughtcrime.securesms.util.StorageUtil;
import java.util.HashMap;
import java.util.Locale;
@@ -86,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;
@@ -98,6 +103,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
public static final String HIDE_ALL_MEDIA_EXTRA = "came_from_all_media";
public static final String SHOW_THREAD_EXTRA = "show_thread";
public static final String SORTING_EXTRA = "sorting";
public static final String IS_VIDEO_GIF = "is_video_gif";
private ViewPager mediaPager;
private View detailsContainer;
@@ -110,6 +116,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
private String initialMediaType;
private long initialMediaSize;
private String initialCaption;
private boolean initialMediaIsVideoGif;
private boolean leftIsRecent;
private MediaPreviewViewModel viewModel;
private ViewPagerListener viewPagerListener;
@@ -119,6 +126,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
private boolean cameFromAllMedia;
private boolean showThread;
private MediaDatabase.Sorting sorting;
private FullscreenHelper fullscreenHelper;
private @Nullable Cursor cursor = null;
@@ -133,10 +141,17 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, attachment.getSize());
intent.putExtra(MediaPreviewActivity.CAPTION_EXTRA, attachment.getCaption());
intent.putExtra(MediaPreviewActivity.LEFT_IS_RECENT_EXTRA, leftIsRecent);
intent.setDataAndType(attachment.getDataUri(), mediaRecord.getContentType());
intent.putExtra(MediaPreviewActivity.IS_VIDEO_GIF, attachment.isVideoGif());
intent.setDataAndType(attachment.getUri(), mediaRecord.getContentType());
return intent;
}
@Override
protected void attachBaseContext(@NonNull Context newBase) {
getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);
super.attachBaseContext(newBase);
}
@SuppressWarnings("ConstantConditions")
@Override
protected void onCreate(Bundle bundle, boolean ready) {
@@ -147,10 +162,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
viewModel = ViewModelProviders.of(this).get(MediaPreviewViewModel.class);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
showSystemUI();
fullscreenHelper = new FullscreenHelper(this);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
@@ -196,7 +208,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
if (threadRecipient != null) {
if (mediaItem.outgoing || threadRecipient.isGroup()) {
if (threadRecipient.isLocalNumber()) {
if (threadRecipient.isSelf()) {
from = getString(R.string.note_to_self);
} else {
to = threadRecipient.getDisplayName(this);
@@ -261,6 +273,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
albumRail = findViewById(R.id.media_preview_album_rail);
albumRailAdapter = new MediaRailAdapter(GlideApp.with(this), this, false);
albumRail.setItemAnimator(null); // Or can crash when set to INVISIBLE while animating by FullscreenHelper https://issuetracker.google.com/issues/148720682
albumRail.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
albumRail.setAdapter(albumRailAdapter);
@@ -273,9 +286,9 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
anchorMarginsToBottomInsets(detailsContainer);
anchorMarginsToTopInsets(toolbarLayout);
fullscreenHelper.configureToolbarSpacer(findViewById(R.id.toolbar_cutout_spacer));
showAndHideWithSystemUI(getWindow(), detailsContainer, toolbarLayout);
fullscreenHelper.showAndHideWithSystemUI(getWindow(), detailsContainer, toolbarLayout);
}
private void initializeResources() {
@@ -286,12 +299,13 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
showThread = intent.getBooleanExtra(SHOW_THREAD_EXTRA, false);
sorting = MediaDatabase.Sorting.values()[intent.getIntExtra(SORTING_EXTRA, 0)];
initialMediaUri = intent.getData();
initialMediaType = intent.getType();
initialMediaSize = intent.getLongExtra(SIZE_EXTRA, 0);
initialCaption = intent.getStringExtra(CAPTION_EXTRA);
leftIsRecent = intent.getBooleanExtra(LEFT_IS_RECENT_EXTRA, false);
restartItem = -1;
initialMediaUri = intent.getData();
initialMediaType = intent.getType();
initialMediaSize = intent.getLongExtra(SIZE_EXTRA, 0);
initialCaption = intent.getStringExtra(CAPTION_EXTRA);
leftIsRecent = intent.getBooleanExtra(LEFT_IS_RECENT_EXTRA, false);
initialMediaIsVideoGif = intent.getBooleanExtra(IS_VIDEO_GIF, false);
restartItem = -1;
}
private void initializeObservers() {
@@ -344,7 +358,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
if (isMediaInDb()) {
LoaderManager.getInstance(this).restartLoader(0, null, this);
} else {
mediaPager.setAdapter(new SingleItemPagerAdapter(getSupportFragmentManager(), initialMediaUri, initialMediaType, initialMediaSize));
mediaPager.setAdapter(new SingleItemPagerAdapter(getSupportFragmentManager(), initialMediaUri, initialMediaType, initialMediaSize, initialMediaIsVideoGif));
if (initialCaption != null) {
detailsContainer.setVisibility(View.VISIBLE);
@@ -379,6 +393,27 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
}
}
private void share() {
MediaItem mediaItem = getCurrentMediaItem();
if (mediaItem != null) {
Uri publicUri = PartAuthority.getAttachmentPublicUri(mediaItem.uri);
String mimeType = Intent.normalizeMimeType(mediaItem.type);
Intent shareIntent = ShareCompat.IntentBuilder.from(this)
.setStream(publicUri)
.setType(mimeType)
.createChooserIntent()
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
startActivity(shareIntent);
} catch (ActivityNotFoundException e) {
Log.w(TAG, "No activity existed to share the media.", e);
Toast.makeText(this, R.string.MediaPreviewActivity_cant_find_an_app_able_to_share_this_media, Toast.LENGTH_LONG).show();
}
}
}
@SuppressWarnings("CodeBlock2Expr")
@SuppressLint("InlinedApi")
private void saveToDisk() {
@@ -386,21 +421,30 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
if (mediaItem != null) {
SaveAttachmentTask.showWarningDialog(this, (dialogInterface, i) -> {
if (StorageUtil.canWriteToMediaStore()) {
performSavetoDisk(mediaItem);
return;
}
Permissions.with(this)
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.ifNecessary()
.withPermanentDenialDialog(getString(R.string.MediaPreviewActivity_signal_needs_the_storage_permission_in_order_to_write_to_external_storage_but_it_has_been_permanently_denied))
.onAnyDenied(() -> Toast.makeText(this, R.string.MediaPreviewActivity_unable_to_write_to_external_storage_without_permission, Toast.LENGTH_LONG).show())
.onAllGranted(() -> {
SaveAttachmentTask saveTask = new SaveAttachmentTask(MediaPreviewActivity.this);
long saveDate = (mediaItem.date > 0) ? mediaItem.date : System.currentTimeMillis();
saveTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Attachment(mediaItem.uri, mediaItem.type, saveDate, null));
performSavetoDisk(mediaItem);
})
.execute();
});
}
}
private void performSavetoDisk(@NonNull MediaItem mediaItem) {
SaveAttachmentTask saveTask = new SaveAttachmentTask(MediaPreviewActivity.this);
long saveDate = (mediaItem.date > 0) ? mediaItem.date : System.currentTimeMillis();
saveTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Attachment(mediaItem.uri, mediaItem.type, saveDate, null));
}
@SuppressLint("StaticFieldLeak")
private void deleteMedia() {
MediaItem mediaItem = getCurrentMediaItem();
@@ -409,7 +453,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setIconAttribute(R.attr.dialog_alert_icon);
builder.setIcon(R.drawable.ic_warning);
builder.setTitle(R.string.MediaPreviewActivity_media_delete_confirmation_title);
builder.setMessage(R.string.MediaPreviewActivity_media_delete_confirmation_message);
builder.setCancelable(true);
@@ -431,36 +475,45 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
public boolean onCreateOptionsMenu(Menu menu) {
menu.clear();
MenuInflater inflater = this.getMenuInflater();
inflater.inflate(R.menu.media_preview, menu);
super.onCreateOptionsMenu(menu);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (!isMediaInDb()) {
menu.findItem(R.id.media_preview__overview).setVisible(false);
menu.findItem(R.id.delete).setVisible(false);
}
// Restricted to API26 because of MemoryFileUtil not supporting lower API levels well
menu.findItem(R.id.media_preview__share).setVisible(Build.VERSION.SDK_INT >= 26);
if (cameFromAllMedia) {
menu.findItem(R.id.media_preview__overview).setVisible(false);
}
super.onPrepareOptionsMenu(menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case R.id.media_preview__overview: showOverview(); return true;
case R.id.media_preview__forward: forward(); return true;
case R.id.save: saveToDisk(); return true;
case R.id.delete: deleteMedia(); return true;
case android.R.id.home: finish(); return true;
}
int itemId = item.getItemId();
if (itemId == R.id.media_preview__overview) { showOverview(); return true; }
if (itemId == R.id.media_preview__forward) { forward(); return true; }
if (itemId == R.id.media_preview__share) { share(); return true; }
if (itemId == R.id.save) { saveToDisk(); return true; }
if (itemId == R.id.delete) { deleteMedia(); return true; }
if (itemId == android.R.id.home) { finish(); return true; }
return false;
}
@@ -541,7 +594,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
@Override
public boolean singleTapOnMedia() {
toggleUiVisibility();
fullscreenHelper.toggleUiVisibility();
return true;
}
@@ -551,32 +604,6 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
finish();
}
private void toggleUiVisibility() {
int systemUiVisibility = getWindow().getDecorView().getSystemUiVisibility();
if ((systemUiVisibility & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0) {
showSystemUI();
} else {
hideSystemUI();
}
}
private void hideSystemUI() {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_IMMERSIVE |
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_FULLSCREEN );
}
private void showSystemUI() {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN );
}
private class ViewPagerListener extends ExtendedOnPageChangedListener {
@Override
@@ -609,21 +636,24 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
private static class SingleItemPagerAdapter extends FragmentStatePagerAdapter implements MediaItemAdapter {
private final Uri uri;
private final String mediaType;
private final long size;
private final Uri uri;
private final String mediaType;
private final long size;
private final boolean isVideoGif;
private MediaPreviewFragment mediaPreviewFragment;
SingleItemPagerAdapter(@NonNull FragmentManager fragmentManager,
@NonNull Uri uri,
@NonNull String mediaType,
long size)
long size,
boolean isVideoGif)
{
super(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
this.uri = uri;
this.mediaType = mediaType;
this.size = size;
this.uri = uri;
this.mediaType = mediaType;
this.size = size;
this.isVideoGif = isVideoGif;
}
@Override
@@ -634,7 +664,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
@NonNull
@Override
public Fragment getItem(int position) {
mediaPreviewFragment = MediaPreviewFragment.newInstance(uri, mediaType, size, true);
mediaPreviewFragment = MediaPreviewFragment.newInstance(uri, mediaType, size, true, isVideoGif);
return mediaPreviewFragment;
}
@@ -692,33 +722,6 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
});
}
private static void anchorMarginsToTopInsets(@NonNull View viewToAnchor) {
ViewCompat.setOnApplyWindowInsetsListener(viewToAnchor, (view, insets) -> {
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
layoutParams.setMargins(insets.getSystemWindowInsetLeft(),
insets.getSystemWindowInsetTop(),
insets.getSystemWindowInsetRight(),
layoutParams.bottomMargin);
view.setLayoutParams(layoutParams);
return insets;
});
}
private static void showAndHideWithSystemUI(@NonNull Window window, @NonNull View... views) {
window.getDecorView().setOnSystemUiVisibilityChangeListener(visibility -> {
boolean hide = (visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
for (View view : views) {
view.animate()
.alpha(hide ? 0 : 1)
.start();
}
});
}
private static class CursorPagerAdapter extends FragmentStatePagerAdapter implements MediaItemAdapter {
@SuppressLint("UseSparseArrays")
@@ -796,7 +799,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
return new MediaItem(Recipient.live(recipientId).get(),
Recipient.live(threadRecipientId).get(),
attachment,
Objects.requireNonNull(attachment.getDataUri()),
Objects.requireNonNull(attachment.getUri()),
mediaRecord.getContentType(),
mediaRecord.getDate(),
mediaRecord.isOutgoing());

View File

@@ -1,12 +1,14 @@
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;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.concurrent.TimeUnit;
public class MuteDialog extends AlertDialog {
@@ -29,7 +31,7 @@ public class MuteDialog extends AlertDialog {
}
public static void show(final Context context, final @NonNull MuteSelectionListener listener, @Nullable Runnable cancelListener) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(context);
builder.setTitle(R.string.MuteDialog_mute_notifications);
builder.setItems(R.array.mute_durations, new DialogInterface.OnClickListener() {
@Override
@@ -38,10 +40,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,15 @@ 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;
import org.whispersystems.libsignal.util.guava.Optional;
@@ -50,31 +49,33 @@ 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) {
super.onCreate(bundle, ready);
assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(R.string.NewConversationActivity__new_message);
}
@Override
public boolean onContactSelected(Optional<RecipientId> recipientId, String number) {
public boolean onBeforeContactSelected(Optional<RecipientId> recipientId, String number) {
if (recipientId.isPresent()) {
launch(Recipient.resolved(recipientId.get()));
} else {
Log.i(TAG, "[onContactSelected] Maybe creating a new recipient.");
if (FeatureFlags.cds() && NetworkConstraint.isMet(this)) {
Log.i(TAG, "[onContactSelected] CDS enabled. Doing contact refresh.");
if (TextSecurePreferences.isPushRegistered(this) && NetworkConstraint.isMet(this)) {
Log.i(TAG, "[onContactSelected] Doing contact refresh.");
AlertDialog progress = SimpleProgressDialog.show(this);
SimpleTask.run(getLifecycle(), () -> {
Recipient resolved = Recipient.external(this, number);
if (!resolved.isRegistered()) {
Log.i(TAG, "[onContactSelected] Not registered. Doing a directory refresh.");
if (!resolved.isRegistered() || !resolved.hasUuid()) {
Log.i(TAG, "[onContactSelected] Not registered or no UUID. Doing a directory refresh.");
try {
DirectoryHelper.refreshDirectoryFor(this, resolved, false);
resolved = Recipient.resolved(resolved.getId());
@@ -96,16 +97,18 @@ public class NewConversationActivity extends ContactSelectionActivity
return true;
}
@Override
public void onSelectionChanged() {
}
private void launch(Recipient recipient) {
Intent intent = new Intent(this, ConversationActivity.class);
intent.putExtra(ConversationActivity.RECIPIENT_EXTRA, recipient.getId());
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);
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, existingThread);
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
startActivity(intent);
finish();
}
@@ -138,11 +141,11 @@ public class NewConversationActivity extends ContactSelectionActivity
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
public boolean onCreateOptionsMenu(Menu menu) {
menu.clear();
getMenuInflater().inflate(R.menu.new_conversation_activity, menu);
super.onPrepareOptionsMenu(menu);
super.onCreateOptionsMenu(menu);
return true;
}

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